commit 12da995a99d38c25afb7c4df6b21683877d496a1 Author: J Carreira Date: Thu Feb 20 20:17:37 2014 +0000 Init repo from r216 of svn repo (before mess things up) diff --git a/CHANGES.TXT b/CHANGES.TXT new file mode 100644 index 0000000..2e6d934 --- /dev/null +++ b/CHANGES.TXT @@ -0,0 +1,1562 @@ +Changes in Version JM 18.3 (since JM 18.2) +------------------------------------------ +- encoder: allow coding with the same GOP/reference picture settings like HM5 (BiL) +- add HM-like example configurations (BiL) + + +Changes in Version JM 18.2 (since JM 18.1) +------------------------------------------ +- encoder: fix MVC interlace encoder/decoder mismatch (AT/YHe/PeP) +- encoder: reference picture list performance fixes (AT/YHe) +- decoder: fix deblocking filter strength for SP frames (KS/AT) + + +Changes in Version JM 18.1 (since JM 18.0) +------------------------------------------ +- encoder/decoder: Direct Mode updates (YHe/KS) +- encoder/decoder: MVC (Stereo High Profile) Interlace Bug fixes (PeP/YHe) +- encoder: Coding structure updates and bug fixes (AL/AT) +- encoder: On the Fly Interpolation for ME/MC (JlT/AL/AT) +- encoder/decoder: Architecture and various software cleanups and naming conventions (KS/AT) +- encoder/decoder: DPB code updates (AT/PeP) +- decoder: Predictive High 444 bug fixes (KS/AT/JjC/JGG) + +Changes in Version JM 18.0 (since JM 17.2) +------------------------------------------ +- MVC decoded picture buffer separation (YHe/AT) +- move MVC parameters into a separate config file (KS) +- add MS Visual Studio 2010 work spaces (AT/KS) +- bug fixes (see bug tracker) + +Changes in Version JM 17.2 (since JM 17.1) +------------------------------------------ +- encoder: fix memory leak for picture based RD-decision (YY) +- rtpdump: fix build in old workspaces (KS) + +Changes in Version JM 17.1 (since JM 17.0) +------------------------------------------ +- decoder: fix delta_pic_order_cnt[0] in IDR frames (KS, bug #57) +- decoder: Direct mode fixes (YHE) +- encoder/decoder: various cleanups and bug fixes (AT/YHE) +- encoder/decoder: rewrite of deblocking functions (AT) +- decoder : rewrite of intra prediction functions (AT) +- encoder/decoder: MVC bug fixes (PeP/AL) +- encoder/decoder: Frame Packing SEI Message (AL) +- decoder: Minor CABAC updates (AT) +- encoder/decoder: Update work spaces for VS 2008 and XCode with x64 and OPENMP support (KS) +- encoder/decoder: Update Makefiles for OPENMP support (KS) +- encoder: avoid crashes by prohibiting incompatible tool combinations (KS/YHE) + +Changes in Version JM 17.0 (since JM 16.2) +------------------------------------------ +- encoder: TIFF input support (LZL) +- encoder: Reorganization/Generalization of RDPictureDecision (YY) +- encoder: Weighted Prediction bug fixes (YY) +- encoder: Hierarchical Coding structure bug fixes (AL) +- encoder: Architecture changes/bug fixes for error resilient video coding (ZC, PeP) +- encoder/decoder: Codec architecture reorganization/structure renaming (AT, AL, CV, PeP, YHe) +- encoder/decoder: lossless coding bug fixes to align code with the spec, and various encoder/decoder mismatch bug fixes(LZ/YY) +- encoder/decoder: initial MVC extension, i.e. stereo high profile, support (CL/SWi/TN) +- encoder/decoder: various architectural improvements/bug fixes for stereo high profile support (AT/AL/PeP/YHe) +- encoder/decoder: deblocking filter reorganization/rewrite (AT/YHe/CV) +- decoder: Multislice handling support (YHe) +- encoder/decoder: motion information handling reorganization (AT/YHe) +- encoder/decoder: direct mode handling reorganization/rewrite (YHe/AT) +- encoder/decoder: 4:2:2/4:4:4 profile support bug fixes (YHe) +- encoder/decoder: Interlace handling bug fixes (YHe, AT) +- encoder/decoder: intra prediction process rewrite (AT, CV) +- decoder: Motion Compensation operation rewrite (CV/AT/YHe) + +Changes in Version JM 16.2 (since JM 16.1) +------------------------------------------ +- encoder: changes necessary for low delay anchor generation (DHo) + see doc/jm16.2_changes.doc for details +- encoder: update encoder.cfg for high performance based on VCEG common coding condition (KS) + +Changes in Version JM 16.1 (since JM 16.0) +------------------------------------------ +- encoder: check slice group parameter size for slice_group_map_type equal to 2 (KS) +- encoder/decoder: SP/SI bug fixes (YL/AL) +- encoder: Integer distortion cost calculation (YHe/AT) +- encoder: Updated and Improved Sequence/GOP design architecture (AL) +- encoder/decoder: Various cleanups/bugfixes (AT) +- encoder/decoder: Deblocking speedups (AT) +- encoder/decoder: add version information command line switches (KS) +- encoder: NAL unit priority bug fixes (KSw) +- encoder: RDOQ bug fixes (YY) +- encoder: Motion estimation and mode decision bug fixes (YHe/AT) +- decoder: fox cropping for IMGPEL equal to 0 (KS) + +Changes in Version JM 16.0 (since JM 15.1) +------------------------------------------ +- encoder: Early termination in various distortion computation functions (AT) +- encoder/decoder: Various speed optimizations/restructuring/cleanups (AT) +- encoder/decoder: removal of almost all global variables (AT) +- encoder/decoder: Severe restructuring and merging of Various encoder and decoder functions in lcommon (AT) +- decoder: Deblocking bug fix in the presence of errors (TB/AT) +- encoder: Rate Control Improvements/Reentrancy (AL) +- encoder: RDOQ/Mode decision bug fixes (YY) +- encoder: Motion Estimation/Mode decision bug fixes (YHe) +- encoder: Motion Estimation reorganization/cleanups (AT) +- encoder/decoder: doxygen cleanups (YHe/AT) +- encoder/decoder: add workspaces for Visual Studio 2009 (Windows) and Xcode (MacOS) + + +Changes in Version JM 15.1 (since JM 15.0) +------------------------------------------ +- encoder/decoder: Redundant picture bug fixes (KS) +- encoder: fix config limit type for IntraProfile (KS, bug id #153) +- decoder: fix copy and paste bug in pps_is_equal() (KS, bug id #157) +- decoder: cleanups to intra prediction functions (AT) +- decoder: 4:4:4 bug fix (AT) +- encoder/decoder: Various bug fixes/cleanups (AT/KS) + +Changes in Version JM 15.0 (since JM 14.2) +------------------------------------------ +- encoder: Various bug fixes relating to MBAFF and High 444P profile (EM) +- encoder: Adaptive Rounding reorganization and bug fixes(EM) +- encoder: Motion Estimation reorganization (AT) +- encoder: Various bugfixes related to 8x8 transform and submacroblock partitions (AT) +- encoder: Extension to support VLC codes > 32 bits (AL) +- encoder: RC bug fixes (ASe) +- encoder: SEI/AU support & cleanups (AL) +- encoder: Various bug fixes and cleanups, including bipred ME (AT) +- encoder: Weighted Prediction offset computation using Motion Compensation (PC, MK, YY) +- encoder: support of explicit sequence information functionality (AT/KS) +- encoder: support of separate & interleaved raw video files (AT) +- encoder: don't allow GenerateMultiplePPS in baseline profile (KS) +- encoder: encoder support of some ANNEX A level limits (AT/KS) +- encoder/decoder: Lossless encoding bug fixes (AT) +- encoder/decoder: memory alloc/free speedups (AT) +- encoder/decoder: VLC speedups (JaB/AT) +- encoder/decoder: don't access uninitialized memory in cabac.c (PL/KS) +- encoder/decoder: various cleanups and bug fixes (KS/AT) +- decoder: Support for 64 bit bitstream I/O (AT/KS) +- decoder: Severe code reorganization and various bug fixes, some relating to High 444P (AT) + +Changes in Version JM 14.2 (since JM 14.1) +------------------------------------------ +- encoder: fix cabac_zero_word calculation (KS) +- encoder: bipredictive ME bug fixes (EM/AT) +- encoder: MBAFF qp bug fix (AT) +- encoder: Statistics collection rewrite (AT) +- encoder: RDOQ CAVLC support & improvements (PC/YY/MK/LL/AT) +- encoder: fix range of DFDisable* parameters (KS) +- decoder: Fix copy and paste error in sei.c (KS) +- decoder: Fix syntax of full frame freeze SEI message (KS) +- encoder/decoder: convert time measurement system calls to be more consistent and don't use "obsolete" functions (KS) + +Changes in Version JM 14.1 (since JM 14.0) +------------------------------------------ +- encoder: fixes in lossless coding (KHH) +- encoder: Improved MC precision using Reordering & Weighed Prediction (AL, AT) +- encoder: Weighted Prediction Extensions (AT, AL) +- encoder: MS-SSIM distortion computation (PeP) +- encoder: Rewrite of Error Resilient RDO (PeP/AT) +- encoder: SSIM distortion computation (ZHL/WK/AT) +- encoder: RGB color space distortion computation (WK/AT) +- encoder: Distortion/Statistics functionality cleanups (AT/WK) +- encoder: RDOQ and Quantization cleanups (LL/AT) +- encoder: RC cleanups (AT) +- encoder: Adaptive Rounding Support for Low Complexity RDO (EM) +- encoder: Multipass RD coding bug fix for PicAFF (AL) +- decoder: Motion vector limit checking (LlL) +- encoder/decoder: Various code optimizations (AT) +- encoder/decoder: Various cleanups /reorganizations (AT) +- decoder: SP/SI slice decoder fixes (AT) +- encoder: fix 4:0:0 encoder bit depth initialization (KS) +- encoder: use SPS id parameter in GenerateSequenceParameterSet (KS) +- encoder: fix number of bits calculation for pic aff with slices/DP (CS) + + +Changes in Version JM 14.0 (since JM 13.2) +------------------------------------------ +- encoder: Bipredictive ME bug fixes (AT) +- encoder: Intra mode decision reorganization (LL/AT) +- encoder: Quantization/transform process reorganization (AT) +- encoder: Trellis based quantization (VCEG-AH21) (PC/YY/MK/LL/AT) +- encoder: WP Cleanups (AT) +- encoder: Lossless Coding Cleanups / Bug fixes (AT) +- encoder: Profile/Level Conformance code cleanups (AT) +- encoder: fix trace file for data partitioning (KS) +- encoder: fix encoding for picture aff (KS) +- encoder: fix memory allocations with num_ref_frames=0 (KS) +- encoder: fix rate control config error message (AL) +- encoder: fix 4:2:2 chroma transform (KS) +- encoder: fix 4:2:2 chroma scaling matrices (SSe) +- encoder: improve profile restrictions (KS) +- decoder: fix 4:2:2 decoding (SWi) +- decoder: allow intra-only deblocking filter configuration in decoder.cfg (KS) +- decoder: add quantizer initialization for data partitioning (PL) +- encoder/decoder: memory assignment reorganization (AT) +- encoder/decoder: deblocking cleanups (AT) + + +Changes in Version JM 13.2 (since JM 13.1) +------------------------------------------ +- encoder: 4:4:4 chroma mismatch fix (4x4 intra) (KS) +- encoder: 4:2:2 chroma mismatch fix (THi) +- encoder: fixes for negative QP (AT) +- encoder: fix trace file and average qp calculation for slices with fixed byte size (AL) +- encoder/decoder: various 4:4:4 fixes (HY) +- decoder: fix temporal direct mode (KS) +- decoder: implement I_PCM for more than 8bpp (KS) + + +Changes in Version JM 13.1 (since JM 13.0) +------------------------------------------ +- encoder: 4:4:4 performance fix (4x4 intra) (KS) +- encoder: always use ChromaMEEnable for 4:4:4 common mode (KS) +- encoder: 4:2:2 transform fix (AT) +- decoder: fix slice_group_id allocation (KS) +- encoder/decoder: fix inline functions for compilers without c99 support (KS) +- encoder/decoder: makefile updates (LW/KS) +- encoder/decoder: 4:0:0 fixes (KS) +- encoder/decoder: further cleanups (AT/KS) + + +Changes in Version JM 13.0 (since JM 12.4) +------------------------------------------ +Professional Profiles: +- encoder/decoder: 4:4:4 combined color coding mode +- encoder/decoder: lossless coding + +- encoder/decoder: remove MS Visual Studio 6 workspaces (KS) +- encoder/decoder: various optimizations (AT/AL) +- encoder/decoder: fix mbuffer.c copy and paste error (KS) +- decoder: allow loss of single partitions (DA/KS) + Note: some loss pattern will require usage of RTP file. +- decoder: indicate wrong emulation prevention (ZH) +- decoder: make memory allocation for slice_group_id dynamic (KS) + +- add simple tool for pseudo-random RTP packet loss (KS) + + +Changes in Version JM 12.4 (since JM 12.3) +------------------------------------------ +Professional Profiles: +- encoder/decoder: 4:4:4 independent mode quantization matrix bug fix (SSe) +- encoder: 4:4:4 independent config file update (SSe) + + +Changes in Version JM 12.3 (since JM 12.2) +------------------------------------------ +Professional Profiles: +- encoder/decoder: 4:4:4 independent mode (SSe) + +- encoder/decoder: add top level Makefile (LW) +- encoder: initialize lprc->AveWb (AL) +- encoder: restrict pel values in simulated decoder (CS) +- encoder: closed IDR GOP support (AT) +- encoder: delayed IDR GOP support (AT) +- encoder: rate control extension for adaptive rounding (AT) +- encoder: chroma ME bug fix (AT) +- encoder: RC bug fixes (AL) +- encoder: top/bottom field slice type decoder output consideration (AT) +- encoder: adjustments to frame_num consideration (AL/AT) +- encoder: removal of secondGOP concept (AT) + + +Changes in Version JM 12.2 (since JM 12.1) +------------------------------------------ + +Professional Profiles: +- encoder: 420/422 intra only coding (SWi) +- encoder/decoder: post-filter hint SEI (SWi) +- encoder/decoder: tone-mapping SEI (ASe) + +- encoder/decoder: cleanup and speed improvements (AT/AL) +- encoder/decoder: deblocking filter speedup (AT) +- encoder/decoder: CAVLC entropy coder speedup (AT) +- encoder/decoder: CABAC arithmetical coder speedup [JVT-U084] (GM/DM/KS) +- encoder: VUI support (AL) +- encoder: further rate control fixes (AL) +- encoder: add error checks for slice group config files (KS) +- encoder: fix I_PCM encoding with CABAC (KS) +- decoder: Motion Compensation speedup (AT) + + +Changes in Version JM 12.1 (since JM 12.0) +------------------------------------------ +- encoder: fix example configuration files (KS/AT) +- encoder: make direct_8x8_inference_flag=1 default (KS) +- decoder: fix compilation with trace enabled (KS) +- encoder/decoder: fix for shift_right_round functions on 64-bit machines (AT) +- encoder/decoder: predict_nnz functions (YDh) +- encoder/decoder: cleanups (KS/AT/AL) + + +Changes in Version JM 12.0 (since JM 11.0) +------------------------------------------ +- encoder: Context Adaptive Lagrange Multiplier [JVT-T046] (JZ) +- encoder: Severe Rate Control reorganization and debugging. Support for interlace coding modes and hierarchical/multi-pass encoding (AL/AT) +- encoder: Lagrangian Cleanups based on "layered" motion estimation (YD/AT) +- encoder: reorganization/unification of motion estimation and compensation functions (AL/AT) +- encoder: Revised Luma/Chroma interpolation (AL/AT) +- encoder: Chroma motion estimation consideration (AL/AT) +- encoder: Separation of intra chroma mode decision and RDO (AL/AT) +- encoder: split up macroblock mode decision (AT) +- encoder: Bug correction relating to 64bit type statistics output (AT) +- encoder: Simple "text" SEI message generation and basic support for VUI parameters (to be extended) (AT) +- encoder: reorganization of adaptive quantization and support of 4:2:2 and 4:4:4 formats (AT) +- encoder: resolved 8x8 intra prediction + MB-AFF bug (AT) +- encoder: resolved illegal WP value vs Eq.8-294 bug (AT) +- encoder: subpel EPZS bug resolutions and addition of bipredictive subpel EPZS (AT) +- encoder: resolve bug with IDR pictures + RDPictureDecision (AT) +- encoder: fix SP/SI memory leaks (AT) +- encoder: bidirectional search for simplified fast ME (BY) +- encoder: fix start code prefix length (SN) +- decoder: update of decoder input parameters (AT) +- encoder: fix incorrect usage of 8x8 transform with direct mode and non-rd-opt coding (DH) +- encoder: fix wrong pointer dereferences (KS/SH) +- encoder: fix SP/SI file i/o issue (ES) +- encoder: allocate less stream buffer memory for slice modes 1 and 2 (KS) +- encoder: fix bit statistics for slice mode 2 (enricomasala) +- decoder: trace file format cleanup (KS) +- decoder: fix psnr calculation for field with IDR (SN) +- decoder: error concealment - conceal intra blocks from decoded blocks first (KS) +- decoder: decoder cleanups and optimizations (AT/KS) +- encoder/decoder: various small code cleanups (AT) +- encoder/decoder: correction of fix for predict_nnz with constrained intra and data partitioning (CK/KS) +- encoder/decoder: fix memory leaks mostly in error paths (KS) +- encoder/decoder: add MS Visual Studio 2005 project files (KS) + + +Changes in Version JM 11.0 (since JM 10.2) +------------------------------------------ +- encoder: FME updated [JVT-R085 and JVT-Q088] (XX) +- encoder: I_PCM support for CABAC (SL) +- encoder: fix crash with large number of frames (AT) +- encoder: disable writing if no yuv output file is specified (AT) +- encoder: disallow POC reorder with field coding (AT) +- encoder: rename Pyramid->Hierarchy (AT/KS) +- encoder: remove remainings of former redundant slice implementation (KS) +- encoder: fix IPCM encoding with rate control (AT/HZ) +- encoder: Intra 8x8 prediction mode write cleanup (KS) +- encoder: Avoid I_PCM trace data during rdopt (KS) +- encoder: LA-RDO bug fix (CZ) +- encoder: disallow DP+CABAC (KS) +- encoder: SP pictures cannot be IDR (KS) +- encoder: fix overwritten line buffer in fast ME (KS) +- encoder: allow picture frame/field encoding of non-reference pictures when DPB is full of reference pictures (AT) +- encoder: enable EPZSSubPelME (AT) +- decoder: start decoding after recovery point SEI (BL) [JVT-R017] +- decoder: remove size restriction when parsing reserved SEI (KS/MW) +- decoder: fix weighted prediction initializations (AT) +- decoder: fix Motion-constrained slice group set SEI message reading (AT) +- decoder: fix dec_picture->slice_id memory leak (KS) +- decoder: fix SEI MMCO list free (RB) +- decoder: make vlc tables static const (SF) +- decoder: fix for poc_order_cnt_type=2 (JXi) +- decoder: fix field combine/split for different reference picture size per slice (KS/AT) +- encoder/decoder: Redundant picture for error resilience [JVT-R058] (CZ) +- encoder/decoder: don't write empty DP NALUs and handle this at the decoder (KS) +- encoder/decoder: fix predict_nnz for constrained intra and data partitioning (SMy/KS) +- encoder/decoder: fix cabac context initilization (DM) +- encoder/decoder: fix various chroma bitdepth related issues (KS/YC) + + +Changes in Version JM 10.2 (since JM 10.1) +------------------------------------------ +- encoder: fast subpixel motion estimation for EPZS [JVT-Q079] (AT) +- encoder: SI picture implementation (ES) +- encoder: lossless coding fixes (SSu) +- encoder: add warning for bit/mb limit (AT) +- encoder: enable I_PCM (for VLC coding) by default (KS) +- encoder: fix non-rd-optimized mode decision (AT) +- encoder: fix memory allocation in search module (TP) +- encoder: fix bitrate output (PP) +- encoder: fix data partitioning with constrained intra prediction (KS) +- encoder: fix bidirectional prediction with RDOpt=2 (AT) +- encoder: fix MBAFF with constrained intra prediction (KS) +- encoder: fix MBAFF with slice mode 2 and restrict slice mode 1 (KS) +- decoder: SI/SP picture updates (ES) +- decoder: add check for QP range (MT) +- decoder: fix/add SEI parsing: pan/scan, timing, stereo, deblocking filter, film grain (MT) +- decoder: fix dummy croma component output for bit depth > 8 (KS) +- decoder: work around problems in error concealment (KS) +- decoder: fix idr psnr output (SB) +- encoder/decoder: update RTP format (SW) + + +Changes in Version JM 10.1 (since JM 10.0) +------------------------------------------ +- encoder/decoder: apply chroma motion vector adjustment only for 4:2:0 (SZ/KS) +- encoder: write vlc run if last mb is skipped () + + +Changes in Version JM 10.0 (since JM 9.8) +----------------------------------------- +- encoder: simplified UMHexagonS fast motion estimation [JVT-P021] (XY) +- encoder: EPZS fast motion estimation [JVT-P026] (AT) +- encoder: fix reference picture reordering problem (AT) +- encoder: disallow (log2_max_frame_num_minus4 == 0 && input->num_ref_frames == 16) (AT) +- decoder: error concealment for lost pictures [JVT-P072] (SB) +- decoder: fix long-term reference picture reordering problem (KS) +- decoder: allow differing nal_ref_idc (!=0) in same AU (JSa) +- fix example config files (KS) + + +Changes for Version JM 9.8 to JM 9.7 +------------------------------------ +- encoder/decoder: fix monochrome pred_weight_table syntax (MT) +- encoder/decoder: fix cropping_flag usage (KS) +- encoder: fix frame_num for reference B pictures (AT) + + +Changes for Version JM 9.7 to JM 9.6 +------------------------------------ +- encoder: revert zero motion vector change in low complexity mode (YH) +- encoder: fix 4:2:2 encoding (KS) +- encoder: fix mb_qp_delta CABAC context selection (KS) +- encoder: weighted prediction fix +- encoder: fix frame_poc setting (AS) +- decoder: fix direct mode rare case problem (AS) +- decoder: fix pic_struct parsing in timing SEI +- decoder: fix parsing of filler data SEI +- encoder/decoder: fix deblocking filter strength calculation for negative POC (AS/KS) +- encoder/decoder: fix frame_poc setting (AS) +- encoder/decoder: fix SE_TRANSFORM_SIZE usage (KS) +- encoder: updates to explicit hierarchical coding and picture coding structures (AT) +- encoder: update/enhance control of log2_max_pic_order_cnt_lsb_minus4 and log2_max_frame_num_minus4 (AT) +- encoder: addition of computation of Sequence Level PSNR statistics (AT) +- encoder: fix frame_num setting for pyramid coding (AT) +- encoder/decoder: fix invalid line in deblocking filter (PL) + + +Changes for Version JM 9.6 to JM 9.5 +------------------------------------ +- encoder: FME fixes (WF) +- encoder: fixes for I_PCM and encoder output (SN) +- encoder: fix rounding for CABAC stuffing +- encoder: lossless mode fixes (WK) +- encoder: increase maximum slice size (WK/KS) +- add platform specific notes to readme.txt + + +Changes for Version JM 9.5 to JM 9.4 +------------------------------------ +- encoder: open GOP support (AT) +- encoder: I_PCM encoding/decoding for CAVLC (AT) +- encoder: I_PCM decoding for non-4:2:0 and CAVLC >8bit (AT) +- encoder: fix encoder/decoder mismatch for non-rd-opt coding (AT) +- encoder: fix crash with bi-predictive search (AT) +- encoder: further speed optimization (AT) +- encoder: fix mismatch in low complexity mode (YH/AT) +- encoder: fix zero motion vector in low complexity mode (YH) +- encoder: fix 8:9:9 bit support (WK) +- encoder: FME improvements (WF) +- encoder/decoder: fix RCT Cb/Cr order (WK) + + +Changes for Version JM 9.4 to JM 9.3 +------------------------------------ +- encoder: fast mode implementation (BJ) +- encoder: FME update (WF) +- encoder: adaptive quantization rounding offset (GS/SSu/AT) +- encoder: restructure encode_one_macroblock (AT) +- encoder: weighted prediction fix (AT) +- encoder: fix reported bit rate with LastFrameNumber parameter (AT) +- encoder: fix cost initialization for Transform8x8Mode=2 (SeS) +- encoder: restrict motion vector size (AT) +- encoder: fix rate control/non-rd-opt mismatch (AT) +- encoder: cleanups (AT) +- encoder: remove memory leak and clean up PPS usage (KS) +- encoder: fix CABAC zero word calculation (KS) +- decoder: fix POC mode 0 calculation (XI) +- decoder: fix timing SEI parsing (IP) +- decoder: fix dangling field output (KS) +- decoder: fix VLC trace output (MT) +- encoder/decoder: large performance and memory usage improvements (AT/KS) +- encoder/decoder: fix CABAC CBP_block_bit (VG) +- encoder/decoder: clean up and fix usage of skip_flag (KS/AM) +- encoder/decoder: implement lossless coding for non 4:4:4 cases (SSu) + + +Changes for Version JM 9.3 to JM 9.2 +------------------------------------ +- encoder: Bi predictive ME (AT) +- encoder: encoder parameter tuning (AT) +- encoder: fix allocation in error concealment (SM) +- encoder: fix allocation in pyramid code (AT) +- encoder: fix qp_const_422 assignment (SKa) +- encoder: fix padding for automatically added borders (SKa) +- encoder: support multiple PPS (AT) +- encoder: picture RD-decision (AT) +- encoder: rate-control fix (SM) +- encoder: restrict num_ref_frames to MaxDpbSize (ZH/KS) +- encoder: allocate rate control memory depending on frame size (KS) +- decoder: open trace file only once (AT) +- decoder: remove duplicate initialization of error states (MA) +- decoder: fix timing SEI parsing (PW/KS) +- decoder: fix CABAC SI context selection (DM/KS) +- encoder/decoder: fix neighboring of TotalCoeff in CAVLC (KS/WC) +- encoder/decoder: fix PSNR calculation if cropping is enabled (KS) + + +Changes for Version JM 9.2 to JM 9.1 +------------------------------------ +- encoder: fix possible integer overflow in quantization offsets (SN/AT) +- encoder: fix I_PCM trace (SN) +- encoder: restructure code (KS) +- unixprep.sh: also convert config files (KS) + + +Changes for Version JM 9.1 to JM 9.0 +------------------------------------ +- encoder: RCT: Enabling inter mode selection (WK) +- encoder: RCT: Correcting I16 mode selection (WK) +- encoder: fix YUV header seek problem (PL) +- encoder: reduce memory usage (KS) +- encoder: remove assert in RC (KS) +- encoder: fix qpBSoffset usage (AT) +- encoder: fix stored B-pictures (KS) +- encoder: fix qp change (AT) +- encoder: fix direct mode selection (KS) +- encoder: fix wrong memory allocation in FastME code (KS) +- encoder: fix IDR encoding (LP/SKa/AT) +- encoder: fix QMatrix config file reading (KS) +- encoder: automatically add borders for picture sizes that are not multiple of 16 (KS) +- encoder: default config parameter initialization (AT) +- encoder: add checks for minimum and maximun values for each config parameter (AT) +- encoder: support for explicit lagrangian parameters (AT) +- encoder: support for explicit rounding offset parameters (AT) +- decoder: allow 4:2:0 file format for monochrome streams (LW/KS) +- decoder: fix VLC coeff reading (WZ) +- decoder: fix second chroma qp offset (TS/KS) +- decoder: fix VUI syntax (SK) +- decoder: new command line interface (AT) +- encoder/decoder: RCT: Correcting lossless coding/decoding (WK) +- encoder/decoder: fix file reading/writing for non-Intel architectures (KS) +- encoder/decoder: Fix YUV 4:0:0 output (SG) +- encoder/decoder: Fix prediction weight calculations (AT) + + +Changes for Version JM 9.0 to JM 8.6 +------------------------------------ + +New Features: +- import FRExt branch (KS) +- encoder: pyramid encoding structure (AT) +- encoder/decoder: YUV 4:0:0 support (VG) +- encoder: thresholding control (AT) + +Fixes/Upates: +- encoder: clean up includes (KS) +- encoder: increase maximum file name length (KS) +- encoder: fix failed merge of temporal direct fix (LP) +- encoder: fix RCT enc/dec mismatch (WK) +- encoder: fix for CAVLC neighbouring total coeff (for RDopt) (SN) +- encoder: fix for CAVLC level limit for small QP (SN) +- encoder: fix memory leaks (CS/KS) +- encoder: disallow RDOptimazation=2 (KS) +- encoder: improve parameter names(AT) +- encoder: fix rate control diff calculation (SM) +- decoder: fix QP output (AT) +- decoder: fix paired field output for increased bit depth (KS) +- decoder: fix img->quad allocation (KS) +- decoder: fix RGB file output (KS) +- decoder: don't crash on PicTiming SEI when no SPS is active (KS) +- encoder/decoder: fix gcc compiler warnings (KS) +- encoder/decoder: fix inverse DC transform (WZ/KS) +- encoder/decoder: reduce memory usage by making imgpel "unsinged short" (KS) + + +Changes for Version JM 8.6 to JM 8.5 +------------------------------------ +- encoder: fix command line checking order (KS) +- encoder: fix coded_frame flag (KS) +- encoder: fix skip mode mb pair problem (KS) +- decoder: fix macroblock counter (KS) +- decoder: fix output field pairing (KS) +- decoder: fix POC previous frame num on MMCO=5(BH) +- decoder: fix max num ref frames in poc cycle +- decoder: allow Annex B leading_zero_8bits and trailing_zero_8bits (ZH) +- decoder: fix SI decoding (MWa) +- encoder/decoder: fix dpb size (KS) +- encoder/decoder: hopefully work around VS compiler optimization bug (KS) +- encoder/decoder: remove a number of gcc warnings (KS) + + +Changes for Version JM 8.5 to JM 8.4 +------------------------------------ +- encoder: fix wrong direct mode selection for non-rd-optimized encoding (KS) +- decoder: fix RPLR (KS) +- encoder: fix rate-control for non-rd-optimized encoding (SM/KS) +- encoder: fix POC mode 1 for stored B pictures (KS) +- encoder: fix MB AFF encoder/decoder mismatch (KS) +- encoder: fix list 1 reference index selection (SN) +- encoder: fix IDR pictures and wrapping around frame_num (TK/KS) +- encoder: fix log2_max_frame_num_minus4 and log2_max_pic_order_cnt_lsb_minus4 (AT) +- encoder/decoder: align chroma sample interpolation to standard text (no real bug, only cleanup) (ZH/KS) + + +Changes for Version JM 8.4 to JM 8.3 +------------------------------------ +- encoder: fix encoder merge bug (AT) +- encoder: count parameter set bits (AT) +- decoder: spatial direct long-term support (KS) +- decoder: fix colocation problem (KS) +- decoder: fix SPS/PPS changes (KS) +- decoder: fix reordering with multiple slices (KS) +- decoder: allow paired output of unpaired fields (KS) +- decoder: fix POC on MMCO=5 (KS) +- decoder: fix picture unmarking problem (KS) +- decoder: SPS activation on buffering SEI (KS) +- decoder: weighted prediction typo (AT) +- decoder: fix CeilLog2 function (KS) + + +Changes for Version JM 8.3 to JM 8.2 +------------------------------------ +- encoder: fast motion estimation fixes und cleanup (WF) +- decoder: fix for SP decoding (ES) +- encoder/decoder: direct mode cleanup and fixes (AT) +- decoder: POC cleanup and fixes (AT) +- encoder: set log2_max_frame_num_minus4 dynamically (AT) +- decoder: fix dangling fields (KS) +- encoder/decoder: fix mismatch in B-pictures with RDOptimization=0 (KS) +- encoder/decoder: fix redundant_pic_cnt syntax element type (KS) +- encoder: fix num_slice_groups_minus1>0 bug (KS) +- decoder: fix field mmco bugs and (KS) +- decoder: fix initial reference picture list generation with long-term pictures (KS) +- decoder: fix new picture detection (KS) +- decoder: fix weighted prediction (KS/AS) +- encoder/decoder: fix max PPS id (KS) +- decoder: remove redundant variables (KS) +- decoder: re-enable non-normative error concealment for non mb-aff (KS/THi) +- decoder: several smaller fixes (KS) + + +Changes for Version JM 8.2 to JM 8.1a +------------------------------------- +- encoder: merge FMO (DW) +- encoder/decoder: add error/warning if DPB size is zero at specified level (KS) +- fix unixprep.sh script for Solaris /bin/sh (DD) + + +Changes for Version JM 8.1a to JM 8.1 +------------------------------------- +- encoder/decoder: fix bug in constrained intra prediction fix (KS) +- encoder/decoder: fix version number typo (KS) + + +Changes for Version JM 8.1 to JM 8.0 +------------------------------------ +- decoder: fix I_PCM decoding for field macroblocks (AS) +- encoder: rate control fix (SM) +- encoder/decoder: fix max DPB size for level 5.0 (KS) +- encoder/decoder: fix constrained intra prediction left neighbour (KS) +- decoder: fix crash on SPS activation in SEI (KS) +- encoder/decoder: documentation updates / remove encodeiff.h (KS) +- encoder: add basic profile checks (KS) + + +Changes for Version JM 8.0 to JM 7.6 +------------------------------------ +- encoder/decoder: SP filter strength (KS) +- decoder: fix decoder snr calculation for streams that contain idr pictures (AT) +- decoder: increase NAL unit buffer size (KS) +- encoder: further statistics fixes (AW) +- encoder: fix wrong LumaPrediction4x4 call (AW) +- encoder: fix reference index writing for MB AFF with one reference frame (AW) +- decoder: fix bottom field first decoding (KS) +- encoder: add profile and level idc to config file (KS) +- encoder/decoder: determine DPB size depending on level (KS) +- encoder/deocder: fix field pairing (KS) +- encoder/deocder: fix memory allocation for reference picture list (KS) +- encoder: decrease list0 size for b slices (KS) +- encoder: make FME a config file option (TK) +- encoder: add -h help option (AT) +- encoder/decoder: fix writing of unpaired field (ZY) +- decoder: fix currMB calculation in i_pcm reading (ZY) +- decoder: set ref_pic_num for each slice (KS/AS) +- decoder: disable deblocking filter P_SLICE simplifications (KS/AS) +- decoder: "hack fix" for direct mode decoding (AT) + +Changes for Version JM7.6 to JM 7.5c +------------------------------------ +- encoder/decoder: temporal direct loop index fix (RV/AT/KS) +- encoder: fix memory leak (AT) +- decoder: reset the wp_offset for the implicit mode (AT) +- encoder: temporary fix for slice mode 2, Won't work with FMO (PK) +- decoder: don't reset poc of other field (OD) +- decoder: fix bw_ref_idx (AT) +- encoder/decoder: fix long_term initialization (JK) +- encoder/decoder: fix pic_num / frame_num_wrap initialization for intra sclices (JK) +- encoder/decoder: datapartition fixed (ZL) +- encoder: fix stored B pictures (AT) +- encoder: small mbuffer.c fixes (AT) +- encoder/decoder: add Visual Studio .NET workspaces (KS) +- encoder: fix random intra blocks (TSh) +- encoder: fix statistics (KS) +- encoder: fix mb delta qp CABAC context selection (KS/AT) +- encoder: Rate control fixes (SM) +- encoder/decoder: fix initial reference picture list generation for long term pictures (RV) +- encoder/decoder: fix no_output_of_prior_pics_flag handling (KS) +- encoder: FAST_ME fixes (JX) + +Changes for Version JM7.5c to JM 7.5b +------------------------------------- +- encoder: add DirectInference parameter (AT) +- encoder: generate interlaced representation, only if interlaced encoding mode (AT/KS) +- encoder: fix picture aff psnr calculation (AT) +- encoder: weighted prediction fix (AT) +- decoder: small direct mode fix (AT) +- encoder/decoder: reference index fix in generation of field representation (AS) +- encoder/decoder: fix CurrPicNum for field calculation (KS) +- encoder: fix CABAC contexts for cbp and skip flag / mb aff (VG/KS) +- encoder: fix invalid usage of 8x8 temporal direct mode (KS) +- decoder: fix field psnr calculation (KS) +- encoder: don't try to output reconstructed sequence, if no file specified (AT) +- encoder: clean exit if input file reading fails (AT) +- encoder: initialize POC before initializing parameter sets (KS) +- encoder: fix POC mode 1 (KS) +- decoder: rename POC mode 1 variables to match text (KS) +- encoder/decoder: fix bottom field access in is_short_term_reference() + and is_long_term_reference() (ML) + +Changes for Version JM7.5b to JM 7.5a +------------------------------------- +Bug fixes +- encoder: b-frame performance fix (KS) +- encoder: CABAC context selection fix (KS) +- encoder: fix typo in rd-opt labda calculation (AT) +- encoder: weighted prediction updates (AT) +- encoder: fix wrong reference index if NumberReferenceFrames=1 (KS) +- encoder: add IDR picture selection parameter (AT) + +Changes for Version JM7.5a to JM 7.5 +------------------------------------ +Bug fixes +- encoder: fix direct mode coding (KS/AT) +- encoder: reenable old rd-opt labda calculation (KS/AT) + +Changes for Version JM7.5 to JM 7.4 +----------------------------------- +Bug fixes +- decoder: SEI parsing (JC) + +- encoder: merge deblocking filter from decoder (KS) +- encoder: merge dpb fixes from decoder (KS) + +- encoder: rewrite most of MB AFF handling, + support list_0 and list_1 properly, etc. (KS) + +- encoder/decoder: fix first_mb_in_slice for mb aff (KS) +- encoder/decoder: deblocking filter with multiple slices (KS) + + +Changes for Version JM7.4 to JM 7.3 +----------------------------------- +Bug fixes +- decoder: lt.ref. pic handling with sliding window (AF) +- decoder: fix CABAC parsing bug for skip_flag (KS) +- decoder: gaps in frame_num (DT) +- decoder: error message, if direct mode fails (BH) +- decoder: fix long term reference pictures (KS) +- decoder: deblocking filter for picture aff (PN) +- decoder: long term picture handling/MMCO (AF/KS) +- decoder: chroma QP offset (JS) +- decoder: frame cropping support (KS) +- decoder: deblocking filter fix (SY, others) + +New features: +- decoder: I_PCM macroblock mode for VLC (DW) +- decoder: I_PCM macroblock mode for CABAC (DW) +- encoder: fast motion estimation +- encoder: rate control + + +Changes for Version JM7.3 to JM 7.2 +----------------------------------- +Bug fixes +- encoder: DPB for field coding (SM) +- encoder: Spatial direct mode (SM) +- decoder: POC mode 2 with multiple slices (BH) +- decoder: data partitioning (has known problem in CAVLC/CABAC parsing when + constrained intra an dp are used) +- both : reference picture list generation +- both : doxygen documentation generation fixes (KS) + + +Changes for Encoder Version JM7.2 to JM 6.2 +-------------------------------------------- +Bug fixes +- DPB correlated things, such as motion search etc.(KS,SM) +- Direct mode(SM) + +Changes for Decoder Version JM 7.2 to JM 7.1 +-------------------------------------------- +Bug fixes +- deblocking filter reference pictures (LK) +- small POC fixes (KS) + +Cleanup +- remove JVT-F100 syntax support (KS) + +Changes for Decoder Version JM 7.1 to JM 7.0 +-------------------------------------------- +Bug fixes +- loop filter (KS) +- weighted prediction (KS) +- reference list generation (KS) +- 8x8 direct modes (AT) +- constrained intra prediction (KS) + + +Changes for Decoder Version JM 7.0 to JM 6.2 +-------------------------------------------- +Bug fixes +- POC updates (BH) +- CABAC dqant and red_idx_lx contexts (KS) +- small cleanups and other fixes + +Other +- removed common directory, put a copy of these file in each + encoder and decoder + + +Changes for Version JM 6.2 to JM 6.1b +-------------------------------------- +Note: This is a decoder only release. Encoding is broken. + +Bug fixes +- rewrote DPB (KS) +- rewrote most of MB AFF handling (KS) +- direct mode updates (AT) + +- many other cleanups and fixes (various poeple) + + +Changes for Version JM 6.1b to JM 6.1a +-------------------------------------- +Bug fixes +* FMO decoding (KS) +* fix motion vector predictor (HS/KS) +* intra prediction mode selection (KS) +* SPS Syntax update frame_height_in_mb -> pic_height_in_mb (KS) +* fix memory leak (KSa) + +Changes for Version JM 6.1a to JM 6.1 +------------------------------------- +Bug fixes +* VLC 0 sign bit (AJ) +* Correct rounding (AJ) +* Chroma intra pred mode order (AJ/KS) +* Loop filter chroma QP mapping (RaS) +* Fix memory leaks (KS) +* MB AFF fixes (HS) +* CABAC text alignment (HS) +* frame_num modulo (KS) +* intra pred allowed mode fixes (HS/KS) + +Cleanups +* remove strange postfilter arrays from decoder (KS) +* remove duplicte decoder frame types (_1 and _MULT) (KS) +* clean up vlc writing (KS) + + +Changes for Version JM 6.1 to JM 6.0a +------------------------------------- +New features +* SEI decoding reenabled and new messages added (KS) +* Weighted Prediction Updates (JB) +* POC updated (DT) +* CABAC slice initializations (HS) + +Bug fixes +* fix mb aff again (KS) + +Cleanups +* remove many gcc warnings (KS) +* remove unused code (KS) +* clean up VLC reading (KS) +* allocate less memory (YW) + + +Changes for Version JM 6.0a to JM 6.0 +------------------------------------- +New features +* chroma loop filter update (CG) + +Bug fixes +* fix overflowing buffer for large image formats (PW/KS) +* fix large memory leak (KS) +* slice coding (RaS) +* fix bit statistics (KS) +* call EBSPtoRBSP at the decoder (TS/KS) + +Cleanups +* remove some of the gcc warnings and old files (KS) + + +Changes for Version JM 6.0 to JM 5.0h-suehring +---------------------------------------------- +New features +* post-Awaji slice header and parameter sets (except POC) (KS) + +Removed features +* ABT (KS) + +Bug fixes +* AFF (picture and mb) (KS) +* Slice parsing with CAVLC (KS) +* CABAC byte alignment (KS) +* lots of stuff I can't remember in detail (KS) + +Cleanups +* lots of stuff I can't remember in detail (KS) + +Known problems +* slices have still encoder mismatch (looks like motion vector prediction) +* FMO not tested, but probably won't work +* SEI disabled (needs update to NAL units) +* weighted prediction implementation in JM 5.0g unfinished +* Error concealment disabled (needs new triggers) +* DP (???) +* I haven't merged any patches, I received since December + +Changes for Version JM 5.0h-suehring to JM 5.0g +----------------------------------------------- +New features +* Sequence and Picture Parameter Sets +* writes Annex B bytestream and RTP packets + + +Changes for Version JM 5.0g to JM 5.0f +-------------------------------------- +New features +* Changes for Weigthed Prediction (JB) + +Note: This version seems to have severe performance problems + +Changes for Version JM 5.0f to JM 5.0e +-------------------------------------- +New features +* Reducing Pixel Dependencies for Intra-Prediction (JVT-E111) (GrC) + + +Changes for Version JM 5.0e to JM 5.0d +-------------------------------------- +New features +* alternate scan for aff coding + + +Changes for Version JM 5.0d to JM 5.0c +-------------------------------------- +New features +* added POC - for implementation details see changes_detail.txt (BH) + +Bug Fixes +* reorder chroma intra pred modes aligned to draft (KS) + +Cleanups (no functional change) +* cleaner parameter transfer for CABAC stuffing words (FB) + + +Changes for Version JM 5.0c to JM 5.0b +-------------------------------------- +New features +* CABC Cleanup and Complexity reduction (FB) + +Bug Fixes +* Chroma intra pred fix (AH/KS) +* Loop filter Clipping (AH) + +Cleanups (no functional change) +* 4x4 intra prediction mode order (KS) +* remove old qp range support (simplifies loop filter) (KS) +* remove some never called code (KS) + + +Changes for Version JM 5.0b to JM 5.0a +-------------------------------------- +New features +* CABAC cleanup (GB/DM) + + +Changes for Version JM 5.0a to JM 5.0 +------------------------------------- +Removed features +* Intra 8x8 sub macroblocks (HS) + +Bug Fixes +* Choose right data partition in RDCost_for_4x4IntraBlocks() MW + + +Changes for Version JM 5.0 to JM 4.4a +------------------------------------- +New features +* Changed startcode length (KS) +* SEI for (SR) + a) Unregistered (arbitrary) data + b) Registered ITU_T_t35 data + c) Random access + d) Pan Scan Information + +Removed features +* Special Position (KS) +* 1/8 pel motion compensation (KS) + +Bug Fixes +* Temporal Direct mode fix for bottom field (LW) +* fix statistics file + + +Changes for Version JM 4.4a to JM 4.4 +------------------------------------- +New features +* MB AFF and CABAC (GB/HS) +Bug Fixes +* fix chroma QP mapping (AH) + + +Changes for Version JM 4.4 to JM 4.3a +------------------------------------- +New features +* FMO mode 3# [JVT-D095] (YW) +* FMO modes 4#~6# [JVT-D097] (YW) +* Scene information SEI message [JVT-D099] (YW) +* Redundant slices [JVT-D101] (YW) + +Note: FMO is broken. + + +Changes for Version JM 4.3a to JM 4.3 +------------------------------------- +New features +* Spare Pictures [JVT-D100] (DT) +* Signaling of Enhanced GOPs [JVT-D098] (DT) + +Bug Fixes +* state table fix (BH) +* fix chroma intra prediction and MB AFF (DH) +* double decoder bitstream buffer size for HD material (KS) +* SP chroma calcultaion fix (MN) +* fix long term picture remove from buffer (DC) + +Changes for Version JM 4.3 to JM 4.2a +------------------------------------- +New features +* Chroma Intra prediction (DH/GB) + +Bug Fixes +* Data partitioning (TO) +* remove assert from ABT (TH/MW) +* fix for constrained intra prediction (TWa) + +Note: MB AFF is broken in this version + + +Changes for Version JM 4.2a to JM 4.2 +------------------------------------- +New features +* Loop Filter Simplification and Improvement (AJ) + + +Changes for Version JM 4.2 to JM 4.1c +------------------------------------- +New features +* Spatial Direct Prediction for MB AFF (AT) + +Bug Fixes +* align simplified intra prediction to text (AH) +* fix simplified intra prediction for mb aff (AH) +* fix spatial direct (YK) +* fix temporal direct (YK) +* MB AFF fixes (LW,RG) + +Cleanups +* clean up decode_one_slice (KS) +* removed commented out code (KS) + + +Changes for Version JM 4.1c to JM 4.1b +-------------------------------------- +New features +* Implicit bi-predictive weighting (YK) + +Bug Fixes +* MAX_QP define (AJ) + + +Changes for Version JM 4.1b to JM 4.1a +-------------------------------------- +New features +* Simplification of Intra Prediction (AH) + +Cleanups +* also always enable EncapsulatedNALPayload at the decoder (KS) +* reference frame check AFF fix (AT) + + +Changes for Version JM 4.1a to JM 4.1 +------------------------------------- +New features +* Spatial Direct Prediction (AT) + Note: Spatial Direct Currently disabled for MB-AFF + +Bug Fixes +* SP chroma bug fixed (XS) + Removed SP Switch flag from SI encoding (AT) + Corrected readSyntaxElement_fixed (AT) +* close reconstruction file only if opened (LWi) +* MB AFF fixes (AT) + +Cleanups +* remove double scan routines (KS) +* always enable EncapsulatedNALPayload (KS) + + +Changes for Version JM 4.1 to JM 4.0d +------------------------------------- +New features +* macroblock adaptive frame/field (LW) + + +Changes for Version JM 4.0d to JM 4.0c +-------------------------------------- +Bug Fixes +* CAVLC/AFF memory allocation (KL) +* Solaris compiler problem (MW) +* CAVLC and ABT updates + + +Changes for Version JM 4.0c to JM 4.0b +------------------------------- +New features +* New Macroblock modes for SP-frames [JVT-B055] (RK) + Note: some problems related to decoding of SI-frames + are reported and have to be fixed + + + +Changes for Version JM 4.0b to JM 4.0a +------------------------------- +New features +* CAVLC [JVT-C028, D034, D036] (KL, JA) +* Low Complexity Diagonal Mode for Intra Prediction [JVT-D059] (GrC) + +Bug Fixes +* Bitstream in MSB first order for CABAC (DM, GB) + + +Changes for Version JM 4.0a to JM 3.9a +------------------------------- +New features +* Improved CABAC [JVT-C060] (HS, GB)) +* Fast Arithmetic Coding for CABAC [JVT-C061] (DM, GB) +* CABAC cleanup [JVT-D019] (GB, DM) +* CABAC and ABT [JVT-D021] (HS, DM, GH)) +* New end-of-slice signaling for CABAC [JVT-D020] (HS) + + +Changes for Version JM 3.9a to JM 3.9 +------------------------------------- + +Bug Fixes +* fix ABT and VLC (MW) +* fix slice mode 2 (KS) + + +Changes for Version JM 3.9 to JM 3.8 +------------------------------------ + +Bug Fixes +* fix bitstream NAL encapsulation for slice modes 1,2 and interlace (KS) +* merge interlace buffer changes (KP/KS) +* fix encoder/decoder mismatch for SP-frames (MW) +* remove unnecessary calculations (AT) +* fix SP compiling warning (FW) +* disable 8x8 intra blocks in data partitioning mode (TO) + +Cleanups +* remove dead code and variables (KS) +* free all prviously allocated memory (KS) + +Note: +* FMO is currently broken + +Changes for Version JM 3.8 to JM 3.7 +------------------------------------ + +New features +* Adaptive Block-size Transforms (MW) + +Changes for Version JM 3.7 to JM 3.6 +------------------------------------ + +New features +* Loop filter complexity reduction [JVT-C094] (AJ) + + +Changes for Version JM 3.6 to JM 3.5 +------------------------------------ + +New features +* support for FMO, see JVT-C089-C092 (SW) + -> FMO requires RTP file format and ConstrainedIntraPrediction = 1 + +Bug Fixes +* many FMO and out-of-order slices related ones (SW) +* fix old QPs (KS) +* fix chroma coding (AT/KS) +* error concealment fix (YW) + +Cleanups +* really remove old start codes (KS) +* remove some unused decoder functions (KS) + +Note: +* in Version 3.5 and 3.6 is in the bit stream format the Slice mode broken +* RTP still has the ASCII Parameter Set format + +Changes for Version JM 3.4 to JM 3.5 +------------------------------------ + +New Features +* improved SP technique [JVT-c114] (FW) +* add syntax flag for switching (FW) + + +Bug Fixes +* new QP range bug fixes (chroma & SP coding) (AT/FW) +* SKIP mode support and Runlength Coding for SP frames (AT/FW) +* Modified lambda weight in RDO for SP frames (AT/FW) + + +Changes for Version JM 3.4 to JM 3.3 +------------------------------------ + +New Features +* stuffing to prevent emulation of start-code [JVT-C064] (SR) +* New start-code for byte-stream format. (SR) +* New method for slice-level QP signaling [JVT-C136] (SR) +* QP range shifted to [0,51] (SR) + -> use #define _OLDSTYLEQP_ for old range + +Bug Fixes +* fix single reference frame problem (AT) +* fix B-Frame coding (AT) +* fix ADAPT_LAST_GROUP (DT) +* fix bit statistics (KS) +* fix search if _FAST_FULL_ME_ disabled (KS) + +Cleanups +* remove old slice-level QP signaling (KS) +* remove old start codes (KS) +* large QP handling cleanups (KS) + + +Changes for Version JM 3.3 to JM 3.2 +------------------------------------ + +New Features +* Consideration of MVs of Direct Mode Macroblocks in B frame MV prediction [JVT-C127] (AT) + +Bug Fixes +* fix deblocking filter for B frames [JVT-C127] (AT) + + +Changes for Version JM 3.2 to JM 3.1 +------------------------------------ + +New Features +* Skip mode motion compensation as defined in JVT-C027 (JL) + + +Changes for Version JM 3.1 to JM 3.0 +------------------------------------ + +New Features +* Quantization range changed from [-8,39] to [-12,39] [JVT-B039] (AH) +* Simplified rounding for transform and quantization [JVT-C136] (AH) +* Simplified formula for intra 16x16 plane prediction [JVT-C136] (AH) + +Bug Fixes +* fix RTP assert (DT) + +Cleanups +* remove gcc warnings (KS) + +Known Problems +* AFF + 1/8 pel motion compensation broken +* if "LastFrameNumber" is used, "FramesToBeEncoded" must be >= "LastFrameNumber" + + +Changes for Version JM 3.0 to JM 2.1 +------------------------------------ + +New Features +* Signaling of "Clean" Random Access Points [JVT-B042, JVT-C083] (DT) + +Bug Fixes +* error concealment fixes (TO) +* constrained intra prediction (GRC) +* align intra pred to CD text (GRC) +* adaptive frame/field fixes + - lambda calculation (LW) + - average psnr output (LW) + - fix slice modes 1 and 2 (LW) + - fix data partitioning (TO) +* add adaptive frame/field parameter consistency checks (KS/LW) +* encoder frame buffer management changes for non-AFF mode (DT) + +Cleanups +* remove old 6 mode intra prediction (KS) + + +Changes for Version JM 2.1 to JM 2.0b +------------------------------------- + +New Features +* adaptive frame/field coding (LW) + +Bug Fixes +* intra 4x4 prediction block availability (several people) +* DP fixes (TO) + + +Changes for Version JM 2.0b to JM 2.0 +------------------------------------- +Bug Fixes +* fix array bounds overflow in cabac.c (KS/IM) +* fix byte sex issues in IFF (KS) +* add UNIX preparation script (KS) + + +Changes for Version JM 2.0 to JM 1.9 +------------------------------------- +I dropped adaptive frame/field coding, so only bugfixes for this release + +Bug Fixes +* decoder delta qp decoding fix (HS) +* correction of wrong calculation of written bits in CABAC mode + (correction according to the new coding engine) (DM) +* major cleanup of the routines related to the statistics reported + in stat.dat (DM): + - correction of wrong calculation of used bits for header and mode info + - addition of new table entries "motion info" and "stuffing bits" + such that the sum of all entries matches _exactly_ the + plotted number of average bits/frame, which in turn is + now equal to the number of bits reported on the console +* correction of wrong calculation of written bytes for CABAC in RTP mode (DM) +* correction of total bits/frame printed out to the data.txt file for with B-frames (JL) +* fix mprr size for new intra pred modes (GC) +* fix frame_rate calculation for B-frames (GH) +* fix restriction on reference frames for intra frame period (KS) +* first step RPSL fixes (KS) +* fix RTP assert (YW) +* tracefile fix (DC) +* fix spelling of config file parameter "NumberReferenceFrames" (MB) + +Changes for Version JM 1.9 to JM 1.8 +------------------------------------- +New Features +* Loopfilter revised (PL) +* INTRA-Prediction on unfiltered content (PL) + +Bug Fixes +* use for each intra pred mode one CABAC context (DM) +* increase version number (KS) +* Interim file format updates (DT) + +Cleanups +* GCC compatibility, remove warnings/unused variables (KS) +* Add UNIX Makefiles (KS/HS) + + +Changes for Version JM 1.8 to JM 1.7 +------------------------------------ +New Features +* New Intra Prediction Modes [JVT-B080] (GrC) + + +Changes for Version JM 1.7 to JM 1.4 +------------------------------------ +New Features +* New Arithmetic Coding Engine [JVT-B036, Moffat/Neal/Witten ACM98] +* Improved CABAC [JVT-B101] (GB) +* Improved MB Pred Modes [JVT-B054] (HS) + +Bug Fixes +* Fix MB statistics (HS) +* Compile fix ERPS test (KS) +* Restrict qp_factor for CABAC initialization (DM/KS) +* Uses MAX_QP for IFF qp encoding (KS) +* Fix decoder TR calculation (again) (AT) +* Fix wrong concealment for B-frames and TR wrap around (KS) +* Correct error handling if first slice (or first frame) was lost (TO) +* Introduced macroblock map for concealment of lost or damaged macroblocks (TO) + + +Changes for Version JM 1.4 to JM 1.0 +------------------------------------ +New Features +* Interim file format according to Appendix III of WD-1 [JVT-A003] (DT) +* Transform and Quantizer changes [JVT-B008, JVT-B038] (AH) +* VLC update [JVT-B029] (LK) +* Updated Error Rebust Macroblock Mode and Reference Frame Selection [JVT-B102] (DK) + +Bug Fixes +* DP & CABAC (TO) + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +People: +KS Karsten Suehring Karsten.Suehring (at) hhi.fraunhofer.de +AT Alexis Michael Tourapis alexismt@ieee.org + +AF Arild Fuldseth arild.fuldseth@tandberg.no +AH Antti Hallapuro antti.hallapuro@nokia.com +AL Athanasios Leontaris athanasios.leontaris@dolby.com +AJ Anthony Joch anthony@ubvideo.com +AM Alan MacDonald newslists@warpzillion.com +AS Albert Simpson ASimpson@amphion.com +ASe Andrew Segall asegall@sharplabs.com +AW Armand Wemelsfelder wemel@planet.nl +BH Barry Haskell bhaskell@apple.com +BJ Byeungwoo Jeon bjeon@yurim.skku.ac.kr +BL Brandon Lin brandon@ubvideo.com +BiL Bin Li yhlibin@mail.ustc.edu.cn +BY Bill Yi bill.xyi@gmail.com +CG Cristina Gomila GomilaC@tce.com +CK Christopher Kotchey ckotchey@us.ibm.com +CL ChongSoon Lim chongsoon.lim@sg.panasonic.com +CS Christian Schmidt schmidt@ece.ucsb.edu +CV Chris Vogt +CZ Chunbo Zhu cbzhu@mail.ustc.edu.cn +DA D. Agrafiotis d.agrafiotis@bristol.ac.uk +DC Doug Chin dougchin@sandvideo.com +DD Dmitriy Demin Dmitriy.Demin@Sun.COM +DH Dzung Hoang dzung.hoang@conexant.com +DK Dimitris Kontopodis dkonto@eikon.tum.de +DM Detlev Marpe +DT Dong Tian tian@cs.tut.fi +DW Dong Wang Dong.Wang@bristol.ac.uk +EM Ehsan Maani emaan@dolby.com +ES Eric Setton esetton@stanford.edu +FB Frank Bossen bossen@docomolabs-usa.com +GB Gabi Blaetterman +GC Guy Cote guy@videolocus.com +GM Gunnar Marten gunnar_marten@web.de +GrC Greg Conklin gregc@real.com +GS Gary Sullivan garysull@microsoft.com +FW Feng Wu fengwu@microsoft.com +HS Heiko Schwarz +HY Haoping Yu haoping.yu@thomson.net +HZ Huipin Zhang hzhang@mobilygen.com +IL Inge Lille-Langoy Inge.Lille-Langoy@telenor.com +IM Iole Moccagatta imoccaga@lsil.com +IP Isabelle Perroux isabelle.perroux@allegrodvt.com +JA James Au james@ubvideo.com +JaB James Bassett jbas021@aucklanduni.ac.nz +JB Jill Boyce BoyceJ@tce.com +JC John Cox jc@sj.co.uk +JGG Jason Garret-Glaser jason@x264.com +JjC Jianjun Chen cjj730@hotmail.com +JK Jeong Kwon Kim kjk@mcubeworks.com +JL Jani Lainema Jani.Lainema@nokia.com +JlT Julien Le Tanou jletanou@gmail.com +JS Joonho Song jhsong@varovision.com +JSa Jose Sanches jose.sanches@st.com +JX Jian Feng Xu fenax@video.mdc.tsinghua.edu.cn +JXi Jun Xin jxin@merl.com +JZ Jun Zhang j_zhang1999@yahoo.com +KL Karl Lillevold Karll@real.com +KHH Ki-Hun Han khhan@dms.sejong.ac.kr +KP Krit Panusopone KPanusopone@gi.com +KSa Kazushi Sato kazushi@av.crl.sony.co.jp +KSw Kumar Swaminathan kswam@dolby.com +LK Louis Kerofsky lkerofsky@sharplabs.com +LL Limin Liu lliu@dolby.com +LlL Loïc Le Loarer loic_leloarer@sdesigns.eu +LW Limin Wang liwang@gi.com +LWi Lowell Winger lwinger@videolocus.com +LP Luca Pezzoni luca.pezzoni@st.com +LZ lzyn llzzyynjupt@sina.com +LZL Larry Luther lzl@dolby.com +MA Mauricio Alvarez alvarez@ac.upc.edu +MB Marcus Barkowsky Marcus.Barkowsky@nt.e-technik.uni-erlangen.de +MG Michael Gallant mgallant@videolocus.com +MK Marta Karczewicz martak@qualcomm.com +ML Maxim Lobasso lobasso@hotmail.com +MN Mike Nilsson mike.nilsson@bt.com +MT Mario Trentini mario_trentini@realmagic.fr +MW Mathias Wien wien@ient.rwth-aachen.de +MWa Michael Walter eiMichaelWalter@web.de +OD Olivier Deygas olivier.deygas@st.com +PC Peison Cheng peisongc@qualcomm.com +PeP Peshala Pahalawatta Peshala.Pahalawatta@dolby.com +PK Petr Kadlec Kadlec@FTW.at +PL Peter List Peter.List@t-systems.de +PN Pavel Novotny pnovotny@lsil.com +PP Purvin Pandit purvin.pandit@thomson.net +PW Ping Wu pwu@tandbergtv.com +RB Roman Barsky romanb@dsp.co.il +RG Rajeev Gandhi rajeev@motorola.com +RK Ragip Kurceren ragip.kurceren@nokia.com +RS Rickard Sjoberg Rickard.Sjoberg@era.ericsson.se +RaS Raghavan Subramaniyan Raghavan.S@motorola.com +RV Rajesh Kumar S Venkata v-rajesh.kumar@st.com +SB Saurav Bandyopadhyay skb3@buffalo.edu +SF Simon Fenney simon.fenney@powervr.com +SG Steve Gordon sgordon@broadcom.com +SH Sven Heithecker heithecker@ida.ing.tu-bs.de +SK Shafi Ullah Khan shafi@sarayusoftech.com +SL Stephan Lachowsky stephan@mobilygen.com +SKa Shinya Kadono kadono.shinya@jp.panasonic.com +SM Siwei Ma swma@jdl.ac.cn +SM Sebastian Manciulea sebastian@splash.ro +SMy Stefaan Mys stefaan.mys@ugent.be +SN Satoshi Nakagawa nakagawa@okilab.net +SR Shankar Regunathan shanre@microsoft.com +SeS Sergey A. Sablin sergey@elecard.net.ru +SSu Shijun Sun ssun@sharplabs.com +SSe Shun-ichi Sekiguchi Sekiguchi.Shunichi@eb.MitsubishiElectric.co.jp +SW Stephan Wenger stewe@stewe.org +SWi Steffen Wittmann Steffen.Wittmann@eu.panasonic.com +SY Steve Yao steveyao@sandvideo.com +SZ Steve Zeng stevezeng@rogers.com +TB Tomás Brandão tomas.brandao@iscte.pt +TH Till Hallbach halbach@tele.ntnu.no +THi Tobias Hinz +TK Thomas Kunlin thomas.kunlin@st.com +TN Takahiro Nishi nishi.takahiro@jp.panasonic.com +TO Tobias Oelbaum drehvial@gmx.net +TP Tom Pycke tom.pycke@ugent.be +TS Teruhiko Suzuki teruhiko@av.crl.sony.co.jp +TSh Tamar Shoham Tamar.Shoham@comverse.com +TSt Thomas Stockhammer stockhammer@lnt.ei.tum.de +TW Thomas Wiegand +TWe Thomas Wedi wedi@tnt.uni-hannover.de +TWa Toby Walker tobyw@usrl.sony.com +VG Valeri George valeri.george@hhi.fraunhofer.de +VV Viktor Varsa viktor.varsa@nokia.com +WC Woong Il Choi creata@ece.skku.ac.kr +WF Wenfang Fu fwf@video.mdc.tsinghua.edu.cn +WK Woo-Shik Kim wooshik.kim@usc.edu +WZ Weimin Zeng wzeng@wischip.com +XI Xin xin@apple.com +XS Xiaoyan Sun sunxiaoyan@msrchina.research.microsoft.com +XX Xiaozhong Xu xxz@video.mdc.tsinghua.edu.cn +XY Xiaoquan Yi xyi@scu.edu +YC Yi-Jen Chiu yi-jen.chiu@intel.com +YD Yunyang Dai ydai@dolby.com +YDh Yves Dhondt yves.dhondt@ugent.be +YH Yu-Wen Huang YW_Huang@mtk.com.tw +YHe Yuwen He yhe@dolby.com +YK Yoshihiro Kikuchi yoshihiro.kikuchi@toshiba.co.jp +YL Yann Lemaguet yann.lemaguet@philips.com +YW Ye-Kui Wang ye-kui.wang@nokia.com +YL Yiting Liao yliao@dolby.com +YX Yanjun Xu yxu@sarnoff.com +YY Yan Ye yye@dolby.com +ZC Zhifeng Chen Zhifeng@ecel.ufl.edu +ZH Zhou Heng zhou_heng@yahoo.com +ZHL Zhen Li zhen.li@dolby.com +ZL Li Zhang zhangli@jdl.ac.cn +ZX Z. Xue jon_xz@yahoo.com +ZY Zheng Yanzhao yzzheng@singnet.com diff --git a/COPYRIGHT_ISO_IEC.txt b/COPYRIGHT_ISO_IEC.txt new file mode 100644 index 0000000..b7b6b05 --- /dev/null +++ b/COPYRIGHT_ISO_IEC.txt @@ -0,0 +1,18 @@ +/********************************************************************** + * Software Copyright Licensing Disclaimer + * + * This software module was originally developed by contributors to the + * course of the development of ISO/IEC 14496-10 for reference purposes + * and its performance may not have been optimized. This software + * module is an implementation of one or more tools as specified by + * ISO/IEC 14496-10. ISO/IEC gives users free license to this software + * module or modifications thereof. Those intending to use this software + * module in products are advised that its use may infringe existing + * patents. ISO/IEC have no liability for use of this software module + * or modifications thereof. The original contributors retain full + * rights to modify and use the code for their own purposes, and to + * assign or donate the code to third-parties. + * + * This copyright notice must be included in all copies or derivative + * works. Copyright (c) ISO/IEC 2004, 2005, 2006, 2007, 2008. + **********************************************************************/ diff --git a/COPYRIGHT_ITU.txt b/COPYRIGHT_ITU.txt new file mode 100644 index 0000000..27361e5 --- /dev/null +++ b/COPYRIGHT_ITU.txt @@ -0,0 +1,32 @@ +/* +*********************************************************************** +* COPYRIGHT AND WARRANTY INFORMATION +* +* Copyright 2001, International Telecommunications Union, Geneva +* +* DISCLAIMER OF WARRANTY +* +* These software programs are available to the user without any +* license fee or royalty on an "as is" basis. The ITU disclaims +* any and all warranties, whether express, implied, or +* statutory, including any implied warranties of merchantability +* or of fitness for a particular purpose. In no event shall the +* contributor or the ITU be liable for any incidental, punitive, or +* consequential damages of any kind whatsoever arising from the +* use of these programs. +* +* This disclaimer of warranty extends to the user of these programs +* and user's customers, employees, agents, transferees, successors, +* and assigns. +* +* The ITU does not represent or warrant that the programs furnished +* hereunder are free of infringement of any third-party patents. +* Commercial implementations of ITU-T Recommendations, including +* shareware, may be subject to royalty fees to patent holders. +* Information regarding the ITU-T patent policy is available from +* the ITU Web site at http://www.itu.int. +* +* THIS IS NOT A GRANT OF PATENT RIGHTS - SEE THE ITU-T PATENT POLICY. +************************************************************************ +*/ + diff --git a/Changes_detail.txt b/Changes_detail.txt new file mode 100644 index 0000000..c1b5ed7 --- /dev/null +++ b/Changes_detail.txt @@ -0,0 +1,195 @@ +Detailed Changes for JM 13.0 +---------------------------- + +JVT-U043 +-------- + +(1) Highlight of the changes to encoder: + +* Two fields - ToneMappingSEIPresentFlag and ToneMappingFile are added to the bottom of encoder.cfg + ToneMappingFile is the tone mapping configuation file + +* #define PRINT_TONE_MAPPING in sei.c to print the tone mapping sei messages + several tone mapping related functions are implemented in sei.c + +* Writing SEI message into bitstream is done at the end of init_frame () in image.c + + +(2) Highlight of the changes to decoder: + +* Define PRINT_TONE_MAPPING at the top of in sei.c to print out the tone mapping sei messages + Tone mapping SEI messages is interpreted in interpret_tone_mapping() in sei.c + +* Define ENABLE_OUTPUT_TONEMAPPING in defines.h to enable the tone-mappping processing. + The actual tone mapping processing is done in output.c write_out_picture() + A tone_mapping flag and tone-mapping look-up-table is added to the StorablePicture stucture. + + +(3) Note: +* The actual tone-mapping processing is perormed only when tone_map_id ==0. +For other tone_map_id, the tone-mapping sei messages are printed out, but no actual processing is performed. + +* Curretnly only the RGB 4:4:4 tone mapping is supported. For other format, it needs color format +conversion before performing the tone mapping process. + + +(4) Test bitstreams: +source Crew_10.rgb, size 1280x720, bit-depth 10, RGB 4:4:4; 10 frames, encoded with all intra +source Crew_8.rgb, size 1280x720, bit-depth 8, RGB 4:4:4; 10 frames, encoded with all intra + + 1) test1.264 // test processing by different model_id. These models are intentionally very different, so that one can easily tell that different tone mappings are applied. + +at frame 0, send: tone_map_id=0, tone_map_cancel_flag=0, tone_map_repetition_period=1, coded_data_bit_depth=10, sei_bit_depth=8, model_id=0 +at frame=2, send: tone_map_id=0, tone_map_cancel_flag=0, tone_map_repetition_period=1, coded_data_bit_depth=10, sei_bit_depth=8, model_id=1 +at frame=4, send: tone_map_id=0, tone_map_cancel_flag=0, tone_map_repetition_period=1, coded_data_bit_depth=10, sei_bit_depth=8, model_id=2 +at frame=6, send: tone_map_id=0, tone_map_cancel_flag=0, tone_map_repetition_period=1, coded_data_bit_depth=10, sei_bit_depth=8, model_id=3 + + 2) test2.264 // test the tone_map_repetition_period and tone_map cancel flag + +at frame 0, send: tone_map_id=0, tone_map_cancel_flag=0, tone_map_repetition_period=0, coded_data_bit_depth=8, sei_bit_depth=8, model_id=1 +at frame 2, send: tone_map_id=0, tone_map_cancel_flag=0, tone_map_repetition_period=5, coded_data_bit_depth=8, sei_bit_depth=8, model_id=1 +at frame 8, send: tone_map_id=0, tone_map_cancel_flag=1 + + 3) test3.264 // test the case of tone_map_id != 0 +at frame 0, send: tone_map_id=1, tone_map_cancel_flag=0, tone_map_repetition_period=1, coded_data_bit_depth=10, sei_bit_depth=8, model_id=1 + + + +Sharp +2/1/2007 + +Changes for JM 7.5 +------------------ +I updated the reference encoder with proper reference picture list handling +(independent list_0 and list_1 prediction), especially for MB and picture AFF. + +Also picture and MB AFF can now be enabled independently in the config file. + +I merged the updated deblocking filter along with many other fixes that were +already in the decoder dpb code. + +This version is not a complete working encoder, but it's a big step forward +in code correction and cleanup. + +I only worked through the main code paths, which means RD-optimization on, +standard motion estimation (no fme), no stored B pictures, no rate-control, +no prediction weights, no FMO. + +The Non-RD-optimized code should probably work, but hasn't been tested. + +The FME implementation copies large sections of encode_one_macroblock inside +a #define. That code duplication is bad coding style, which is the main +reason why I didn't touch it. I did some modifications in fast_me.c, but +due to some interface changes the file won't compile when enabling the +#define FAST_ME + +The rate control makes many assumptions from the config file AFF options. +I tried to update these, but I'm not sure if this works. In some places the +if/else decisions seemed redundant. There were also lots of flags that +indicated frame or field coding. I tried to reduce these to a minimum. + +I put some suggestions for updating FME/rate control in the section +"implementation hints" below. + +RDopt=2 mode: The simulated decoders of this mode actually don't have +anything to do with current real decoders. I also think, the compile fixes +that went into this section probably broke the mode at all. I would suggest +to remove the mode as long as there is nobody willing to invest much +time in a proper upgrade. So, is somebody interested in working on +this mode? TU Munich? + +The weigted prediction functions make some keen assumptions on the reference +picture list organization (e.g. that there is only one list which contains +exactly one backward reference picture in case of B pictures...) +I vaguely remember Jill Boyce saying something like: WP can't work properly +in the current reference software. We will fix that when there is working +reference picture list support. +Well, we now have proper reference picture list support... + +In case of enabling stored B pictures the bidirectional prediction functions +need also an update. They make also assumptions about the reference picture +list sturcture. + + +known problems: +--------------- +- num_slice_groups_minus1>0 (FMO) is broken + +- slice coding needs to be checked (fixed number of bytes has been reported to fail) + +- weigted prediction doesn't work + +- RDOpt mode 2 doesn't work + +- stored B pictures need to be checkeded (function call is disabled) + +- rate control needs to be checked + +- FME needs update + +- direct mode mismatches with HHI software if direct_8x8_inference_flag=false + (ldecod matches lencod) + +- data partitioning? + +- profile and level are set hard coded + +- CABAC doesn't work for mb aff (context model selection problem at the encoder, + HHI is working on a fix) + + +implementation hints: +--------------------- +- all reference picture indexes and motion vectors are stored in enc_picture + (global arrays are removed) + +- all_mv has additional dimension for LIST_0 / LIST_1 + +- img->MbAffFrameFlag=1 indicates MB AFF coding in current picture + +- img->mb_data[img->current_mb_nr].mb_field=1 indicates field coding for current mb pair + +- (img->current_mb_nr%2)==0 indicates top mb (of mb pair) + +- img->structure= TOP_FIELD/BOTTOM_FIELD/FRAME indiactes picture structure + +- img->pix_x, img->pix_y -> current pixel coordinates in enc_picture + +- img->opix_x, img->opix_y -> current pixel coordinates in original and reference picture + +- img->block_x, img->block_y -> current 4x4 block coordinates in enc_picture + + +(KS) + + +Changes for JM 6.2 +------------------ + +The decoder should be nearly in JVT-G50 (final draft) state. + +Known problems: + - the old Parameter Set syntax is used by default. Enable + #define G50_SPS + in defines.h for the new syntax + - the transform/inverse transform has not been reversed + - the direct modes seem to have some mismatches (compared with the + HHI implementation) for MB AFF (Alexis Tourapis is working on that) + - PCM macroblock mode not supported + - deblocking filter is not aligned to the text + - reference picture reordering / mmco hasn't got much testing + +The encoder in this version is completely broken. I started merging some +code from the decoder, but currently don't have the time to finish that. + +If you're interested in encoder work, please contact me. + +Karsten +Changes for JM 7.1 encoder +-------------------------- +Known problems: + - Decoder sometimes can't decode the bitstream with CABAC on, + multiple reference and B slice coding option. + - constrained intra prediction + +Siwei \ No newline at end of file diff --git a/FREXT_changes.txt b/FREXT_changes.txt new file mode 100644 index 0000000..9ea7f25 --- /dev/null +++ b/FREXT_changes.txt @@ -0,0 +1,167 @@ +Fidelity Range Extensions Development +====================================================================== + +for later FRExt Changes see CHANGES.txt + + +From v.2.1 to v.2.2 +---------------- +- fixed bug on wrong assignment of luma_transform_size_8x8_flag when intra coding is selected in inter pictures for CAVLC +- changed normalization for SAD cost for 4x4 and 8x8 +- allow Intra16x16 to be included in Transform8x8Mode=2 +- changed calculation of coefficient cost for dct_luma8x8 for CAVLC +- fixed bug on difference in debug and release mode for I pictures in encoder +- fixed bug on initialisation error for cost when transform 8x8 mode is 0 during P coding in encoder +- fixed CAVLC decoding of level > 16 +- merge up to JM 8.6 + +From v.2.0a to v.2.1 +---------------- +- Residue Color Transform(RCT) is implemented (can be used for RGB-sequences) +- file I/O part is modified to support 8-9-9 bit file input (luma 8 bit, chroma 9 bit) +- added the maximum pixel value for chroma part (different bitdepth values for luma and chroma) +- encoder: fixed the difference between the FRExt spec and JM code for determining ctxIdxInc for significant_.. (field coded macroblocks). +- encoder: fixed DC_PRED initialisation of intrapred[][]-array for non-4x4/8x8 intra MBs +- encoder: fixed overflowing of diff-variables while distortion calculation (for huge frame sizes) +- encoder: fixed clipping of chroma QP value in dct_chroma() +- encoder: fixed pre-filtering for 8x8 intra +- encoder: the range for delta_qp is extended (depends on YUV-Format) +- encoder: fixed pos2ctx_map and pos2ctx_last context mapping for chroma YUV422/YUV444 +- decoder: fixed conditional statement for qp_per_uv in CHROMA DC YUV444 path +- decoder: 64 bit file access for output and reference file (KS) +- decoder: complete VUI parsing (fixes streams with _real_ VUI data) (KS) +- decoder: known bug - QP report + +From v.2.0 to v.2.0a +---------------- +- in config file: luma/chroma bitdepth info is extended to 12 bit +- CBP intra/inter mapping for 8x8-intra macroblocks is fixed +- CABAC context switching (frame/field) while MBAFF mode is fixed (in write_significance_map()) + +From v.1.9c to v.2.0 +---------------- +- updated to JM reference software ver. 8.4 (all corresponding changes are in CHANGES.TXT) +- merged JM 8.5 POC mode 1 fix +- added new CABAC ctx ini-tables +- CAVLC coding mode support for 8x8 transform +- PicUnitBitDepth is changed to BitDepthLuma and BitDepthChroma (encoder cfg-file changed) +- FREXT chrominance qp offsets CbQPOffset and CrQPOffset are added (encoder cfg-file changed) +- FREXT profile idc numbers are updated (beginning from 100 now) and through #define implemented +- fixes for lossless mode: rgb-sequence reading (cfg file is updated with 'RGBinput' parameter) +- bug fixed for writing/reading of trasform_size_8x8_flag when DIRECT-mode and DirectInferenceFlag is disabled +- encoder: bit setting for cbp_blk-chroma is alligned to decoder method +- decoder: error concealment is aligned to FREXT but not tested +- decoder: fixed bug of encoder-decoder mismatch in MBAFF mode + + +From v.1.9b to v.1.9c +---------------- +- setting of available Q-matrix pic scaling list is changed +- decoder: added new default Q-matrix (in v.1.9a was not complete implemented) +- added lossless_qpprime_y_zero funcionality (encoder config file is also extended) +- decoder: bug fixed in derivation of QPy while mb_qp_delta reading + +From v.1.9a to v.1.9b +---------------- +- encoder: bug fixed for B_Direct_8x8 (while Non-RDOpt Mode) + +From v.1.9 to v.1.9a +---------------- +- added new default Q-matrix +- encoder: bug fixed, restoring of motion vector data for P8x8 MBs with transform size 4x4 +- encoder: bug fixed in YUV422 transform and quantizing process (q_bits422, qp_const422 added) +- encoder: changed the mode choosing for 8x8 and 4x4 transform sizes for P8x8-MBtype (now modes 0(B_DIRECT_8x8) and/or 4 can be taken for 8x8 transform) +- changed transform_size_8x8_flag bitstream output to intra-part and inter-part(with checking for cbp_luma==0) +- changed frame statistic output for 8x8 and 4x4 transform separation (with considering of CBP_luma==0) + + +From v.1.8 to v.1.9 +---------------- +- TRANSFORM SIZE FLAG Context Models for P-Frame are extended (CABAC) +- fixed qp_const assigning for luma coeff reading in decoder +- removed rounding for chroma (YUV 420) while dequantizing (refer to FRExt Spec.) +- fixed QP assigning for Macroblock after Delta-QP reading in decoder +- fixed DIAG_DOWN_RIGHT pred mode for 8x8 intra pred +- removed CBP writing when B-Skip and CABAC while rdopt +- code restructuring: writeMBHeader() is changed to writeMBLayer() +- Changed slice-based rounding offset to MB-based rounding offset in the encoder ( this improves significantly picture quality, can we keep this way? ) +- When Transform8x8Mode==2, Direct_8x8 mode sub-macroblock type is disabled. +- Configuration file encoder_highquality_HD.cfg is added to assist encoding of high-res HD content. + + +From v.1.7 to v.1.8 +---------------- +- inserted syntax for Constraint_set3 flag in encoder and decoder +- fixed syntax error during luma 8x8 coefficient decoding when the total number of coefficient is 64 +- changed syntax for transform_size_8x8_flag to be placed at the correct location for mb_type with sub_mb_pred for encoder and decoder to follow the standards +- changed order of 8x8 transform direction to performing vertical direction first instead of horizontal first. +- added condition to check for intra-coded neighbours when constrained intra prediction flag is on, for intra 8x8 coding for encoder +- added setting of high cost for temporal direct mode when 8x8transform only is chosen and co-located pic is not available in encoder +- changed high cost for direct mode when temporal direct mode is not allowed in encoder. Previous value will cause overflow in total cost +- fixed B_skip mode to stop sending/reading of 8x8 transform flag in encoder and decoder +- changed encoding using 8x8transform to be only equal to 1 when Transform8x8Mode in cfg file is equal to 2 for RD-on for encoder +- skipped selecting of B_skip mode with 8x8transform_flag=1 when RD-on in encoder because it is not valid mode +- fixed setting of NoSubMbPartSizeLessThan8x8Flag to zero when Intra16x16 mode is chosen in encoder to prevent encoder sending of 8x8transform flag + +- fixed sending (in encoder) and receiving (in decoder) of q_matrix values only in zig_zag scan +- fixed the correct mapping of matrix data to quantisation values in encoder and decoder +- fixed using of wrong quantized levels for de-quantisation in encoder and decoder +- switch order of getting transform values and inverse DC chroma420 level in encoder and decoder +- removed Intra8x8_ChromaU, Intra8x8_ChromaV, Inter8x8_ChromaU, Inter8x8_ChromaV matrix in encoder and decoder +- changed total matrix list to 8 according to standards +- changed scalingList routine to follow the style stated in the standards in encoder and decoder +- changed variables' names in encoder and decoder: + Old Names -> New Names + scaling_matrix_present_flag -> seq_scaling_matrix_present_flag + scaling_list_present_flag -> seq_scaling_list_present_flag + scaling_matrix_refinement_present_flag -> pic_scaling_matrix_present_flag + scaling_list_refinement_present_flag -> pic_scaling_list_present_flag + +- changed assigning of default matrix and fall-back rule for q matrix +- added syntax in sps for chroma_format_idc and lossless_qpprime in encoder and decoder +- changed location of pps fidelity range extension syntax to end of pps in encoder and decoder + +From v.1.6 to v.1.7 +---------------- +- changed Chroma Intra DC calculation for YUV422 and YUV444 + +From v.1.3 to v.1.6 +---------------- +- added YUV422, YUV444 Formats + +V.1.3 +---------------- +- added Q-matrix syntax and semantics in encoder and decoder +- Q-matrix parameters are obtained from a file set in encoder.cfg +- Q-matrix flags can be set in the encoder.cfg +- fixed calculating of cost for Intra8x8 using SATD8x8 +- 8x8 transform is now able to be used with rd-off +- New option for Transform8x8Mode, 2 for rd-off 8x8 transform mode only +- changed getting of qp_const in dct to be macroblock-based instead of slice-based +- changed output display to show Intra MB for all coding type +- fixed bug on I8MB, storing of ipredmode in wrong location +- fixed bug on I8MB, include setting of ipredmode to DC if Inter 8x8 is chosen +- fixed ref idx for direct mode +- updated changes from jm81a + + +v.1.2 +---------------- +- new PROFILE_IDCs (for Fidelity Extensions) are added +- Transform8x8Mode can be managed only at encoder site +- LowPassForIntra8x8 is turned off +- '#ifdef MIXED_TRANSFORM_SIZES' removed +- small code resructuring and cleaning + + +v.1.1 +---------------- +- QP scaling added (negative QPs are possible now) +- lambda(rdcost) scaling added +- luma/chroma bit depth variables to SPS added + +v.1.0 +---------------- +- Mixed Transform Sizes and Variable Bit Depth (v.6.0) added + + diff --git a/JM.xcodeproj/project.pbxproj b/JM.xcodeproj/project.pbxproj new file mode 100644 index 0000000..da3431c --- /dev/null +++ b/JM.xcodeproj/project.pbxproj @@ -0,0 +1,1661 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 44; + objects = { + +/* Begin PBXBuildFile section */ + 436FC29E0D85FBC500D8E371 /* rtpdump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 436FC25A0D85FB3900D8E371 /* rtpdump.cpp */; }; + 436FC2B20D85FC9400D8E371 /* rtp_loss.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 436FC2AD0D85FC4B00D8E371 /* rtp_loss.cpp */; }; + 71927CF71472DF74000AB618 /* annexb.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C891472DF74000AB618 /* annexb.c */; }; + 71927CF81472DF74000AB618 /* biariencode.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C8A1472DF74000AB618 /* biariencode.c */; }; + 71927CF91472DF74000AB618 /* block.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C8B1472DF74000AB618 /* block.c */; }; + 71927CFA1472DF74000AB618 /* cabac.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C8C1472DF74000AB618 /* cabac.c */; }; + 71927CFB1472DF74000AB618 /* cconv_yuv2rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C8D1472DF74000AB618 /* cconv_yuv2rgb.c */; }; + 71927CFC1472DF74000AB618 /* configfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C8E1472DF74000AB618 /* configfile.c */; }; + 71927CFD1472DF74000AB618 /* conformance.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C8F1472DF74000AB618 /* conformance.c */; }; + 71927CFE1472DF74000AB618 /* context_ini.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C901472DF74000AB618 /* context_ini.c */; }; + 71927CFF1472DF74000AB618 /* errdo_dist_mhyp.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C911472DF74000AB618 /* errdo_dist_mhyp.c */; }; + 71927D001472DF74000AB618 /* errdo.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C921472DF74000AB618 /* errdo.c */; }; + 71927D011472DF74000AB618 /* explicit_gop.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C931472DF74000AB618 /* explicit_gop.c */; }; + 71927D021472DF74000AB618 /* explicit_seq.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C941472DF74000AB618 /* explicit_seq.c */; }; + 71927D031472DF74000AB618 /* filehandle.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C951472DF74000AB618 /* filehandle.c */; }; + 71927D041472DF74000AB618 /* fmo.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C961472DF74000AB618 /* fmo.c */; }; + 71927D051472DF74000AB618 /* get_block_otf.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C971472DF74000AB618 /* get_block_otf.c */; }; + 71927D061472DF74000AB618 /* header.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C981472DF74000AB618 /* header.c */; }; + 71927D071472DF74000AB618 /* image_mp.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C991472DF74000AB618 /* image_mp.c */; }; + 71927D081472DF74000AB618 /* image.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C9A1472DF74000AB618 /* image.c */; }; + 71927D091472DF74000AB618 /* img_chroma.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C9B1472DF74000AB618 /* img_chroma.c */; }; + 71927D0A1472DF74000AB618 /* img_dist_ms_ssim.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C9C1472DF74000AB618 /* img_dist_ms_ssim.c */; }; + 71927D0B1472DF74000AB618 /* img_dist_snr.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C9D1472DF74000AB618 /* img_dist_snr.c */; }; + 71927D0C1472DF74000AB618 /* img_dist_ssim.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C9E1472DF74000AB618 /* img_dist_ssim.c */; }; + 71927D0D1472DF74000AB618 /* img_distortion.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927C9F1472DF74000AB618 /* img_distortion.c */; }; + 71927D0E1472DF74000AB618 /* img_luma.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA01472DF74000AB618 /* img_luma.c */; }; + 71927D0F1472DF74000AB618 /* intra_chroma.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA11472DF74000AB618 /* intra_chroma.c */; }; + 71927D101472DF74000AB618 /* intra4x4.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA21472DF74000AB618 /* intra4x4.c */; }; + 71927D111472DF74000AB618 /* intra8x8.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA31472DF74000AB618 /* intra8x8.c */; }; + 71927D121472DF74000AB618 /* intra16x16.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA41472DF74000AB618 /* intra16x16.c */; }; + 71927D131472DF74000AB618 /* intrarefresh.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA51472DF74000AB618 /* intrarefresh.c */; }; + 71927D141472DF74000AB618 /* lambda.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA61472DF74000AB618 /* lambda.c */; }; + 71927D151472DF74000AB618 /* leaky_bucket.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA71472DF74000AB618 /* leaky_bucket.c */; }; + 71927D161472DF74000AB618 /* lencod.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA81472DF74000AB618 /* lencod.c */; }; + 71927D171472DF74000AB618 /* list_reorder.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CA91472DF74000AB618 /* list_reorder.c */; }; + 71927D181472DF74000AB618 /* lln_mc_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CAA1472DF74000AB618 /* lln_mc_prediction.c */; }; + 71927D191472DF74000AB618 /* loop_filter_mbaff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CAB1472DF74000AB618 /* loop_filter_mbaff.c */; }; + 71927D1A1472DF74000AB618 /* loop_filter_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CAC1472DF74000AB618 /* loop_filter_normal.c */; }; + 71927D1B1472DF74000AB618 /* loopFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CAD1472DF74000AB618 /* loopFilter.c */; }; + 71927D1C1472DF74000AB618 /* macroblock_P444.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CAE1472DF74000AB618 /* macroblock_P444.c */; }; + 71927D1D1472DF74000AB618 /* macroblock.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CAF1472DF74000AB618 /* macroblock.c */; }; + 71927D1E1472DF74000AB618 /* mb_access.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB01472DF74000AB618 /* mb_access.c */; }; + 71927D1F1472DF74000AB618 /* mbuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB11472DF74000AB618 /* mbuffer.c */; }; + 71927D201472DF74000AB618 /* mc_prediction_otf.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB21472DF74000AB618 /* mc_prediction_otf.c */; }; + 71927D211472DF74000AB618 /* mc_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB31472DF74000AB618 /* mc_prediction.c */; }; + 71927D221472DF74000AB618 /* md_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB41472DF74000AB618 /* md_common.c */; }; + 71927D231472DF74000AB618 /* md_distortion.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB51472DF74000AB618 /* md_distortion.c */; }; + 71927D241472DF74000AB618 /* md_high.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB61472DF74000AB618 /* md_high.c */; }; + 71927D251472DF74000AB618 /* md_highfast.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB71472DF74000AB618 /* md_highfast.c */; }; + 71927D261472DF74000AB618 /* md_highloss.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB81472DF74000AB618 /* md_highloss.c */; }; + 71927D271472DF74000AB618 /* md_low.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CB91472DF74000AB618 /* md_low.c */; }; + 71927D281472DF74000AB618 /* me_distortion_otf.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CBA1472DF74000AB618 /* me_distortion_otf.c */; }; + 71927D291472DF74000AB618 /* me_distortion.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CBB1472DF74000AB618 /* me_distortion.c */; }; + 71927D2A1472DF74000AB618 /* me_epzs_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CBC1472DF74000AB618 /* me_epzs_common.c */; }; + 71927D2B1472DF74000AB618 /* me_epzs_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CBD1472DF74000AB618 /* me_epzs_int.c */; }; + 71927D2C1472DF74000AB618 /* me_epzs_sub.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CBE1472DF74000AB618 /* me_epzs_sub.c */; }; + 71927D2D1472DF74000AB618 /* me_epzs.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CBF1472DF74000AB618 /* me_epzs.c */; }; + 71927D2E1472DF74000AB618 /* me_fullfast_otf.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC01472DF74000AB618 /* me_fullfast_otf.c */; }; + 71927D2F1472DF74000AB618 /* me_fullfast.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC11472DF74000AB618 /* me_fullfast.c */; }; + 71927D301472DF74000AB618 /* me_fullsearch.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC21472DF74000AB618 /* me_fullsearch.c */; }; + 71927D311472DF74000AB618 /* me_umhex.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC31472DF74000AB618 /* me_umhex.c */; }; + 71927D321472DF74000AB618 /* me_umhexsmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC41472DF74000AB618 /* me_umhexsmp.c */; }; + 71927D331472DF74000AB618 /* mmco.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC51472DF74000AB618 /* mmco.c */; }; + 71927D341472DF74000AB618 /* mode_decision_P8x8.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC61472DF74000AB618 /* mode_decision_P8x8.c */; }; + 71927D351472DF74000AB618 /* mode_decision.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC71472DF74000AB618 /* mode_decision.c */; }; + 71927D361472DF74000AB618 /* mv_direct.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC81472DF74000AB618 /* mv_direct.c */; }; + 71927D371472DF74000AB618 /* mv_search.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CC91472DF74000AB618 /* mv_search.c */; }; + 71927D381472DF74000AB618 /* nal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CCA1472DF74000AB618 /* nal.c */; }; + 71927D391472DF74000AB618 /* nalu.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CCB1472DF74000AB618 /* nalu.c */; }; + 71927D3A1472DF74000AB618 /* output.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CCC1472DF74000AB618 /* output.c */; }; + 71927D3B1472DF74000AB618 /* parset.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CCD1472DF74000AB618 /* parset.c */; }; + 71927D3C1472DF74000AB618 /* pred_struct.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CCE1472DF74000AB618 /* pred_struct.c */; }; + 71927D3D1472DF74000AB618 /* q_around.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CCF1472DF74000AB618 /* q_around.c */; }; + 71927D3E1472DF74000AB618 /* q_matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD01472DF74000AB618 /* q_matrix.c */; }; + 71927D3F1472DF74000AB618 /* q_offsets.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD11472DF74000AB618 /* q_offsets.c */; }; + 71927D401472DF74000AB618 /* quant4x4_2step.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD21472DF74000AB618 /* quant4x4_2step.c */; }; + 71927D411472DF74000AB618 /* quant4x4_around.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD31472DF74000AB618 /* quant4x4_around.c */; }; + 71927D421472DF74000AB618 /* quant4x4_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD41472DF74000AB618 /* quant4x4_normal.c */; }; + 71927D431472DF74000AB618 /* quant4x4_trellis.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD51472DF74000AB618 /* quant4x4_trellis.c */; }; + 71927D441472DF74000AB618 /* quant4x4.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD61472DF74000AB618 /* quant4x4.c */; }; + 71927D451472DF74000AB618 /* quant8x8_around.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD71472DF74000AB618 /* quant8x8_around.c */; }; + 71927D461472DF74000AB618 /* quant8x8_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD81472DF74000AB618 /* quant8x8_normal.c */; }; + 71927D471472DF74000AB618 /* quant8x8_trellis.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CD91472DF74000AB618 /* quant8x8_trellis.c */; }; + 71927D481472DF74000AB618 /* quant8x8.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CDA1472DF74000AB618 /* quant8x8.c */; }; + 71927D491472DF74000AB618 /* quantChroma_2step.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CDB1472DF74000AB618 /* quantChroma_2step.c */; }; + 71927D4A1472DF74000AB618 /* quantChroma_around.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CDC1472DF74000AB618 /* quantChroma_around.c */; }; + 71927D4B1472DF74000AB618 /* quantChroma_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CDD1472DF74000AB618 /* quantChroma_normal.c */; }; + 71927D4C1472DF74000AB618 /* quantChroma_trellis.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CDE1472DF74000AB618 /* quantChroma_trellis.c */; }; + 71927D4D1472DF74000AB618 /* quantChroma.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CDF1472DF74000AB618 /* quantChroma.c */; }; + 71927D4E1472DF74000AB618 /* ratectl.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE01472DF74000AB618 /* ratectl.c */; }; + 71927D4F1472DF74000AB618 /* rc_quadratic.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE11472DF74000AB618 /* rc_quadratic.c */; }; + 71927D501472DF74000AB618 /* rd_intra_jm_low.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE21472DF74000AB618 /* rd_intra_jm_low.c */; }; + 71927D511472DF74000AB618 /* rd_intra_jm.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE31472DF74000AB618 /* rd_intra_jm.c */; }; + 71927D521472DF74000AB618 /* rd_intra_jm444.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE41472DF74000AB618 /* rd_intra_jm444.c */; }; + 71927D531472DF74000AB618 /* rdopt_coding_state.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE51472DF74000AB618 /* rdopt_coding_state.c */; }; + 71927D541472DF74000AB618 /* rdopt.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE61472DF74000AB618 /* rdopt.c */; }; + 71927D551472DF74000AB618 /* rdoq_cabac.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE71472DF74000AB618 /* rdoq_cabac.c */; }; + 71927D561472DF74000AB618 /* rdoq_cavlc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE81472DF74000AB618 /* rdoq_cavlc.c */; }; + 71927D571472DF74000AB618 /* rdoq.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CE91472DF74000AB618 /* rdoq.c */; }; + 71927D581472DF74000AB618 /* rdpicdecision.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CEA1472DF74000AB618 /* rdpicdecision.c */; }; + 71927D591472DF74000AB618 /* report.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CEB1472DF74000AB618 /* report.c */; }; + 71927D5A1472DF74000AB618 /* rtp.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CEC1472DF74000AB618 /* rtp.c */; }; + 71927D5B1472DF74000AB618 /* sei.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CED1472DF74000AB618 /* sei.c */; }; + 71927D5C1472DF74000AB618 /* slice.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CEE1472DF74000AB618 /* slice.c */; }; + 71927D5D1472DF74000AB618 /* symbol.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CEF1472DF74000AB618 /* symbol.c */; }; + 71927D5E1472DF74000AB618 /* transform8x8_H444.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF01472DF74000AB618 /* transform8x8_H444.c */; }; + 71927D5F1472DF74000AB618 /* transform8x8.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF11472DF74000AB618 /* transform8x8.c */; }; + 71927D601472DF74000AB618 /* vlc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF21472DF74000AB618 /* vlc.c */; }; + 71927D611472DF74000AB618 /* weighted_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF31472DF74000AB618 /* weighted_prediction.c */; }; + 71927D621472DF74000AB618 /* wp_lms.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF41472DF74000AB618 /* wp_lms.c */; }; + 71927D631472DF74000AB618 /* wp_mciter.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF51472DF74000AB618 /* wp_mciter.c */; }; + 71927D641472DF74000AB618 /* wp_mcprec.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927CF61472DF74000AB618 /* wp_mcprec.c */; }; + 71927D991472DF98000AB618 /* annexb.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D651472DF98000AB618 /* annexb.c */; }; + 71927D9A1472DF98000AB618 /* biaridecod.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D661472DF98000AB618 /* biaridecod.c */; }; + 71927D9B1472DF98000AB618 /* block.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D671472DF98000AB618 /* block.c */; }; + 71927D9C1472DF98000AB618 /* cabac.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D681472DF98000AB618 /* cabac.c */; }; + 71927D9D1472DF98000AB618 /* configfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D691472DF98000AB618 /* configfile.c */; }; + 71927D9E1472DF98000AB618 /* context_ini.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D6A1472DF98000AB618 /* context_ini.c */; }; + 71927D9F1472DF98000AB618 /* dec_statistics.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D6B1472DF98000AB618 /* dec_statistics.c */; }; + 71927DA01472DF98000AB618 /* decoder_test.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D6C1472DF98000AB618 /* decoder_test.c */; }; + 71927DA11472DF98000AB618 /* erc_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D6D1472DF98000AB618 /* erc_api.c */; }; + 71927DA21472DF98000AB618 /* erc_do_i.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D6E1472DF98000AB618 /* erc_do_i.c */; }; + 71927DA31472DF98000AB618 /* erc_do_p.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D6F1472DF98000AB618 /* erc_do_p.c */; }; + 71927DA41472DF98000AB618 /* errorconcealment.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D701472DF98000AB618 /* errorconcealment.c */; }; + 71927DA51472DF98000AB618 /* filehandle.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D711472DF98000AB618 /* filehandle.c */; }; + 71927DA61472DF98000AB618 /* fmo.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D721472DF98000AB618 /* fmo.c */; }; + 71927DA71472DF98000AB618 /* header.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D731472DF98000AB618 /* header.c */; }; + 71927DA81472DF98000AB618 /* image.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D741472DF98000AB618 /* image.c */; }; + 71927DA91472DF98000AB618 /* intra_chroma_pred_mbaff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D751472DF98000AB618 /* intra_chroma_pred_mbaff.c */; }; + 71927DAA1472DF98000AB618 /* intra_chroma_pred.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D761472DF98000AB618 /* intra_chroma_pred.c */; }; + 71927DAB1472DF98000AB618 /* intra_pred_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D771472DF98000AB618 /* intra_pred_common.c */; }; + 71927DAC1472DF98000AB618 /* intra4x4_pred_mbaff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D781472DF98000AB618 /* intra4x4_pred_mbaff.c */; }; + 71927DAD1472DF98000AB618 /* intra4x4_pred_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D791472DF98000AB618 /* intra4x4_pred_normal.c */; }; + 71927DAE1472DF98000AB618 /* intra4x4_pred.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D7A1472DF98000AB618 /* intra4x4_pred.c */; }; + 71927DAF1472DF98000AB618 /* intra8x8_pred_mbaff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D7B1472DF98000AB618 /* intra8x8_pred_mbaff.c */; }; + 71927DB01472DF98000AB618 /* intra8x8_pred_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D7C1472DF98000AB618 /* intra8x8_pred_normal.c */; }; + 71927DB11472DF98000AB618 /* intra8x8_pred.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D7D1472DF98000AB618 /* intra8x8_pred.c */; }; + 71927DB21472DF98000AB618 /* intra16x16_pred_mbaff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D7E1472DF98000AB618 /* intra16x16_pred_mbaff.c */; }; + 71927DB31472DF98000AB618 /* intra16x16_pred_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D7F1472DF98000AB618 /* intra16x16_pred_normal.c */; }; + 71927DB41472DF98000AB618 /* intra16x16_pred.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D801472DF98000AB618 /* intra16x16_pred.c */; }; + 71927DB51472DF98000AB618 /* ldecod.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D811472DF98000AB618 /* ldecod.c */; }; + 71927DB61472DF98000AB618 /* leaky_bucket.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D821472DF98000AB618 /* leaky_bucket.c */; }; + 71927DB71472DF98000AB618 /* loop_filter_mbaff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D831472DF98000AB618 /* loop_filter_mbaff.c */; }; + 71927DB81472DF98000AB618 /* loop_filter_normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D841472DF98000AB618 /* loop_filter_normal.c */; }; + 71927DB91472DF98000AB618 /* loopFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D851472DF98000AB618 /* loopFilter.c */; }; + 71927DBA1472DF98000AB618 /* macroblock.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D861472DF98000AB618 /* macroblock.c */; }; + 71927DBB1472DF98000AB618 /* mb_access.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D871472DF98000AB618 /* mb_access.c */; }; + 71927DBC1472DF98000AB618 /* mb_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D881472DF98000AB618 /* mb_prediction.c */; }; + 71927DBD1472DF98000AB618 /* mb_read.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D891472DF98000AB618 /* mb_read.c */; }; + 71927DBE1472DF98000AB618 /* mbuffer_mvc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D8A1472DF98000AB618 /* mbuffer_mvc.c */; }; + 71927DBF1472DF98000AB618 /* mbuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D8B1472DF98000AB618 /* mbuffer.c */; }; + 71927DC01472DF98000AB618 /* mc_direct.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D8C1472DF98000AB618 /* mc_direct.c */; }; + 71927DC11472DF98000AB618 /* mc_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D8D1472DF98000AB618 /* mc_prediction.c */; }; + 71927DC21472DF98000AB618 /* nal.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D8E1472DF98000AB618 /* nal.c */; }; + 71927DC31472DF98000AB618 /* nalu.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D8F1472DF98000AB618 /* nalu.c */; }; + 71927DC41472DF98000AB618 /* output.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D901472DF98000AB618 /* output.c */; }; + 71927DC51472DF98000AB618 /* parset.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D911472DF98000AB618 /* parset.c */; }; + 71927DC61472DF98000AB618 /* quant.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D921472DF98000AB618 /* quant.c */; }; + 71927DC71472DF98000AB618 /* read_comp_cabac.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D931472DF98000AB618 /* read_comp_cabac.c */; }; + 71927DC81472DF98000AB618 /* read_comp_cavlc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D941472DF98000AB618 /* read_comp_cavlc.c */; }; + 71927DC91472DF98000AB618 /* rtp.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D951472DF98000AB618 /* rtp.c */; }; + 71927DCA1472DF98000AB618 /* sei.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D961472DF98000AB618 /* sei.c */; }; + 71927DCB1472DF98000AB618 /* transform8x8.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D971472DF98000AB618 /* transform8x8.c */; }; + 71927DCC1472DF98000AB618 /* vlc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927D981472DF98000AB618 /* vlc.c */; }; + 71927E201472DFE1000AB618 /* blk_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E121472DFE1000AB618 /* blk_prediction.c */; }; + 71927E211472DFE1000AB618 /* config_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E131472DFE1000AB618 /* config_common.c */; }; + 71927E221472DFE1000AB618 /* img_io.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E141472DFE1000AB618 /* img_io.c */; }; + 71927E231472DFE1000AB618 /* img_process.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E151472DFE1000AB618 /* img_process.c */; }; + 71927E241472DFE1000AB618 /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E161472DFE1000AB618 /* input.c */; }; + 71927E251472DFE1000AB618 /* io_raw.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E171472DFE1000AB618 /* io_raw.c */; }; + 71927E261472DFE1000AB618 /* io_tiff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E181472DFE1000AB618 /* io_tiff.c */; }; + 71927E271472DFE1000AB618 /* mbuffer_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E191472DFE1000AB618 /* mbuffer_common.c */; }; + 71927E281472DFE1000AB618 /* memalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1A1472DFE1000AB618 /* memalloc.c */; }; + 71927E291472DFE1000AB618 /* mv_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1B1472DFE1000AB618 /* mv_prediction.c */; }; + 71927E2A1472DFE1000AB618 /* nalucommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1C1472DFE1000AB618 /* nalucommon.c */; }; + 71927E2B1472DFE1000AB618 /* parsetcommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1D1472DFE1000AB618 /* parsetcommon.c */; }; + 71927E2C1472DFE1000AB618 /* transform.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1E1472DFE1000AB618 /* transform.c */; }; + 71927E2D1472DFE1000AB618 /* win32.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1F1472DFE1000AB618 /* win32.c */; }; + 71927E2E1472DFE1000AB618 /* blk_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E121472DFE1000AB618 /* blk_prediction.c */; }; + 71927E2F1472DFE1000AB618 /* config_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E131472DFE1000AB618 /* config_common.c */; }; + 71927E301472DFE1000AB618 /* img_io.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E141472DFE1000AB618 /* img_io.c */; }; + 71927E311472DFE1000AB618 /* img_process.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E151472DFE1000AB618 /* img_process.c */; }; + 71927E321472DFE1000AB618 /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E161472DFE1000AB618 /* input.c */; }; + 71927E331472DFE1000AB618 /* io_raw.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E171472DFE1000AB618 /* io_raw.c */; }; + 71927E341472DFE1000AB618 /* io_tiff.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E181472DFE1000AB618 /* io_tiff.c */; }; + 71927E351472DFE1000AB618 /* mbuffer_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E191472DFE1000AB618 /* mbuffer_common.c */; }; + 71927E361472DFE1000AB618 /* memalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1A1472DFE1000AB618 /* memalloc.c */; }; + 71927E371472DFE1000AB618 /* mv_prediction.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1B1472DFE1000AB618 /* mv_prediction.c */; }; + 71927E381472DFE1000AB618 /* nalucommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1C1472DFE1000AB618 /* nalucommon.c */; }; + 71927E391472DFE1000AB618 /* parsetcommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1D1472DFE1000AB618 /* parsetcommon.c */; }; + 71927E3A1472DFE1000AB618 /* transform.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1E1472DFE1000AB618 /* transform.c */; }; + 71927E3B1472DFE1000AB618 /* win32.c in Sources */ = {isa = PBXBuildFile; fileRef = 71927E1F1472DFE1000AB618 /* win32.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 436FC2980D85FB4900D8E371 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 436FC2A60D85FC1C00D8E371 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 43FA4B130D4EECBB001709F1 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 8DD76FAF0486AB0100D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 434D2AC20D5C1C3E00610974 /* decoder.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = decoder.cfg; path = bin/decoder.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AC40D5C1C3E00610974 /* encoder.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = encoder.cfg; path = bin/encoder.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AC50D5C1C3E00610974 /* encoder_baseline.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = encoder_baseline.cfg; path = bin/encoder_baseline.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AC60D5C1C3E00610974 /* encoder_extended.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = encoder_extended.cfg; path = bin/encoder_extended.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AC80D5C1C3E00610974 /* encoder_main.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = encoder_main.cfg; path = bin/encoder_main.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AC90D5C1C3E00610974 /* encoder_tonemapping.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = encoder_tonemapping.cfg; path = bin/encoder_tonemapping.cfg; sourceTree = SOURCE_ROOT; }; + 434D2ACA0D5C1C3E00610974 /* encoder_yuv422.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = encoder_yuv422.cfg; path = bin/encoder_yuv422.cfg; sourceTree = SOURCE_ROOT; }; + 434D2ACD0D5C1C3E00610974 /* leakybucketrate.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = leakybucketrate.cfg; path = bin/leakybucketrate.cfg; sourceTree = SOURCE_ROOT; }; + 434D2ACE0D5C1C3E00610974 /* q_matrix.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = q_matrix.cfg; path = bin/q_matrix.cfg; sourceTree = SOURCE_ROOT; }; + 434D2ACF0D5C1C3E00610974 /* q_matrix2.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = q_matrix2.cfg; path = bin/q_matrix2.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AD00D5C1C3E00610974 /* q_matrix_def.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = q_matrix_def.cfg; path = bin/q_matrix_def.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AD10D5C1C3E00610974 /* q_offset.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = q_offset.cfg; path = bin/q_offset.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AD30D5C1C3E00610974 /* sg0conf.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = sg0conf.cfg; path = bin/sg0conf.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AD40D5C1C3E00610974 /* sg2conf.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = sg2conf.cfg; path = bin/sg2conf.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AD50D5C1C3E00610974 /* sg6conf.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = sg6conf.cfg; path = bin/sg6conf.cfg; sourceTree = SOURCE_ROOT; }; + 434D2AD80D5C1C3E00610974 /* ToneMapping.cfg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ToneMapping.cfg; path = bin/ToneMapping.cfg; sourceTree = SOURCE_ROOT; }; + 436FC25A0D85FB3900D8E371 /* rtpdump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rtpdump.cpp; path = rtpdump/rtpdump.cpp; sourceTree = ""; }; + 436FC29C0D85FB4900D8E371 /* rtpdump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rtpdump; sourceTree = BUILT_PRODUCTS_DIR; }; + 436FC2AA0D85FC1C00D8E371 /* rtp_loss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rtp_loss; sourceTree = BUILT_PRODUCTS_DIR; }; + 436FC2AC0D85FC4B00D8E371 /* rtp_loss.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rtp_loss.h; path = rtp_loss/rtp_loss.h; sourceTree = SOURCE_ROOT; }; + 436FC2AD0D85FC4B00D8E371 /* rtp_loss.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rtp_loss.cpp; path = rtp_loss/rtp_loss.cpp; sourceTree = SOURCE_ROOT; }; + 436FC2AE0D85FC4B00D8E371 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ReadMe.txt; path = rtp_loss/ReadMe.txt; sourceTree = SOURCE_ROOT; }; + 43FA4B170D4EECBB001709F1 /* ldecod */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ldecod; sourceTree = BUILT_PRODUCTS_DIR; }; + 71927C2D1472DF4A000AB618 /* annexb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = annexb.h; path = lencod/inc/annexb.h; sourceTree = ""; }; + 71927C2E1472DF4A000AB618 /* biariencode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = biariencode.h; path = lencod/inc/biariencode.h; sourceTree = ""; }; + 71927C2F1472DF4A000AB618 /* block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = block.h; path = lencod/inc/block.h; sourceTree = ""; }; + 71927C301472DF4A000AB618 /* cabac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cabac.h; path = lencod/inc/cabac.h; sourceTree = ""; }; + 71927C311472DF4A000AB618 /* cconv_yuv2rgb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cconv_yuv2rgb.h; path = lencod/inc/cconv_yuv2rgb.h; sourceTree = ""; }; + 71927C321472DF4A000AB618 /* configfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = configfile.h; path = lencod/inc/configfile.h; sourceTree = ""; }; + 71927C331472DF4A000AB618 /* conformance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = conformance.h; path = lencod/inc/conformance.h; sourceTree = ""; }; + 71927C341472DF4A000AB618 /* context_ini.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = context_ini.h; path = lencod/inc/context_ini.h; sourceTree = ""; }; + 71927C351472DF4A000AB618 /* contributors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = contributors.h; path = lencod/inc/contributors.h; sourceTree = ""; }; + 71927C361472DF4A000AB618 /* defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = defines.h; path = lencod/inc/defines.h; sourceTree = ""; }; + 71927C371472DF4A000AB618 /* elements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elements.h; path = lencod/inc/elements.h; sourceTree = ""; }; + 71927C381472DF4A000AB618 /* errdo_dist_mhyp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = errdo_dist_mhyp.h; path = lencod/inc/errdo_dist_mhyp.h; sourceTree = ""; }; + 71927C391472DF4A000AB618 /* errdo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = errdo.h; path = lencod/inc/errdo.h; sourceTree = ""; }; + 71927C3A1472DF4A000AB618 /* explicit_gop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = explicit_gop.h; path = lencod/inc/explicit_gop.h; sourceTree = ""; }; + 71927C3B1472DF4A000AB618 /* explicit_seq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = explicit_seq.h; path = lencod/inc/explicit_seq.h; sourceTree = ""; }; + 71927C3C1472DF4A000AB618 /* filehandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = filehandle.h; path = lencod/inc/filehandle.h; sourceTree = ""; }; + 71927C3D1472DF4A000AB618 /* fmo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fmo.h; path = lencod/inc/fmo.h; sourceTree = ""; }; + 71927C3E1472DF4A000AB618 /* get_block_otf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = get_block_otf.h; path = lencod/inc/get_block_otf.h; sourceTree = ""; }; + 71927C3F1472DF4A000AB618 /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = global.h; path = lencod/inc/global.h; sourceTree = ""; }; + 71927C401472DF4A000AB618 /* header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = header.h; path = lencod/inc/header.h; sourceTree = ""; }; + 71927C411472DF4A000AB618 /* image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = image.h; path = lencod/inc/image.h; sourceTree = ""; }; + 71927C421472DF4A000AB618 /* img_chroma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = img_chroma.h; path = lencod/inc/img_chroma.h; sourceTree = ""; }; + 71927C431472DF4A000AB618 /* img_dist_ms_ssim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = img_dist_ms_ssim.h; path = lencod/inc/img_dist_ms_ssim.h; sourceTree = ""; }; + 71927C441472DF4A000AB618 /* img_dist_snr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = img_dist_snr.h; path = lencod/inc/img_dist_snr.h; sourceTree = ""; }; + 71927C451472DF4A000AB618 /* img_dist_ssim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = img_dist_ssim.h; path = lencod/inc/img_dist_ssim.h; sourceTree = ""; }; + 71927C461472DF4A000AB618 /* img_distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = img_distortion.h; path = lencod/inc/img_distortion.h; sourceTree = ""; }; + 71927C471472DF4A000AB618 /* img_luma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = img_luma.h; path = lencod/inc/img_luma.h; sourceTree = ""; }; + 71927C481472DF4A000AB618 /* intra4x4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = intra4x4.h; path = lencod/inc/intra4x4.h; sourceTree = ""; }; + 71927C491472DF4A000AB618 /* intra8x8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = intra8x8.h; path = lencod/inc/intra8x8.h; sourceTree = ""; }; + 71927C4A1472DF4A000AB618 /* intra16x16.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = intra16x16.h; path = lencod/inc/intra16x16.h; sourceTree = ""; }; + 71927C4B1472DF4A000AB618 /* intrarefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = intrarefresh.h; path = lencod/inc/intrarefresh.h; sourceTree = ""; }; + 71927C4C1472DF4A000AB618 /* lambda.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lambda.h; path = lencod/inc/lambda.h; sourceTree = ""; }; + 71927C4D1472DF4A000AB618 /* leaky_bucket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = leaky_bucket.h; path = lencod/inc/leaky_bucket.h; sourceTree = ""; }; + 71927C4E1472DF4A000AB618 /* list_reorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = list_reorder.h; path = lencod/inc/list_reorder.h; sourceTree = ""; }; + 71927C4F1472DF4A000AB618 /* lln_mc_prediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lln_mc_prediction.h; path = lencod/inc/lln_mc_prediction.h; sourceTree = ""; }; + 71927C501472DF4A000AB618 /* loop_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = loop_filter.h; path = lencod/inc/loop_filter.h; sourceTree = ""; }; + 71927C511472DF4A000AB618 /* macroblock_p444.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macroblock_p444.h; path = lencod/inc/macroblock_p444.h; sourceTree = ""; }; + 71927C521472DF4A000AB618 /* macroblock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macroblock.h; path = lencod/inc/macroblock.h; sourceTree = ""; }; + 71927C531472DF4A000AB618 /* mbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mbuffer.h; path = lencod/inc/mbuffer.h; sourceTree = ""; }; + 71927C541472DF4A000AB618 /* mc_prediction_otf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mc_prediction_otf.h; path = lencod/inc/mc_prediction_otf.h; sourceTree = ""; }; + 71927C551472DF4A000AB618 /* mc_prediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mc_prediction.h; path = lencod/inc/mc_prediction.h; sourceTree = ""; }; + 71927C561472DF4A000AB618 /* md_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = md_common.h; path = lencod/inc/md_common.h; sourceTree = ""; }; + 71927C571472DF4A000AB618 /* md_distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = md_distortion.h; path = lencod/inc/md_distortion.h; sourceTree = ""; }; + 71927C581472DF4A000AB618 /* me_distortion_otf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_distortion_otf.h; path = lencod/inc/me_distortion_otf.h; sourceTree = ""; }; + 71927C591472DF4A000AB618 /* me_distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_distortion.h; path = lencod/inc/me_distortion.h; sourceTree = ""; }; + 71927C5A1472DF4A000AB618 /* me_epzs_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_epzs_common.h; path = lencod/inc/me_epzs_common.h; sourceTree = ""; }; + 71927C5B1472DF4A000AB618 /* me_epzs_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_epzs_int.h; path = lencod/inc/me_epzs_int.h; sourceTree = ""; }; + 71927C5C1472DF4A000AB618 /* me_epzs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_epzs.h; path = lencod/inc/me_epzs.h; sourceTree = ""; }; + 71927C5D1472DF4A000AB618 /* me_fullfast_otf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_fullfast_otf.h; path = lencod/inc/me_fullfast_otf.h; sourceTree = ""; }; + 71927C5E1472DF4A000AB618 /* me_fullfast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_fullfast.h; path = lencod/inc/me_fullfast.h; sourceTree = ""; }; + 71927C5F1472DF4A000AB618 /* me_fullsearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_fullsearch.h; path = lencod/inc/me_fullsearch.h; sourceTree = ""; }; + 71927C601472DF4A000AB618 /* me_umhex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_umhex.h; path = lencod/inc/me_umhex.h; sourceTree = ""; }; + 71927C611472DF4A000AB618 /* me_umhexsmp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = me_umhexsmp.h; path = lencod/inc/me_umhexsmp.h; sourceTree = ""; }; + 71927C621472DF4A000AB618 /* mmco.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mmco.h; path = lencod/inc/mmco.h; sourceTree = ""; }; + 71927C631472DF4A000AB618 /* mode_decision_p8x8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mode_decision_p8x8.h; path = lencod/inc/mode_decision_p8x8.h; sourceTree = ""; }; + 71927C641472DF4A000AB618 /* mode_decision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mode_decision.h; path = lencod/inc/mode_decision.h; sourceTree = ""; }; + 71927C651472DF4A000AB618 /* mv_search.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mv_search.h; path = lencod/inc/mv_search.h; sourceTree = ""; }; + 71927C661472DF4A000AB618 /* nal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nal.h; path = lencod/inc/nal.h; sourceTree = ""; }; + 71927C671472DF4A000AB618 /* nalu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nalu.h; path = lencod/inc/nalu.h; sourceTree = ""; }; + 71927C681472DF4A000AB618 /* output.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = output.h; path = lencod/inc/output.h; sourceTree = ""; }; + 71927C691472DF4A000AB618 /* params.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = params.h; path = lencod/inc/params.h; sourceTree = ""; }; + 71927C6A1472DF4A000AB618 /* parset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parset.h; path = lencod/inc/parset.h; sourceTree = ""; }; + 71927C6B1472DF4A000AB618 /* pred_struct_adapt_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pred_struct_adapt_types.h; path = lencod/inc/pred_struct_adapt_types.h; sourceTree = ""; }; + 71927C6C1472DF4A000AB618 /* pred_struct_adapt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pred_struct_adapt.h; path = lencod/inc/pred_struct_adapt.h; sourceTree = ""; }; + 71927C6D1472DF4A000AB618 /* pred_struct_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pred_struct_types.h; path = lencod/inc/pred_struct_types.h; sourceTree = ""; }; + 71927C6E1472DF4A000AB618 /* pred_struct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pred_struct.h; path = lencod/inc/pred_struct.h; sourceTree = ""; }; + 71927C6F1472DF4A000AB618 /* q_around.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = q_around.h; path = lencod/inc/q_around.h; sourceTree = ""; }; + 71927C701472DF4A000AB618 /* q_matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = q_matrix.h; path = lencod/inc/q_matrix.h; sourceTree = ""; }; + 71927C711472DF4A000AB618 /* q_offsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = q_offsets.h; path = lencod/inc/q_offsets.h; sourceTree = ""; }; + 71927C721472DF4A000AB618 /* quant4x4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quant4x4.h; path = lencod/inc/quant4x4.h; sourceTree = ""; }; + 71927C731472DF4A000AB618 /* quant8x8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quant8x8.h; path = lencod/inc/quant8x8.h; sourceTree = ""; }; + 71927C741472DF4A000AB618 /* quantChroma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quantChroma.h; path = lencod/inc/quantChroma.h; sourceTree = ""; }; + 71927C751472DF4A000AB618 /* ratectl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ratectl.h; path = lencod/inc/ratectl.h; sourceTree = ""; }; + 71927C761472DF4A000AB618 /* rc_quadratic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rc_quadratic.h; path = lencod/inc/rc_quadratic.h; sourceTree = ""; }; + 71927C771472DF4A000AB618 /* rc_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rc_types.h; path = lencod/inc/rc_types.h; sourceTree = ""; }; + 71927C781472DF4A000AB618 /* rd_intra_jm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rd_intra_jm.h; path = lencod/inc/rd_intra_jm.h; sourceTree = ""; }; + 71927C791472DF4A000AB618 /* rd_intra_jm444.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rd_intra_jm444.h; path = lencod/inc/rd_intra_jm444.h; sourceTree = ""; }; + 71927C7A1472DF4A000AB618 /* rdopt_coding_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rdopt_coding_state.h; path = lencod/inc/rdopt_coding_state.h; sourceTree = ""; }; + 71927C7B1472DF4A000AB618 /* rdopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rdopt.h; path = lencod/inc/rdopt.h; sourceTree = ""; }; + 71927C7C1472DF4A000AB618 /* rdoq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rdoq.h; path = lencod/inc/rdoq.h; sourceTree = ""; }; + 71927C7D1472DF4A000AB618 /* refbuf_otf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = refbuf_otf.h; path = lencod/inc/refbuf_otf.h; sourceTree = ""; }; + 71927C7E1472DF4A000AB618 /* refbuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = refbuf.h; path = lencod/inc/refbuf.h; sourceTree = ""; }; + 71927C7F1472DF4A000AB618 /* rtp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rtp.h; path = lencod/inc/rtp.h; sourceTree = ""; }; + 71927C801472DF4A000AB618 /* sei.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sei.h; path = lencod/inc/sei.h; sourceTree = ""; }; + 71927C811472DF4A000AB618 /* slice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = slice.h; path = lencod/inc/slice.h; sourceTree = ""; }; + 71927C821472DF4A000AB618 /* symbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = symbol.h; path = lencod/inc/symbol.h; sourceTree = ""; }; + 71927C831472DF4A000AB618 /* transform8x8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = transform8x8.h; path = lencod/inc/transform8x8.h; sourceTree = ""; }; + 71927C841472DF4A000AB618 /* vlc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vlc.h; path = lencod/inc/vlc.h; sourceTree = ""; }; + 71927C851472DF4A000AB618 /* wp_lms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wp_lms.h; path = lencod/inc/wp_lms.h; sourceTree = ""; }; + 71927C861472DF4A000AB618 /* wp_mciter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wp_mciter.h; path = lencod/inc/wp_mciter.h; sourceTree = ""; }; + 71927C871472DF4A000AB618 /* wp_mcprec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wp_mcprec.h; path = lencod/inc/wp_mcprec.h; sourceTree = ""; }; + 71927C881472DF4A000AB618 /* wp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wp.h; path = lencod/inc/wp.h; sourceTree = ""; }; + 71927C891472DF74000AB618 /* annexb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = annexb.c; path = lencod/src/annexb.c; sourceTree = ""; }; + 71927C8A1472DF74000AB618 /* biariencode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = biariencode.c; path = lencod/src/biariencode.c; sourceTree = ""; }; + 71927C8B1472DF74000AB618 /* block.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = block.c; path = lencod/src/block.c; sourceTree = ""; }; + 71927C8C1472DF74000AB618 /* cabac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cabac.c; path = lencod/src/cabac.c; sourceTree = ""; }; + 71927C8D1472DF74000AB618 /* cconv_yuv2rgb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cconv_yuv2rgb.c; path = lencod/src/cconv_yuv2rgb.c; sourceTree = ""; }; + 71927C8E1472DF74000AB618 /* configfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = configfile.c; path = lencod/src/configfile.c; sourceTree = ""; }; + 71927C8F1472DF74000AB618 /* conformance.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = conformance.c; path = lencod/src/conformance.c; sourceTree = ""; }; + 71927C901472DF74000AB618 /* context_ini.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = context_ini.c; path = lencod/src/context_ini.c; sourceTree = ""; }; + 71927C911472DF74000AB618 /* errdo_dist_mhyp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = errdo_dist_mhyp.c; path = lencod/src/errdo_dist_mhyp.c; sourceTree = ""; }; + 71927C921472DF74000AB618 /* errdo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = errdo.c; path = lencod/src/errdo.c; sourceTree = ""; }; + 71927C931472DF74000AB618 /* explicit_gop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = explicit_gop.c; path = lencod/src/explicit_gop.c; sourceTree = ""; }; + 71927C941472DF74000AB618 /* explicit_seq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = explicit_seq.c; path = lencod/src/explicit_seq.c; sourceTree = ""; }; + 71927C951472DF74000AB618 /* filehandle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = filehandle.c; path = lencod/src/filehandle.c; sourceTree = ""; }; + 71927C961472DF74000AB618 /* fmo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fmo.c; path = lencod/src/fmo.c; sourceTree = ""; }; + 71927C971472DF74000AB618 /* get_block_otf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = get_block_otf.c; path = lencod/src/get_block_otf.c; sourceTree = ""; }; + 71927C981472DF74000AB618 /* header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = header.c; path = lencod/src/header.c; sourceTree = ""; }; + 71927C991472DF74000AB618 /* image_mp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = image_mp.c; path = lencod/src/image_mp.c; sourceTree = ""; }; + 71927C9A1472DF74000AB618 /* image.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = image.c; path = lencod/src/image.c; sourceTree = ""; }; + 71927C9B1472DF74000AB618 /* img_chroma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = img_chroma.c; path = lencod/src/img_chroma.c; sourceTree = ""; }; + 71927C9C1472DF74000AB618 /* img_dist_ms_ssim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = img_dist_ms_ssim.c; path = lencod/src/img_dist_ms_ssim.c; sourceTree = ""; }; + 71927C9D1472DF74000AB618 /* img_dist_snr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = img_dist_snr.c; path = lencod/src/img_dist_snr.c; sourceTree = ""; }; + 71927C9E1472DF74000AB618 /* img_dist_ssim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = img_dist_ssim.c; path = lencod/src/img_dist_ssim.c; sourceTree = ""; }; + 71927C9F1472DF74000AB618 /* img_distortion.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = img_distortion.c; path = lencod/src/img_distortion.c; sourceTree = ""; }; + 71927CA01472DF74000AB618 /* img_luma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = img_luma.c; path = lencod/src/img_luma.c; sourceTree = ""; }; + 71927CA11472DF74000AB618 /* intra_chroma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = intra_chroma.c; path = lencod/src/intra_chroma.c; sourceTree = ""; }; + 71927CA21472DF74000AB618 /* intra4x4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = intra4x4.c; path = lencod/src/intra4x4.c; sourceTree = ""; }; + 71927CA31472DF74000AB618 /* intra8x8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = intra8x8.c; path = lencod/src/intra8x8.c; sourceTree = ""; }; + 71927CA41472DF74000AB618 /* intra16x16.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = intra16x16.c; path = lencod/src/intra16x16.c; sourceTree = ""; }; + 71927CA51472DF74000AB618 /* intrarefresh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = intrarefresh.c; path = lencod/src/intrarefresh.c; sourceTree = ""; }; + 71927CA61472DF74000AB618 /* lambda.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lambda.c; path = lencod/src/lambda.c; sourceTree = ""; }; + 71927CA71472DF74000AB618 /* leaky_bucket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = leaky_bucket.c; path = lencod/src/leaky_bucket.c; sourceTree = ""; }; + 71927CA81472DF74000AB618 /* lencod.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lencod.c; path = lencod/src/lencod.c; sourceTree = ""; }; + 71927CA91472DF74000AB618 /* list_reorder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = list_reorder.c; path = lencod/src/list_reorder.c; sourceTree = ""; }; + 71927CAA1472DF74000AB618 /* lln_mc_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lln_mc_prediction.c; path = lencod/src/lln_mc_prediction.c; sourceTree = ""; }; + 71927CAB1472DF74000AB618 /* loop_filter_mbaff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loop_filter_mbaff.c; path = lencod/src/loop_filter_mbaff.c; sourceTree = ""; }; + 71927CAC1472DF74000AB618 /* loop_filter_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loop_filter_normal.c; path = lencod/src/loop_filter_normal.c; sourceTree = ""; }; + 71927CAD1472DF74000AB618 /* loopFilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loopFilter.c; path = lencod/src/loopFilter.c; sourceTree = ""; }; + 71927CAE1472DF74000AB618 /* macroblock_P444.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = macroblock_P444.c; path = lencod/src/macroblock_P444.c; sourceTree = ""; }; + 71927CAF1472DF74000AB618 /* macroblock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = macroblock.c; path = lencod/src/macroblock.c; sourceTree = ""; }; + 71927CB01472DF74000AB618 /* mb_access.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mb_access.c; path = lencod/src/mb_access.c; sourceTree = ""; }; + 71927CB11472DF74000AB618 /* mbuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mbuffer.c; path = lencod/src/mbuffer.c; sourceTree = ""; }; + 71927CB21472DF74000AB618 /* mc_prediction_otf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mc_prediction_otf.c; path = lencod/src/mc_prediction_otf.c; sourceTree = ""; }; + 71927CB31472DF74000AB618 /* mc_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mc_prediction.c; path = lencod/src/mc_prediction.c; sourceTree = ""; }; + 71927CB41472DF74000AB618 /* md_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md_common.c; path = lencod/src/md_common.c; sourceTree = ""; }; + 71927CB51472DF74000AB618 /* md_distortion.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md_distortion.c; path = lencod/src/md_distortion.c; sourceTree = ""; }; + 71927CB61472DF74000AB618 /* md_high.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md_high.c; path = lencod/src/md_high.c; sourceTree = ""; }; + 71927CB71472DF74000AB618 /* md_highfast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md_highfast.c; path = lencod/src/md_highfast.c; sourceTree = ""; }; + 71927CB81472DF74000AB618 /* md_highloss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md_highloss.c; path = lencod/src/md_highloss.c; sourceTree = ""; }; + 71927CB91472DF74000AB618 /* md_low.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md_low.c; path = lencod/src/md_low.c; sourceTree = ""; }; + 71927CBA1472DF74000AB618 /* me_distortion_otf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_distortion_otf.c; path = lencod/src/me_distortion_otf.c; sourceTree = ""; }; + 71927CBB1472DF74000AB618 /* me_distortion.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_distortion.c; path = lencod/src/me_distortion.c; sourceTree = ""; }; + 71927CBC1472DF74000AB618 /* me_epzs_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_epzs_common.c; path = lencod/src/me_epzs_common.c; sourceTree = ""; }; + 71927CBD1472DF74000AB618 /* me_epzs_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_epzs_int.c; path = lencod/src/me_epzs_int.c; sourceTree = ""; }; + 71927CBE1472DF74000AB618 /* me_epzs_sub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_epzs_sub.c; path = lencod/src/me_epzs_sub.c; sourceTree = ""; }; + 71927CBF1472DF74000AB618 /* me_epzs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_epzs.c; path = lencod/src/me_epzs.c; sourceTree = ""; }; + 71927CC01472DF74000AB618 /* me_fullfast_otf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_fullfast_otf.c; path = lencod/src/me_fullfast_otf.c; sourceTree = ""; }; + 71927CC11472DF74000AB618 /* me_fullfast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_fullfast.c; path = lencod/src/me_fullfast.c; sourceTree = ""; }; + 71927CC21472DF74000AB618 /* me_fullsearch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_fullsearch.c; path = lencod/src/me_fullsearch.c; sourceTree = ""; }; + 71927CC31472DF74000AB618 /* me_umhex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_umhex.c; path = lencod/src/me_umhex.c; sourceTree = ""; }; + 71927CC41472DF74000AB618 /* me_umhexsmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = me_umhexsmp.c; path = lencod/src/me_umhexsmp.c; sourceTree = ""; }; + 71927CC51472DF74000AB618 /* mmco.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mmco.c; path = lencod/src/mmco.c; sourceTree = ""; }; + 71927CC61472DF74000AB618 /* mode_decision_P8x8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mode_decision_P8x8.c; path = lencod/src/mode_decision_P8x8.c; sourceTree = ""; }; + 71927CC71472DF74000AB618 /* mode_decision.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mode_decision.c; path = lencod/src/mode_decision.c; sourceTree = ""; }; + 71927CC81472DF74000AB618 /* mv_direct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mv_direct.c; path = lencod/src/mv_direct.c; sourceTree = ""; }; + 71927CC91472DF74000AB618 /* mv_search.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mv_search.c; path = lencod/src/mv_search.c; sourceTree = ""; }; + 71927CCA1472DF74000AB618 /* nal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nal.c; path = lencod/src/nal.c; sourceTree = ""; }; + 71927CCB1472DF74000AB618 /* nalu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nalu.c; path = lencod/src/nalu.c; sourceTree = ""; }; + 71927CCC1472DF74000AB618 /* output.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = output.c; path = lencod/src/output.c; sourceTree = ""; }; + 71927CCD1472DF74000AB618 /* parset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parset.c; path = lencod/src/parset.c; sourceTree = ""; }; + 71927CCE1472DF74000AB618 /* pred_struct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pred_struct.c; path = lencod/src/pred_struct.c; sourceTree = ""; }; + 71927CCF1472DF74000AB618 /* q_around.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = q_around.c; path = lencod/src/q_around.c; sourceTree = ""; }; + 71927CD01472DF74000AB618 /* q_matrix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = q_matrix.c; path = lencod/src/q_matrix.c; sourceTree = ""; }; + 71927CD11472DF74000AB618 /* q_offsets.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = q_offsets.c; path = lencod/src/q_offsets.c; sourceTree = ""; }; + 71927CD21472DF74000AB618 /* quant4x4_2step.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant4x4_2step.c; path = lencod/src/quant4x4_2step.c; sourceTree = ""; }; + 71927CD31472DF74000AB618 /* quant4x4_around.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant4x4_around.c; path = lencod/src/quant4x4_around.c; sourceTree = ""; }; + 71927CD41472DF74000AB618 /* quant4x4_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant4x4_normal.c; path = lencod/src/quant4x4_normal.c; sourceTree = ""; }; + 71927CD51472DF74000AB618 /* quant4x4_trellis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant4x4_trellis.c; path = lencod/src/quant4x4_trellis.c; sourceTree = ""; }; + 71927CD61472DF74000AB618 /* quant4x4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant4x4.c; path = lencod/src/quant4x4.c; sourceTree = ""; }; + 71927CD71472DF74000AB618 /* quant8x8_around.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant8x8_around.c; path = lencod/src/quant8x8_around.c; sourceTree = ""; }; + 71927CD81472DF74000AB618 /* quant8x8_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant8x8_normal.c; path = lencod/src/quant8x8_normal.c; sourceTree = ""; }; + 71927CD91472DF74000AB618 /* quant8x8_trellis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant8x8_trellis.c; path = lencod/src/quant8x8_trellis.c; sourceTree = ""; }; + 71927CDA1472DF74000AB618 /* quant8x8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quant8x8.c; path = lencod/src/quant8x8.c; sourceTree = ""; }; + 71927CDB1472DF74000AB618 /* quantChroma_2step.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quantChroma_2step.c; path = lencod/src/quantChroma_2step.c; sourceTree = ""; }; + 71927CDC1472DF74000AB618 /* quantChroma_around.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quantChroma_around.c; path = lencod/src/quantChroma_around.c; sourceTree = ""; }; + 71927CDD1472DF74000AB618 /* quantChroma_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quantChroma_normal.c; path = lencod/src/quantChroma_normal.c; sourceTree = ""; }; + 71927CDE1472DF74000AB618 /* quantChroma_trellis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quantChroma_trellis.c; path = lencod/src/quantChroma_trellis.c; sourceTree = ""; }; + 71927CDF1472DF74000AB618 /* quantChroma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quantChroma.c; path = lencod/src/quantChroma.c; sourceTree = ""; }; + 71927CE01472DF74000AB618 /* ratectl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ratectl.c; path = lencod/src/ratectl.c; sourceTree = ""; }; + 71927CE11472DF74000AB618 /* rc_quadratic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rc_quadratic.c; path = lencod/src/rc_quadratic.c; sourceTree = ""; }; + 71927CE21472DF74000AB618 /* rd_intra_jm_low.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rd_intra_jm_low.c; path = lencod/src/rd_intra_jm_low.c; sourceTree = ""; }; + 71927CE31472DF74000AB618 /* rd_intra_jm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rd_intra_jm.c; path = lencod/src/rd_intra_jm.c; sourceTree = ""; }; + 71927CE41472DF74000AB618 /* rd_intra_jm444.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rd_intra_jm444.c; path = lencod/src/rd_intra_jm444.c; sourceTree = ""; }; + 71927CE51472DF74000AB618 /* rdopt_coding_state.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rdopt_coding_state.c; path = lencod/src/rdopt_coding_state.c; sourceTree = ""; }; + 71927CE61472DF74000AB618 /* rdopt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rdopt.c; path = lencod/src/rdopt.c; sourceTree = ""; }; + 71927CE71472DF74000AB618 /* rdoq_cabac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rdoq_cabac.c; path = lencod/src/rdoq_cabac.c; sourceTree = ""; }; + 71927CE81472DF74000AB618 /* rdoq_cavlc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rdoq_cavlc.c; path = lencod/src/rdoq_cavlc.c; sourceTree = ""; }; + 71927CE91472DF74000AB618 /* rdoq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rdoq.c; path = lencod/src/rdoq.c; sourceTree = ""; }; + 71927CEA1472DF74000AB618 /* rdpicdecision.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rdpicdecision.c; path = lencod/src/rdpicdecision.c; sourceTree = ""; }; + 71927CEB1472DF74000AB618 /* report.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = report.c; path = lencod/src/report.c; sourceTree = ""; }; + 71927CEC1472DF74000AB618 /* rtp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rtp.c; path = lencod/src/rtp.c; sourceTree = ""; }; + 71927CED1472DF74000AB618 /* sei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sei.c; path = lencod/src/sei.c; sourceTree = ""; }; + 71927CEE1472DF74000AB618 /* slice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = slice.c; path = lencod/src/slice.c; sourceTree = ""; }; + 71927CEF1472DF74000AB618 /* symbol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbol.c; path = lencod/src/symbol.c; sourceTree = ""; }; + 71927CF01472DF74000AB618 /* transform8x8_H444.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = transform8x8_H444.c; path = lencod/src/transform8x8_H444.c; sourceTree = ""; }; + 71927CF11472DF74000AB618 /* transform8x8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = transform8x8.c; path = lencod/src/transform8x8.c; sourceTree = ""; }; + 71927CF21472DF74000AB618 /* vlc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vlc.c; path = lencod/src/vlc.c; sourceTree = ""; }; + 71927CF31472DF74000AB618 /* weighted_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = weighted_prediction.c; path = lencod/src/weighted_prediction.c; sourceTree = ""; }; + 71927CF41472DF74000AB618 /* wp_lms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wp_lms.c; path = lencod/src/wp_lms.c; sourceTree = ""; }; + 71927CF51472DF74000AB618 /* wp_mciter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wp_mciter.c; path = lencod/src/wp_mciter.c; sourceTree = ""; }; + 71927CF61472DF74000AB618 /* wp_mcprec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wp_mcprec.c; path = lencod/src/wp_mcprec.c; sourceTree = ""; }; + 71927D651472DF98000AB618 /* annexb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = annexb.c; sourceTree = ""; }; + 71927D661472DF98000AB618 /* biaridecod.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = biaridecod.c; sourceTree = ""; }; + 71927D671472DF98000AB618 /* block.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = block.c; sourceTree = ""; }; + 71927D681472DF98000AB618 /* cabac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cabac.c; sourceTree = ""; }; + 71927D691472DF98000AB618 /* configfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = configfile.c; sourceTree = ""; }; + 71927D6A1472DF98000AB618 /* context_ini.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = context_ini.c; sourceTree = ""; }; + 71927D6B1472DF98000AB618 /* dec_statistics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dec_statistics.c; sourceTree = ""; }; + 71927D6C1472DF98000AB618 /* decoder_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = decoder_test.c; sourceTree = ""; }; + 71927D6D1472DF98000AB618 /* erc_api.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = erc_api.c; sourceTree = ""; }; + 71927D6E1472DF98000AB618 /* erc_do_i.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = erc_do_i.c; sourceTree = ""; }; + 71927D6F1472DF98000AB618 /* erc_do_p.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = erc_do_p.c; sourceTree = ""; }; + 71927D701472DF98000AB618 /* errorconcealment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = errorconcealment.c; sourceTree = ""; }; + 71927D711472DF98000AB618 /* filehandle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filehandle.c; sourceTree = ""; }; + 71927D721472DF98000AB618 /* fmo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmo.c; sourceTree = ""; }; + 71927D731472DF98000AB618 /* header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = header.c; sourceTree = ""; }; + 71927D741472DF98000AB618 /* image.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = image.c; sourceTree = ""; }; + 71927D751472DF98000AB618 /* intra_chroma_pred_mbaff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra_chroma_pred_mbaff.c; sourceTree = ""; }; + 71927D761472DF98000AB618 /* intra_chroma_pred.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra_chroma_pred.c; sourceTree = ""; }; + 71927D771472DF98000AB618 /* intra_pred_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra_pred_common.c; sourceTree = ""; }; + 71927D781472DF98000AB618 /* intra4x4_pred_mbaff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra4x4_pred_mbaff.c; sourceTree = ""; }; + 71927D791472DF98000AB618 /* intra4x4_pred_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra4x4_pred_normal.c; sourceTree = ""; }; + 71927D7A1472DF98000AB618 /* intra4x4_pred.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra4x4_pred.c; sourceTree = ""; }; + 71927D7B1472DF98000AB618 /* intra8x8_pred_mbaff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra8x8_pred_mbaff.c; sourceTree = ""; }; + 71927D7C1472DF98000AB618 /* intra8x8_pred_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra8x8_pred_normal.c; sourceTree = ""; }; + 71927D7D1472DF98000AB618 /* intra8x8_pred.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra8x8_pred.c; sourceTree = ""; }; + 71927D7E1472DF98000AB618 /* intra16x16_pred_mbaff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra16x16_pred_mbaff.c; sourceTree = ""; }; + 71927D7F1472DF98000AB618 /* intra16x16_pred_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra16x16_pred_normal.c; sourceTree = ""; }; + 71927D801472DF98000AB618 /* intra16x16_pred.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intra16x16_pred.c; sourceTree = ""; }; + 71927D811472DF98000AB618 /* ldecod.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ldecod.c; sourceTree = ""; }; + 71927D821472DF98000AB618 /* leaky_bucket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = leaky_bucket.c; sourceTree = ""; }; + 71927D831472DF98000AB618 /* loop_filter_mbaff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = loop_filter_mbaff.c; sourceTree = ""; }; + 71927D841472DF98000AB618 /* loop_filter_normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = loop_filter_normal.c; sourceTree = ""; }; + 71927D851472DF98000AB618 /* loopFilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = loopFilter.c; sourceTree = ""; }; + 71927D861472DF98000AB618 /* macroblock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = macroblock.c; sourceTree = ""; }; + 71927D871472DF98000AB618 /* mb_access.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mb_access.c; sourceTree = ""; }; + 71927D881472DF98000AB618 /* mb_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mb_prediction.c; sourceTree = ""; }; + 71927D891472DF98000AB618 /* mb_read.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mb_read.c; sourceTree = ""; }; + 71927D8A1472DF98000AB618 /* mbuffer_mvc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbuffer_mvc.c; sourceTree = ""; }; + 71927D8B1472DF98000AB618 /* mbuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbuffer.c; sourceTree = ""; }; + 71927D8C1472DF98000AB618 /* mc_direct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc_direct.c; sourceTree = ""; }; + 71927D8D1472DF98000AB618 /* mc_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc_prediction.c; sourceTree = ""; }; + 71927D8E1472DF98000AB618 /* nal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nal.c; sourceTree = ""; }; + 71927D8F1472DF98000AB618 /* nalu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nalu.c; sourceTree = ""; }; + 71927D901472DF98000AB618 /* output.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = output.c; sourceTree = ""; }; + 71927D911472DF98000AB618 /* parset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parset.c; sourceTree = ""; }; + 71927D921472DF98000AB618 /* quant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = quant.c; sourceTree = ""; }; + 71927D931472DF98000AB618 /* read_comp_cabac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = read_comp_cabac.c; sourceTree = ""; }; + 71927D941472DF98000AB618 /* read_comp_cavlc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = read_comp_cavlc.c; sourceTree = ""; }; + 71927D951472DF98000AB618 /* rtp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtp.c; sourceTree = ""; }; + 71927D961472DF98000AB618 /* sei.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sei.c; sourceTree = ""; }; + 71927D971472DF98000AB618 /* transform8x8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = transform8x8.c; sourceTree = ""; }; + 71927D981472DF98000AB618 /* vlc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vlc.c; sourceTree = ""; }; + 71927DCD1472DFB3000AB618 /* annexb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = annexb.h; sourceTree = ""; }; + 71927DCE1472DFB3000AB618 /* biaridecod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = biaridecod.h; sourceTree = ""; }; + 71927DCF1472DFB3000AB618 /* block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = block.h; sourceTree = ""; }; + 71927DD01472DFB3000AB618 /* cabac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cabac.h; sourceTree = ""; }; + 71927DD11472DFB3000AB618 /* configfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = configfile.h; sourceTree = ""; }; + 71927DD21472DFB3000AB618 /* context_ini.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = context_ini.h; sourceTree = ""; }; + 71927DD31472DFB3000AB618 /* contributors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contributors.h; sourceTree = ""; }; + 71927DD41472DFB3000AB618 /* dec_statistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dec_statistics.h; sourceTree = ""; }; + 71927DD51472DFB3000AB618 /* defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = defines.h; sourceTree = ""; }; + 71927DD61472DFB3000AB618 /* elements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = elements.h; sourceTree = ""; }; + 71927DD71472DFB3000AB618 /* erc_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = erc_api.h; sourceTree = ""; }; + 71927DD81472DFB3000AB618 /* erc_do.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = erc_do.h; sourceTree = ""; }; + 71927DD91472DFB3000AB618 /* erc_globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = erc_globals.h; sourceTree = ""; }; + 71927DDA1472DFB3000AB618 /* errorconcealment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = errorconcealment.h; sourceTree = ""; }; + 71927DDB1472DFB3000AB618 /* filehandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filehandle.h; sourceTree = ""; }; + 71927DDC1472DFB3000AB618 /* fmo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmo.h; sourceTree = ""; }; + 71927DDD1472DFB3000AB618 /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = global.h; sourceTree = ""; }; + 71927DDE1472DFB3000AB618 /* h264decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = h264decoder.h; sourceTree = ""; }; + 71927DDF1472DFB3000AB618 /* header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = header.h; sourceTree = ""; }; + 71927DE01472DFB3000AB618 /* image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = image.h; sourceTree = ""; }; + 71927DE11472DFB3000AB618 /* intra4x4_pred.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intra4x4_pred.h; sourceTree = ""; }; + 71927DE21472DFB3000AB618 /* intra8x8_pred.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intra8x8_pred.h; sourceTree = ""; }; + 71927DE31472DFB3000AB618 /* intra16x16_pred.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intra16x16_pred.h; sourceTree = ""; }; + 71927DE41472DFB3000AB618 /* leaky_bucket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = leaky_bucket.h; sourceTree = ""; }; + 71927DE51472DFB3000AB618 /* loop_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_filter.h; sourceTree = ""; }; + 71927DE61472DFB3000AB618 /* loopfilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loopfilter.h; sourceTree = ""; }; + 71927DE71472DFB3000AB618 /* macroblock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macroblock.h; sourceTree = ""; }; + 71927DE81472DFB3000AB618 /* mb_prediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mb_prediction.h; sourceTree = ""; }; + 71927DE91472DFB3000AB618 /* mbuffer_mvc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mbuffer_mvc.h; sourceTree = ""; }; + 71927DEA1472DFB3000AB618 /* mbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mbuffer.h; sourceTree = ""; }; + 71927DEB1472DFB3000AB618 /* mc_prediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mc_prediction.h; sourceTree = ""; }; + 71927DEC1472DFB3000AB618 /* nalu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nalu.h; sourceTree = ""; }; + 71927DED1472DFB3000AB618 /* output.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = output.h; sourceTree = ""; }; + 71927DEE1472DFB3000AB618 /* parset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parset.h; sourceTree = ""; }; + 71927DEF1472DFB3000AB618 /* quant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quant.h; sourceTree = ""; }; + 71927DF01472DFB3000AB618 /* rtp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtp.h; sourceTree = ""; }; + 71927DF11472DFB3000AB618 /* sei.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sei.h; sourceTree = ""; }; + 71927DF21472DFB3000AB618 /* transform8x8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transform8x8.h; sourceTree = ""; }; + 71927DF31472DFB3000AB618 /* vlc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vlc.h; sourceTree = ""; }; + 71927DF41472DFCB000AB618 /* blk_prediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blk_prediction.h; sourceTree = ""; }; + 71927DF51472DFCB000AB618 /* config_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_common.h; sourceTree = ""; }; + 71927DF61472DFCB000AB618 /* ctx_tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ctx_tables.h; sourceTree = ""; }; + 71927DF71472DFCB000AB618 /* distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = distortion.h; sourceTree = ""; }; + 71927DF81472DFCB000AB618 /* enc_statistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = enc_statistics.h; sourceTree = ""; }; + 71927DF91472DFCB000AB618 /* fast_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fast_memory.h; sourceTree = ""; }; + 71927DFA1472DFCB000AB618 /* frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = frame.h; sourceTree = ""; }; + 71927DFB1472DFCB000AB618 /* ifunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ifunctions.h; sourceTree = ""; }; + 71927DFC1472DFCB000AB618 /* img_io.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img_io.h; sourceTree = ""; }; + 71927DFD1472DFCB000AB618 /* img_process_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img_process_types.h; sourceTree = ""; }; + 71927DFE1472DFCB000AB618 /* img_process.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img_process.h; sourceTree = ""; }; + 71927DFF1472DFCB000AB618 /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input.h; sourceTree = ""; }; + 71927E001472DFCB000AB618 /* io_image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = io_image.h; sourceTree = ""; }; + 71927E011472DFCB000AB618 /* io_raw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = io_raw.h; sourceTree = ""; }; + 71927E021472DFCB000AB618 /* io_tiff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = io_tiff.h; sourceTree = ""; }; + 71927E031472DFCB000AB618 /* io_video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = io_video.h; sourceTree = ""; }; + 71927E041472DFCB000AB618 /* lagrangian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lagrangian.h; sourceTree = ""; }; + 71927E051472DFCB000AB618 /* mb_access.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mb_access.h; sourceTree = ""; }; + 71927E061472DFCB000AB618 /* mbuffer_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mbuffer_common.h; sourceTree = ""; }; + 71927E071472DFCB000AB618 /* memalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memalloc.h; sourceTree = ""; }; + 71927E081472DFCB000AB618 /* mv_prediction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mv_prediction.h; sourceTree = ""; }; + 71927E091472DFCB000AB618 /* nalucommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nalucommon.h; sourceTree = ""; }; + 71927E0A1472DFCB000AB618 /* parsetcommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parsetcommon.h; sourceTree = ""; }; + 71927E0B1472DFCB000AB618 /* quant_params.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quant_params.h; sourceTree = ""; }; + 71927E0C1472DFCB000AB618 /* report.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = report.h; sourceTree = ""; }; + 71927E0D1472DFCB000AB618 /* transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transform.h; sourceTree = ""; }; + 71927E0E1472DFCB000AB618 /* typedefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = typedefs.h; sourceTree = ""; }; + 71927E0F1472DFCB000AB618 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; + 71927E101472DFCB000AB618 /* vui_params.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vui_params.h; sourceTree = ""; }; + 71927E111472DFCB000AB618 /* win32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = win32.h; sourceTree = ""; }; + 71927E121472DFE1000AB618 /* blk_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blk_prediction.c; sourceTree = ""; }; + 71927E131472DFE1000AB618 /* config_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = config_common.c; sourceTree = ""; }; + 71927E141472DFE1000AB618 /* img_io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = img_io.c; sourceTree = ""; }; + 71927E151472DFE1000AB618 /* img_process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = img_process.c; sourceTree = ""; }; + 71927E161472DFE1000AB618 /* input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = input.c; sourceTree = ""; }; + 71927E171472DFE1000AB618 /* io_raw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = io_raw.c; sourceTree = ""; }; + 71927E181472DFE1000AB618 /* io_tiff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = io_tiff.c; sourceTree = ""; }; + 71927E191472DFE1000AB618 /* mbuffer_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbuffer_common.c; sourceTree = ""; }; + 71927E1A1472DFE1000AB618 /* memalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memalloc.c; sourceTree = ""; }; + 71927E1B1472DFE1000AB618 /* mv_prediction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mv_prediction.c; sourceTree = ""; }; + 71927E1C1472DFE1000AB618 /* nalucommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nalucommon.c; sourceTree = ""; }; + 71927E1D1472DFE1000AB618 /* parsetcommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parsetcommon.c; sourceTree = ""; }; + 71927E1E1472DFE1000AB618 /* transform.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = transform.c; sourceTree = ""; }; + 71927E1F1472DFE1000AB618 /* win32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = win32.c; sourceTree = ""; }; + 8DD76FB20486AB0100D96B5E /* lencod */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lencod; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 436FC2970D85FB4900D8E371 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 436FC2A50D85FC1C00D8E371 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43FA4B100D4EECBB001709F1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8DD76FAD0486AB0100D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* JM */ = { + isa = PBXGroup; + children = ( + 71C9040E0FE2828A0095EA3A /* lcommon */, + 43FA4B190D4EED45001709F1 /* ldecod */, + 43FA4A0F0D4EE917001709F1 /* lencod */, + 436FC24E0D85FA8A00D8E371 /* rtp_loss */, + 436FC24F0D85FA9A00D8E371 /* rtpdump */, + 434D2ABF0D5C1C0D00610974 /* Configs */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = JM; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FB20486AB0100D96B5E /* lencod */, + 43FA4B170D4EECBB001709F1 /* ldecod */, + 436FC29C0D85FB4900D8E371 /* rtpdump */, + 436FC2AA0D85FC1C00D8E371 /* rtp_loss */, + ); + name = Products; + sourceTree = ""; + }; + 434D2ABF0D5C1C0D00610974 /* Configs */ = { + isa = PBXGroup; + children = ( + 434D2AC20D5C1C3E00610974 /* decoder.cfg */, + 434D2AC40D5C1C3E00610974 /* encoder.cfg */, + 434D2AC50D5C1C3E00610974 /* encoder_baseline.cfg */, + 434D2AC60D5C1C3E00610974 /* encoder_extended.cfg */, + 434D2AC80D5C1C3E00610974 /* encoder_main.cfg */, + 434D2AC90D5C1C3E00610974 /* encoder_tonemapping.cfg */, + 434D2ACA0D5C1C3E00610974 /* encoder_yuv422.cfg */, + 434D2ACD0D5C1C3E00610974 /* leakybucketrate.cfg */, + 434D2ACE0D5C1C3E00610974 /* q_matrix.cfg */, + 434D2ACF0D5C1C3E00610974 /* q_matrix2.cfg */, + 434D2AD00D5C1C3E00610974 /* q_matrix_def.cfg */, + 434D2AD10D5C1C3E00610974 /* q_offset.cfg */, + 434D2AD30D5C1C3E00610974 /* sg0conf.cfg */, + 434D2AD40D5C1C3E00610974 /* sg2conf.cfg */, + 434D2AD50D5C1C3E00610974 /* sg6conf.cfg */, + 434D2AD80D5C1C3E00610974 /* ToneMapping.cfg */, + ); + name = Configs; + sourceTree = ""; + }; + 436FC24E0D85FA8A00D8E371 /* rtp_loss */ = { + isa = PBXGroup; + children = ( + 436FC2AE0D85FC4B00D8E371 /* ReadMe.txt */, + 436FC2AD0D85FC4B00D8E371 /* rtp_loss.cpp */, + 436FC2AC0D85FC4B00D8E371 /* rtp_loss.h */, + ); + name = rtp_loss; + sourceTree = ""; + }; + 436FC24F0D85FA9A00D8E371 /* rtpdump */ = { + isa = PBXGroup; + children = ( + 436FC25A0D85FB3900D8E371 /* rtpdump.cpp */, + ); + name = rtpdump; + sourceTree = ""; + }; + 43FA4A0F0D4EE917001709F1 /* lencod */ = { + isa = PBXGroup; + children = ( + 43FA4A100D4EE91C001709F1 /* inc */, + 43FA4A110D4EE920001709F1 /* src */, + ); + name = lencod; + sourceTree = ""; + }; + 43FA4A100D4EE91C001709F1 /* inc */ = { + isa = PBXGroup; + children = ( + 71927C2D1472DF4A000AB618 /* annexb.h */, + 71927C2E1472DF4A000AB618 /* biariencode.h */, + 71927C2F1472DF4A000AB618 /* block.h */, + 71927C301472DF4A000AB618 /* cabac.h */, + 71927C311472DF4A000AB618 /* cconv_yuv2rgb.h */, + 71927C321472DF4A000AB618 /* configfile.h */, + 71927C331472DF4A000AB618 /* conformance.h */, + 71927C341472DF4A000AB618 /* context_ini.h */, + 71927C351472DF4A000AB618 /* contributors.h */, + 71927C361472DF4A000AB618 /* defines.h */, + 71927C371472DF4A000AB618 /* elements.h */, + 71927C381472DF4A000AB618 /* errdo_dist_mhyp.h */, + 71927C391472DF4A000AB618 /* errdo.h */, + 71927C3A1472DF4A000AB618 /* explicit_gop.h */, + 71927C3B1472DF4A000AB618 /* explicit_seq.h */, + 71927C3C1472DF4A000AB618 /* filehandle.h */, + 71927C3D1472DF4A000AB618 /* fmo.h */, + 71927C3E1472DF4A000AB618 /* get_block_otf.h */, + 71927C3F1472DF4A000AB618 /* global.h */, + 71927C401472DF4A000AB618 /* header.h */, + 71927C411472DF4A000AB618 /* image.h */, + 71927C421472DF4A000AB618 /* img_chroma.h */, + 71927C431472DF4A000AB618 /* img_dist_ms_ssim.h */, + 71927C441472DF4A000AB618 /* img_dist_snr.h */, + 71927C451472DF4A000AB618 /* img_dist_ssim.h */, + 71927C461472DF4A000AB618 /* img_distortion.h */, + 71927C471472DF4A000AB618 /* img_luma.h */, + 71927C481472DF4A000AB618 /* intra4x4.h */, + 71927C491472DF4A000AB618 /* intra8x8.h */, + 71927C4A1472DF4A000AB618 /* intra16x16.h */, + 71927C4B1472DF4A000AB618 /* intrarefresh.h */, + 71927C4C1472DF4A000AB618 /* lambda.h */, + 71927C4D1472DF4A000AB618 /* leaky_bucket.h */, + 71927C4E1472DF4A000AB618 /* list_reorder.h */, + 71927C4F1472DF4A000AB618 /* lln_mc_prediction.h */, + 71927C501472DF4A000AB618 /* loop_filter.h */, + 71927C511472DF4A000AB618 /* macroblock_p444.h */, + 71927C521472DF4A000AB618 /* macroblock.h */, + 71927C531472DF4A000AB618 /* mbuffer.h */, + 71927C541472DF4A000AB618 /* mc_prediction_otf.h */, + 71927C551472DF4A000AB618 /* mc_prediction.h */, + 71927C561472DF4A000AB618 /* md_common.h */, + 71927C571472DF4A000AB618 /* md_distortion.h */, + 71927C581472DF4A000AB618 /* me_distortion_otf.h */, + 71927C591472DF4A000AB618 /* me_distortion.h */, + 71927C5A1472DF4A000AB618 /* me_epzs_common.h */, + 71927C5B1472DF4A000AB618 /* me_epzs_int.h */, + 71927C5C1472DF4A000AB618 /* me_epzs.h */, + 71927C5D1472DF4A000AB618 /* me_fullfast_otf.h */, + 71927C5E1472DF4A000AB618 /* me_fullfast.h */, + 71927C5F1472DF4A000AB618 /* me_fullsearch.h */, + 71927C601472DF4A000AB618 /* me_umhex.h */, + 71927C611472DF4A000AB618 /* me_umhexsmp.h */, + 71927C621472DF4A000AB618 /* mmco.h */, + 71927C631472DF4A000AB618 /* mode_decision_p8x8.h */, + 71927C641472DF4A000AB618 /* mode_decision.h */, + 71927C651472DF4A000AB618 /* mv_search.h */, + 71927C661472DF4A000AB618 /* nal.h */, + 71927C671472DF4A000AB618 /* nalu.h */, + 71927C681472DF4A000AB618 /* output.h */, + 71927C691472DF4A000AB618 /* params.h */, + 71927C6A1472DF4A000AB618 /* parset.h */, + 71927C6B1472DF4A000AB618 /* pred_struct_adapt_types.h */, + 71927C6C1472DF4A000AB618 /* pred_struct_adapt.h */, + 71927C6D1472DF4A000AB618 /* pred_struct_types.h */, + 71927C6E1472DF4A000AB618 /* pred_struct.h */, + 71927C6F1472DF4A000AB618 /* q_around.h */, + 71927C701472DF4A000AB618 /* q_matrix.h */, + 71927C711472DF4A000AB618 /* q_offsets.h */, + 71927C721472DF4A000AB618 /* quant4x4.h */, + 71927C731472DF4A000AB618 /* quant8x8.h */, + 71927C741472DF4A000AB618 /* quantChroma.h */, + 71927C751472DF4A000AB618 /* ratectl.h */, + 71927C761472DF4A000AB618 /* rc_quadratic.h */, + 71927C771472DF4A000AB618 /* rc_types.h */, + 71927C781472DF4A000AB618 /* rd_intra_jm.h */, + 71927C791472DF4A000AB618 /* rd_intra_jm444.h */, + 71927C7A1472DF4A000AB618 /* rdopt_coding_state.h */, + 71927C7B1472DF4A000AB618 /* rdopt.h */, + 71927C7C1472DF4A000AB618 /* rdoq.h */, + 71927C7D1472DF4A000AB618 /* refbuf_otf.h */, + 71927C7E1472DF4A000AB618 /* refbuf.h */, + 71927C7F1472DF4A000AB618 /* rtp.h */, + 71927C801472DF4A000AB618 /* sei.h */, + 71927C811472DF4A000AB618 /* slice.h */, + 71927C821472DF4A000AB618 /* symbol.h */, + 71927C831472DF4A000AB618 /* transform8x8.h */, + 71927C841472DF4A000AB618 /* vlc.h */, + 71927C851472DF4A000AB618 /* wp_lms.h */, + 71927C861472DF4A000AB618 /* wp_mciter.h */, + 71927C871472DF4A000AB618 /* wp_mcprec.h */, + 71927C881472DF4A000AB618 /* wp.h */, + ); + name = inc; + sourceTree = ""; + }; + 43FA4A110D4EE920001709F1 /* src */ = { + isa = PBXGroup; + children = ( + 71927C891472DF74000AB618 /* annexb.c */, + 71927C8A1472DF74000AB618 /* biariencode.c */, + 71927C8B1472DF74000AB618 /* block.c */, + 71927C8C1472DF74000AB618 /* cabac.c */, + 71927C8D1472DF74000AB618 /* cconv_yuv2rgb.c */, + 71927C8E1472DF74000AB618 /* configfile.c */, + 71927C8F1472DF74000AB618 /* conformance.c */, + 71927C901472DF74000AB618 /* context_ini.c */, + 71927C911472DF74000AB618 /* errdo_dist_mhyp.c */, + 71927C921472DF74000AB618 /* errdo.c */, + 71927C931472DF74000AB618 /* explicit_gop.c */, + 71927C941472DF74000AB618 /* explicit_seq.c */, + 71927C951472DF74000AB618 /* filehandle.c */, + 71927C961472DF74000AB618 /* fmo.c */, + 71927C971472DF74000AB618 /* get_block_otf.c */, + 71927C981472DF74000AB618 /* header.c */, + 71927C991472DF74000AB618 /* image_mp.c */, + 71927C9A1472DF74000AB618 /* image.c */, + 71927C9B1472DF74000AB618 /* img_chroma.c */, + 71927C9C1472DF74000AB618 /* img_dist_ms_ssim.c */, + 71927C9D1472DF74000AB618 /* img_dist_snr.c */, + 71927C9E1472DF74000AB618 /* img_dist_ssim.c */, + 71927C9F1472DF74000AB618 /* img_distortion.c */, + 71927CA01472DF74000AB618 /* img_luma.c */, + 71927CA11472DF74000AB618 /* intra_chroma.c */, + 71927CA21472DF74000AB618 /* intra4x4.c */, + 71927CA31472DF74000AB618 /* intra8x8.c */, + 71927CA41472DF74000AB618 /* intra16x16.c */, + 71927CA51472DF74000AB618 /* intrarefresh.c */, + 71927CA61472DF74000AB618 /* lambda.c */, + 71927CA71472DF74000AB618 /* leaky_bucket.c */, + 71927CA81472DF74000AB618 /* lencod.c */, + 71927CA91472DF74000AB618 /* list_reorder.c */, + 71927CAA1472DF74000AB618 /* lln_mc_prediction.c */, + 71927CAB1472DF74000AB618 /* loop_filter_mbaff.c */, + 71927CAC1472DF74000AB618 /* loop_filter_normal.c */, + 71927CAD1472DF74000AB618 /* loopFilter.c */, + 71927CAE1472DF74000AB618 /* macroblock_P444.c */, + 71927CAF1472DF74000AB618 /* macroblock.c */, + 71927CB01472DF74000AB618 /* mb_access.c */, + 71927CB11472DF74000AB618 /* mbuffer.c */, + 71927CB21472DF74000AB618 /* mc_prediction_otf.c */, + 71927CB31472DF74000AB618 /* mc_prediction.c */, + 71927CB41472DF74000AB618 /* md_common.c */, + 71927CB51472DF74000AB618 /* md_distortion.c */, + 71927CB61472DF74000AB618 /* md_high.c */, + 71927CB71472DF74000AB618 /* md_highfast.c */, + 71927CB81472DF74000AB618 /* md_highloss.c */, + 71927CB91472DF74000AB618 /* md_low.c */, + 71927CBA1472DF74000AB618 /* me_distortion_otf.c */, + 71927CBB1472DF74000AB618 /* me_distortion.c */, + 71927CBC1472DF74000AB618 /* me_epzs_common.c */, + 71927CBD1472DF74000AB618 /* me_epzs_int.c */, + 71927CBE1472DF74000AB618 /* me_epzs_sub.c */, + 71927CBF1472DF74000AB618 /* me_epzs.c */, + 71927CC01472DF74000AB618 /* me_fullfast_otf.c */, + 71927CC11472DF74000AB618 /* me_fullfast.c */, + 71927CC21472DF74000AB618 /* me_fullsearch.c */, + 71927CC31472DF74000AB618 /* me_umhex.c */, + 71927CC41472DF74000AB618 /* me_umhexsmp.c */, + 71927CC51472DF74000AB618 /* mmco.c */, + 71927CC61472DF74000AB618 /* mode_decision_P8x8.c */, + 71927CC71472DF74000AB618 /* mode_decision.c */, + 71927CC81472DF74000AB618 /* mv_direct.c */, + 71927CC91472DF74000AB618 /* mv_search.c */, + 71927CCA1472DF74000AB618 /* nal.c */, + 71927CCB1472DF74000AB618 /* nalu.c */, + 71927CCC1472DF74000AB618 /* output.c */, + 71927CCD1472DF74000AB618 /* parset.c */, + 71927CCE1472DF74000AB618 /* pred_struct.c */, + 71927CCF1472DF74000AB618 /* q_around.c */, + 71927CD01472DF74000AB618 /* q_matrix.c */, + 71927CD11472DF74000AB618 /* q_offsets.c */, + 71927CD21472DF74000AB618 /* quant4x4_2step.c */, + 71927CD31472DF74000AB618 /* quant4x4_around.c */, + 71927CD41472DF74000AB618 /* quant4x4_normal.c */, + 71927CD51472DF74000AB618 /* quant4x4_trellis.c */, + 71927CD61472DF74000AB618 /* quant4x4.c */, + 71927CD71472DF74000AB618 /* quant8x8_around.c */, + 71927CD81472DF74000AB618 /* quant8x8_normal.c */, + 71927CD91472DF74000AB618 /* quant8x8_trellis.c */, + 71927CDA1472DF74000AB618 /* quant8x8.c */, + 71927CDB1472DF74000AB618 /* quantChroma_2step.c */, + 71927CDC1472DF74000AB618 /* quantChroma_around.c */, + 71927CDD1472DF74000AB618 /* quantChroma_normal.c */, + 71927CDE1472DF74000AB618 /* quantChroma_trellis.c */, + 71927CDF1472DF74000AB618 /* quantChroma.c */, + 71927CE01472DF74000AB618 /* ratectl.c */, + 71927CE11472DF74000AB618 /* rc_quadratic.c */, + 71927CE21472DF74000AB618 /* rd_intra_jm_low.c */, + 71927CE31472DF74000AB618 /* rd_intra_jm.c */, + 71927CE41472DF74000AB618 /* rd_intra_jm444.c */, + 71927CE51472DF74000AB618 /* rdopt_coding_state.c */, + 71927CE61472DF74000AB618 /* rdopt.c */, + 71927CE71472DF74000AB618 /* rdoq_cabac.c */, + 71927CE81472DF74000AB618 /* rdoq_cavlc.c */, + 71927CE91472DF74000AB618 /* rdoq.c */, + 71927CEA1472DF74000AB618 /* rdpicdecision.c */, + 71927CEB1472DF74000AB618 /* report.c */, + 71927CEC1472DF74000AB618 /* rtp.c */, + 71927CED1472DF74000AB618 /* sei.c */, + 71927CEE1472DF74000AB618 /* slice.c */, + 71927CEF1472DF74000AB618 /* symbol.c */, + 71927CF01472DF74000AB618 /* transform8x8_H444.c */, + 71927CF11472DF74000AB618 /* transform8x8.c */, + 71927CF21472DF74000AB618 /* vlc.c */, + 71927CF31472DF74000AB618 /* weighted_prediction.c */, + 71927CF41472DF74000AB618 /* wp_lms.c */, + 71927CF51472DF74000AB618 /* wp_mciter.c */, + 71927CF61472DF74000AB618 /* wp_mcprec.c */, + ); + name = src; + sourceTree = ""; + }; + 43FA4B190D4EED45001709F1 /* ldecod */ = { + isa = PBXGroup; + children = ( + 71C904B60FE283800095EA3A /* inc */, + 71C904D80FE283800095EA3A /* src */, + ); + name = ldecod; + sourceTree = ""; + }; + 71C9040E0FE2828A0095EA3A /* lcommon */ = { + isa = PBXGroup; + children = ( + 71C904180FE283370095EA3A /* inc */, + 71C904320FE283370095EA3A /* src */, + ); + name = lcommon; + sourceTree = ""; + }; + 71C904180FE283370095EA3A /* inc */ = { + isa = PBXGroup; + children = ( + 71927DF41472DFCB000AB618 /* blk_prediction.h */, + 71927DF51472DFCB000AB618 /* config_common.h */, + 71927DF61472DFCB000AB618 /* ctx_tables.h */, + 71927DF71472DFCB000AB618 /* distortion.h */, + 71927DF81472DFCB000AB618 /* enc_statistics.h */, + 71927DF91472DFCB000AB618 /* fast_memory.h */, + 71927DFA1472DFCB000AB618 /* frame.h */, + 71927DFB1472DFCB000AB618 /* ifunctions.h */, + 71927DFC1472DFCB000AB618 /* img_io.h */, + 71927DFD1472DFCB000AB618 /* img_process_types.h */, + 71927DFE1472DFCB000AB618 /* img_process.h */, + 71927DFF1472DFCB000AB618 /* input.h */, + 71927E001472DFCB000AB618 /* io_image.h */, + 71927E011472DFCB000AB618 /* io_raw.h */, + 71927E021472DFCB000AB618 /* io_tiff.h */, + 71927E031472DFCB000AB618 /* io_video.h */, + 71927E041472DFCB000AB618 /* lagrangian.h */, + 71927E051472DFCB000AB618 /* mb_access.h */, + 71927E061472DFCB000AB618 /* mbuffer_common.h */, + 71927E071472DFCB000AB618 /* memalloc.h */, + 71927E081472DFCB000AB618 /* mv_prediction.h */, + 71927E091472DFCB000AB618 /* nalucommon.h */, + 71927E0A1472DFCB000AB618 /* parsetcommon.h */, + 71927E0B1472DFCB000AB618 /* quant_params.h */, + 71927E0C1472DFCB000AB618 /* report.h */, + 71927E0D1472DFCB000AB618 /* transform.h */, + 71927E0E1472DFCB000AB618 /* typedefs.h */, + 71927E0F1472DFCB000AB618 /* types.h */, + 71927E101472DFCB000AB618 /* vui_params.h */, + 71927E111472DFCB000AB618 /* win32.h */, + ); + name = inc; + path = lcommon/inc; + sourceTree = ""; + }; + 71C904320FE283370095EA3A /* src */ = { + isa = PBXGroup; + children = ( + 71927E121472DFE1000AB618 /* blk_prediction.c */, + 71927E131472DFE1000AB618 /* config_common.c */, + 71927E141472DFE1000AB618 /* img_io.c */, + 71927E151472DFE1000AB618 /* img_process.c */, + 71927E161472DFE1000AB618 /* input.c */, + 71927E171472DFE1000AB618 /* io_raw.c */, + 71927E181472DFE1000AB618 /* io_tiff.c */, + 71927E191472DFE1000AB618 /* mbuffer_common.c */, + 71927E1A1472DFE1000AB618 /* memalloc.c */, + 71927E1B1472DFE1000AB618 /* mv_prediction.c */, + 71927E1C1472DFE1000AB618 /* nalucommon.c */, + 71927E1D1472DFE1000AB618 /* parsetcommon.c */, + 71927E1E1472DFE1000AB618 /* transform.c */, + 71927E1F1472DFE1000AB618 /* win32.c */, + ); + name = src; + path = lcommon/src; + sourceTree = ""; + }; + 71C904B60FE283800095EA3A /* inc */ = { + isa = PBXGroup; + children = ( + 71927DCD1472DFB3000AB618 /* annexb.h */, + 71927DCE1472DFB3000AB618 /* biaridecod.h */, + 71927DCF1472DFB3000AB618 /* block.h */, + 71927DD01472DFB3000AB618 /* cabac.h */, + 71927DD11472DFB3000AB618 /* configfile.h */, + 71927DD21472DFB3000AB618 /* context_ini.h */, + 71927DD31472DFB3000AB618 /* contributors.h */, + 71927DD41472DFB3000AB618 /* dec_statistics.h */, + 71927DD51472DFB3000AB618 /* defines.h */, + 71927DD61472DFB3000AB618 /* elements.h */, + 71927DD71472DFB3000AB618 /* erc_api.h */, + 71927DD81472DFB3000AB618 /* erc_do.h */, + 71927DD91472DFB3000AB618 /* erc_globals.h */, + 71927DDA1472DFB3000AB618 /* errorconcealment.h */, + 71927DDB1472DFB3000AB618 /* filehandle.h */, + 71927DDC1472DFB3000AB618 /* fmo.h */, + 71927DDD1472DFB3000AB618 /* global.h */, + 71927DDE1472DFB3000AB618 /* h264decoder.h */, + 71927DDF1472DFB3000AB618 /* header.h */, + 71927DE01472DFB3000AB618 /* image.h */, + 71927DE11472DFB3000AB618 /* intra4x4_pred.h */, + 71927DE21472DFB3000AB618 /* intra8x8_pred.h */, + 71927DE31472DFB3000AB618 /* intra16x16_pred.h */, + 71927DE41472DFB3000AB618 /* leaky_bucket.h */, + 71927DE51472DFB3000AB618 /* loop_filter.h */, + 71927DE61472DFB3000AB618 /* loopfilter.h */, + 71927DE71472DFB3000AB618 /* macroblock.h */, + 71927DE81472DFB3000AB618 /* mb_prediction.h */, + 71927DE91472DFB3000AB618 /* mbuffer_mvc.h */, + 71927DEA1472DFB3000AB618 /* mbuffer.h */, + 71927DEB1472DFB3000AB618 /* mc_prediction.h */, + 71927DEC1472DFB3000AB618 /* nalu.h */, + 71927DED1472DFB3000AB618 /* output.h */, + 71927DEE1472DFB3000AB618 /* parset.h */, + 71927DEF1472DFB3000AB618 /* quant.h */, + 71927DF01472DFB3000AB618 /* rtp.h */, + 71927DF11472DFB3000AB618 /* sei.h */, + 71927DF21472DFB3000AB618 /* transform8x8.h */, + 71927DF31472DFB3000AB618 /* vlc.h */, + ); + name = inc; + path = ldecod/inc; + sourceTree = ""; + }; + 71C904D80FE283800095EA3A /* src */ = { + isa = PBXGroup; + children = ( + 71927D651472DF98000AB618 /* annexb.c */, + 71927D661472DF98000AB618 /* biaridecod.c */, + 71927D671472DF98000AB618 /* block.c */, + 71927D681472DF98000AB618 /* cabac.c */, + 71927D691472DF98000AB618 /* configfile.c */, + 71927D6A1472DF98000AB618 /* context_ini.c */, + 71927D6B1472DF98000AB618 /* dec_statistics.c */, + 71927D6C1472DF98000AB618 /* decoder_test.c */, + 71927D6D1472DF98000AB618 /* erc_api.c */, + 71927D6E1472DF98000AB618 /* erc_do_i.c */, + 71927D6F1472DF98000AB618 /* erc_do_p.c */, + 71927D701472DF98000AB618 /* errorconcealment.c */, + 71927D711472DF98000AB618 /* filehandle.c */, + 71927D721472DF98000AB618 /* fmo.c */, + 71927D731472DF98000AB618 /* header.c */, + 71927D741472DF98000AB618 /* image.c */, + 71927D751472DF98000AB618 /* intra_chroma_pred_mbaff.c */, + 71927D761472DF98000AB618 /* intra_chroma_pred.c */, + 71927D771472DF98000AB618 /* intra_pred_common.c */, + 71927D781472DF98000AB618 /* intra4x4_pred_mbaff.c */, + 71927D791472DF98000AB618 /* intra4x4_pred_normal.c */, + 71927D7A1472DF98000AB618 /* intra4x4_pred.c */, + 71927D7B1472DF98000AB618 /* intra8x8_pred_mbaff.c */, + 71927D7C1472DF98000AB618 /* intra8x8_pred_normal.c */, + 71927D7D1472DF98000AB618 /* intra8x8_pred.c */, + 71927D7E1472DF98000AB618 /* intra16x16_pred_mbaff.c */, + 71927D7F1472DF98000AB618 /* intra16x16_pred_normal.c */, + 71927D801472DF98000AB618 /* intra16x16_pred.c */, + 71927D811472DF98000AB618 /* ldecod.c */, + 71927D821472DF98000AB618 /* leaky_bucket.c */, + 71927D831472DF98000AB618 /* loop_filter_mbaff.c */, + 71927D841472DF98000AB618 /* loop_filter_normal.c */, + 71927D851472DF98000AB618 /* loopFilter.c */, + 71927D861472DF98000AB618 /* macroblock.c */, + 71927D871472DF98000AB618 /* mb_access.c */, + 71927D881472DF98000AB618 /* mb_prediction.c */, + 71927D891472DF98000AB618 /* mb_read.c */, + 71927D8A1472DF98000AB618 /* mbuffer_mvc.c */, + 71927D8B1472DF98000AB618 /* mbuffer.c */, + 71927D8C1472DF98000AB618 /* mc_direct.c */, + 71927D8D1472DF98000AB618 /* mc_prediction.c */, + 71927D8E1472DF98000AB618 /* nal.c */, + 71927D8F1472DF98000AB618 /* nalu.c */, + 71927D901472DF98000AB618 /* output.c */, + 71927D911472DF98000AB618 /* parset.c */, + 71927D921472DF98000AB618 /* quant.c */, + 71927D931472DF98000AB618 /* read_comp_cabac.c */, + 71927D941472DF98000AB618 /* read_comp_cavlc.c */, + 71927D951472DF98000AB618 /* rtp.c */, + 71927D961472DF98000AB618 /* sei.c */, + 71927D971472DF98000AB618 /* transform8x8.c */, + 71927D981472DF98000AB618 /* vlc.c */, + ); + name = src; + path = ldecod/src; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 436FC25B0D85FB4900D8E371 /* rtpdump */ = { + isa = PBXNativeTarget; + buildConfigurationList = 436FC2990D85FB4900D8E371 /* Build configuration list for PBXNativeTarget "rtpdump" */; + buildPhases = ( + 436FC25C0D85FB4900D8E371 /* Sources */, + 436FC2970D85FB4900D8E371 /* Frameworks */, + 436FC2980D85FB4900D8E371 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = rtpdump; + productInstallPath = "$(HOME)/bin"; + productName = JM; + productReference = 436FC29C0D85FB4900D8E371 /* rtpdump */; + productType = "com.apple.product-type.tool"; + }; + 436FC2A20D85FC1C00D8E371 /* rtp_loss */ = { + isa = PBXNativeTarget; + buildConfigurationList = 436FC2A70D85FC1C00D8E371 /* Build configuration list for PBXNativeTarget "rtp_loss" */; + buildPhases = ( + 436FC2A30D85FC1C00D8E371 /* Sources */, + 436FC2A50D85FC1C00D8E371 /* Frameworks */, + 436FC2A60D85FC1C00D8E371 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = rtp_loss; + productInstallPath = "$(HOME)/bin"; + productName = JM; + productReference = 436FC2AA0D85FC1C00D8E371 /* rtp_loss */; + productType = "com.apple.product-type.tool"; + }; + 43FA4AD50D4EECBB001709F1 /* ldecod */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43FA4B140D4EECBB001709F1 /* Build configuration list for PBXNativeTarget "ldecod" */; + buildPhases = ( + 43FA4AD60D4EECBB001709F1 /* Sources */, + 43FA4B100D4EECBB001709F1 /* Frameworks */, + 43FA4B130D4EECBB001709F1 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ldecod; + productInstallPath = "$(HOME)/bin"; + productName = JM; + productReference = 43FA4B170D4EECBB001709F1 /* ldecod */; + productType = "com.apple.product-type.tool"; + }; + 8DD76FA90486AB0100D96B5E /* lencod */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "lencod" */; + buildPhases = ( + 8DD76FAB0486AB0100D96B5E /* Sources */, + 8DD76FAD0486AB0100D96B5E /* Frameworks */, + 8DD76FAF0486AB0100D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = lencod; + productInstallPath = "$(HOME)/bin"; + productName = JM; + productReference = 8DD76FB20486AB0100D96B5E /* lencod */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "JM" */; + compatibilityVersion = "Xcode 3.0"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* JM */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76FA90486AB0100D96B5E /* lencod */, + 43FA4AD50D4EECBB001709F1 /* ldecod */, + 436FC25B0D85FB4900D8E371 /* rtpdump */, + 436FC2A20D85FC1C00D8E371 /* rtp_loss */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 436FC25C0D85FB4900D8E371 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 436FC29E0D85FBC500D8E371 /* rtpdump.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 436FC2A30D85FC1C00D8E371 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 436FC2B20D85FC9400D8E371 /* rtp_loss.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43FA4AD60D4EECBB001709F1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 71927D991472DF98000AB618 /* annexb.c in Sources */, + 71927D9A1472DF98000AB618 /* biaridecod.c in Sources */, + 71927D9B1472DF98000AB618 /* block.c in Sources */, + 71927D9C1472DF98000AB618 /* cabac.c in Sources */, + 71927D9D1472DF98000AB618 /* configfile.c in Sources */, + 71927D9E1472DF98000AB618 /* context_ini.c in Sources */, + 71927D9F1472DF98000AB618 /* dec_statistics.c in Sources */, + 71927DA01472DF98000AB618 /* decoder_test.c in Sources */, + 71927DA11472DF98000AB618 /* erc_api.c in Sources */, + 71927DA21472DF98000AB618 /* erc_do_i.c in Sources */, + 71927DA31472DF98000AB618 /* erc_do_p.c in Sources */, + 71927DA41472DF98000AB618 /* errorconcealment.c in Sources */, + 71927DA51472DF98000AB618 /* filehandle.c in Sources */, + 71927DA61472DF98000AB618 /* fmo.c in Sources */, + 71927DA71472DF98000AB618 /* header.c in Sources */, + 71927DA81472DF98000AB618 /* image.c in Sources */, + 71927DA91472DF98000AB618 /* intra_chroma_pred_mbaff.c in Sources */, + 71927DAA1472DF98000AB618 /* intra_chroma_pred.c in Sources */, + 71927DAB1472DF98000AB618 /* intra_pred_common.c in Sources */, + 71927DAC1472DF98000AB618 /* intra4x4_pred_mbaff.c in Sources */, + 71927DAD1472DF98000AB618 /* intra4x4_pred_normal.c in Sources */, + 71927DAE1472DF98000AB618 /* intra4x4_pred.c in Sources */, + 71927DAF1472DF98000AB618 /* intra8x8_pred_mbaff.c in Sources */, + 71927DB01472DF98000AB618 /* intra8x8_pred_normal.c in Sources */, + 71927DB11472DF98000AB618 /* intra8x8_pred.c in Sources */, + 71927DB21472DF98000AB618 /* intra16x16_pred_mbaff.c in Sources */, + 71927DB31472DF98000AB618 /* intra16x16_pred_normal.c in Sources */, + 71927DB41472DF98000AB618 /* intra16x16_pred.c in Sources */, + 71927DB51472DF98000AB618 /* ldecod.c in Sources */, + 71927DB61472DF98000AB618 /* leaky_bucket.c in Sources */, + 71927DB71472DF98000AB618 /* loop_filter_mbaff.c in Sources */, + 71927DB81472DF98000AB618 /* loop_filter_normal.c in Sources */, + 71927DB91472DF98000AB618 /* loopFilter.c in Sources */, + 71927DBA1472DF98000AB618 /* macroblock.c in Sources */, + 71927DBB1472DF98000AB618 /* mb_access.c in Sources */, + 71927DBC1472DF98000AB618 /* mb_prediction.c in Sources */, + 71927DBD1472DF98000AB618 /* mb_read.c in Sources */, + 71927DBE1472DF98000AB618 /* mbuffer_mvc.c in Sources */, + 71927DBF1472DF98000AB618 /* mbuffer.c in Sources */, + 71927DC01472DF98000AB618 /* mc_direct.c in Sources */, + 71927DC11472DF98000AB618 /* mc_prediction.c in Sources */, + 71927DC21472DF98000AB618 /* nal.c in Sources */, + 71927DC31472DF98000AB618 /* nalu.c in Sources */, + 71927DC41472DF98000AB618 /* output.c in Sources */, + 71927DC51472DF98000AB618 /* parset.c in Sources */, + 71927DC61472DF98000AB618 /* quant.c in Sources */, + 71927DC71472DF98000AB618 /* read_comp_cabac.c in Sources */, + 71927DC81472DF98000AB618 /* read_comp_cavlc.c in Sources */, + 71927DC91472DF98000AB618 /* rtp.c in Sources */, + 71927DCA1472DF98000AB618 /* sei.c in Sources */, + 71927DCB1472DF98000AB618 /* transform8x8.c in Sources */, + 71927DCC1472DF98000AB618 /* vlc.c in Sources */, + 71927E201472DFE1000AB618 /* blk_prediction.c in Sources */, + 71927E211472DFE1000AB618 /* config_common.c in Sources */, + 71927E221472DFE1000AB618 /* img_io.c in Sources */, + 71927E231472DFE1000AB618 /* img_process.c in Sources */, + 71927E241472DFE1000AB618 /* input.c in Sources */, + 71927E251472DFE1000AB618 /* io_raw.c in Sources */, + 71927E261472DFE1000AB618 /* io_tiff.c in Sources */, + 71927E271472DFE1000AB618 /* mbuffer_common.c in Sources */, + 71927E281472DFE1000AB618 /* memalloc.c in Sources */, + 71927E291472DFE1000AB618 /* mv_prediction.c in Sources */, + 71927E2A1472DFE1000AB618 /* nalucommon.c in Sources */, + 71927E2B1472DFE1000AB618 /* parsetcommon.c in Sources */, + 71927E2C1472DFE1000AB618 /* transform.c in Sources */, + 71927E2D1472DFE1000AB618 /* win32.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8DD76FAB0486AB0100D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 71927CF71472DF74000AB618 /* annexb.c in Sources */, + 71927CF81472DF74000AB618 /* biariencode.c in Sources */, + 71927CF91472DF74000AB618 /* block.c in Sources */, + 71927CFA1472DF74000AB618 /* cabac.c in Sources */, + 71927CFB1472DF74000AB618 /* cconv_yuv2rgb.c in Sources */, + 71927CFC1472DF74000AB618 /* configfile.c in Sources */, + 71927CFD1472DF74000AB618 /* conformance.c in Sources */, + 71927CFE1472DF74000AB618 /* context_ini.c in Sources */, + 71927CFF1472DF74000AB618 /* errdo_dist_mhyp.c in Sources */, + 71927D001472DF74000AB618 /* errdo.c in Sources */, + 71927D011472DF74000AB618 /* explicit_gop.c in Sources */, + 71927D021472DF74000AB618 /* explicit_seq.c in Sources */, + 71927D031472DF74000AB618 /* filehandle.c in Sources */, + 71927D041472DF74000AB618 /* fmo.c in Sources */, + 71927D051472DF74000AB618 /* get_block_otf.c in Sources */, + 71927D061472DF74000AB618 /* header.c in Sources */, + 71927D071472DF74000AB618 /* image_mp.c in Sources */, + 71927D081472DF74000AB618 /* image.c in Sources */, + 71927D091472DF74000AB618 /* img_chroma.c in Sources */, + 71927D0A1472DF74000AB618 /* img_dist_ms_ssim.c in Sources */, + 71927D0B1472DF74000AB618 /* img_dist_snr.c in Sources */, + 71927D0C1472DF74000AB618 /* img_dist_ssim.c in Sources */, + 71927D0D1472DF74000AB618 /* img_distortion.c in Sources */, + 71927D0E1472DF74000AB618 /* img_luma.c in Sources */, + 71927D0F1472DF74000AB618 /* intra_chroma.c in Sources */, + 71927D101472DF74000AB618 /* intra4x4.c in Sources */, + 71927D111472DF74000AB618 /* intra8x8.c in Sources */, + 71927D121472DF74000AB618 /* intra16x16.c in Sources */, + 71927D131472DF74000AB618 /* intrarefresh.c in Sources */, + 71927D141472DF74000AB618 /* lambda.c in Sources */, + 71927D151472DF74000AB618 /* leaky_bucket.c in Sources */, + 71927D161472DF74000AB618 /* lencod.c in Sources */, + 71927D171472DF74000AB618 /* list_reorder.c in Sources */, + 71927D181472DF74000AB618 /* lln_mc_prediction.c in Sources */, + 71927D191472DF74000AB618 /* loop_filter_mbaff.c in Sources */, + 71927D1A1472DF74000AB618 /* loop_filter_normal.c in Sources */, + 71927D1B1472DF74000AB618 /* loopFilter.c in Sources */, + 71927D1C1472DF74000AB618 /* macroblock_P444.c in Sources */, + 71927D1D1472DF74000AB618 /* macroblock.c in Sources */, + 71927D1E1472DF74000AB618 /* mb_access.c in Sources */, + 71927D1F1472DF74000AB618 /* mbuffer.c in Sources */, + 71927D201472DF74000AB618 /* mc_prediction_otf.c in Sources */, + 71927D211472DF74000AB618 /* mc_prediction.c in Sources */, + 71927D221472DF74000AB618 /* md_common.c in Sources */, + 71927D231472DF74000AB618 /* md_distortion.c in Sources */, + 71927D241472DF74000AB618 /* md_high.c in Sources */, + 71927D251472DF74000AB618 /* md_highfast.c in Sources */, + 71927D261472DF74000AB618 /* md_highloss.c in Sources */, + 71927D271472DF74000AB618 /* md_low.c in Sources */, + 71927D281472DF74000AB618 /* me_distortion_otf.c in Sources */, + 71927D291472DF74000AB618 /* me_distortion.c in Sources */, + 71927D2A1472DF74000AB618 /* me_epzs_common.c in Sources */, + 71927D2B1472DF74000AB618 /* me_epzs_int.c in Sources */, + 71927D2C1472DF74000AB618 /* me_epzs_sub.c in Sources */, + 71927D2D1472DF74000AB618 /* me_epzs.c in Sources */, + 71927D2E1472DF74000AB618 /* me_fullfast_otf.c in Sources */, + 71927D2F1472DF74000AB618 /* me_fullfast.c in Sources */, + 71927D301472DF74000AB618 /* me_fullsearch.c in Sources */, + 71927D311472DF74000AB618 /* me_umhex.c in Sources */, + 71927D321472DF74000AB618 /* me_umhexsmp.c in Sources */, + 71927D331472DF74000AB618 /* mmco.c in Sources */, + 71927D341472DF74000AB618 /* mode_decision_P8x8.c in Sources */, + 71927D351472DF74000AB618 /* mode_decision.c in Sources */, + 71927D361472DF74000AB618 /* mv_direct.c in Sources */, + 71927D371472DF74000AB618 /* mv_search.c in Sources */, + 71927D381472DF74000AB618 /* nal.c in Sources */, + 71927D391472DF74000AB618 /* nalu.c in Sources */, + 71927D3A1472DF74000AB618 /* output.c in Sources */, + 71927D3B1472DF74000AB618 /* parset.c in Sources */, + 71927D3C1472DF74000AB618 /* pred_struct.c in Sources */, + 71927D3D1472DF74000AB618 /* q_around.c in Sources */, + 71927D3E1472DF74000AB618 /* q_matrix.c in Sources */, + 71927D3F1472DF74000AB618 /* q_offsets.c in Sources */, + 71927D401472DF74000AB618 /* quant4x4_2step.c in Sources */, + 71927D411472DF74000AB618 /* quant4x4_around.c in Sources */, + 71927D421472DF74000AB618 /* quant4x4_normal.c in Sources */, + 71927D431472DF74000AB618 /* quant4x4_trellis.c in Sources */, + 71927D441472DF74000AB618 /* quant4x4.c in Sources */, + 71927D451472DF74000AB618 /* quant8x8_around.c in Sources */, + 71927D461472DF74000AB618 /* quant8x8_normal.c in Sources */, + 71927D471472DF74000AB618 /* quant8x8_trellis.c in Sources */, + 71927D481472DF74000AB618 /* quant8x8.c in Sources */, + 71927D491472DF74000AB618 /* quantChroma_2step.c in Sources */, + 71927D4A1472DF74000AB618 /* quantChroma_around.c in Sources */, + 71927D4B1472DF74000AB618 /* quantChroma_normal.c in Sources */, + 71927D4C1472DF74000AB618 /* quantChroma_trellis.c in Sources */, + 71927D4D1472DF74000AB618 /* quantChroma.c in Sources */, + 71927D4E1472DF74000AB618 /* ratectl.c in Sources */, + 71927D4F1472DF74000AB618 /* rc_quadratic.c in Sources */, + 71927D501472DF74000AB618 /* rd_intra_jm_low.c in Sources */, + 71927D511472DF74000AB618 /* rd_intra_jm.c in Sources */, + 71927D521472DF74000AB618 /* rd_intra_jm444.c in Sources */, + 71927D531472DF74000AB618 /* rdopt_coding_state.c in Sources */, + 71927D541472DF74000AB618 /* rdopt.c in Sources */, + 71927D551472DF74000AB618 /* rdoq_cabac.c in Sources */, + 71927D561472DF74000AB618 /* rdoq_cavlc.c in Sources */, + 71927D571472DF74000AB618 /* rdoq.c in Sources */, + 71927D581472DF74000AB618 /* rdpicdecision.c in Sources */, + 71927D591472DF74000AB618 /* report.c in Sources */, + 71927D5A1472DF74000AB618 /* rtp.c in Sources */, + 71927D5B1472DF74000AB618 /* sei.c in Sources */, + 71927D5C1472DF74000AB618 /* slice.c in Sources */, + 71927D5D1472DF74000AB618 /* symbol.c in Sources */, + 71927D5E1472DF74000AB618 /* transform8x8_H444.c in Sources */, + 71927D5F1472DF74000AB618 /* transform8x8.c in Sources */, + 71927D601472DF74000AB618 /* vlc.c in Sources */, + 71927D611472DF74000AB618 /* weighted_prediction.c in Sources */, + 71927D621472DF74000AB618 /* wp_lms.c in Sources */, + 71927D631472DF74000AB618 /* wp_mciter.c in Sources */, + 71927D641472DF74000AB618 /* wp_mcprec.c in Sources */, + 71927E2E1472DFE1000AB618 /* blk_prediction.c in Sources */, + 71927E2F1472DFE1000AB618 /* config_common.c in Sources */, + 71927E301472DFE1000AB618 /* img_io.c in Sources */, + 71927E311472DFE1000AB618 /* img_process.c in Sources */, + 71927E321472DFE1000AB618 /* input.c in Sources */, + 71927E331472DFE1000AB618 /* io_raw.c in Sources */, + 71927E341472DFE1000AB618 /* io_tiff.c in Sources */, + 71927E351472DFE1000AB618 /* mbuffer_common.c in Sources */, + 71927E361472DFE1000AB618 /* memalloc.c in Sources */, + 71927E371472DFE1000AB618 /* mv_prediction.c in Sources */, + 71927E381472DFE1000AB618 /* nalucommon.c in Sources */, + 71927E391472DFE1000AB618 /* parsetcommon.c in Sources */, + 71927E3A1472DFE1000AB618 /* transform.c in Sources */, + 71927E3B1472DFE1000AB618 /* win32.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB928608733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = ""; + LIBRARY_SEARCH_PATHS = ""; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = lencod; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = lencod/inc; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB928708733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = ""; + LIBRARY_SEARCH_PATHS = ""; + PRODUCT_NAME = lencod; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = lencod/inc; + }; + name = Release; + }; + 1DEB928A08733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_OPENMP_SUPPORT = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Debug; + }; + 1DEB928B08733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + ENABLE_OPENMP_SUPPORT = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Release; + }; + 436FC29A0D85FB4900D8E371 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = ""; + PRODUCT_NAME = rtpdump; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = ""; + ZERO_LINK = YES; + }; + name = Debug; + }; + 436FC29B0D85FB4900D8E371 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = ""; + PRODUCT_NAME = rtpdump; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Release; + }; + 436FC2A80D85FC1C00D8E371 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = ""; + PRODUCT_NAME = rtp_loss; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = ""; + ZERO_LINK = YES; + }; + name = Debug; + }; + 436FC2A90D85FC1C00D8E371 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = ""; + PRODUCT_NAME = rtp_loss; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Release; + }; + 43FA4B150D4EECBB001709F1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = ""; + LIBRARY_SEARCH_PATHS = ""; + PRODUCT_NAME = ldecod; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = ldecod/inc; + ZERO_LINK = YES; + }; + name = Debug; + }; + 43FA4B160D4EECBB001709F1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = ""; + LIBRARY_SEARCH_PATHS = ""; + PREBINDING = NO; + PRELINK_LIBS = ""; + PRODUCT_NAME = ldecod; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + USER_HEADER_SEARCH_PATHS = ldecod/inc; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "lencod" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928608733DD80010E9CD /* Debug */, + 1DEB928708733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "JM" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928A08733DD80010E9CD /* Debug */, + 1DEB928B08733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 436FC2990D85FB4900D8E371 /* Build configuration list for PBXNativeTarget "rtpdump" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 436FC29A0D85FB4900D8E371 /* Debug */, + 436FC29B0D85FB4900D8E371 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 436FC2A70D85FC1C00D8E371 /* Build configuration list for PBXNativeTarget "rtp_loss" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 436FC2A80D85FC1C00D8E371 /* Debug */, + 436FC2A90D85FC1C00D8E371 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43FA4B140D4EECBB001709F1 /* Build configuration list for PBXNativeTarget "ldecod" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43FA4B150D4EECBB001709F1 /* Debug */, + 43FA4B160D4EECBB001709F1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7cabcb6 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +### +### Makefile for JM H.264/AVC encoder/decoder +### +### generated for UNIX/LINUX environments +### by Limin Wang(lance.lmwang@gmail.com) +### + +SUBDIRS := ldecod lencod rtpdump rtp_loss + +### include debug information: 1=yes, 0=no +DBG?= 0 +### enforce 32-bit build : 1=yes, 0=no +M32?= 0 +### static link : 1=yes, 0=no +STC?= 0 +### OPENMP support : 1=yes, 0=no +OPENMP?= 1 + +export DBG +export STC +export M32 +export OPENMP + +.PHONY: default all distclean clean tags depend $(SUBDIRS) + +default: all + +all: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +clean depend: + @echo "Cleaning dependencies" + @for i in $(SUBDIRS); do make -C $$i $@; done + +tags: + @echo "update tag table at top directory" + @ctags -R . + @for i in $(SUBDIRS); do make -C $$i $@; done + +distclean: clean + @echo "Cleaning all" + @rm -f tags + @for i in $(SUBDIRS); do make -C $$i $@; done + diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..1ee2889 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,195 @@ +JM Reference Software README +============================ + +The latest version of this software can be obtained from: + + http://iphome.hhi.de/suehring/tml + +For reporting bugs please use the JM bug tracking system located at: + + https://ipbt.hhi.fraunhofer.de + + +Please send comments and additions to Karsten.Suehring (at) hhi.fraunhofer.de and alexis.tourapis@dolby.com + +====================================================================================== +NOTE: This file contains only a quick overview. + + More detailed information can be found the "JM Reference Software Manual" in the + doc/ subdirectory of this package. +====================================================================================== + +1. Compilation +2. Command line parameters +3. Input/Output file format +4. Configuration files +5. Platform specific notes + + +1. Compilation +-------------- + +1.1 Windows +----------- + + Workspaces for MS Visual C++ 2003/2005/2008/2010 are provided with the names + + jm_vc7.sln - MS Visual C++ 2003 + jm_vc8.sln - MS Visual C++ 2005 + jm_vc9.sln - MS Visual C++ 2008 + jm_vc10.sln - MS Visual C++ 2010 + + These contain encoder and decoder projects. + + +1.2 Unix +-------- + + Before compiling in a UNIX environment please run the "unixprep.sh" script which + will remove the DOS LF characters from the files and create object directories. + + Makefiles for GNU make are provided at the top level and in the lencod and ldecod directories. + + +1.3 MacOS X +----------- + + A workspace for XCode can be found in the main directory. The project can also be build + using the UNIX build process (make). + + +2. Command line parameters +-------------------------- + +2.1 Encoder +----------- + + lencod.exe [-h] [-d default-file] [-f file] [-p parameter=value] + + All Parameters are initially taken from DEFAULTCONFIGFILENAME, defined in + configfile.h (typically: "encoder.cfg") + + -h + Show help on parameters. + + -d default-file + Use the specified file as default configuration instead of the file in + DEFAULTCONFIGFILENAME. + + -f file + If an -f parameter is present in the command line then + this file is used to update the defaults of DEFAULTCONFIGFILENAME. + There can be more than one -f parameters present. + + -p parameter=value + + If -p parameters are present then + these overide the default and the additional config file's settings, + and are themselfes overridden by future -p parameters. There must + be whitespace between -f and -p commands and their respecitive + parameters. + -v + Show short version info. + -V + Show long version info. + +2.2 Decoder +----------- + + ldecod.exe [-h] [-d default-file] [-f file] [-p parameter=value] + + All Parameters are initially taken from DEFAULTCONFIGFILENAME, defined in + configfile.h (typically: "encoder.cfg") + + -h + Show help on parameters. + + -d default-file + Use the specified file as default configuration instead of the file in + DEFAULTCONFIGFILENAME. + + -f file + If an -f parameter is present in the command line then + this file is used to update the defaults of DEFAULTCONFIGFILENAME. + There can be more than one -f parameters present. + + -p parameter=value + + If -p parameters are present then + these overide the default and the additional config file's settings, + and are themselfes overridden by future -p parameters. There must + be whitespace between -f and -p commands and their respecitive + parameters. + -v + Show short version info. + -V + Show long version info. + + + +3. Input/Output file format +--------------------------- + + The source video material is read from raw YUV 4:2:0 data files. + For output the same format is used. + + +4. Configuration files +---------------------- + + Sample encoder and decode configuration files are provided in the bin/ directory. + These contain explanatory comments for each parameter. + + The generic structure is explained here. + +4.1 Encoder +----------- + = # Comments + + Whitespace is space and \t + + are the predefined names for Parameters and are case sensitive. + See configfile.h for the definition of those names and their + mapping to configinput->values. + + are either integers [0..9]* or strings. + Integers must fit into the wordlengths, signed values are generally + assumed. Strings containing no whitespace characters can be used directly. + Strings containing whitespace characters are to be inclosed in double + quotes ("string with whitespace") + The double quote character is forbidden (may want to implement something + smarter here). + + Any Parameters whose ParameterName is undefined lead to the termination of the program + with an error message. + + Known bug/Shortcoming: zero-length strings (i.e. to signal an non-existing file + have to be coded as "". + +4.2 Decoder +----------- + Beginning with JM 17.0 the decoder uses the same config file style like the encoder. + + +5. Platform specific notes +-------------------------- + This section contains hints for compiling and running the JM software on different + operating systems. + +5.1 MacOS X +----------- + MacOs X has a UNIX core so most of the UNIX compile process will work. You might need + the following modifications: + + a) Before Leopard (MacOS 10.5): in Makefile change "CC = $(shell which gcc)" to "CC = gcc" + (it seems "which" doesn't work) + + b) MacOS "Tiger" (MacOS 10.4) doesn't come with ftime. We suggest using a third party ftime + implementation, e.g. from: + + http://darwinsource.opendarwin.org/10.3.4/OpenSSL096-3/openssl/crypto/ftime.c + +5.2 FreeBSD +----------- + You might need to add "-lcompat" to LIBS in the Makefiles for correct linking. + diff --git a/bin/HM-like/encoder_JM_Intra_HE.cfg b/bin/HM-like/encoder_JM_Intra_HE.cfg new file mode 100644 index 0000000..b48c205 --- /dev/null +++ b/bin/HM-like/encoder_JM_Intra_HE.cfg @@ -0,0 +1,660 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "D:\origCfP\BQSquare_416x240_60.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 30 # Number of frames to be coded +FrameRate = 60.0 # Frame Rate per second (0.1-100.0) +Enable32Pulldown = 0 # Enable 'hard' 3:2 pulldown (modifying the inpur data) + # 0 = disabled + # 1 = A, B, Bt|Cb, Ct|Db, D + # 2 = A, B, C, Ct|Db, D +SEIVUI32Pulldown = 0 # Enable 3:2 pulldown through VUI and SEI metadata signaling. Five methods are supported: + # 0 = disabled + # 1 = A, Bt|Bb, Bt|Cb, Ct|Cb, D + # 2 = A, B, C, C, D + # 3 = At|Ab, Bt|Bb, Bt|Cb, Ct|Cb, Dt|Db + # 4 = A, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + # 5 = At|Ab, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + +SourceWidth = 416 # Source frame width +SourceHeight = 240 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 416 # Output frame width +OutputHeight = 240 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "" # Coding statistics file + +NumberOfViews = 1 # Number of views to encode (1=1 view, 2=2 views) +View1ConfigFile = "encoder_view1.cfg" # Config file name for second view +########################################################################################## +# Encoder Control +########################################################################################## +Grayscale = 0 # Encode in grayscale (Currently only works for 8 bit YUV 420 input) +ProfileIDC = 100 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra, 118=Multiview High Profile, 128=Stereo High Profile) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 51 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 1 # Period of I-pictures (0=only first) +IDRPeriod = 1 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 0 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 32 # Quant. param for I Slices (0-51) +QPPSlice = 33 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 128 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 4 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 1 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 0 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 0 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 33 # Quant. param for B slices (0-51) +BRefPicQPOffset = 0 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 4 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 4 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 2 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 0 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 0 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "B0r2B1r3B2r2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 1 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 0 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 0 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 64 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 1 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 1 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 1 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPSliceITest = 1 # Perform Slice level RD decision between P and I slices. Default value is 1 (enabled). +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 2 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 0 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 1 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 1 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 1 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 1 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 0 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 0 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 1 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 1 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 1 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 1 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 3 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 1 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. + +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/HM-like/encoder_JM_LP_HE.cfg b/bin/HM-like/encoder_JM_LP_HE.cfg new file mode 100644 index 0000000..a04cd30 --- /dev/null +++ b/bin/HM-like/encoder_JM_LP_HE.cfg @@ -0,0 +1,671 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "D:\origCfP\BQSquare_416x240_60.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 30 # Number of frames to be coded +FrameRate = 60.0 # Frame Rate per second (0.1-100.0) +Enable32Pulldown = 0 # Enable 'hard' 3:2 pulldown (modifying the inpur data) + # 0 = disabled + # 1 = A, B, Bt|Cb, Ct|Db, D + # 2 = A, B, C, Ct|Db, D +SEIVUI32Pulldown = 0 # Enable 3:2 pulldown through VUI and SEI metadata signaling. Five methods are supported: + # 0 = disabled + # 1 = A, Bt|Bb, Bt|Cb, Ct|Cb, D + # 2 = A, B, C, C, D + # 3 = At|Ab, Bt|Bb, Bt|Cb, Ct|Cb, Dt|Db + # 4 = A, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + # 5 = At|Ab, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + +SourceWidth = 416 # Source frame width +SourceHeight = 240 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 416 # Output frame width +OutputHeight = 240 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "" # Coding statistics file + +NumberOfViews = 1 # Number of views to encode (1=1 view, 2=2 views) +View1ConfigFile = "encoder_view1.cfg" # Config file name for second view +########################################################################################## +# Encoder Control +########################################################################################## +Grayscale = 0 # Encode in grayscale (Currently only works for 8 bit YUV 420 input) +ProfileIDC = 100 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra, 118=Multiview High Profile, 128=Stereo High Profile) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 51 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 0 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 32 # Quant. param for I Slices (0-51) +QPPSlice = 33 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 128 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 4 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 1 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 0 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 1 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 0 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 3 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 1 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 33 # Quant. param for B slices (0-51) +BRefPicQPOffset = 0 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 4 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 4 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BLevel0MoreRef = 0 # 0: Use the same number of reference pictures as the other B pictures + # 1: Use more reference frame pictures for B pictures at level 0 +BIdenticalList = 0 # 0: not used; 1: used for B pictures at level 0; 2: used for all B pictures + # 1 and 2 need to set ReferenceReorder to 1 +CRA = 0 # 0: do not use CRA like random access support; 1 use CRA like random access support + # only used for random access cases, LowDelay != 1 +HM50RefStructure = 0 # 0: do not use HM-5.0 like referencing structure; 1 use HM-5.0 like referencing structure for random access +LDRefSetting = 1 # 0: use nearest pictures as reference frames + # 1: use one nearest + POC%4==0 pictures as reference frames, as JCTVC-F701 + # Only low delay is support, please do not use it for other coding structure + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 3 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 0 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "P0r2P1r1P2r2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 1 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 0 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 0 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 128 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 1 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 1 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 1 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPSliceITest = 1 # Perform Slice level RD decision between P and I slices. Default value is 1 (enabled). +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 1 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 2 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 0 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 1 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 1 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 1 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 0 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 0 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 0 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 1 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 1 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 1 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 1 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 3 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 1 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. + +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/HM-like/encoder_JM_RA_B_HE.cfg b/bin/HM-like/encoder_JM_RA_B_HE.cfg new file mode 100644 index 0000000..f194f83 --- /dev/null +++ b/bin/HM-like/encoder_JM_RA_B_HE.cfg @@ -0,0 +1,671 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "D:\origCfP\BQSquare_416x240_60.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 30 # Number of frames to be coded +FrameRate = 60.0 # Frame Rate per second (0.1-100.0) +Enable32Pulldown = 0 # Enable 'hard' 3:2 pulldown (modifying the inpur data) + # 0 = disabled + # 1 = A, B, Bt|Cb, Ct|Db, D + # 2 = A, B, C, Ct|Db, D +SEIVUI32Pulldown = 0 # Enable 3:2 pulldown through VUI and SEI metadata signaling. Five methods are supported: + # 0 = disabled + # 1 = A, Bt|Bb, Bt|Cb, Ct|Cb, D + # 2 = A, B, C, C, D + # 3 = At|Ab, Bt|Bb, Bt|Cb, Ct|Cb, Dt|Db + # 4 = A, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + # 5 = At|Ab, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + +SourceWidth = 416 # Source frame width +SourceHeight = 240 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 416 # Output frame width +OutputHeight = 240 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "" # Coding statistics file + +NumberOfViews = 1 # Number of views to encode (1=1 view, 2=2 views) +View1ConfigFile = "encoder_view1.cfg" # Config file name for second view +########################################################################################## +# Encoder Control +########################################################################################## +Grayscale = 0 # Encode in grayscale (Currently only works for 8 bit YUV 420 input) +ProfileIDC = 100 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra, 118=Multiview High Profile, 128=Stereo High Profile) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 51 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 0 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 32 # Quant. param for I Slices (0-51) +QPPSlice = 33 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 128 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 4 # Number of previous frames used for inter motion search (0-16) + +PList0References = 4 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 1 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 1 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 0 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 1 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 7 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 33 # Quant. param for B slices (0-51) +BRefPicQPOffset = 0 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 2 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 2 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BLevel0MoreRef = 1 # 0: Use the same number of reference pictures as the other B pictures + # 1: Use more reference frame pictures for B pictures at level 0 +BIdenticalList = 1 # 0: not used; 1: used for B pictures at level 0; 2: used for all B pictures + # 1 and 2 need to set ReferenceReorder to 1 +CRA = 1 # 0: do not use CRA like random access support; 1 use CRA like random access support + # only used for random access cases, LowDelay != 1 +HM50RefStructure = 1 # 0: do not use HM-5.0 like referencing structure; 1 use HM-5.0 like referencing structure for random access +LDRefSetting = 0 # 0: use nearest pictures as reference frames + # 1: use one nearest + POC%4==0 pictures as reference frames, as JCTVC-F701 + # Only low delay is support, please do not use it for other coding structure + +BReferencePictures = 2 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 3 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 0 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "B3r1B1r2b0e3b2e3B5r2b4e3b6e3" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 0 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 128 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 1 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 1 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 1 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPSliceITest = 1 # Perform Slice level RD decision between P and I slices. Default value is 1 (enabled). +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 1 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 2 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 1 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 1 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 1 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 1 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 0 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 0 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 1 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 1 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 1 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 1 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 3 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 1 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. + +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/HM-like/per-sequence_JM/BQMall.cfg b/bin/HM-like/per-sequence_JM/BQMall.cfg new file mode 100644 index 0000000..159d508 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BQMall.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BQMall_832x480_60.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 832 # Input frame width +SourceHeight = 480 # Input frame height +FramesToBeEncoded = 600 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BQSquare.cfg b/bin/HM-like/per-sequence_JM/BQSquare.cfg new file mode 100644 index 0000000..28b8d67 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BQSquare.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BQSquare_416x240_60.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 416 # Input frame width +SourceHeight = 240 # Input frame height +FramesToBeEncoded = 600 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BQTerrace.cfg b/bin/HM-like/per-sequence_JM/BQTerrace.cfg new file mode 100644 index 0000000..5f8777e --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BQTerrace.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BQTerrace_1920x1080_60.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1920 # Input frame width +SourceHeight = 1080 # Input frame height +FramesToBeEncoded = 600 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BasketballDrill.cfg b/bin/HM-like/per-sequence_JM/BasketballDrill.cfg new file mode 100644 index 0000000..5ef6435 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BasketballDrill.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BasketballDrill_832x480_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 832 # Input frame width +SourceHeight = 480 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BasketballDrillText.cfg b/bin/HM-like/per-sequence_JM/BasketballDrillText.cfg new file mode 100644 index 0000000..0af9c81 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BasketballDrillText.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BasketballDrillText_832x480_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 832 # Input frame width +SourceHeight = 480 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BasketballDrive.cfg b/bin/HM-like/per-sequence_JM/BasketballDrive.cfg new file mode 100644 index 0000000..9c74a16 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BasketballDrive.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BasketballDrive_1920x1080_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1920 # Input frame width +SourceHeight = 1080 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BasketballPass.cfg b/bin/HM-like/per-sequence_JM/BasketballPass.cfg new file mode 100644 index 0000000..f5ef023 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BasketballPass.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BasketballPass_416x240_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 416 # Input frame width +SourceHeight = 240 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/BlowingBubbles.cfg b/bin/HM-like/per-sequence_JM/BlowingBubbles.cfg new file mode 100644 index 0000000..90dcdb5 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/BlowingBubbles.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/BlowingBubbles_416x240_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 416 # Input frame width +SourceHeight = 240 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/Cactus.cfg b/bin/HM-like/per-sequence_JM/Cactus.cfg new file mode 100644 index 0000000..7523c8d --- /dev/null +++ b/bin/HM-like/per-sequence_JM/Cactus.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/Cactus_1920x1080_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1920 # Input frame width +SourceHeight = 1080 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/ChinaSpeed.cfg b/bin/HM-like/per-sequence_JM/ChinaSpeed.cfg new file mode 100644 index 0000000..c87e772 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/ChinaSpeed.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/ChinaSpeed_1024x768_30.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 30 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1024 # Input frame width +SourceHeight = 768 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/Kimono.cfg b/bin/HM-like/per-sequence_JM/Kimono.cfg new file mode 100644 index 0000000..a552b66 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/Kimono.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/Kimono1_1920x1080_24.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 24 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1920 # Input frame width +SourceHeight = 1080 # Input frame height +FramesToBeEncoded = 240 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/NebutaFestival_10bit.cfg b/bin/HM-like/per-sequence_JM/NebutaFestival_10bit.cfg new file mode 100644 index 0000000..e5bd91b --- /dev/null +++ b/bin/HM-like/per-sequence_JM/NebutaFestival_10bit.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/NebutaFestival_2560x1600_60_10bit_crop.yuv" +SourceBitDepthLuma = 10 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 10 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 2560 # Input frame width +SourceHeight = 1600 # Input frame height +FramesToBeEncoded = 300 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/ParkScene.cfg b/bin/HM-like/per-sequence_JM/ParkScene.cfg new file mode 100644 index 0000000..986a5bc --- /dev/null +++ b/bin/HM-like/per-sequence_JM/ParkScene.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/ParkScene_1920x1080_24.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 24 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1920 # Input frame width +SourceHeight = 1080 # Input frame height +FramesToBeEncoded = 240 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/PartyScene.cfg b/bin/HM-like/per-sequence_JM/PartyScene.cfg new file mode 100644 index 0000000..c0dc6dc --- /dev/null +++ b/bin/HM-like/per-sequence_JM/PartyScene.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/PartyScene_832x480_50.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 50 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 832 # Input frame width +SourceHeight = 480 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/PeopleOnStreet.cfg b/bin/HM-like/per-sequence_JM/PeopleOnStreet.cfg new file mode 100644 index 0000000..f9f4e60 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/PeopleOnStreet.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/PeopleOnStreet_2560x1600_30_crop.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 30 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 2560 # Input frame width +SourceHeight = 1600 # Input frame height +FramesToBeEncoded = 150 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/RaceHorses.cfg b/bin/HM-like/per-sequence_JM/RaceHorses.cfg new file mode 100644 index 0000000..40c0aeb --- /dev/null +++ b/bin/HM-like/per-sequence_JM/RaceHorses.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../../origCfP/RaceHorses_416x240_30.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 30 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 416 # Input frame width +SourceHeight = 240 # Input frame height +FramesToBeEncoded = 300 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/RaceHorsesC.cfg b/bin/HM-like/per-sequence_JM/RaceHorsesC.cfg new file mode 100644 index 0000000..5c36847 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/RaceHorsesC.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/RaceHorses_832x480_30.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 30 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 832 # Input frame width +SourceHeight = 480 # Input frame height +FramesToBeEncoded = 300 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/SlideEditing.cfg b/bin/HM-like/per-sequence_JM/SlideEditing.cfg new file mode 100644 index 0000000..cea6a29 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/SlideEditing.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/SlideEditing_1280x720_30.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 30 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1280 # Input frame width +SourceHeight = 720 # Input frame height +FramesToBeEncoded = 300 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/SlideShow.cfg b/bin/HM-like/per-sequence_JM/SlideShow.cfg new file mode 100644 index 0000000..a0f6da6 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/SlideShow.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/SlideShow_1280x720_20.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 20 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1280 # Input frame width +SourceHeight = 720 # Input frame height +FramesToBeEncoded = 500 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/SteamLocomotiveTrain_10bit.cfg b/bin/HM-like/per-sequence_JM/SteamLocomotiveTrain_10bit.cfg new file mode 100644 index 0000000..96c5607 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/SteamLocomotiveTrain_10bit.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/SteamLocomotiveTrain_2560x1600_60_10bit_crop.yuv" +SourceBitDepthLuma = 10 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 10 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 2560 # Input frame width +SourceHeight = 1600 # Input frame height +FramesToBeEncoded = 300 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/Traffic.cfg b/bin/HM-like/per-sequence_JM/Traffic.cfg new file mode 100644 index 0000000..2b37a20 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/Traffic.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/Traffic_2560x1600_30_crop.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 30 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 2560 # Input frame width +SourceHeight = 1600 # Input frame height +FramesToBeEncoded = 150 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/Vidyo1.cfg b/bin/HM-like/per-sequence_JM/Vidyo1.cfg new file mode 100644 index 0000000..866f05c --- /dev/null +++ b/bin/HM-like/per-sequence_JM/Vidyo1.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/vidyo1_1280x720_60.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1280 # Input frame width +SourceHeight = 720 # Input frame height +FramesToBeEncoded = 600 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/Vidyo3.cfg b/bin/HM-like/per-sequence_JM/Vidyo3.cfg new file mode 100644 index 0000000..3957fcb --- /dev/null +++ b/bin/HM-like/per-sequence_JM/Vidyo3.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/vidyo3_1280x720_60.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1280 # Input frame width +SourceHeight = 720 # Input frame height +FramesToBeEncoded = 600 # Number of frames to be coded diff --git a/bin/HM-like/per-sequence_JM/Vidyo4.cfg b/bin/HM-like/per-sequence_JM/Vidyo4.cfg new file mode 100644 index 0000000..a940b20 --- /dev/null +++ b/bin/HM-like/per-sequence_JM/Vidyo4.cfg @@ -0,0 +1,9 @@ +#======== File I/O =============== +InputFile = "../../origCfP/vidyo4_1280x720_60.yuv" +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +FrameRate = 60 # Frame Rate per second +FrameSkip = 0 # Number of frames to be skipped in input +SourceWidth = 1280 # Input frame width +SourceHeight = 720 # Input frame height +FramesToBeEncoded = 600 # Number of frames to be coded diff --git a/bin/ToneMapping.cfg b/bin/ToneMapping.cfg new file mode 100644 index 0000000..5972c63 --- /dev/null +++ b/bin/ToneMapping.cfg @@ -0,0 +1,25 @@ +## configure file for tone mapping SEI message, +## must follow the format "keyword = xx" exactly +## +tone_map_id = 0 +tone_map_cancel_flag = 0 +tone_map_repetition_period = 1 +coded_data_bit_depth = 10 +sei_bit_depth = 8 +model_id = 0 + +## model_id 0: linear mapping +min_value = 0 +max_value = 1023 + +## model_id 1: sigmoidal mapping +sigmoid_midpoint = 512 +sigmoid_width = 960 + +## model_id 2: user-defined table mapping, start_of_coded_interval has (1< = # Comment +# +########################################################################################## +# Files +########################################################################################## +InputFile = "ChampTower_Stereo.264" # H.264/AVC coded bitstream +OutputFile = "ChampTower_Stereo.yuv" # Output file, YUV/RGB +RefFile = "ChampTower_REF.yuv" # Ref sequence (for SNR) +WriteUV = 1 # Write 4:2:0 chroma components for monochrome streams +FileFormat = 0 # NAL mode (0=Annex B, 1: RTP packets) +RefOffset = 0 # SNR computation offset +POCScale = 2 # Poc Scale (1 or 2) +########################################################################################## +# HRD parameters +########################################################################################## +#R_decoder = 500000 # Rate_Decoder +#B_decoder = 104000 # B_decoder +#F_decoder = 73000 # F_decoder +#LeakyBucketParamFile = "leakybucketparam.cfg" # LeakyBucket Params +########################################################################################## +# decoder control parameters +########################################################################################## +DisplayDecParams = 1 # 1: Display parameters; +ConcealMode = 0 # Err Concealment(0:Off,1:Frame Copy,2:Motion Copy) +RefPOCGap = 2 # Reference POC gap (2: IPP (Default), 4: IbP / IpP) +POCGap = 2 # POC gap (2: IPP /IbP/IpP (Default), 4: IPP with frame skip = 1 etc.) +IDRPeriod = 10 # IDR Period +Silent = 0 # Silent decode +IntraProfileDeblocking = 1 # Enable Deblocking filter in intra only profiles (0=disable, 1=filter according to SPS parameters) +DecFrmNum = 0 # Number of frames to be decoded (-n) +########################################################################################## +# Frame Loss Concealment Parameters +########################################################################################## +ConcealMode = 1 # Err Concealment(0:Off,1:Frame Copy,2:Motion Copy) +# SearchMode Brief +# SearchMode = 0: Uses the previous reference pic for concealment of reference frames +# within the same view +# SearchMode = 1: Uses the closest frame to conceal (inc concealed frames) +# SearchMode = 2: Uses the closest frame to conceal (not concealed frames) +SearchModeRef = 2 +SearchModeNonRef = 1 +########################################################################################## +# MVC decoding parameters +########################################################################################## +DecodeAllLayers = 1 # Decode all views (-mpr) diff --git a/bin/decoder_stereo.cfg b/bin/decoder_stereo.cfg new file mode 100644 index 0000000..6866c4b --- /dev/null +++ b/bin/decoder_stereo.cfg @@ -0,0 +1,40 @@ +# This is a file containing input parameters to the JVT H.264/AVC decoder. +# The text line following each parameter is discarded by the decoder. +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de +# +# New Input File Format is as follows +# = # Comment +# +########################################################################################## +# Files +########################################################################################## +InputFile = "test.264" # H.264/AVC coded bitstream +OutputFile = "test_dec.yuv" # Output file, YUV/RGB +RefFile = "test_rec.yuv" # Ref sequence (for SNR) +WriteUV = 1 # Write 4:2:0 chroma components for monochrome streams +FileFormat = 0 # NAL mode (0=Annex B, 1: RTP packets) +RefOffset = 0 # SNR computation offset +POCScale = 2 # Poc Scale (1 or 2) +########################################################################################## +# HRD parameters +########################################################################################## +#R_decoder = 500000 # Rate_Decoder +#B_decoder = 104000 # B_decoder +#F_decoder = 73000 # F_decoder +#LeakyBucketParamFile = "leakybucketparam.cfg" # LeakyBucket Params +########################################################################################## +# decoder control parameters +########################################################################################## +DisplayDecParams = 0 # 1: Display parameters; +ConcealMode = 0 # Err Concealment(0:Off,1:Frame Copy,2:Motion Copy) +RefPOCGap = 2 # Reference POC gap (2: IPP (Default), 4: IbP / IpP) +POCGap = 2 # POC gap (2: IPP /IbP/IpP (Default), 4: IPP with frame skip = 1 etc.) +Silent = 0 # Silent decode +IntraProfileDeblocking = 1 # Enable Deblocking filter in intra only profiles (0=disable, 1=filter according to SPS parameters) +DecFrmNum = 0 # Number of frames to be decoded (-n) +########################################################################################## +# MVC decoding parameters +########################################################################################## +DecodeAllLayers = 1 # Decode all views (-mpr) diff --git a/bin/encoder.cfg b/bin/encoder.cfg new file mode 100644 index 0000000..c38f893 --- /dev/null +++ b/bin/encoder.cfg @@ -0,0 +1,671 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "foreman_part_qcif.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 3 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +Enable32Pulldown = 0 # Enable 'hard' 3:2 pulldown (modifying the inpur data) + # 0 = disabled + # 1 = A, B, Bt|Cb, Ct|Db, D + # 2 = A, B, C, Ct|Db, D +SEIVUI32Pulldown = 0 # Enable 3:2 pulldown through VUI and SEI metadata signaling. Five methods are supported: + # 0 = disabled + # 1 = A, Bt|Bb, Bt|Cb, Ct|Cb, D + # 2 = A, B, C, C, D + # 3 = At|Ab, Bt|Bb, Bt|Cb, Ct|Cb, Dt|Db + # 4 = A, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + # 5 = At|Ab, Bt|Bb, Bt|Cb, Ct|Db, Dt|Db + +SourceWidth = 176 # Source frame width +SourceHeight = 144 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 176 # Output frame width +OutputHeight = 144 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +PixelFormat = 0 # Pixel Format for 422 packed inputs + # 0: UYVY + # 1: YUY2/YUYV + # 2: YVYU + # 3: BGR (Unsupported) + # 4: V210 (Video Clarity) + +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +NumberOfViews = 1 # Number of views to encode (1=1 view, 2=2 views) +View1ConfigFile = "encoder_view1.cfg" # Config file name for second view +########################################################################################## +# Encoder Control +########################################################################################## +Grayscale = 0 # Encode in grayscale (Currently only works for 8 bit YUV 420 input) +ProfileIDC = 100 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra, 118=Multiview High Profile, 128=Stereo High Profile) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range +MESoftenSSEMetric = 0 # soften lambda criterion for SSE ME +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +OnTheFlyFractMCP = 0 # Perform on-the-fly fractional pixel interpolation for Motion Compensation and Motion Estimation + # 0: Disable, interpolate & store all positions + # 1: Store full pel & interpolated 1/2 pel positions; 1/4 pel positions interpolate on-the-fly + # 2: Store only full pell positions; 1/2 & 1/4 pel positions interpolate on-the-fly +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 1 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 2 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 7 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 3 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b3r0b1r1b0e2b2e2b5r1b4e2b6e2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 1 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 2 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 1 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPSliceITest = 1 # Perform Slice level RD decision between P and I slices. Default value is 1 (enabled). +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 1 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 0 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 0 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 16 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 1 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 5 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 0 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 0 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 3 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B, 3: Pic Boundary + P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. + +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 1 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/encoder_baseline.cfg b/bin/encoder_baseline.cfg new file mode 100644 index 0000000..e7c6e6d --- /dev/null +++ b/bin/encoder_baseline.cfg @@ -0,0 +1,376 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "foreman_part_qcif.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 3 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +SourceWidth = 176 # Source frame width +SourceHeight = 144 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 176 # Output frame width +OutputHeight = 144 # Output frame height + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +########################################################################################## +# Encoder Control +########################################################################################## +ProfileIDC = 66 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 0 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 2 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE +########################################################################################## +# Output Control, NALs +########################################################################################## + +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 44 # maximum P Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 36 # maximum I Slice QP value for rate control + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb + # 4: with additional MB level lambda info + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 1 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 16 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 4 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 4 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorINRef = 4 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 4 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 0 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + diff --git a/bin/encoder_extended.cfg b/bin/encoder_extended.cfg new file mode 100644 index 0000000..088397c --- /dev/null +++ b/bin/encoder_extended.cfg @@ -0,0 +1,524 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "foreman_part_qcif.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 3 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +SourceWidth = 176 # Source frame width +SourceHeight = 144 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 176 # Output frame width +OutputHeight = 144 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Recontruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +########################################################################################## +# Encoder Control +########################################################################################## +ProfileIDC = 88 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 0 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 2 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 1 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 0 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b1r0b3r0b2e2b0e2b4r2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 1 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 1 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb + + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 1 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 16 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 4 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 4 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 4 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 4 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 4 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 4 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 4 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 4 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 0 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 0 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 0 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 0 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 1 # 1-5: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 1 # copy Mode from first QP tested +RDOQ_CP_MV = 1 # copy MV from first QP tested +RDOQ_Fast = 1 # Fast RDOQ decision method for multiple QPs + + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 0 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + diff --git a/bin/encoder_fast.cfg b/bin/encoder_fast.cfg new file mode 100644 index 0000000..064b942 --- /dev/null +++ b/bin/encoder_fast.cfg @@ -0,0 +1,648 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "/data/foreman_176x144_30p.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 30 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +Enable32Pulldown = 0 # Enforce 3:2 pulldown methods + # 0 = disabled + # 1 = A, B, Bt|Cb, Ct|Db, D + # 2 = A, B, C, Ct|Db, D +SourceWidth = 176 # Source frame width +SourceHeight = 144 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 176 # Output frame width +OutputHeight = 144 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +########################################################################################## +# Encoder Control +########################################################################################## +Grayscale = 0 # Encode in grayscale (Currently only works for 8 bit YUV 420 input) +ProfileIDC = 100 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra, 118=Multiview High Profile, 128=Stereo High Profile) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 0 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 1 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 2 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 7 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 3 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b3r0b1r1b0e2b2e2b5r1b4e2b6e2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 1 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 1 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 1 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 1 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 0 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 0 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 1 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 0 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 5 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 0 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 3 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 1 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/encoder_main.cfg b/bin/encoder_main.cfg new file mode 100644 index 0000000..2b8109e --- /dev/null +++ b/bin/encoder_main.cfg @@ -0,0 +1,499 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "foreman_part_qcif.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 3 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +SourceWidth = 176 # Source frame width +SourceHeight = 144 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 176 # Output frame width +OutputHeight = 144 # Output frame height + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Recontruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +########################################################################################## +# Encoder Control +########################################################################################## +ProfileIDC = 77 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 0 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 1 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 0 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b1r0b3r0b2e2b0e2b4r2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 1 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 1 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb + # 4: with additional MB level lambda info + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 1 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 16 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 4 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 4 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 4 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 4 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 4 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 4 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 4 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 4 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 0 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 0 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 0 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 0 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 1 # 1-5: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 1 # copy Mode from first QP tested +RDOQ_CP_MV = 1 # copy MV from first QP tested +RDOQ_Fast = 1 # Fast RDOQ decision method for multiple QPs + + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 0 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + diff --git a/bin/encoder_stereo.cfg b/bin/encoder_stereo.cfg new file mode 100644 index 0000000..e52ffe1 --- /dev/null +++ b/bin/encoder_stereo.cfg @@ -0,0 +1,650 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "sample_left_320x240.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 3 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +Enable32Pulldown = 0 # Enforce 3:2 pulldown methods + # 0 = disabled + # 1 = A, B, Bt|Cb, Ct|Db, D + # 2 = A, B, C, Ct|Db, D +SourceWidth = 320 # Source frame width +SourceHeight = 240 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 320 # Output frame width +OutputHeight = 240 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +NumberOfViews = 2 # Number of views to encode (1=1 view, 2=2 views) +View1ConfigFile = "encoder_view1.cfg" # Config file name for second view +########################################################################################## +# Encoder Control +########################################################################################## +Grayscale = 0 # Encode in grayscale (Currently only works for 8 bit YUV 420 input) +ProfileIDC = 128 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra, 118=Multiview High Profile, 128=Stereo High Profile) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 1 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 2 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 7 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 3 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b3r0b1r1b0e2b2e2b5r1b4e2b6e2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 0 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 0 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 0 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 1 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 0 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 0 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 1 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 0 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 5 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 0 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 3 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/encoder_tonemapping.cfg b/bin/encoder_tonemapping.cfg new file mode 100644 index 0000000..4696272 --- /dev/null +++ b/bin/encoder_tonemapping.cfg @@ -0,0 +1,570 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "Crew_10.rgb" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 10 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +SourceWidth = 1280 # Source frame width +SourceHeight = 720 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 1280 # Output frame width +OutputHeight = 720 # Output frame height + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +########################################################################################## +# Encoder Control +########################################################################################## +ProfileIDC = 244 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 51 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 1 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 0 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +SendAUD = 0 # Send Access Delimiter Unit NALU (for every access unit) +ResendSPS = 0 # Resend SPS (0: disabled, 1: all Intra pictures, 2: only for IDR, 3: for IDR and OpenGOP I) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 0 # Number of B coded frames inserted (0=not used) +PReplaceBSlice = 0 # Replace B-coded slices with P-coded slices when NumberBFrames>0 +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 0 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b3r0b1r1b0e2b2e2b5r1b4e2b6e2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ExplicitSeqCoding = 0 # Enable support for explicit sequence coding +ExplicitSeqFile = "explicit_seq.cfg" +LowDelay = 0 # Apply HierarchicalCoding without delay (i.e., encode in the captured/display order) +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 1 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) +SetFirstAsLongTerm = 0 # Set first frame as long term + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +SPSwitchPeriod = 0 # Switch period (in terms of switching SP/SI frames) between bitstream 1 and bitstream 2 +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 2 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 0 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 3 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 1 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 10 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 10 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 0 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 0 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 1 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 16 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 8 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 8 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 8 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 8 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 8 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 8 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 8 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 8 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 8 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 8 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 0 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 1 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 1 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 5 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 0 # copy Mode from first QP tested +RDOQ_CP_MV = 0 # copy MV from first QP tested +RDOQ_Fast = 0 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 0 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 1 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + diff --git a/bin/encoder_view1.cfg b/bin/encoder_view1.cfg new file mode 100644 index 0000000..318b2a0 --- /dev/null +++ b/bin/encoder_view1.cfg @@ -0,0 +1,102 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.de + + +########################################################################################## +# Second View configuration +########################################################################################## +InputFile = "sample_right_320x240.yuv" # Input sequence 2 for the MVC profile +ReconFile = "test_rec2.yuv" # Reconstruction YUV file 2 for the MVC profile + +########################################################################################## +# Encoder Control +########################################################################################## +SearchRange = 32 # Max search range for view 1 (requires SepViewInterSearch) +DisableSubpelME = 0 # Disable Subpixel Motion Estimation for view 1 (0=off/default, 1=on) (requires SepViewInterSearch) +DisableIntraInInter = 0 # Disable Intra modes for inter slices for view 1 (requires SepViewInterSearch) + +PList0Refs = 0 # View 1 P slice List 0 reference override (0 disable, N <= (NumberReferenceFrames + 1)) (requires SepViewInterSearch) + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) (requires SepViewInterSearch) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) (requires SepViewInterSearch) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) (requires SepViewInterSearch) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) (requires SepViewInterSearch) + +MVCEnableInterViewFlag = 1 # enable inter view flag +MVCInterViewReorder = 1 # Reorder References according to interview pictures (0=off, 1=enable) +QPOffset = 0 # QP offset during rate control for View 1 +SepViewInterSearch = 0 # If set, allows different InterSearch modes to be set for each view (default is 0 - disabled) +NoResidueRDO = 1 # Test no residue case for View 1 during RDO (0: disabled, 1: enabled - default) +MVCInterViewForceB = 0 # Force B coded pictures for Enhancement layer (assuming list order is as desired, this may be able to provide some coding gains) + +########################################################################################## +# B Slices +########################################################################################## + +BList0Refs = 0 # View 1 B slice List 0 reference override (0 disable, N <= (NumberReferenceFrames + 1)) (requires SepViewInterSearch) +BList1Refs = 1 # View 1 B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) (requires SepViewInterSearch) + +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default) for view 1. Note that range is halved for every extra refinement. Requires SepViewInterSearch. + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 3 # Defined same as above, but for view 1 (requires SepViewInterSearch to be set) + +EPZSMinThresScale = 0 # Enh layer scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. EnableEnhLayerEPZSScalers must be 1. +EPZSMedThresScale = 1 # Enh layer scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. EnableEnhLayerEPZSScalers must be 1. +EPZSMaxThresScale = 2 # Enh layer scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. EnableEnhLayerEPZSScalers must be 1. +EPZSSubPelThresScale = 1 # Enh layer EPZS Subpel ME Threshold scaler. EnableEnhLayerEPZSScalers must be 1. + diff --git a/bin/encoder_yuv422.cfg b/bin/encoder_yuv422.cfg new file mode 100644 index 0000000..4bd8b13 --- /dev/null +++ b/bin/encoder_yuv422.cfg @@ -0,0 +1,635 @@ +# New Input File Format is as follows +# = # Comment +# +# See configfile.h for a list of supported ParameterNames +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de + + +########################################################################################## +# Files +########################################################################################## +InputFile = "foreman_part_qcif_422.yuv" # Input sequence +InputHeaderLength = 0 # If the inputfile has a header, state it's length in byte here +StartFrame = 0 # Start frame for encoding. (0-N) +FramesToBeEncoded = 3 # Number of frames to be coded +FrameRate = 30.0 # Frame Rate per second (0.1-100.0) +SourceWidth = 176 # Source frame width +SourceHeight = 144 # Source frame height +SourceResize = 0 # Resize source size for output +OutputWidth = 176 # Output frame width +OutputHeight = 144 # Output frame height +ProcessInput = 0 # Filter Input Sequence +Interleaved = 0 # 0: Planar input, 1: Packed input +StandardRange = 0 # 0: Standard range 1: Full range (RGB input) +VideoCode = 1 # Video codes for RGB ==> YUV conversions + # 0 = NULL, + # 1 = ITU_REC709, + # 2 = CCIR_601, + # 3 = FCC, + # 4 = ITU_REC624BG, + # 5 = SMPTE_170M, + # 6 = SMPTE_240M, + # 7 = SMPTE_260M, + # 8 = ITU_REC709_EXACT + +TraceFile = "trace_enc.txt" # Trace file +ReconFile = "test_rec.yuv" # Reconstruction YUV file +OutputFile = "test.264" # Bitstream +StatsFile = "stats.dat" # Coding statistics file + +########################################################################################## +# Encoder Control +########################################################################################## +ProfileIDC = 122 # Profile IDC (66=baseline, 77=main, 88=extended; FREXT Profiles: 100=High, 110=High 10, 122=High 4:2:2, 244=High 4:4:4, 44=CAVLC 4:4:4 Intra) +IntraProfile = 0 # Activate Intra Profile for FRExt (0: false, 1: true) + # (e.g. ProfileIDC=110, IntraProfile=1 => High 10 Intra Profile) +LevelIDC = 40 # Level IDC (e.g. 20 = level 2.0) + +IntraPeriod = 0 # Period of I-pictures (0=only first) +IDRPeriod = 0 # Period of IDR pictures (0=only first) +AdaptiveIntraPeriod = 1 # Adaptive intra period +AdaptiveIDRPeriod = 0 # Adaptive IDR period +IntraDelay = 0 # Intra (IDR) picture delay (i.e. coding structure of PPIPPP... ) +EnableIDRGOP = 0 # Support for IDR closed GOPs (0: disabled, 1: enabled) +EnableOpenGOP = 0 # Support for open GOPs (0: disabled, 1: enabled) +QPISlice = 28 # Quant. param for I Slices (0-51) +QPPSlice = 28 # Quant. param for P Slices (0-51) +FrameSkip = 0 # Number of frames to be skipped in input (e.g 2 will code every third frame). + # Note that this now excludes intermediate (i.e. B) coded pictures +ChromaQPOffset = 0 # Chroma QP offset (-51..51) + +DisableSubpelME = 0 # Disable Subpixel Motion Estimation (0=off/default, 1=on) +SearchRange = 32 # Max search range + +MEDistortionFPel = 0 # Select error metric for Full-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionHPel = 2 # Select error metric for Half-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MEDistortionQPel = 2 # Select error metric for Quarter-Pel ME (0: SAD, 1: SSE, 2: Hadamard SAD) +MDDistortion = 2 # Select error metric for Mode Decision (0: SAD, 1: SSE, 2: Hadamard SAD) +SkipDeBlockNonRef = 0 # Skip Deblocking (regardless of DFParametersFlag) for non-reference frames (0: off, 1: on) +ChromaMCBuffer = 1 # Calculate Color component interpolated values in advance and store them. + # Provides a trade-off between memory and computational complexity + # (0: disabled/default, 1: enabled) +ChromaMEEnable = 0 # Take into account Color component information during ME + # (0: only first component/default, + # 1: All Color components - Integer refinement only + # 2: All Color components - All refinements) +ChromaMEWeight = 1 # Weighting for chroma components. This parameter should have a relationship with color format. + +NumberReferenceFrames = 5 # Number of previous frames used for inter motion search (0-16) + +PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +Log2MaxFNumMinus4 = 0 # Sets log2_max_frame_num_minus4 (-1 : based on FramesToBeEncoded/Auto, >=0 : Log2MaxFNumMinus4) +Log2MaxPOCLsbMinus4 = -1 # Sets log2_max_pic_order_cnt_lsb_minus4 (-1 : Auto, >=0 : Log2MaxPOCLsbMinus4) + +GenerateMultiplePPS = 0 # Transmit multiple parameter sets. Currently parameters basically enable all WP modes (0: diabled, 1: enabled) +ResendPPS = 0 # Resend PPS (with pic_parameter_set_id 0) for every coded Frame/Field pair (0: disabled, 1: enabled) + +MbLineIntraUpdate = 0 # Error robustness(extra intra macro block updates)(0=off, N: One GOB every N frames are intra coded) +RandomIntraMBRefresh = 0 # Forced intra MBs per picture + +########################################################################################## +# PSlice Mode types +########################################################################################## +PSliceSkip = 1 # P-Slice Skip mode consideration (0=disable, 1=enable) +PSliceSearch16x16 = 1 # P-Slice Inter block search 16x16 (0=disable, 1=enable) +PSliceSearch16x8 = 1 # P-Slice Inter block search 16x8 (0=disable, 1=enable) +PSliceSearch8x16 = 1 # P-Slice Inter block search 8x16 (0=disable, 1=enable) +PSliceSearch8x8 = 1 # P-Slice Inter block search 8x8 (0=disable, 1=enable) +PSliceSearch8x4 = 1 # P-Slice Inter block search 8x4 (0=disable, 1=enable) +PSliceSearch4x8 = 1 # P-Slice Inter block search 4x8 (0=disable, 1=enable) +PSliceSearch4x4 = 1 # P-Slice Inter block search 4x4 (0=disable, 1=enable) + +########################################################################################## +# BSlice Mode types +########################################################################################## + +BSliceDirect = 1 # B-Slice Skip mode consideration (0=disable, 1=enable) +BSliceSearch16x16 = 1 # B-Slice Inter block search 16x16 (0=disable, 1=enable) +BSliceSearch16x8 = 1 # B-Slice Inter block search 16x8 (0=disable, 1=enable) +BSliceSearch8x16 = 1 # B-Slice Inter block search 8x16 (0=disable, 1=enable) +BSliceSearch8x8 = 1 # B-Slice Inter block search 8x8 (0=disable, 1=enable) +BSliceSearch8x4 = 1 # B-Slice Inter block search 8x4 (0=disable, 1=enable) +BSliceSearch4x8 = 1 # B-Slice Inter block search 4x8 (0=disable, 1=enable) +BSliceSearch4x4 = 1 # B-Slice Inter block search 4x4 (0=disable, 1=enable) + +BiPredSearch16x16 = 1 # B-Slice Bi-prediction block search 16x16 (0=disable, 1=enable) +BiPredSearch16x8 = 1 # B-Slice Bi-prediction block search 16x8 (0=disable, 1=enable) +BiPredSearch8x16 = 1 # B-Slice Bi-prediction block search 8x16 (0=disable, 1=enable) +BiPredSearch8x8 = 0 # B-Slice Bi-prediction block search 8x8 (0=disable, 1=enable) + +DisableIntra4x4 = 0 # Disable Intra 4x4 modes +DisableIntra16x16 = 0 # Disable Intra 16x16 modes +DisableIntraInInter = 0 # Disable Intra modes for inter slices +IntraDisableInterOnly = 0 # Apply Disabling Intra conditions only to Inter Slices (0:disable/default,1: enable) +Intra4x4ParDisable = 0 # Disable Vertical & Horizontal 4x4 +Intra4x4DiagDisable = 0 # Disable Diagonal 45degree 4x4 +Intra4x4DirDisable = 0 # Disable Other Diagonal 4x4 +Intra16x16ParDisable = 0 # Disable Vertical & Horizontal 16x16 +Intra16x16PlaneDisable = 0 # Disable Planar 16x16 +ChromaIntraDisable = 0 # Disable Intra Chroma modes other than DC +EnableIPCM = 1 # Enable IPCM macroblock mode + +DisposableP = 0 # Enable Disposable P slices in the primary layer (0: disable/default, 1: enable) +DispPQPOffset = 0 # Quantizer offset for disposable P slices (0: default) + +PreferDispOrder = 1 # Prefer display order when building the prediction structure as opposed to coding order (affects intra and IDR periodic insertion, among others) +PreferPowerOfTwo = 0 # Prefer prediction structures that have lengths expressed as powers of two +FrmStructBufferLength = 16 # Length of the frame structure unit buffer; it can be overriden for certain cases + +ChangeQPFrame = 0 # Frame in display order from which to apply the Change QP offsets +ChangeQPI = 0 # Change QP offset value for I_SLICE +ChangeQPP = 0 # Change QP offset value for P_SLICE +ChangeQPB = 0 # Change QP offset value for B_SLICE +ChangeQPSI = 0 # Change QP offset value for SI_SLICE +ChangeQPSP = 0 # Change QP offset value for SP_SLICE + +########################################################################################## +# B Slices +########################################################################################## + +NumberBFrames = 1 # Number of B coded frames inserted (0=not used) +QPBSlice = 30 # Quant. param for B slices (0-51) +BRefPicQPOffset = -1 # Quantization offset for reference B coded pictures (-51..51) +DirectModeType = 1 # Direct Mode Type (0:Temporal 1:Spatial) +DirectInferenceFlag = 1 # Direct Inference Flag (0: Disable 1: Enable) +BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames) +BList1References = 1 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames) + # 1 List1 reference is usually recommended for normal GOP Structures. + # A larger value is usually more appropriate if a more flexible + # structure is used (i.e. using HierarchicalCoding) + +BReferencePictures = 0 # Referenced B coded pictures (0=off, 1=B references for secondary layer, 2=B references for primary layer) + +HierarchicalCoding = 0 # B hierarchical coding (0= off, 1= 2 layers, 2= 2 full hierarchy, 3 = explicit) +HierarchyLevelQPEnable = 1 # Adjust QP based on hierarchy level (in increments of 1). Overrides BRefPicQPOffset behavior.(0=off, 1=on) +ExplicitHierarchyFormat = "b1r0b3r0b2e2b0e2b4r2" # Explicit Enhancement GOP. Format is {FrameDisplay_orderReferenceQP}. + # Valid values for reference type is r:reference, e:non reference. +ReferenceReorder = 1 # Reorder References according to Poc distance for HierarchicalCoding (0=off, 1=enable, 2=use when LowDelay is set) +PocMemoryManagement = 1 # Memory management based on Poc Distances for HierarchicalCoding (0=off, 1=on, 2=use when LowDelay is set) + +BiPredMotionEstimation = 1 # Enable Bipredictive based Motion Estimation (0:disabled, 1:enabled) +BiPredMERefinements = 3 # Bipredictive ME extra refinements (0: single, N: N extra refinements (1 default) +BiPredMESearchRange = 16 # Bipredictive ME Search range (8 default). Note that range is halved for every extra refinement. +BiPredMESubPel = 2 # Bipredictive ME Subpixel Consideration (0: disabled, 1: single level, 2: dual level) + + +########################################################################################## +# SP Frames +########################################################################################## + +SPPicturePeriodicity = 0 # SP-Picture Periodicity (0=not used) +QPSPSlice = 36 # Quant. param of SP-Slices for Prediction Error (0-51) +QPSISlice = 36 # Quant. param of SI-Slices for Prediction Error (0-51) +QPSP2Slice = 35 # Quant. param of SP/SI-Slices for Predicted Blocks (0-51) +SI_FRAMES = 0 # SI frame encoding flag (0=not used, 1=used) +SP_output = 0 # Controls whether coefficients will be output to encode switching SP frames (0=no, 1=yes) +SP_output_name = "low_quality.dat" # Filename for SP output coefficients +SP2_FRAMES = 0 # switching SP frame encoding flag (0=not used, 1=used) +SP2_input_name1 = "high_quality.dat" # Filename for the first swithed bitstream coefficients +SP2_input_name2 = "low_quality.dat" # Filename for the second switched bitstream coefficients + +########################################################################################## +# Output Control, NALs +########################################################################################## + +SymbolMode = 1 # Symbol mode (Entropy coding method: 0=UVLC, 1=CABAC) +OutFileMode = 0 # Output file mode, 0:Annex B, 1:RTP +PartitionMode = 0 # Partition Mode, 0: no DP, 1: 3 Partitions per Slice + +########################################################################################## +# CABAC context initialization +########################################################################################## + +ContextInitMethod = 1 # Context init (0: fixed, 1: adaptive) +FixedModelNumber = 0 # model number for fixed decision for inter slices ( 0, 1, or 2 ) + +########################################################################################## +# Interlace Handling +######################################################################################### + +PicInterlace = 0 # Picture AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding) +MbInterlace = 0 # Macroblock AFF (0: frame coding, 1: field coding, 2:adaptive frame/field coding, 3: frame MB-only AFF) +IntraBottom = 0 # Force Intra Bottom at GOP Period + +########################################################################################## +# Weighted Prediction +######################################################################################### + +WeightedPrediction = 0 # P picture Weighted Prediction (0=off, 1=explicit mode) +WeightedBiprediction = 0 # B picture Weighted Prediciton (0=off, 1=explicit mode, 2=implicit mode) +ChromaWeightSupport = 1 # Enable consideration of weights for Chroma components +UseWeightedReferenceME = 1 # Use weighted reference for ME (0=off, 1=on) +WPMethod = 1 # WP method (0: DC based, 1: LMS based) +WPIterMC = 0 # Iterative Motion compensated based weighted prediction method +EnhancedBWeightSupport = 0 # Enhanced B Weight support (needs revisit if we wish to merge with WPMethod) +WPMCPrecision = 0 # Improved Motion Compensation Precision using WP based methods. + # Clones WP references with slightly modified rounding offsets (Requires RDPictureDecision and GenerateMultiplePPS) : + # 0: disabled (default) + # 1: Up to one additional coding pass. Ref0 is 0, ref1 is 0 with a -1 offset + # 2: Up to two additional coding passes. (1) Ref0 is 0, ref1 is 0 with a -1 offset, (1) Ref0 is 0 with a -1 offset, ref1 is 0 +WPMCPrecFullRef = 0 # Increases the number of references in the reference picture lists to account + # for the lost reference slot when reordering is used during a coding pass in WPMCPrecision for reference replication. + # The number of references in non-reordered passes stays unchanged +WPMCPrecBSlice = 1 # 2: Apply rounding on every B slice. This efectively disables the evaluation of alternative QPs during RDPictureDecision. + # 1: Disable rounding for non-reference B slices. Non-reference B slices are evaluated for alternative QPs during RDPictureDecision. + # 0: Disable rounding for B slices. + +########################################################################################## +# Picture based Multi-pass encoding +######################################################################################### + +RDPictureDecision = 0 # Perform multiple pass coding and make RD optimal decision among them +RDPSliceBTest = 0 # Perform Slice level RD decision between P and B slices. +RDPictureMaxPassISlice = 1 # Max number of coding passes for I slices, valid values [1,3], default is 1 +RDPictureMaxPassPSlice = 2 # Max number of coding passes for P slices, valid values [1,6], default is 2 +RDPictureMaxPassBSlice = 3 # Max number of coding passes for B slices, valid values [1,6], default is 3 +RDPictureFrameQPPSlice = 0 # Perform additional frame level QP check (QP+/-1) for P slices, 0: disabled (default), 1: enabled +RDPictureFrameQPBSlice = 0 # Perform additional frame level QP check (QP+/-1) for B slices, 0: disabled, 1: enabled (default) +RDPictureDeblocking = 0 # Perform another coding pass to check non-deblocked picture, 0: disabled (default), 1: enabled +RDPictureDirectMode = 0 # Perform another coding pass to check the alternative direct mode for B slices, , 0: disabled (default), 1: enabled + +########################################################################################## +# Deblocking filter parameters +########################################################################################## + +DFParametersFlag = 0 # Configure deblocking filter (0=parameters below ignored, 1=parameters sent) + # Note that for pictures with multiple slice types, + # only the type of the first slice will be considered. +DFDisableRefISlice = 0 # Disable deblocking filter in reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaRefISlice = 0 # Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefISlice = 0 # Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefISlice = 0 # Disable deblocking filter in non reference I coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefISlice = 0 # Non Reference I coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefISlice = 0 # Non Reference I coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefPSlice = 0 # Disable deblocking filter in reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaRefPSlice = 0 # Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefPSlice = 0 # Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefPSlice = 0 # Disable deblocking filter in non reference P coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefPSlice = 0 # Non Reference P coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefPSlice = 0 # Non Reference P coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableRefBSlice = 0 # Disable deblocking filter in reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaRefBSlice = 0 # Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaRefBSlice = 0 # Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFDisableNRefBSlice = 0 # Disable deblocking filter in non reference B coded pictures (0=Filter, 1=No Filter). +DFAlphaNRefBSlice = 0 # Non Reference B coded pictures Alpha offset div. 2, {-6, -5, ... 0, +1, .. +6} +DFBetaNRefBSlice = 0 # Non Reference B coded pictures Beta offset div. 2, {-6, -5, ... 0, +1, .. +6} + +########################################################################################## +# Error Resilience / Slices +########################################################################################## + +SliceMode = 0 # Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback) +SliceArgument = 50 # Slice argument (Arguments to modes 1 and 2 above) + +num_slice_groups_minus1 = 0 # Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc. +slice_group_map_type = 0 # 0: Interleave, 1: Dispersed, 2: Foreground with left-over, + # 3: Box-out, 4: Raster Scan 5: Wipe + # 6: Explicit, slice_group_id read from SliceGroupConfigFileName +slice_group_change_direction_flag = 0 # 0: box-out clockwise, raster scan or wipe right, + # 1: box-out counter clockwise, reverse raster scan or wipe left +slice_group_change_rate_minus1 = 85 # +SliceGroupConfigFileName = "sg0conf.cfg" # Used for slice_group_map_type 0, 2, 6 + +UseRedundantPicture = 0 # 0: not used, 1: enabled +NumRedundantHierarchy = 1 # 0-4 +PrimaryGOPLength = 10 # GOP length for redundant allocation (1-16) + # NumberReferenceFrames must be no less than PrimaryGOPLength when redundant slice enabled +NumRefPrimary = 1 # Actually used number of references for primary slices (1-16) + +########################################################################################## +# Search Range Restriction / RD Optimization +########################################################################################## + +RestrictSearchRange = 2 # restriction for (0: blocks and ref, 1: ref, 2: no restrictions) +RDOptimization = 1 # rd-optimized mode decision + # 0: RD-off (Low complexity mode) + # 1: RD-on (High complexity mode) + # 2: RD-on (Fast high complexity mode - not work in FREX Profiles) + # 3: with losses +I16RDOpt = 0 # perform rd-optimized mode decision for Intra 16x16 MB + # 0: SAD-based mode decision for Intra 16x16 MB + # 1: RD-based mode decision for Intra 16x16 MB +SubMBCodingState = 1 # submacroblock coding state + # 0: lowest complexity, do not store or reset coding state during sub-MB mode decision + # 1: medium complexity, reset to master coding state (for current mode) during sub-MB mode decision + # 2: highest complexity, store and reset coding state during sub-MB mode decision +DistortionSSIM = 0 # Compute SSIM distortion. (0: disabled/default, 1: enabled) +DistortionMS_SSIM = 0 # Compute Multiscale SSIM distortion. (0: disabled/default, 1: enabled) +SSIMOverlapSize = 8 # Overlap size to calculate SSIM distortion (1: pixel by pixel, 8: no overlap) +DistortionYUVtoRGB = 0 # Calculate distortion in RGB domain after conversion from YCbCr (0:off, 1:on) +CtxAdptLagrangeMult = 0 # Context Adaptive Lagrange Multiplier + # 0: disabled (default) + # 1: enabled (works best when RDOptimization=0) +FastCrIntraDecision = 1 # Fast Chroma intra mode decision (0:off, 1:on) +DisableThresholding = 0 # Disable Thresholding of Transform Coefficients (0:off, 1:on) +DisableBSkipRDO = 0 # Disable B Skip Mode consideration from RDO Mode decision (0:off, 1:on) +BiasSkipRDO = 0 # Negative Bias for Skip/DirectSkip modes (0: off, 1: on) +ForceTrueRateRDO = 0 # Force true rate (even zero values) during RDO process +SkipIntraInInterSlices = 0 # Skips Intra mode checking in inter slices if certain mode decisions are satisfied (0: off, 1: on) +WeightY = 1 # Luma weight for RDO +WeightCb = 1 # Cb weight for RDO +WeightCr = 1 # Cr weight for RDO + +########################################################################################## +# Explicit Lambda Usage +########################################################################################## +UseExplicitLambdaParams = 0 # Use explicit lambda scaling parameters (0:disabled, 1:enable lambda weight, 2: use explicit lambda value) +UpdateLambdaChromaME = 0 # Update lambda given Chroma ME consideration +FixedLambdaISlice = 0.1 # Fixed Lambda value for I slices +FixedLambdaPSlice = 0.1 # Fixed Lambda value for P slices +FixedLambdaBSlice = 0.1 # Fixed Lambda value for B slices +FixedLambdaRefBSlice = 0.1 # Fixed Lambda value for Referenced B slices +FixedLambdaSPSlice = 0.1 # Fixed Lambda value for SP slices +FixedLambdaSISlice = 0.1 # Fixed Lambda value for SI slices + +LambdaWeightISlice = 0.65 # scaling param for I slices. This will be used as a multiplier i.e. lambda=LambdaWeightISlice * 2^((QP-12)/3) +LambdaWeightPSlice = 0.68 # scaling param for P slices. This will be used as a multiplier i.e. lambda=LambdaWeightPSlice * 2^((QP-12)/3) +LambdaWeightBSlice = 0.68 # scaling param for B slices. This will be used as a multiplier i.e. lambda=LambdaWeightBSlice * 2^((QP-12)/3) +LambdaWeightRefBSlice = 0.68 # scaling param for Referenced B slices. This will be used as a multiplier i.e. lambda=LambdaWeightRefBSlice * 2^((QP-12)/3) +LambdaWeightSPSlice = 0.68 # scaling param for SP slices. This will be used as a multiplier i.e. lambda=LambdaWeightSPSlice * 2^((QP-12)/3) +LambdaWeightSISlice = 0.65 # scaling param for SI slices. This will be used as a multiplier i.e. lambda=LambdaWeightSISlice * 2^((QP-12)/3) + +LossRateA = 5 # expected packet loss rate of the channel for the first partition, only valid if RDOptimization = 3 +LossRateB = 0 # expected packet loss rate of the channel for the second partition, only valid if RDOptimization = 3 +LossRateC = 0 # expected packet loss rate of the channel for the third partition, only valid if RDOptimization = 3 +FirstFrameCorrect = 0 # If 1, the first frame is encoded under the assumption that it is always correctly received. +NumberOfDecoders = 30 # Numbers of decoders used to simulate the channel, only valid if RDOptimization = 3 +RestrictRefFrames = 0 # Doesnt allow reference to areas that have been intra updated in a later frame. + +########################################################################################## +# Additional Stuff +######################################################################################### + +UseConstrainedIntraPred = 0 # If 1, Inter pixels are not used for Intra macroblock prediction. + +NumberofLeakyBuckets = 8 # Number of Leaky Bucket values +LeakyBucketRateFile = "leakybucketrate.cfg" # File from which encoder derives rate values +LeakyBucketParamFile = "leakybucketparam.cfg" # File where encoder stores leakybucketparams + +NumFramesInELayerSubSeq = 0 # number of frames in the Enhanced Scalability Layer(0: no Enhanced Layer) + +SparePictureOption = 0 # (0: no spare picture info, 1: spare picture available) +SparePictureDetectionThr = 6 # Threshold for spare reference pictures detection +SparePicturePercentageThr = 92 # Threshold for the spare macroblock percentage + +PicOrderCntType = 0 # (0: POC mode 0, 1: POC mode 1, 2: POC mode 2) + +######################################################################################## +#Rate control +######################################################################################## + +RateControlEnable = 0 # 0 Disable, 1 Enable +Bitrate = 45020 # Bitrate(bps) +InitialQP = 0 # Initial Quantization Parameter for the first I frame + # InitialQp depends on two values: Bits Per Picture, + # and the GOP length +BasicUnit = 0 # Number of MBs in the basic unit + # should be a fraction of the total number + # of MBs in a frame ("0" sets a BU equal to a frame) +ChannelType = 0 # type of channel( 1=time varying channel; 0=Constant channel) +RCUpdateMode = 0 # Rate Control type. Modes supported : + # 0 = original JM rate control, + # 1 = rate control that is applied to all frames regardless of the slice type, + # 2 = original plus intelligent QP selection for I and B slices (including Hierarchical), + # 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics + # +RCISliceBitRatio = 1.0 # target ratio of bits for I-coded pictures compared to P-coded Pictures (for RCUpdateMode=3) +RCBSliceBitRatio0 = 0.5 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 0 (for RCUpdateMode=3) +RCBSliceBitRatio1 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 1 (for RCUpdateMode=3) +RCBSliceBitRatio2 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 2 (for RCUpdateMode=3) +RCBSliceBitRatio3 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 3 (for RCUpdateMode=3) +RCBSliceBitRatio4 = 0.25 # target ratio of bits for B-coded pictures compared to P-coded Pictures - temporal level 4 (for RCUpdateMode=3) +RCBoverPRatio = 0.45 # ratio of bit rate usage of a B-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCIoverPRatio = 3.80 # ratio of bit rate usage of an I-coded picture over a P-coded picture for the SAME QP (for RCUpdateMode=3) +RCMinQPPSlice = 8 # minimum P Slice QP value for rate control +RCMaxQPPSlice = 42 # maximum P Slice QP value for rate control +RCMinQPBSlice = 8 # minimum B Slice QP value for rate control +RCMaxQPBSlice = 42 # maximum B Slice QP value for rate control +RCMinQPISlice = 8 # minimum I Slice QP value for rate control +RCMaxQPISlice = 42 # maximum I Slice QP value for rate control +RCMinQPSPSlice = 8 # minimum SP Slice QP value for rate control +RCMaxQPSPSlice = 40 # maximum SP Slice QP value for rate control +RCMinQPSISlice = 8 # minimum SI Slice QP value for rate control +RCMaxQPSISlice = 42 # maximum SI Slice QP value for rate control +RCMaxQPChange = 4 # maximum QP change for frames of the base layer + +######################################################################################## +#Fast Mode Decision +######################################################################################## +EarlySkipEnable = 0 # Early skip detection (0: Disable 1: Enable) +SelectiveIntraEnable = 0 # Selective Intra mode decision (0: Disable 1: Enable) + +######################################################################################## +#FREXT stuff +######################################################################################## + +YUVFormat = 2 # YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) +RGBInput = 0 # 1=RGB input, 0=GBR or YUV input +SeparateColourPlane = 0 # 4:4:4 coding: 0=Common mode, 1=Independent mode +SourceBitDepthLuma = 8 # Source Bit Depth for Luma color component (8...14 bits) +SourceBitDepthChroma = 8 # Source Bit Depth for Chroma color components (8...14 bits) +SourceBitDepthRescale = 0 # Rescale bit depth of source for output (0: Disable 1: Enable) +OutputBitDepthLuma = 8 # Output Bit Depth for Luma color component (8...14 bits) +OutputBitDepthChroma = 8 # Output Bit Depth for Chroma color components (8...14 bits) + +CbQPOffset = 0 # Chroma QP offset for Cb-part (-51..51) +CrQPOffset = 0 # Chroma QP offset for Cr-part (-51..51) +Transform8x8Mode = 1 # (0: only 4x4 transform, 1: allow using 8x8 transform additionally, 2: only 8x8 transform) +ReportFrameStats = 0 # (0:Disable Frame Statistics 1: Enable) +DisplayEncParams = 0 # (0:Disable Display of Encoder Params 1: Enable) +Verbose = 1 # level of display verboseness + # 0: short, 1: normal (default), 2: detailed, 3: detailed/nvb +SkipGlobalStats = 0 # Disable global stat accumulation (Set to 1 to avoid bipred core dump) + +######################################################################################## +#Q-Matrix (FREXT) +######################################################################################## +QmatrixFile = "q_matrix.cfg" + +ScalingMatrixPresentFlag = 0 # Enable Q_Matrix (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag0 = 3 # Intra4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag1 = 3 # Intra4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag2 = 3 # Intra4x4_chromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag3 = 3 # Inter4x4_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag4 = 3 # Inter4x4_ChromaU (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag5 = 3 # Inter4x4_ChromaV (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag6 = 3 # Intra8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag7 = 3 # Inter8x8_Luma (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag8 = 3 # Intra8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag9 = 3 # Inter8x8_ChromaU for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag10 = 3 # Intra8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) +ScalingListPresentFlag11 = 3 # Inter8x8_ChromaV for 4:4:4 (0 Not present, 1 Present in SPS, 2 Present in PPS, 3 Present in both SPS & PPS) + +######################################################################################## +#Rounding Offset control +######################################################################################## + +OffsetMatrixPresentFlag = 1 # Enable Explicit Offset Quantization Matrices (0: disable 1: enable) +QOffsetMatrixFile = "q_offset.cfg" # Explicit Quantization Matrices file + +AdaptiveRounding = 1 # Enable Adaptive Rounding based on JVT-N011 (0: disable, 1: enable) +AdaptRoundingFixed = 1 # Enable Global Adaptive rounding for all qps (0: disable, 1: enable - default/old) +AdaptRndPeriod = 16 # Period in terms of MBs for updating rounding offsets. + # 0 performs update at the picture level. Default is 16. 1 is as in JVT-N011. +AdaptRndChroma = 1 # Enables coefficient rounding adaptation for chroma + +AdaptRndWFactorIRef = 4 # Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndWFactorPRef = 4 # Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndWFactorBRef = 4 # Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndWFactorINRef = 4 # Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndWFactorPNRef = 4 # Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndWFactorBNRef = 4 # Adaptive Rounding Weight for B slices in non reference pictures /4096 + +AdaptRndCrWFactorIRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in reference pictures /4096 +AdaptRndCrWFactorPRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in reference pictures /4096 +AdaptRndCrWFactorBRef = 4 # Chroma Adaptive Rounding Weight for B slices in reference pictures /4096 +AdaptRndCrWFactorINRef = 4 # Chroma Adaptive Rounding Weight for I/SI slices in non reference pictures /4096 +AdaptRndCrWFactorPNRef = 4 # Chroma Adaptive Rounding Weight for P/SP slices in non reference pictures /4096 +AdaptRndCrWFactorBNRef = 4 # Chroma Adaptive Rounding Weight for B slices in non reference pictures /4096 + +################################################################ +# Rate Distortion Optimized Quantization +################################################################ +UseRDOQuant = 0 # Use Rate Distortion Optimized Quantization (0=disable, 1=enable) +RDOQ_DC = 0 # Enable Rate Distortion Optimized Quantization for DC components (0=disable, 1=enable) +RDOQ_CR = 0 # Enable Rate Distortion Optimized Quantization for Chroma components (0=disable, 1=enable) +RDOQ_DC_CR = 0 # Enable Rate Distortion Optimized Quantization for Chroma DC components (0=disable, 1=enable) +RDOQ_QP_Num = 1 # 1-9: Number of QP tested in RDO_Q (I/P/B slice) +RDOQ_CP_Mode = 1 # copy Mode from first QP tested +RDOQ_CP_MV = 1 # copy MV from first QP tested +RDOQ_Fast = 1 # Fast RDOQ decision method for multiple QPs + +######################################################################################## +#Lossless Coding (FREXT) +######################################################################################## + +LosslessCoding = 0 # Enable lossless coding when qpprime_y is zero (0 Disabled, 1 Enabled) + +######################################################################################## +#Fast Motion Estimation Control Parameters +######################################################################################## + +SearchMode = 0 # Motion estimation mode + # -1 = Full Search + # 0 = Fast Full Search (default) + # 1 = UMHexagon Search + # 2 = Simplified UMHexagon Search + # 3 = Enhanced Predictive Zonal Search (EPZS) + +UMHexDSR = 1 # Use Search Range Prediction. Only for UMHexagonS method + # (0:disable, 1:enabled/default) +UMHexScale = 3 # Use Scale_factor for different image sizes. Only for UMHexagonS method + # (0:disable, 3:/default) + # Increasing value can speed up Motion Search. + +EPZSPattern = 2 # Select EPZS primary refinement pattern. + # (0: small diamond, 1: square, 2: extended diamond/default, + # 3: large diamond, 4: SBP Large Diamond, + # 5: PMVFAST ) +EPZSDualRefinement = 3 # Enables secondary refinement pattern. + # (0:disabled, 1: small diamond, 2: square, + # 3: extended diamond/default, 4: large diamond, + # 5: SBP Large Diamond, 6: PMVFAST ) +EPZSFixedPredictors = 2 # Enables Window based predictors + # (0:disabled, 1: P only, 2: P and B/default) +EPZSTemporal = 1 # Enables temporal predictors + # (0: disabled, 1: enabled/default) +EPZSSpatialMem = 1 # Enables spatial memory predictors + # (0: disabled, 1: enabled/default) +EPZSBlockType = 1 # Enables block type Predictors + # (0: disabled, 1: enabled/default) +EPZSMinThresScale = 0 # Scaler for EPZS minimum threshold (0 default). + # Increasing value can speed up encoding. +EPZSMedThresScale = 1 # Scaler for EPZS median threshold (1 default). + # Increasing value can speed up encoding. +EPZSMaxThresScale = 2 # Scaler for EPZS maximum threshold (1 default). + # Increasing value can speed up encoding. +EPZSSubPelME = 1 # EPZS Subpel ME consideration +EPZSSubPelMEBiPred = 1 # EPZS Subpel ME consideration for BiPred partitions +EPZSSubPelThresScale = 2 # EPZS Subpel ME Threshold scaler +EPZSSubPelGrid = 1 # Perform EPZS using a subpixel grid + +######################################################################################## +# SEI Parameters +######################################################################################## + +ToneMappingSEIPresentFlag = 0 # Enable Tone mapping SEI (0 Not present, 1 Present) +ToneMappingFile = "ToneMapping.cfg" + +GenerateSEIMessage = 0 # Generate an SEI Text Message +SEIMessageText = "H.264/AVC Encoder" # Text SEI Message + +UseMVLimits = 0 # Use MV Limits +SetMVXLimit = 512 # Horizontal MV Limit (in integer units) +SetMVYLimit = 512 # Vertical MV Limit (in integer units) + +######################################################################################## +# VUI Parameters +######################################################################################## +# the variables below do not affect encoding and decoding +# (many are dummy variables but others can be useful when supported by the decoder) + +EnableVUISupport = 0 # Enable VUI Parameters + +# display parameters +VUI_aspect_ratio_info_present_flag = 0 +VUI_aspect_ratio_idc = 1 +VUI_sar_width = 0 +VUI_sar_height = 0 +VUI_overscan_info_present_flag = 0 +VUI_overscan_appropriate_flag = 0 +VUI_video_signal_type_present_flag = 0 +VUI_video_format = 5 +VUI_video_full_range_flag = 0 +VUI_colour_description_present_flag = 0 +VUI_colour_primaries = 2 +VUI_transfer_characteristics = 2 +VUI_matrix_coefficients = 2 +VUI_chroma_location_info_present_flag = 0 +VUI_chroma_sample_loc_type_top_field = 0 +VUI_chroma_sample_loc_type_bottom_field = 0 +VUI_timing_info_present_flag = 0 +VUI_num_units_in_tick = 1000 +VUI_time_scale = 60000 +VUI_fixed_frame_rate_flag = 0 + +# nal hrd parameters +VUI_nal_hrd_parameters_present_flag = 0 +VUI_nal_cpb_cnt_minus1 = 0 +VUI_nal_bit_rate_scale = 0 +VUI_nal_cpb_size_scale = 0 +VUI_nal_bit_rate_value_minus1 = 0 +VUI_nal_cpb_size_value_minus1 = 0 +VUI_nal_vbr_cbr_flag = 0 +VUI_nal_initial_cpb_removal_delay_length_minus1 = 23 +VUI_nal_cpb_removal_delay_length_minus1 = 23 +VUI_nal_dpb_output_delay_length_minus1 = 23 +VUI_nal_time_offset_length = 24 + +# vlc hrd parameters +VUI_vcl_hrd_parameters_present_flag = 0 +VUI_vcl_cpb_cnt_minus1 = 0 +VUI_vcl_bit_rate_scale = 0 +VUI_vcl_cpb_size_scale = 0 +VUI_vcl_bit_rate_value_minus1 = 0 +VUI_vcl_cpb_size_value_minus1 = 0 +VUI_vcl_vbr_cbr_flag = 0 +VUI_vcl_initial_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_cpb_removal_delay_length_minus1 = 23 +VUI_vcl_dpb_output_delay_length_minus1 = 23 +VUI_vcl_time_offset_length = 24 +VUI_low_delay_hrd_flag = 0 + +# other parameters (i.e. bitsream restrictions) +VUI_pic_struct_present_flag = 0 +VUI_bitstream_restriction_flag = 0 +VUI_motion_vectors_over_pic_boundaries_flag = 1 +VUI_max_bytes_per_pic_denom = 0 +VUI_max_bits_per_mb_denom = 0 +VUI_log2_max_mv_length_vertical = 16 +VUI_log2_max_mv_length_horizontal = 16 +VUI_num_reorder_frames = 16 +VUI_max_dec_frame_buffering = 16 + diff --git a/bin/explicit_seq.cfg b/bin/explicit_seq.cfg new file mode 100644 index 0000000..8ec728a --- /dev/null +++ b/bin/explicit_seq.cfg @@ -0,0 +1,136 @@ +Sequence { +FrameCount : 19 +Frame +{ +SeqNumber : 0 +SliceType : I +IDRPicture : 1 +Reference : 1 +} +Frame +{ +SeqNumber : 2 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 1 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 4 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 3 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 6 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 5 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 8 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 7 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 10 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 9 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 12 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 11 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 14 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 13 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 16 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 15 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +Frame +{ +SeqNumber : 18 +SliceType : P +IDRPicture : 0 +Reference : 1 +} +Frame +{ +SeqNumber : 17 +SliceType : B +IDRPicture : 0 +Reference : 0 +} +} diff --git a/bin/foreman_part_qcif.yuv b/bin/foreman_part_qcif.yuv new file mode 100644 index 0000000..5c0b70b --- /dev/null +++ b/bin/foreman_part_qcif.yuv @@ -0,0 +1 @@ ++Øþùûþþýûüþþþþþýûþþþþþùîàââáßáâáßàãåß¿›œ¨¾ÖÛÖ×ÛÛÛØ×ÛÝÜÙÝÝÜÞÜÜßßßÛÖÕØÝáÔħ‘“””Œ�…tu†µßÞÝßÞÝÞÔÌÙÙÑÑÑÒÓ×Ô˜o�†}y§ÏÏÏÔÔØÖÔ××ÑÐÔÒËÀ¾Éº�€¢ÖÓÐÖ×ÙÙÕÐÎÏÉÌ®ww§ÈÍÒÐÏÏÈÃÏÉ“r¦ÑÏÊÁººÈÀ�i—ÀÆÖ¾1ÆÁÓäÍÕ¹ÓϺøÆËзØÄÆîкÕíâááâáààâæçÞÁ�’£¸ÉÑÔÕÒÔÙÛÙ×ÚÙÛÝÛÜÜÝÝÝÞßßÜØÔÝàÕÀ¤—““—šŒuv{Œ©ÐÞÝÝÜÜÛÚÛÇ¿ØÒÎÑÐÑÑÈÑΘu…ˆvvªÎÏÒÓ××ÒÓÓÑÎÏÏËÆÌν¬Ž~ªÖÕÔÖØÙÕÑÎÏÉÉÁœvyªÊÑÑÏÎÎÎÌѼ‚}´ÑÍÅÃÀÈÆ¦xn¦ÍÒ¾0±«Å­¹ˆ¿Ãгް±‡Ê°Š»Ë¦´çãááàßáäåÚÁ¢‘—¬ÉØÜÙÕÔÕ×ÙÓÎØÙÔÙÜÛÜÜÝÛÝÙØÙÙÝÛÓºŸ‘�‘——Š{qx”·ÖáãßÜÜÜÜÝÜÛÙÙÙÔÑÒÐÏÐÍÐͼ’t…„ms¤ÊÏÓ×ÖÓÓÔÒÑÐÌÌÏÎÏÂÀ¯„|­×ÓÔÙÙØÔÍÎÎÎÌÌ«z‚·ÎÌÍÍÏÊËÎÓ²w€ÀÓÊÆÄË˵˜os´Ô¼.Öᩱ½Æ Ëб¥­Ä¿œÑË®¡åΡÐçàÝáæàÖ¾¢™¡·ÐÙÙØËÉÖÖØÜÙÍÏÛØÖÛÚÛÛÛÝÖÓ×ÙÝÝͰ–‰‰—�’†{xƒ�ÁÙâáÞÛÜÝÝÜÝÝÛÚÜÚÖÔÓÒÏÑÑÒѸ°Â�o�†stŸÅÌÒÕÕÕÖÒÒÔÍÊÎÌÑȼé~z²ØÔÖØØ×ÐÍÐÐÈÌÒ±}‹¹ÂÉÍÎÆËÐÐÓ¬sŠÇÏÆÇÎп¶£o~ý)¹Ð´ËäâÈÖâáãäáàÒÝâçÚåÝÕßàáæãÔº¥›£½ÕÖÖÕÖÖÃÈÖÖØÚØ×ÙÙØÛÚÖÛÝÚÙÔØáÜˬ�…Š—™‘�tu‰«ÉÜâáÞÛÞÝÝÝÞßàßÞàßÛØÓÍÌÎÑÐÐÑǼÌË”p}…wv ÈÐÓÓÔ×ÖÒÓÏËÉÌÓÉ¿ÃÂ¥~·×ÒÕÕ×ÖÓÑÐÍËÌȨv�´ÅÌÍÍËÏÐÒÕ£k’ÉÏÌÏÒÇ¿À›n�²‚­²×æÝÔÜåãäåãââßâãèáàææååÕ´›™”²ÒÚ×ÔÔÓ×ÙרÖÙ×Ó×ÚÚØÖØØÙÚÙÛÛÜ×ç’……“œ’sw“¶ÑÚÙÝÛÙÍÖ×ÙâäæèéëêëêéèãÝÚØÔÏÐÏÑÉÄÓÏšmzŠ€|£ÌÒÑÖÔÕÕÎÐÐÊÐÖËÃÂÊ˨{·ÖÔÔÖÕÖÒÐÐÍËÆÆœqŽ¿ÌÍÍÊËÎÌÕÑ‘i›ÍÍÎÐǽ¼¶ŒlˆwÂØÓÕÛÞáßÜÛÚÚÚÚÝÜÚÔÜäãàÔ¶Ÿ˜�¨·ÒÛÚ×ÙÙÙÙÙÜ××ÙÙØØÙÚÛÙÙÖ×ÛßßѸ �‹�˜�~{v›¿Øáߨ×ÛÝÕÇÔÔáêëììëìììììíííìêäÜÖÍÏÓÏÍÐÏžq{Œ�{ ÌÒÕÓÒÖÏËÎÐÓÔÍÇÉÉÈÁ x~¸ØÔÕÓÒÔÑÐÍÏÊÈÈ™tŸÌÑÍËÍÍÌÍÔăl£ËÎÏʽº·°Šq~ÛàÙàãããâáàÜÜÝÞÝÝÞâæÝɶž˜¤¸ÈËÖØÕÛÝÛÙÛÙØÙÖØÛÞÛ××ר××ÖÙÜͱ“†ˆ‘–Ž}qp„£ÆÚÝÝÙØÜÝÛÜÜâåèëêëëëëëëëëëêêêëíìëçßÔÒÓÐÊÐÓ§wzŠ�x�ÊÓÒÕ×ÕÅÆÒÎÌËÈÌǼ¹·šu�¾ØÔÔÓÕÒÏÐÍÎÌÍË�s¯ÒÍÌÐÎÌÍÎÓÀ|p²ÑÎËÀû¾³ƒƒ×ßâááááâßÛÝÝÛÜÞâãÛä‘—©ÀÉÌÒ×רÛÝÝÛÙÖÖÓÓ×ÙÛÙÔÕÖÕÖÛÛÓĬ“ƒˆ�–‰uoqŒ±ÅÕáØÐÙÝÞÝØÛâçêìíëêëëìëëëëëìëëëëêëìíìå×ÐÐ˾ÉÓ¶|vˆu—ÆÑÑØÕÍÎÓÑÍÊÊÎÎÇ¿¿¼™x‡ÂÙÓÓÕÓÏÏÍÏÍÉÍÀ‡€¶ËËÏÎÍÎÎÎÖ¶u~½ÒÎÈÈÁ¼¿¡ˆØâßàááàÝÙÝÞÛÜâäÕ»¤•™£µÏÔÎÎÍÓÙÜÝÜÛ×Ô×ÙÓÔÙÛÕÓÕÕÙÛÚÕÀ£�‰‹“›Šzmw’³ÍÞÕÑØØÛÞÞÝÜßåêëëëêëëëììëìììììììëëëììëëíèÚÐμ½È¿¨qr‡~q•ÊÓÕÓÏÔÕÔÓÍÍÎÌÍÉÀÀ¹–r…ÂÖÐÔÖÖÔÒÏÍÌÉ´ÊÍÏÌÌÎÎÐ×­r„ÁÓÎÊ¿½½®ˆØãààáßÝÚÝØÓààÓ¸�‘–¦ÁÎÒÕÏËÎÑ×ÚÜÝÙØØÖÔÔØÖÙÚÕÐÙÝÛζŸ�ŠŽ–“‰yny›¿ÒÔÕÙØØÝßÞÞÝÝâéìëëëëëìëëëëììììììììëëììììììíçØÏÌÉǭ®sr…u–ÉÓÑÈÏÕÓÔÐÍËÊËÉý³�rˆÈ×ÒÖØÙÔÎËÍÎÊͱzƒ·ÊÏÊÈÏÎÒÖÔ£g‹ÊÑÐÈÂÀ«‡ÙáÞÝÞÞÝѵ›ºÒº¤�” ¶ÍÒÑ×ÖÊÍÎÑÕÛÝÞÝÚÙÙÃÅÖÒÓÕØÙÜδœŽŒ’•Œup€ ÂÚßÚÕ×ÜÝÝÕÖÞÞáæêëëëìëëëììëëëëëìëëìëëìëìëìììëëìå×ÐÍÍÅÂÓ«kqˆ~o�¿ÎÉÎÔÔÒÏÍÌÌËÊȽ·±—t�É×ÑÒÖÔÏÍÎÎÎÌɪx‡¶ËÅÄÎÍÒÒÔЖk˜ÌÐÌÇÅ«†Øàâææãα’q•¢“–£µ¼ÇÔÑÐÙÓÌÐÏÑÖÚÛÛÜÚÚÖÍÏÑÑÖÛÔȲ˜�”˜•‡xmtŒ¬ÌÞàÛ×ÙÝÜÜÝÛÑÕàäéëêêëëëëììììëëëëììëëëëëëìììëëëììëëå×ÎÍýÊÑ¥ns†}nнÑÓÕÖÔÏÎÍÎÌÈÈdz¬¶¶švŽÊÖÌÑÓÏÑÎÎÎÎÉÇ©wнÁ¾ËÏÏÒÑÖÏŽj¤ÐÉÈ̱‡Ûçáɾ¹£�™Œ�¥¸ÈÑÏÄÎÒÔÙÐÐÐÓÚÜÚÛÛØÖØÖØÕÔÚ×ħ“�“�šˆto{˜»ÓßáÛ×ÓÙÜÜÛÜÝÙÛãçêëêëëëëëëììëëëììììììëëììììììëëëëëëêéäØÏÈÊÌÏÓ¨qq…‚t‹ÂØÔÖ×ÑÐÐÏÍÉÅÇ¿³µ½ºžv‘ÎÔÏÖÓÑÐÑÎÌÌÈÇ¢s‘º½ÈÎÏÑÒÑØÈƒs´ÏÃdz‹ÒÀ¥Ž†…���Š–²ÉÏÓÖÑÐ×ÊÒÖÏÐÎÖÜÛÛÜÛÙÖÒÖÓÑͺ£’‘”——ˆurƒ¡ÃÚàÝ××ÙÚÙÜÖÒÜÝÝÞäéëëëëìëëëëëìëëëëëììëëëììììììììëëëëëëëèèä×ÎÎÎËÌѬonˆ„o…ÃÖÑÔÓÑÑÏÌËÅÂÉÀ½¾¸¸–u•ÎÖÒÐÑÕÔÑÍÍÌÇÈ�r‡¥ÃÌÎÐÒÓÓÙ¿€½¼¼²}¦‘�š„ov¡¯´ÌÖÕÑÐÑÕÙÔÏÖÒÍÉÏÙÙÚÜÜÖÔר֯®—Š‹”š�~tv�°ÍÜÞÚØ×ÙÞÝÛÚÛÕÓßÞÞåêëêëëìììëëëëëëëëììëëëìëëìëëìëëëëëëëëëëêèèäÕÌÏÍÊÌЯzp„€j‚¾ÓÐÑÑÑÑÌËÉÃÄÁ¿Àº®¨šs”ÎϽËÕÔÔÒÎÎÈÉÊ—i�ºÊÌÏÏÒÒÒÙ¹{ˆ·Ã°m¢¹ÉË¢ju²ØÚÚÖÔÓÔÕ×ÔÑÚÔÍÏÊÓØØÚÚ××ÛÖ锈ˆ’š�uoz�®ÕáßÛØØÜÜÜÕÔÛ×ÖÜÞרåéêêëëëììëìëëëëëëëìììëëììììêëëëëëëëëëëëêêéèéâÔÎÎÏÍËѹ|nƒ€kƒ¼ÔÍÏÑÑÎËÊÉÅÃÁÃÁ¶¯¸�o™ÏÈÊÓÓÕÖÒÎËÆÌÊ’oŸÅÊÍÎÑÑÒÕØ°vŽÅµÌÛßÜÊ­½ÐÏÑÓÖÔÒ×××ÔרÏÍÏÒ×ÖÕÙÜÛÖĨ�†‹’’†vju ÃÔÝàÚÛÓÐÜØÙÛÏÒÜÛÜÜÜ×ÞéêëëëëëëëëëëìëëììëëìììëìëìëëëëëëëëëëëëëëêéççèáÓÎÏÏÌÊм„o„„p�¸ÉÆÐÔÐÌÉÈÅÁÂÄÆÇ¾»®�qŸÐÎÐÔÔÖÕÒÏÊÆÑĆsªÉÌÏÐÑÒÓÕÖ¥r›´ŠÖØØÓÍ×ÙÔÕÖÕÖÑÐÖ×ÖÖØÑËÍÎÓÔ×ÛÜÓÀ§�ˆ�–�yhn„ŸÅÝáßÛÛÝßÕÑÜØ×ÚÙÛÜÝÞÜÝåêêëëëëëëìììëìììëìììëìììììëëëìììëìëëëëëëëëêéèèèèàÑÍÏÏÍÊо{fƒp~­ÆÍÒÒÏËÆÈÿÂÈËŽ°°’q¡ÏÓÔÓÕÕÔÐËÊËμƒ{´ÌÌÐÐÐÔÔÖЙu�†ÔÕÑÐËÎÏÔÖÔרÑÐÖØÓ××ÌËÎÏÕÛÜл¡Œ†Š�‡rej†¯ÑßàÚØÙÛÝÝÝÜÛÛÛÛÜÜÝÞÞÜÞäêëëëëëëëëììììëìëìììììëìììììììëìììììëëëëêëëëêééèéçÝÑÎÎÌÌËÏ»€d{‚p~²ÌËÐÑÏÎÌÆÂÁÁÉʼ¦²½�v¦ÒÔÔÖÕÕÒËËÎÌÏ¿€…¾ÊÍÏÐÒÔÓÔÉ’q‡ÕÔÎÌÃÌÓØÖÔÓÔÒÒØ×ÐÔÔÍÍÐÖØÌ´š�ˆ‰Šƒp]gŒ·ØâÛÔÕÛÞÝÜÛÜÜÚÚÚÚÛÝÜßÖÓÞãèêëëëëëìëëëìëëëëëììììììììììììììììëìëëëëëêëëëêééééèæÛÐÎÍÏÐËÓÉ‹ex‚t{¯ÏËÍÐÐÌÇÂÁ¾ÄÌì³Ç¿‹t¨ÑÒÒÓÓÔÏÍÑÎËи|‹ÂÍÌÐÐÑÒÑÐÇ�‰ÐÒÐËÆÏÖÖÖ×ÓÒÒÕÙÔÔÔÏÏÐÎÆ®•Š‹Œ‰~nhp�»ÚàÜØÖÔÛ×ÒÚÝÜÝÜÛÛÛÛÜÛÛÝÕÒáèéêëêëëëìëëëëëëëëëììëììììëëëìëëìììëëìëëëêëëëëêéèèèèçãÖÏÏÏÐÍÉÔÍ�dv€qy®ÌÌÌÎËÉÄÁÂÄÇË·¸É˱t¬ÓÓÔÔÔÓÍÎÎÍËÒ±|–ÈÎÏÑÑÒÒËͱˆÎÓÐÍÏÔÚÖÔØ×ÓÒØ×ÔÖÖÕÏ»¤’ŠŽ’‹{mfv—½ÙáÜ×ÕÙÛÜÝÖÑÜÝÚÙÛÜÚÚÜÜÛÜÛÝßåèéêëêêêëëëëëëëëëëëëëëëìëìëëëëëëìììëëëëëëëëëëëêéèèéèçæÝÐËÎÏÎÍËÓË–hr€rv§ÍÌÉÊÊÇÃÃÅÃÊÂÂÑË»«‚x³×ÔÕÕÖÓÑÑÏÍÌÒ³|›ÌÎÌÑÓÓÌǵ†ÐÔÎÍÎÖÙÔÖÙÕÒÔÕÖÛÛϹžŽ‰‹�Š{liwœÅÚßÛÖÖ×ÛÛÛÛÜÜÝØÕÚØÚÜÚÛÛÛÜÝÜÝãèèééêêêêêëëëëêëëëëëëëëëììììììëëëììëììëëëëëëëëêêêéééèçåâÕÊÌÍÎÎÎËÐÑ�hs€vw¨ÐÌÇÉÇÈÅÂÄÊÇÈÔÏ¿³¬w³ÓÐÒÔ××ÔÎÍÍÌÒ±{žËÊÎÑÑÎк†ÏÐÌÌÒØÔÒÔÕÑÒÖÛÙзž‰‚Ž–ŒuekªÁÔáÙÔ×ÚÚØÜÜÛÛÛÜÛÖÕÙÙÚÛÛÛÛÜÝÛÜàæèééêêêêêêëëëëëëëìëëëëëììëëëìëììëëëëììëëëëëëëêêêéééèèææåßÑÌÎÎÎÎÌÊÎÍ‹ax�rq¤ÏËÆÇÈÆÇÇÄ¿ÇÐÐË®²¦wxµÓÏÑÕØÖÐÏÒÎÌׯz£ÊÍÍÍÌм…ÍÏËÍ××ÒÓÓÏÔÜÚǬ”„„�•‹{st�²ÉßÚÔ×רÜÜÜÝÜÛÛÚÚÚÚÜÛØ×ÚÛÛØ×ÝÝÜÝãæèééêêêêêêêëëëëêëëëëëëëëëëëëëëëëëëììììëëêëëëëêêêêéèèèèçæäÙÎÏÏÍÌÌÍÉÌÁ•oqylmžÆÆÊÍÈÊËÄ·ÀÐÏÈ»²®§}{½ÓÐÓÖÕÕÖÖÒÎÏמv¨ÍÎÏÍÏ»…ÎÒÍÏÖÒÑÕÙØÖÆªŒ~ƒ�Ž„tlx™ÁÛáߨÖÙÙÚÛÜÜÜÛÚÚÚÛÚÙÚÛÛÛÚÛÛÛÙØÜÝÜßäæçèêêêêêêéêêêëêêêëëëëëëëëëëëëëìëëëìëëëëëëëëëëêêéééèèèèçæäßÑÌÎÌËÌËËÊÑÔ ms}ql“ÃÎÎÈÊÏÎÀÁÓÔʾ¶­º©w�¹ÒÓÒÓÖ×ÖÔÔÐÐÉ”|¯ÎÎÎи…ËÍÎÑÑÒÙÜ×Ĥˆ~†�‡{pl} ÃÛáÛÖØÛÜÛÙÛÜÝ××ÚÙÚÙÛÜÛÛÚÛÛÛÛÙÚÚÚÙØÜâåçèèééééêêêêêêëëêëêêëëëëëëëììëëìëëëëëëëëëëëëëëêêêééèèèèçæåãÖÍÎÍÍÌËÊËÊÏÕ®}v|qj–ÂÌËÍÎÏÇÇÓÑÌľµ´º¦yƒ¾ÖÒÔÕÕ×ÖÔÔÏÍÉ•~²ÍÍÑ·ƒÇÉÍÕÛÛ϶ ‰‡‹ƒrdm‰­ÍßáÝÖÖÚÛÚÜÝÜÜÛÛרÛÚÚÚÚÚÚÚÙÚÚÚÚÙÙØÖרÝäæççèééééééëëêêêëëëêëëêëëëëëììììììììëëëëëëëëëìëëëêêééèèççææäÞÔÏÍÍÌÌËËÌÉÐÙ°qpyqo’½ËËÌÎÊËÓÏÉÆÀ¸±³¹§|ŠÅØÒÕÖ××ÕÕÕÍÎË„¹ÏѶ|·ÉÙÞË«‘ƒ‚…Š‚nbp’¾ÖááÛØÙÜÜÛÛÜÜÝÞÜÚÚÛÜÛÛÛÛÙÙØØÙÚÙÛÚØÚÝàÞÛàäæçèéèéééêêëëëëëëëëëëëëëëëëììììíëìíìììëëëëëëëëëëëêêêééèççæåäâÛÓÎËËËÊÊËËÊÎÒ©uq{zt‘ºËÎÒÐÍÔÔÍżº·¯³º¥{ŽÈÕÔÖ×ÙØØØÔËÊÁŒˆ¼Ò¸k˜Å̰‘„�‹~ml|ŸÆÛáÞØÕÙÜÜÛÜÜÛÜÜÝÜÛÛÛÚØ×ÙØØÛÚÙÙÙØØØÛÞáÞËÃÙâäææççèéééêêëëëëìëëëêëëëëëëëëëëììëììììëëëììëëëëëëêêêêêèéççææåãÝÕÏÊËÊÊËÊÉËÍÒׯys‚{x•ÂÒÑÎÊÒÔÐÊ»¿¼¹¶´¡z‘É×ÓÕÙØÙÖÔÐÊÏ»ƒ�Ƽsžž•†‹�‡{oq�µÐááÚÕ×ÙØÛÛÚÛÜÛÚÚÜÞÛÙÛÛÙØÙÚ×ÖÙÚÙ×ÖÖÛßßÔÁ¨Ž©ÝâäåæççèéééêêêêêêêêëëêêëëëìëëêëìììëëëëëëëìëëëëëëëêêêêêéèéèççæåãßÕÍÍÌÊÉËÌÊËËÍÑÔ±yr�{u“ÂÓÌËÒÓÐÍȼ½¾À¹°µ§�–ÇÔÓÖרÖÓÐÍÊη—¶…¯€Š’ƒni~˜·ÝåáÙÑÖÚÚÛÛÛÚÚÜÝÙÚÝßÞÜÚÛÚÙÚÙØØØ××ÖÙÞÝ×DZ›Žˆ”ÆááäåæçèèéééêêêêêêéêëëëëëëëëìëëëëìëëëëëëìëëììëëëëëëêêêêééèèçææåäâÙÏÍÍÌÅÈÍÉÊÇÅÉËÒ±sl{|u“ÈÒËÑÔÑÊǽ¾ÄÀ²¶É­}˜ÌÖÑÔØ×ÔÐÎËËЭ‹�µˆwql|ŸÈÞãßÙØ×ÔÙÚÚÚÛÚÚÛרÛÜÝÞÜÚÛÚÙÙØ×ÖÕÔÕÜàÞζŸ�Š�œŸ±ØàáäåæçèèéééêêêêêëêêëêëëëëëëëëëììëëëììëììëëìëëëìëëëêêêêéèèççææåäãÞÔÍÍÍÇÈÎÊÉÉÈÌËÌѱwq�zs‘ÃÐÏÔÔÌÊÉÄÃÄô¸ÊÄ—~šÈÕÓרÕÐÐÎÌËЬwv¡zm…¬ÎÛÛÜØÙÜÜÚÚÙÙÛÛÚÙÚÚÕÖÛ×ÙÜØ×ÙÚÚÙÖÔÖÙÜÜÕÈ±Žƒ‰•Ÿ�˜Š®Ýßâäåæçèèéêéêêêêëëëëëêëëëëëëêëììììëëëììììëëëëëëëëëëêêêêêèèèçææåãâà×ÏÎÌËËÍÌËËÊÅÌÏÐÙ¿‚m{si�ÃÒÑÔÑÌËÇÁ½Á»¼Èì’zŸÍÔÓÖÕÒÒÑÎËËΤiˆ�¹ÔÝßÚ×ÙÜÝÝÜÝÜÙÙÛÛÚØÙÛÛÚÛÖØÛÙÙÙÙÖÖÙÜßÙ˸Ÿ’�‰’œ™Ž�zƒÀàßâäæççèèéêêêêêêëëëêëêëëëëëëëëìììëëìììììëëëëëëëëëëëêëêêééèèèçææäããÚÌÍÍÊËÌÊËÈÆÂÌÂ½ÏØÁƒqxqpŒ¾ÓÑÒÑÍÊÅÀ¾¼ÀËÆ°¢Œ|ŸÒÔÓÓÑÑÑÏÍÉ;u¾ÓÞÞØÖÚÜÛÝÝÛÜÜØÚÚÚÛØØÚÛÚÚÛÛÚÚÚÙ××ÛßÜÑ»¢‘Œ‘™›–Œ„}xw|®ÚÜàâäåæççéêêêêêêéêëëëêêëëëëëììëëììëëìììììììëëëëììëëëëëêêêéèèèçççåäãÞÐÅÈÉÊÌËÌÁÅÍË»¬ÈÌׄpyuk„¼ÒɽÉÐÉÅ¿ÄÊÍ· ž‹u¥ÔÔÑÐÏÑÑÎÍ͸†ÜßÔÕÙÙÙÛÚÜÝÜÛÚØÚÛÛÚØÚÚÚÚÚÚÚÙרÛàÝÒë•‹Ž™ž™�„yuvtsuˆÂÜÜàâäååæçèééêêëëêêëëëëêëëëëëëëëëììëìììëëëìëëëëëìëëëëëëëêéééèèèèçæåãáØÈÇÊÌÌÌÎÊÊÌÊÊÆÊËÍׯ�pvxi‚»Ç®ÂÒÉÄÇËËÌÑÁ­¥©ˆn¦ÒÒÐÒÐÑÏÍÍ·†ÓÙÖØÙÙÚÝÝÜÜÙÙÚÛÛÚÛÛØÙÙÙÙÙÖÖ×ÛÝÙÊ²šŠŠ’œ¡�Šzuusps{Œ¢ÀÑØÞàâäääæçèéêêëëëêêêêêêëëëìëëëëëëëììììììëëëëëìëëëëëëëëëëêééééèèçççåäãÜÐÊËÏÊÃÊÍÍÌÌÍÏËÊÌÏÖÌ—qzuk‚³ÈÊÎÌÄÆÌÏÏÐȶ¦««…q£ÑÐÐÓÕÒÏи…ÔÙ×ÙÚÛÜÜÝÝÛÓÖÛÚØØÙØØÙØØ×Ô×ßßÖ¿¥�„Ž™Ÿœ�…{vuuuvƒœºÑÞÞÖÚÞáããååæçéêëëêêëëêëêëëëëëëëììëìììììëëììëëëìëëëëëëëëëëëëëêêêéèèèççæåäßÑÈËÎÍÈÇÆÍÍËËËËÊÍÍÈÒÑ•pzvmªÆÍÍÈÆÄÌÑÏʺ¬­«¤…o¨ÕÑÒÕÒÐÔ»†ÕÚÚÚÚÜÜÚÛÝÜØØÚØÖ××Õ××Õ×ÛÜÛ̵žŽ‹“œŸ˜‹ƒ~zssu‚™°ÉÚßßÝÒÐÜßáãäåæçèêêêëëêëëëëëëêêëëëëëëëìììëëìëëëëëëëëêêêêêëëëêêëêêêêéèèèèçææåâÖËÌÎÏÎÌÊÍÎÌÈÊËÈÍÏÌÌÔÏšsuxszªËÉÅÅÀÈÑÑËÁÀ½­¤ª‰r§ÌÏÑÓÑÖ¿‡ÖÝÙÙÛÜÜÙÚÛÛÜÙÙØØØÓÓ×ÙÜÝÔĬ�…�œ¡œ’„~~|xv{Œ©¾ÔãÜÙØ×Ù×ÕÜßàâääæçèéêêëëêëêêêêêêêëêêëëëëëëëëëìëêêêêëëëêêêéêëëëëêëëëëêééèéèçææäâÙËÈËËËÎÎÎÌÌÌËÆÁÉÍÎÐÍÔÑžqu}vƒ¯Ç¼ÁÈÉÐÒÌÃÇÀ³°²°‡o¥ÐÒÒÒÕ¼†ÕÛרÙÙÚÛÛÛÚÙÙÙØ×ÕÓÙÞÙ̹¥•’”�¢™‹{zyz�Šž¼ÔáÕÒÙÐÔÛÚÙÖØÜÞàâäååçèêêêêëêééêêêëëëëììííììëìììíììíííííííîíííìììëìëëëêëëëêêêêêêéèæàÒËÍÌÊËËÌÌÍÏÍÆÂÈÌÍÐÎÍÓÒ¡qszs|¬¹½ÌÊÌÑËþ½»µ´¸º‘|±ÖÒÑÖ»†ÔÚØÙÚÙÚÚÚÚÙ×ÖÕÖÙØ×Ò«—’˜¡£œ’†}yxvx‚š¼ÐÚàßÙÔÕÕ×ÛÛÛÚÔ×ÝßàâäæææéêêééêëììëëéèæäáßÝÜÜÜÜÜÜÛÚÚÙÙØØÙÙÙÙØÖÕÓÒÐÎÍËÌÌËÊÉÉÉÉÊÌÏÑÔÕ×ÚÚÛÚØÚÙÖÖÓÏÎÎÍÎÌÅÄÈËÎÐÑÎÒÔšiszkxš·ÈËÎÎÎÆ¿Âº¾Áƽ‰|´ÕÑÔ»†ÓÙ×ÚÝÝÛÙÙÙÕÔÙÝÞØÃ¬š””›¤£™‰~|wswŠ¥ÁÖàÞÛÙ××ÚÛÚÛÛÚÛÛÕØÝßáãäåæçééêëììëèãÝØÑËÆÁ¿½¼¼¼º¸´¯¬«ª¥Ÿ™—˜—™››™—“���’”•˜›œžŸ £¥¥§¨ª®±³¶¸½ÀÃÈÌÑÕ×ÖÑÍÌÌÉÅÆÊËÎÐÏÍÓÏ¢utwir¥ÈÍÑÑÐÈÀÂÀ¿ÄÂÂÄ®w±ÓÓº…ÓÙÙÙÛÛÙÖØÙÚÝÛп§‘ˆ‹š£ •‡{ywyy…®ÏÞàÜØÒÖÜÚÚÛÚÛÛÜÚÚÚÖÚÞßáâäåæçéììéäÝÓÊÁºµ²¯¬©§¥£ž™“އ„|{vrppoopvxxtmkkmqux{…‰�’—œ¡¥§§¨§¦¨ª«ªª­±µºÀËÒÐÌÊËÊÈÌÍÌÍÍÏÍÏÌ¡lo{ky°ÐÍÑÐȿÿ»ÅÂÄÈ¿¨}xºØ¼„ÔÝÚØÕÖ×ÙÞÜÒÁ«œ�‰�˜›”�†~vsw~‹ ¯¿ÞßÚ×ÔØÙÚÛÙÛÛÙÙÜÛÙØÙÖÛÞàáãäæèééäÛÑÆ½·´²³³°¬¥�”Œ…zwsppojhihhhjkntvuoe_]adfjmruy}�„…‰’�©¯±±¯±±°°¯®¯¯°´ÂÍÎÌÊÉÈÌÍÌÌÍÎÎʶágrui{²ÐÏÍÈÆÇüÈÈÊËÄ¿¯‚�¾¿…Ó×Õ×ÛÝÜÓÅ´¡––š—’�މ�ywuvŠ¥·ÑÛÙÙÙרÙÑ×ÜÚÙÚÜÛÚØÌÐÛ×Ö×ÜÞßáãåèèâ×Ê¿¹¸¸¹¹µ¯¦œ’ˆ€ytrpmlkjkigc_\[[[\bhijd[Z[[Z[[`ehnqux{zxz…•¢®²±±³µ¶µ´´·´·ÆÍÍÍËÉËÍÌÍËÊÎÐÃÉÖ dlzmz°ÍÍÆÅÉÇÃÆÅÊÍÈþ°€…©†ÔרÞÙɲ ••˜žž”‹†�{uu€…’´ÐßààÛØÔ×ÚÙÚÚÛÛÙØÛÚÚÛ×ÌÓÜÚÖÙÜßàáäçâÖÇ¿½½½»¶¬¢˜�‡ƒ~wqlkhfdcb^[WTQOPSSOMSXWVSOONLMRUWUX^diouy{vx�„�£±µµ·¹¸¸¸º¸¸ÆÎÍÍÌÊËÎÍÍËËÏÏÏÌÑÕ empv¨ÎÈÀÇÆÃÇÁ¿ÈË÷¹«yy†ÔÓÉ»§™‘“™œ•�„|yxz~‡Ÿ¿ËÓâßÙÙÕ×Ù×ÙÛÛÜÝÜÛÛÜØÓÙÚÛÜÛÛÜ×ÙÞßáåäÙÊ¿½¿¾¸®¡•Œ†ƒ�}ypg^WRSX]ZTSWWVWZ^`^^a`][ZWND@BMX[WSPT\bhmsv~‰†�‚•®µ¸º¹º»¼¸¹ÇÌËÊËËÌÍÎÍÌÍÏÌÌÏÏÒÖ¤eq~ms¦ÉÃÁ¿ÀÍÈ¿ÇÌȹµ¶—s­ž™–—››•Œ†zwv|‰�¸ÎßãâÞ×Õ×רÚÚÙÚÜÛÛÚÛÜÛÜÚØÚÜÜÛÚÛÛØÚßáäßÎÁÀÀ¹«œ”Žˆ„ƒ‚€|xsoid]WVZaffglorsqpnmljihfedb]WTU^gigbUKKR\chms{„ˆ‚{�«µ¹»º»½¹»ÇËËËÌËÌÍÍÎÎÍÍËÍÑÓÏÑÙ©ko|ns©Ç½¹½ËÐÉÍÍËÁ½º¦•rŽˆ—œ˜Š�}zxvwƒ˜±ÆÕßáÝÚØÙ×ÕÚØÛÜÜÖ×ÙÛÙ×ÛÛÚÛÜÜÛÚÚÚÚÚØØÞâà×Ǿ¿¸¥�„�ƒ„„…‚~yrmjjjmpqtwywtuutvxyxwtrolmnljgeccfjjmlmhYHEKU`fkns}†|t’®³¹ºº»·ÁÌÈÊËÊËÌÍÌÍÍÌÍÍÎÐÒÒÏÒÙªorƒux­Å¼½ÈËÌÑÎÌÆÀÁ«žsž�‰‚{yyus~•ª¾ÖÞÝÝÙÍÓÝÛÚÛÛÛÛÜÜÜÛØ×ÜÛ×ÙÚÖÙÛÙÛÕÓÚÙÚÛÜÞÙÎÄ¿¶£�€„‡‡…‚zunjikosvy{}~}|zvuwxxxwwxwsqrpnmkijnnmnnool^QJMV_goqsvwr}¡¯³¸¹¸²£·ÌÇÈËËÎÌÌÍÆÉÎÌÍÑÑÑÑÏÎШsz‡v}©´¸ÉÇÈÑÑÑÌÃöŸs–�xutwy„š»×ßàÜ×רÛÖØÜÜÖÙÞÜÛÛÛÛÜÛØÕÛÚ×ÚרÜÚÙÙ×ÚÜÞÜØÑÉŽ¥‡{~‚†ˆ‡ƒ€zuqlimpruwyz{}||||{ywwxyyvuwxvsppqrompssttttqojcZSSYajqsstvx“¬¯²¶¸ª|²ÊÉÉÉÎÍÌÎËËÎÍÉÎÒÒÐÑÌÇ̬xtƒsvФÄÊÊÎÒÓÐÉÈ»§i�uvyzЦÄÜÜ×ÚÙ×ÙÛÚÛÞÜÛÛÚÚÜÜÚÙÛÚÛÜÙÕØÖØÛÜÛ×ÑÙÜÛÜÛÕÐÌË̹”wq~‡†„„�|wrnllptttvxzzyxuqpopqprtwyvstuurqqrpnnpqqqpnpqpmid\Z\aflsuvxx�§®°µµ™|o{¯ËÇÇËËËÍÍÌÎÍÉËÐÑÎÏÏÌËÕ²us|uu”ÀÇÌÏÑÑÏÌ̽ª^x�•©»ÏÜÞÜÏÍÚÚÚÚÙÙÚÚÜÛÛÜÛÛÛÛØÙÛÛÚÛܨרÙÛÛ×ÐÒ×ÖÒÍËÌÏϳƒot|„‡„�}xtqommruuvwxwusmd_^`begjmpsuvttsrrrrqqsqnmjgdcdhlmmjfa^aeiqsvz{�¥±¶µ˜‚{qz«ÌÉÆÉËÊÆÄÍÍÎÌÍÏÍÍÍÏÏÐØ¸}q�y|¦ÅÊÎÐÐÏËÌÆ°j¦ÈÛÞáßÙÕÖÙÚÛÚÙÙÙÛÛÙÜÛÛÚÚÚÛÜÛÚÚÚÚÙÔØÙØÚÙÙÙØÐÕÐÉÌÑÒήyiv||‚‡�|vrqppqstsuxvqjdc\VTV\_`bejmmqsrsrrstuuuuqkgc^YVTX_eikkhaaejmsy~ƒ‘¤²µ¼šn{ƒrx§ÊÊÉÊÊÈÅÉËÌÍÌÎÎÎÍÏÐÍÏØ¹zlyuu¤ÈÎÑÑÎÉÌ̵ˆÜÚÖÛØÖÙÚÚÛÛÙØÙÙÛÜÜÛÚÚÛÛÜÛÚÚÙÙÙØÚØÓ×ÙÙÙÙ×רØÖÎÐÒÒÌ­�ks}}|€ƒ�xnopprvuqqqng_XTPNPSUY^aachlknpprsstvxwusmhfb\WOJIKS]eijgcbfpy�„�—¤¯·ÈÄ—s{�znrŸÇËÈÈÌÌÉÉÊÍÌÌÎÍÎÐÎÍÍÍ×¹xk�tr¤ÎÐÐÐÇÊÏ´ŠÙÆÄÙØÚÚÚÚÙÚÙÙÙÙÛÜÜÛ×ÙÛ××ÚÙÙØÙÙØÕ×ÙÖרÔÖÙרØÔÏÒÓͳ�€xx}~~}€…}qllquvsqngbZSQOKOTWXZ^bcehlmnoqrrssuwxvrkhfb[VRLFCFNW^che`iyˆ‹’ ¬³ÃÎËÌ¥ro}|po”ÁËÆÊÊÈÉÉÊÌÊÌÊÍÏÌÍÎÌÎØ»|r�px«ÌÏÒÉÇε…ÓÒÒÙØÙÚÚÚÙÚÚ×ÕØØÙÛÚÚÛÜÖÔÙØ×ØØ×ÖÒÖØÖ××Ö×ÔÒ×ÖÑÎÒнž�‰{y~xy��sjpvxwqkd_][]bddcefdcddffhkmnprrqrrsvxvqkgdc^ZWNGFEEHQ]eigty|Œ’�«´¿ÌÎÎÓÓ¡su�€tm�»ÈÆÇÈÊËËËËËËÎÐÍÌÍÌÍÏÕ½€q€{{«ÍËÉËϹ…ÓÛÙÙÙØÚÚÙÙÙÚÓÒ×ÓÖÛÙÚÜØÖØ×ÓÓØØÖ××רÖÔ×ÚÚÓÓ×ÖÏÎÓÈ­˜Ž‡yw€}xqntsjnuwyumdabhmsuvyvtrppmkklmmmopssqqrrttsojgffb]ZVSRPNORW^hillz”£¯µÀÊËÑÑÏÐϸ‡u€vl„²ÈÇÈËÍÌËÌÌÊÍÏÎÌÎÌÌÏËÑ»~o†}~­ËÉÌѺ‡ÔÚ×ÙÙÙÙÙÖØÙØØØÙÙÙÙÙÙÙÕÔÙØÔÕÙÙ×ØÙØØÕÒØÚ×ÖÖÕÕÎÎϽ¤‘Œ‰xwxqlihcltvwxqkkpuz}|xx{ywutttrqrsrqrsutrrqrrqqnkiiheeggddfggfa_ceck‰¨±¹ÄÍÎÉËÌÏÒÓØ»�st€ym€±ËÊÊÀ·ÉÊËÊÌÍÎÌÍÊÌÑÌÈϸqƒ{€¬ÉÊι‡ÕØ×ÙØÚÙØÙÙ×ÖÙÚÙÚÙÖØØØØ×ØÙÚÙ×רÙÙØØØ××ÔÒÔרØÏÌ˸Ÿ‰ŒŠxz|rkfe]druwxuqrw~}{xxxvsrsrrsttssrstutqooqqppoljiiiklkjloooqspiii|¦¶»ÅÎÎÏŪÄÑÎÎÐÒÍ›sx‚}oy¨ÇȺ¶ÅÈÊËÌÍÍÌÌÉÌÏÎËËϾ‰o{y¡Äʶ†ÕÚ××ØØØÙÙÙÖØ××ÙØÙÙÙרØÖÓØÙØ×ÕÖÔÖØÖÕÓÕØÛÝ×˺©ÀÍ»£��ˆz{xnebZTiswyxuxz~€|zyvuutpmmnoqrssttttttqoooppnomjikkjhhiklmnquxwrwš¹ÂÌÐÎÎÐ̺ÊÔÍÏÑÒØÓ¤rqƒ|ls¡ÈÃÃÇÅÆËÊÌÍÌÍÎÍÊÇÇËÉÎÉ”s}w�È·†ÕÛ××ØØØØØÚÚØØÙ×Ö××ÙØØØÖÔØ××××ÖÒÒÕÖÙÜÚÔÊ»ª™Œ…¨È½¬šŽ…�}sh`]OXnvxyxx|}�~wuusrpnjebcfkmqsttttvvtqooppponkjkjfbaeiklorsw|z�¸ÉÎÐÐÌÌÐÓÕËÈÎÒÑÐÐÒͨwp‚}lr ÃÄÆÄÅÊÊÊÌÍÍÍÌÊÈÉËËÆÔÑ•oƒ�z¡´†ÔØÖÔÕØØØÙ×ÖØÙÙ×ÖÓÒØØØÖØÙØØÖÔÔÕÙÚÚÕÎŰŸ‘‰ŠŒ�‘›½Æµ¡�‡ˆ�pd]ULarxyzz{}~~yuspkgdb_\[YY^cilpqtuuvtrppqqqolige`YV[bhjloqqty}”ÂÏÌÎÑÍÍÎÐÎÄÂÊÑÑÏÐÐÑÖ¸|k|}no”¾ÇÁÇÊÉÉËÌÌÌÌÌÏÍËËÇÊÕÊ’o�ƒyއÏÒÕÑÑØÙÖÌÒÖÙÕÖÚØ××ÖÖ×ÕÖÖÔÖØØÚÚÖÍ»§™�…‡‹�”™™”‘˜·Â¯š�Œƒnc\PQdsy{zz~€}xtqkfcbcb^[XVUUX^cinqtvvvusrrqqkeb^WOLQVXYZ`ejlpw}’½ÊÉËÏÑÐÏÏÐÎÈÈÏÐÎÏÒÐÏØÂ†n€rj�»ÃÃÉÈÉÌÌËÌÍÊÊËÌÍÊËÏÒË–q�…u…ÑÖÖÖÖ×ÙÕÍÕØÙØÙÚרØÖÖÕ×ÚØØÛÚÓÆµ¢“‰‡Š�”™˜•�‡�ytn{£¹´¥•…pc[OTcsz||}€~zuogadhiijd^YUSSQTZ_diouxxwwwusnb\XOHHMSTURLJS^flu|•¾ÌÎÂÆÐÐÏÎÑÒÍÍÐÑÏÑÑÎÎÏÙÌ“t�qj‡µÅÇÉÈÌÍÌÍÍÊÉÊÊÏÎÍÑÍÐÎ�q~„…ÔÙרØ×ÙÙÚÕÖÚÛÙØ×ÕÓÓÖÚÝÔÏÌÁ¯ž�ˆ‰‰�•‹ŒŠ€yvrkggeeak�¬¸±�ŠvYKTcr{~�€€|uoe`cgiiigc^YQMOOOSX]bipwzzzzzwhXSKCDHNSW[]XOMT`hpz—ÁÉÉÇÉÎÊÍÏÏÐÑÐÐÐÐÏÏÌÏÐÎ×Кqu}ui~°ÆÆÉÊÌÌÌËÉËÊÈÌÌÍÏÎËÏΟov‡Ó×רÙÙÚÚÙÖÖÙ×ÓÓÕØÖ×ÖϽ¦¤Ÿ“‹‹�”™’Žƒwtnhigffghijljiv�£¤”uTLVcq}€�‚€~yrh`bedbcb`^ZTMFGLORW[aflu{||{|yeSJB@?CJQX]bc^SNXemx�ÄžÍÍÉËËÏÏÎÐÑÏÎÏÎÎÍÐÒÐÎÔÑ›nq|vi|ªÄÉÈÌÌËËÈÉÉËÌÈËÏÌÌÏÐÑ¥o‡ÕÙÖÕÖØÙÙØÔÑÕ×ÙÛÛØÉ¸®ŸŒ�ˆŒ“˜™—�‚wsmmjjlomjjllnnmqojlrzp[QNYao~‚ƒ‚|wodbdabcbcc`[UMHEHRXZ^agmtz}}~{iSGA>=ACBBCDEGNY][^iorw{ƒƒƒƒ|jYQHA??@@>>CDDLZcn…³ÇÈËÊÈÈËʾÆÎÍÐÎÎÏÐÐÎÎÎÑÐÍÑÕÑÎÔÍ�su}vo�ºÉÉÈËÌÍÊËÍÎÎÍÐÑÎѽ‡ÒÙÙÑIJŸ�‹�’˜Ÿ¡£’|x{{qkkgeimnonnnnnmmnqpopoorssqoopomkbUIKQVmƒ††„}vqmkie]TQTUVYYVRRRUVW[empty~�ƒ…†…‚ubSNLHFIOQUZ`e^]gq†±ÅÆÉÊÊÈÉËÅËÏÏÏÎÎÏÑÐÏÏÍÌÍÑÒÔÒÐÎÓÔ§qp{un†²ÇÇÊÍËÊÍÏÏÎÏÐÐÉν…ƹ¥•Œ‰�“› ¢›—Š{pfoqkgihkmnnonlllklmnopppqrqpqqooponq|hSJQWn†‰ˆ…€xvvvtqoljhhgd`[VVWY[`hmpty}€�ƒ‡‰‰†}obXTPLKOW^bgoqlpw„œ¹ÇÆÈËÊÉÈÎÏÑÏÏÑÎÎÐËÏÐÎÌÈÏÑÔÑÑÓÑÔÖ¬xlyun€«ÅÇÊÉËÌÍÏÐÏÑÏËλp”‰‰Ž˜¡¡ž•Šuonp{zk_]cedffdhlkjjjjknnmnnopqooponnonnwzxubSTXp‡‰‰ˆ…€~~}zyusolifb^[[[]bgnsuwz}€�ƒ†Š�‹ˆ�xqlb]ZUQRW\dkpuy~‡�‰·ËÈÆÉÊÊÍÎÎÍÇÄÌÏÌÊÑÐÐÎÏÎÐÓÓÒÑÓÓÕÚ»�mxwmz¤ÂÄÇÌËÊÎÐÐÐÐÐлnš�£¦ “�umkp|ˆž¼¿´¦„\RX]][\`cfhijikklmmonpqpppnnklmpwihsrhZXu‰‰ˆŠˆ…„‚�}}yrokfedbcdfimsxyz|€�€„ˆŒ��‹…~utpieb`\[\clqw~‚Šƒi|¯ËÊÆÈÌÌÌËÌŽÌÐÍÎÑÐÌÌÐÎÏÒÓÒÒÓÉÊÒØÃ‹nvwnx¢¿ÄÆÊÌÌÏÐÎÎÎѺx¦˜ˆ}uopx‡—­½ÄÔÚÇÆØÐ¡dKKORUY[^adffggijjkmnmmmmopnlkqshgmwte^z‹‹‹‹ˆ††…‚€~zvtqnnnoonqsvy{{{~���€‚ˆ�“”�‰�yuurnkkkkklpvz„ŠŠqcn—ÄÍÅÈÉÊÍÍÍÏÍÇÎÎÎÏÊÍÏÌÏÓÒÑÑÏ¿ÃÐÑÚɉlvxoy¢ÀÄÇËÌÍÏÏÎÏÓºezmnt†—¬ÀÍÔÔÏÈÐÍÀÂÐÖÓ­qK?CJORSVZ^`bcdehjllijkjlnpomsriioxwpn‚Œ‹ŒŒ‹‰ˆ‡…ƒ�}|zxwvvwwwxyz|}}~‚ƒ‚�‚…Š�’”�Š„yvvutrqqqrvy}€„‰Œ|p^]‡ºËÈÆËÌÍÍÐÌÇÍÎÐÎÌÏÎÌÌÑÐÐÎÌÍÏÐÔÒÙÊ�krvpw—»ÅÅÊÍÎÏÏÏѽ`„”«¿Ï×ÜÝÚØÔÍÌÓÐÁÁÄÀÆÍ±yQ?;AGJLQTV[]_behjijkjjkjlonssihs{tsyˆŠŠ�Ž�ŒŠˆˆ‡†…ƒ€|{|||{|~~€‚„„ƒ‚ƒ‡‰�›¡™Ž†€{wwvvxwvwwz}‚„…‹Švrrhc{«ÆÆÇÍÌÊÍÎËÉÎÑÏÌÏÐÏËÍÑÐÎÐÏÎÏÒÑÑÚÏ–mq|sq�¯ÀÃÉÌÏÐÍλyÈÚÝßßÜÙÕÖÖÖÔÖ×Ƚ¿ÂÀ¼½¿®ŒbE47@DHLOSUZ]`befghhhihilkpsiiv|x{~‰Š‰��Ž�Œ‹‹‹‹Š‡„„‚�‚�€~~€€€€‚ƒƒ„ƒ„‡‰�žµ»°Ÿ�‚|ywwuwz{}}}�…†‡�ŒmbpwpanšÁÌÉÊÊÊËËÉÌÍÏÇÄÏÐÎÎÏÎÏÐÎÍÏÏÏÓÏØÕ£rr|qp‹«ÀÆÇËÐÏй‚×Ý×Õ×ÖØÙ××ÖÓØÏÃÂÂÀ¾»½º»±ŽnO947>DIKMQUZ^acbceeefgihmthjx‚ƒ}}Š‹‰Ž���‘‘��Ž‹‰‰ˆ†…ƒƒ‚‚���€�ƒ�€€‚…‹’¢µÂû­š‡}ywwuvz{}�‚„‡ˆ‰Ž�oWYgvugiŒºÉÆÇÈÈËÌÌÌÎÉÆÎÏÎÑÎËÏÐÏÐÐÐÒÔÑÏÖØ¬tjuuv‰ªÂÅÃËÐÑ»…ÎÒ×ÚØÖÖÔÕ×ÓÓÒÀ»¼½ºÂ¼µºµ´©‰r[D427>CEINUXZ]__accdfffjtjiz†ƒin‰‹‹Ž��‘““’���ŒŒŒŠŠ‡…„……„ƒƒƒ�~~€‚ƒŒž®»ÁÀº°¤Ž~wttvyzz}�„…ˆ‹‹ŽŽpXQTetwmbx©ÆÈÆÉÉÊÍÎÌÌÏÎÎÎÐÐÍÎÑÐÑÏÏÒÓÔÓÐÓ×µ„ntxt|¦ÆÄÈÍÑ»…ÓÙרÔÒÓÍÔÓÏÕÏ¿º»»ºÀ·­ºº¸·Ÿ€paP<106=AGLOQVZ[]`abcbcdsni|‚uYb…‹‹Ž‘‘‘’““‘�������‹‡††…„„‚�~€�‚ˆ—¥¬´»½¸¯¥“€vqptz{|�…‡‰Š‹�ŽrZVRT\n{p^kšÂËÇÆÉÌÍËÊÍÍÎÍÍÐÐÍÍÏÑÐÏÐÓÔÓÓÏÑ×È“kqunw�»ÀÅͺ�ÕÞÙ×ÎÒÖÔÓÒÔ×ɼÁÁÀ¾²·¾¼¾º·«�}tk[F5/27=BFJOSVX[]^^^a`mpl}|jWg…ŠŠŽ’“”””•“‘‘’‘�ދЉ†…„‚‚€}}��…“¡¤©±¶·±ª¢•…xomptw|€�…ˆ‰Š‹�ŽpXYZYX]kvufd†¶ÉÆÄÉËÌÌËÌÏÐÑÏËËÍÍÎÍÎÐÒÒÑÑÑÐÏÔÍ›nlujiаÄǹ…ÕÚØØÔרÖÑÒÖÔó½ÁÂýµ¸¼¼»·®£‹vl`Q@4/18>BFKOSVXYYZ\_clo{xcZv‰ˆ‹�““•–”’““““‘��Šˆ‡„ƒ‚€€~z}„…„Œ™žž¤¬°¯ª¦¡˜�‚tlkmqw|€ƒ†‰Œ‹�Œr`cea\\\bqxi^v§ÇÈÆËÌÌÈÌÏÍÏÏÉÊÎÎÎÉÍÑÑÑÐÏÎÐÐÎÒѦokxol‘·Çµ†ÕÜ××ÖÖÕÖÖÖÙО¾Á¿²²»º¹¹¶³š�|smeXJ:0/28>CFKORTVWY^[dqzvba~‰ˆ��‘“““’‘“”‘‘‘�ŽŠ‡…‚‚€}zz€†††Œ“–𠦧§¦¤ š“Œ|mihmsy€ƒ„†Š‰‹Šviifd_\[[^kwpcm–¿ËÊÊËÉÅËÆÅÌÈÈËÎÏÎÏÐÑÑÒÑÏÐÑÐÌÏѰxkyrm…¶·…ÔÚ×ÖÔÖÖÖ×ÛͽÄÇÅù»º¶·º¸¸º¹ªŒzvqi\NC8/-39>AFJNQUXZYaqyvcd~†‡Œ�‘’“’’””“‘��Ž‹ˆ‡…�€}}zux}€‚„†‡ˆ�™¢¢ ¡ ›”އ|mgehpx}‚ƒ‚†‡Š‹tfgd`]ZZ^[]gtvic�±ËÈÇÈÁÇÌÍÈÇÍËÌÍÎÐÏÐÏÐÒÏÏÏÎÏÍÎ׸{juolƒŸ…ÏÔÖÖרØÖÙÕ¼·ÅÄÅÃÄÿ¿ºµ¸»»½¸±Ÿ…~yvph`VL?4-.3:>CFJQWWX_nyxji{…‡‹��‘“‘‘’’‘Ž�ŽŒ‰†…‚}}zvqorrhenx{~ˆ•˜”“’ކxoqmgdfnv{~�ƒ…†‹Špbdd`^]\][XYerulau¦ÄÆÆÈÉÎÏÊÏÌÉÊËËÌÎÏÎÎÏÏÍÍÍÏÑÑÏÕ¾ƒmsuju…Ó×ÕØÚÙÚÙÜÐÃÈÈÅÄÅÄÄÀÀÁ»·¼¾¿¹´°”‚}xsojc^SG:0,/5;?DJQXXZhx}}~w‡‰Ž‘‘’�����‹ŒŒŠˆ‡„€|{zyvngfcVJLXju{�„ƒ‚‚l[anqlgekt{~€�ƒ†‹†j`ddcb_]\[Y[]`gtufi’»ËÈÇÊÌÌÎÊÇÉÊÊÌÍÎÎÐÏÏÎÎÌËÐÑÐÎÖÆ•pqsj†ÓÚØÚÜÛÛÜÛÓÍÌÉÆÄÅÃÁÁ¿µ²»¿º¶µ¦‰�}xtokgbYJ@:1,06=BFOUWaty…‹zvƒ‡��‘�ŽŽŽŒ‹‹Š‰‰‰‡ƒ~ywxxxtlb]ZWPLRapuvuuvnXWfqwvojkry|~�„Š„h`cca^^``_]\ZX[guvid¯ÊÈÆÌÌËÌÊÄËÏÍÌÌÎÑÐÏÎÎÍÊËÍÏÐÏØÒ¡rot†ÓÛÛÛÜÜÝÝÙÍÊÊÊÊÈÆÇÇÆÆÅú­µ¿»´²°•‚�|yuoedcZRJA6-,184.-3:?DM^u|‹‹‡€ƒ�‘��‹‰ˆˆ‡„ƒ„ƒƒ�~|||~~~{vpkhhllkmmllicfmquz}€|wtwyz|~ƒŠyecb`fg_]][^`_[XXWYjytce�ºÈÈÇËÉð¼ÍËÉÊÍÎÐÏÌÍÎÍÍÐÐÏÑÏÕÕ°{‡×ÞÜÝÝÝÛÛÔÊËÍÏÍÍÎÌÈȼÀÃÁ½º¸´¸´´¡‡‚zutsnhddd^UME<30/4@PVs‡ˆ…~|�‹��‹Š‰ˆ‡†ƒ‚‚€�€€‚‚�€}|zxtpnmmkhfffdgmtx}€��‚€}{wvvx{�‡raaaacc_^ZY_`ba^ZWVYdprg_{«ÆÇÆÄÄÄÆÈÉÇÈÍÐÒÏÍÎËÌÍÏÐÍÏÑÏÒØ´‡ØßÝÝÜÜÝÛÏÉÊÊÍÍÉÈÌÊÈÇÅÄÅ¿»¹¹¶º·³®•…�|vsokihe`XWSKB:21>LPb‡‰ƒ€ƒ‚ˆ�Œ‹ŠŠ‰‡†„‚�€‚ƒ‚„…„‚‚�€€~}zxsnkhebbcgnuz~�ƒƒƒ„ƒ��|vtuz�…l^_bcb`]\\^_^ab`\YX[[^jvnbošÀÇÅÇÍËÄÃÄÇÍÏÑÏÎÏÎÌÍÏÏÏÑÒÑÑÓÁ‡×àÝÜÜÝÞÖÊËÍÌÊËÆÅÇÊÅÂÈÇÅÄþ»¸¶¶µ¶¨Šƒ€yvqkljd\SZ[VPIDAGGJP{އ‰Š���ŠŒ�‹ˆ‡„„„……‡ˆˆ‡„ƒ„„ƒƒ‚€~|vrlgeccfkqx}€�ƒ…†‡„„„zqs|ƒ…k_`aa_^]]_`__]]]]\Z\\W\lzyda‰·ÇÅÅÄÇÆÃÇÌÆËÐÎÏÌËÌÍÍÏÒÑÒÓÔº‡ÖÜÝÝÝÞÜÓÊÍÏÎÌÍËËÇÇÄÀÅÇÈÈÅÿº³´¸¸µ›„ƒ~|xqpof[]\XWZYROUONHb‰††…tt�ŽŠŠŒ‹‰ˆ…„†‡ˆ‹Œ‹‡„……„ƒƒ‚�€~ysld``chnsx|�„„„……�ƒƒ�~su~…�h``_\[\^__`^]_``__\YXZZ\euvf`|ªÅÈÅÈÇÄÇÊÇËÏÌÍËÊËËÎÏÑÒÐÑÕ½ˆÕÖÛÞÙÚÙÏÌÊËÌÍËÅËÉÆÆÆÇÈÈÅÀÁ¼º¹»»¸°ª’†ƒ�|xsokdeb[V[caZZXWNQuƒ�|gfˆ�‹‰‹Œ‹‰‡†ˆŠ‹Œ‹Š†ƒ„ƒƒ„„‚�€€}xrkdbfksy|€ˆ�‡‚���‚………}{‚‡}d_`_\Z]^^`_]]acb`_][Z\ZWV\hsocn›ÄÊÆÆÅÅÊÎÏÍÍÎÌÊÈÌÏÏÍÎÌËÔ¾ˆ×ÝÜÜØÖØÑÎÊÊÎÌÌÊËÉÉÉÈÉÉÇÄÁ½¸¹¼»»º²²¢‰†€|}xpnmifc_]`cb_\\YQWnvqee„�‹‹�Ž�‹‰‰‹Ž��‹‡…ƒ�‚ƒƒƒƒ†‰…~{xsqsux{~ƒ��ˆ}|„……‡ƒ€…ˆ{c`^]_\^`__``^```_]^\\ZYWWST`qtdf�¸ËÈÃÅËÍÎÍÍÍÊÉÊÆÃÌÊÆÍÏÓ½‡ØßÛÛÙ×ÎËÑÑÏÑÐÐÑÍÌÆÆÊÊÉÆÅÇĿ¾µ¶¹º·³˜‰�||ywrnljgdb__eec_\VJHMRdn�ŠŠ‹��ŒŠŠ��ŽŽŠ„�€}||~���…ƒxooprttrnmos|�~yurx‚…ˆ†ƒ‡ˆxb]X]baa`^_c`^b`]_^\Z[ZZZWUUT[mtjcy©ÇÄÃÊÌÌÎÇÅÊÉÊÆÀÉËÌÏÑÔ½†ÖÝÛÚÙÙÀ¶ÏÒÐÐÑÏÐÍËÈÀÇÇÇÈÇÈÉÆÄľ¹¸¹·¹ªŒƒ�{zvqomlihebcdd`ZSM@8>_r}ŒŠ‰Š‹‹�‹‹���Œ‡�{wvwwvtroliea]\__^\\\[]bikllmrz‚‡Š‰‡‰‰wda^ca^_^`bb^]__\^][\\]]\YWXYSVhuoal˜»ÄÆËËÌÊÈÈÆÈÊÉÉËÎÐÐÒ½‡ÖÞÚÙÚÖÉÅÎÑÓÒÑÐÐÏÏÎÄÆÇÆÇÇÅÅÄÃÅÅÂÀ¹µ·°’‚…ƒ{zurpolihfc`a`[RMH??\s|ЋЋ‹‹ŒŒ�ŽŒŽŠƒ}uqonle^Z[]a^[ZXSQRRTXVPOKHM[gpy�‡ˆŠ‰‰ˆuc`\[[[^`b^UZ^[[]^^^aa_^\ZWW[YUVcsugd…²ËËÉÉÌÍÉÆÇÉÆÇËÌÎÏÒ¼‰ÙÜÛÞØÐÎÒÑÒÔÒÑÐÎÎÏÎÍÉ¿ÂÄÆÆÃÃÃÂÃÅÆ¾µ¶´§�†…�|zywsjighjie``^YRLF@Yw}ˆ‹‹ŠŠŒŒ�Ž��Œˆ‚zqbPFCFJS]acbtxmffih`_aVG11;>Ibt}‚…‰Š‰‡pXRNJS^`ab^X]^]]`ca__^^^][Y[^_]XW`rykbx©ÉËÈÊËËÈÄÆÆÅÊÌÍÎÒ¼‡ÖÚÖ×ÎÇËÍÑÑÏÑÑÍÍÍÍÍÏŵ¿ÇÅÅÅÄÅÆÅÅź¹¹¹¤Œ‡…‚ywxummjiligb][YTMH?Ry�…‹‹ŠŠ‹ŒŽŽŽŽ‰†‚xcH:8:?ANZMI[{€tijmgWIEEGJY\UMUky…Š‹‹†kVQNLUaba_bed`]]`ba`^]__]^_^_^^^[Y_nyscl™ÂÍÉÉÈÇÇÄÇÆÅÊÍÏÑ»†ÔßÎÎÐÈÎÏÑÑÑÕÒÎÍÎÎÎÍÄ¿ÅÇÄÆÇÅÇÉÉÅÿ¾¾¼´›‰„}usttutoljhgd\YUPJDDFIKOMHIJIJNPRRTUSPLNRSRTX\[[\ZZZ]_bdda`^WUTVYXWWWRM…ÐÎÍÎÐÑÏËÍÏÐÐÑÐÏÐÎÍÐÏÎÎÍÌÊËÆÄËËÇÊÍÉÇÊÃÄÃÃÅ¿¾ÃÇÅÅÂÂÀ¿½¸Ÿ‘“��Œ†{‰‚iWRRQUUZbfjI10/16AIPUWZ^_ab```aabbba]YX]enu}…ŠƒVAEHMR]lfG:AEHJLKNQQMJNMLLLIHIMQRTUWXYYXY^cbcggfggb\XXYXVTU\YP…ÐÑÌËÎÑÑÍÎÍÍÑÒÐÏÍÌÍÏÎÎÎÌÉÉÌÃÄÊÊËÌÊÇÉÊÂÃÉÇÆÅÂÃ¿ÂÆÃÄÁ¿¼º©•‘��Œ„{||…�€cNMQSTR[biiD30//2:ELOPQSVYXXYYZ[YWQPW`fjpx†‹‚T?CCIOU`olM:>@@DGILQPOPKHHHKLLMQRSTTRSVWZ_bbdeddbc_[WVYZVTTXZV…ÏÐÊËÊÉÈÊËÈÊÎÑÏËÌÎÏÐÎÍÎÎÊÊÍÊÈÆÈÍÉÇÆÈÉÈÇÅÆÈÇÃÄ¿ÃÇÅÅþº¶¯ ”��Œ‚yrƒ„„ƒv]IINSQQ\akb@3///06;DIJKLNPRQQPOMLLV`dgntz‚‡Š‚SDLMQ[bnU972./125;BFGGHIILPSY^aekpu|�…†ˆ‚R:@AEJRZ_fkyyhtyM8;@FGILMLRVWZZYWRPOQSSTRRTW[\XXWYYXWTRTTPS^ca…ÎÏËÉÊÌÌÊËÍÎÎÍÐÏÍÍÏÑÐÏÌËÍÉÈÈÇÈÊÊÊÉÊÊÊËÈÈÇÄ¿½ÅÈÈÇÇÆÆÃ¾À½¼²§š’šœœ�ƒŒŠtnsvjS@?IMSZcjM9930024;BJOQRQSVY[]`elosy~ƒ†‡ˆ�R8=ACISX^ekq~�—¤Š^K@>EIKJHIORVYYXNGJLNNMOTTRWYSQPUSPQUY[]aa`aa…ÎÏÍÉÈÉËÌÆÊÏÌËÍÎÎËÌÐÎÏÎÍËÉËÉÊËËÉÊÌÉ»ÅÊÈÇÈÆÁÀÄÇÈÆÅÆ´°ÀÁ¾·«¦š�•œ�™�†‰nkloo\E>FNTXagG7753126=FMRTTVY[^afjnrx}�„‡‡ˆ�R6:=AHRX^gmq|�…›�|iK>@GLKLNPSUVWSIGMONMLONNOPSSU]ZXY\]_a[TUUY„ÏÏÍÉÊÌÌÎÊÍÐÏÎÌÈÊÎÎÊÊÎÌÎÏÐËÈÊËËÉÊÉÆ½ÅÈÈÈÆÆÄÃÅÈÈÇÇȶ±Àºµª¥¢ž“•¡¡£–‡ƒˆznegnvdNAAKSWcaB7645448@IOTWZ[^aejmpw|�ƒ†‡‡€Q49<@IRX_ekv‡”ƒMRs�†sQD?@GKKMPQSUWSNTWRSTSSUUSZ][ZUTTV^ZRg‡œ“[ƒÎÎÌÊÉÌÌÍÍÏÍÌÍÏÈÉÍÍËÎÎÌËÎÏÌËÊÌÌÉÆÅÉËÈÇÈÉÆÅÇÇÌÌþ½»º¹°£ž¡¢  —’ž¤§œŠ‚ˆ„tngcongYG@ENUh_?967788;CLTY[[^afkoty|~�„†††O28;?ISZadn„�‘„O3;J`ryv[I<><:99:?HPTVY]chlqtw|€ƒ†‡‡†P/5:?GS\al€Ž��xRG=77Dt™”Š^D>@HKJNQQTSQQNONPUTf�Ž}{›§£ƒožÒÎÚÝâȃÉÊÉÆÈËÊÉÉÅÇÍÍÊÇÇÉÈÊËÉÊÍÊÊÍÍÃÂÇÄÄÄÆÄÄÄÅÆÄ»´±¬©©§¥£�˜™›–Ž•™›™ˆˆ†xqy�‰‡ysntl`behkd\SP^[?:9;<=>?DJOV[_ehlpty~‚ƒ„†…ƒ~V/3;?HU_iŽ�ŽŠfCFJKC9Ce…–‹†zX<>DEAEEJQQZhr]Rh‘Öஞ¬Ÿyw²ÞÛÄÉÌÆ­‚ÉÈÅÃÃÊÈÇÆÆÍÍÍËÈÇÃÅÊÎËÈÍËÊÌÍÈÄÆÂÀÂÁÀÁº¯©¦¥¦ª®®¨ž–”—œ›�Š�™�ŽŒ˜†|Š‹†yglvpfa[]^ekt…ІoYK?98:?AFMUZ_eilpuxz|~‚€|wZ726=HR`yˆ‹‹‹VBCFILI=4AZt‹š‰iWG?P\`lx€œ¬§{^k�ÒÒ®§¤�…©Ä·®­ª§¥”‚ÉÅÁÅÈÊÍÎÇÅÌÊÆÈÊÉÉÊËÎÌÈÈÉÈÈËÉÇÅÃÃÀ½½»·´¬©ª¨¥¨®°¦˜‘‘•œ£ “‡…Žž”Œ—™›¢–‚„|q}€zy‚xjefjy�”œ¢¢˜ŠvaTMKOU[agntx|€�„ˆ‹��‹„‚fC=9?Md�“–˜˜•�jPOOQQSVPA>E[q•² t�½ ™–•§ÁǺ°¬‹¤ÇÁ¹º¹¸¿¼²±³´´´¶©�ÆÆÄÂÅÊÌÍÊÈÉÆÂÆÉÉËËËÊÉÈÇÈÈÈÉÆÅľ¸³¯«¨ª©©«ªª¯²©™ŒŠŽ— ¤ “‰…�•Š‹�š�u`WRSUQQRVSMHCGMNRSYgmzzmZA89@NW[iw|€ƒƒ�€}yumfcaadfda]XQG;5434@O]bachmqvy{|€mPEDDFKPW`g^OVeƒ¸ÈÉÉÌÏÎÍÐÐÎÎÎÎÎÎÑÑÎÎÖ»jw|nm’»ÉÈÉËÊÌÉÈÊÉÌÉÉÍÎÊÍÎÒ¿…‡ÔÙÕÕÔÖÙÙÖÕÒÔÙÛÚ×Óê�–‹��‹‘šš’‰qmkjjjkmmkjjlmnlmpqpkgeYECB:ALRXhyƒƒ„„�|ysmhda`YOHC?>:620002AVdc`cinrvy|€‚‚vVA>=?BFNYfiVTf”ÄÆÊÍÎÎÎÐÍËÏÎÏÏÐÎÑÐÎÎÐÖÇ�js~tnŒ¹ËÊÊËËÊËÊÈÍÌÈÍËÈÊËÌÔ·…ÑÚ××ÖÔÔÕÕØØÛÖË¿¬š‹‡‰‰�“‘�‹‰‚wlgddiljlkkllllopomoonqshSG?AB:AJOWiy�„………�|wrmjgfaVKEDCDFHIGEDIT\\[_glosw{‚„„~dC987987:I^YWo¨ËÊÉÌÏÑÏÏËÄÆÊÍÎÏÏÎÎÎÐÒÒÜÒŸrs}sj‚²ËÊÊÊÉËÌÊËÎÌÎÍÊÈÈÎμ…ÏÖÓÓÖÙÙÙ×ÑÅ·¦š�ŽŒ„�š–•”�„wmiffhjiimlllmmloonooooonmkkpkYMF@CLPWhz�„†ˆ†ƒ~wtsssqmid_\\\][WSPPRTUV\elprvz}€ƒ…†„tYHD@>=716BO\€ºÊÈÉËÊËÎÍÏËÆËÍÏÏÎÍÏÏÊÎÔÒÖÖ¯}oytl}­ÊÊÊÈÉÍÍËÌÍÎÐÎÍÍÎк…ÎÓ×ÚÛØÌºª�”��•œŸ•„�Œ‡~yrhefjjklnnmnllnqnnonoqppooomly�ucNCJQRWi}…†‡‰ˆ†„}~~|ywtqmkigc_ZVUUVVY_florvz}�ƒ†ˆˆ~fTMKLLIJOKK^ŽÅÉÇÉÌÿÌÍÎÏÎÏÎÐÎÎÍÏÐÎÏÓÓÎÐÔºƒoz|oy§ÆËÈÉÌÍËÊÌÍÍÍÍÑÏÑ»‡Ô×ÏÄ´¢”‹Š‘—› ¢›“ypyxnhhheimnpnmnmmmnnprpopoqrrpnoqoxxlqvqcUVTQYn€‡ˆ‡ˆ‰‰ˆ†…„‚}{wsokheb`]\[\^aekqsux{~€�‚„‡ŠŠ…r_UQQUY_gi^e”ÅÊÉÈËÈÇÎÏÏÎÍÍÎÐÎÎËËËÎÑÓÑÑÏÏÖĈjwzou�ÁÈÈÌÌÊËÍÎÍÍÎÑËÊ»ƒ»©—‹ˆŒ”›Ÿ¡�”ŠƒslgfkiehhhkklnnkklkklmmoopppqppqoonoqxkeksuslcXO]v„ˆ‰‰‰‹‹‰‰ˆ‡…‚�~{vqmjihgefggjmrvwy|}€€�ƒ†‰‹Œ‰pd\USY`iqqr—ÂÈÉÊÇÊÐÏÐÍÐÐÌÏÍÌÐÍÌÉÌÐÒÑÐÒÑÑÙÈŽmszor•½ÇÈÈÉËÌÏÏÍÐÐË̺o‘Š�–ž¥¡—‹~vpmn|�•†n[Z_abcabhiijkjjlnnnnopppnoonmmlrtjjkrvvsmd\k�‰ŠŠŠ‹�Œ‹‹‰‰‡„ƒ�}zxvtssrrqqsvxz{{|}€‚�€�‚†Œ�‘ކ{qid^X[dnu{šÄÆÆÉÊÌÎÎÌÉÁÇÏÎÊÏÑÐÏÎÏÏÑÓÒÑÒÓÓÙÑœorypp޶ÄÄÊËÊËÎÐÐÐÏкo ¤¥ –†xnkmx‹šªÇÒÇÄ·‰\OTXXY[^beghijkklmnnoponooollkttiijx{wtrpp|ˆ‹Š‰Š�Ž��ŽŒ‹‰‡†…‚€~}|{{{yyz|}}~~~‚ƒ‚�€‚‡Ž“•’‹�ytpmigipx‘¹ÎÈÆËÍËÌÊË¿ÅÐÎÍÐÐÎËÎÐÎÑÒÓÒÔÍÆÎÖÔ©vqyrnŒµÃÅÈËËÍÐÏÍÍмwž‹|snqxˆ›­»ÉÉÏÚÌÀÏÝÓŸ`IGKPSVZ\^adfffghjmnkkmmnppnkutijo~|stvux‚‰‹ŠˆŠ��‘��Ž�‹‹‹Š‰ˆ†„‚��€}~~€€€€‚„„‚�‚…‰�‘”“Ž…}zxttssuz‚ˆŠ«ÍÊÇÉÊÌÍÍÏÐÈÊÏÎÏÍÊÏÎÍÑÒÑÑÑȾËÐÕÛ«spyrpŒµÄÆÊÍÌÎÐÏÏÒ½avnu„—­¾ÏÖØ×ÓÉËÐÈÀÇËÑЩnG>AHLOQUY\_abceilmiikkklnonvwjlt€}z}|y{ƒ‹Œ‹ˆŠŽ�’‘�‘‘�‘���Œ‰ˆ†…„„„ƒ€€��€�‚„…„ƒƒ…‡‰Œ” ¢˜Š{{{zyyz}ƒŒwjžÇÌÆÈÌÍÌÎÐÈËÎÏÐÌÎÐÌËÏÐÏÐÍÍÏÏÓÓÔØ®umvsq…­ÃÅÈÌÍÐÐÐÑ»e–©ÀÏÚÝÞÝÚÔÔÓÐÒÔļ¿ÆÉ¨vT>8>EHLORVY\_behjijijjikmntxlmvƒ…ˆzp{}„‹ŒŒŠŠ��‘‘’”•••“‘�ŽŒŒŠˆ‡…„„ƒ‚‚‚��ƒ„„‚�ƒ„‡ŠŽš®»¹¬™„{{|~~~�…ŽˆihŽ»ÊÆÉÌÊËÎÍÉËÐÐÌÌÐÏÌÍÏÐÏÏÐÎÍÐÑÑÖÛµ{kyyn~¡ºÃÆÊÍÏÎϺvÊßáÝÛÙØ××Ö×ÔÔØÎÁÀÂý¹½¼¯ŠbD67>DHKNQUY\`cfefgghhijjoxmlx…‡„b^y~„ˆŠ‹Š‹Ž‘’“••——–•“‘‘��Œ‹Š‡……†……„ƒƒ‚�~�ƒ†‹š¯ÀĽ´¥�}yx{~€‚ƒ‡Œ�|ib}­ÊËÈÊÊÊÌÉËÍÍËÂËÑÏÎÏÎÎÐÐÎÍÏÍÒÑÒÛ¾ƒmyxm}žºÄÆÊÎÎк{Ì×Õ××רØ×רÓ×ÒÃÀÁ¿¾½º¼¹¹«‰lP:26?DGILPV\_a`aceedfhhkxqm{…‚qT\u€ƒˆŠ‹‰‹Ž�“•••———–”“”•“‘��‹ˆ‡†…„„„ƒ�~}€€€‚‡“¤³»½¹´ª•xy{}ƒ„ˆ��|wqer ÅÉÇÈÉÊÌÌÍÎÍÆËÐÎÐÑËÌÐÏÐÒÐÑÓÒÏÑÚÆ‰jqvt~›ºÄÄÉÎѹ‡ÓÔÔÚÙÖÕÒÐ×ÓÑÖǺº»¹½Â±´º´´ ƒpYD416BFJOSVYXZ]_]bsx€rcixˆ‰„�‚…ˆŠ�‘’“””“”••””’‘�ŽŒ‰†…ƒ�€}zxz~‚……†ˆ‹�“œ¡¡¢¡ ž•onsx}€„ŠŒv`^]]hvtbd‰¸ËÆÉÌÌÉÊÎÍÍÏËÈÍÏÏËËÏÐÐÑÐÏÎÑÐÏÕÀ†huwi~ªÃ´‡ÕÝÙ×ÕÖÕÕרÚÑÅÅÃÂÃÀ¿»²¹»¸¸¹·¯�ztndYI;2/19@AFKORUX[\]`ox€{kov~‰†€�…‡Š��’’““’’“’“��ŽŽ�‰‡…ƒ€~~~|wssttmiov{|�‹•˜—––”Šxljouz€ˆ‰ta]\\[cqtic|ªÇÌÉËËÆÅÊÄÊÉÇÊÎÐÎÎÐÐÏÑÒÏÎÑÑÎÌÓÅ‘ktxov¡´†Ô×Õ×ÕÖØÖÔÚÒ¸¼ÇÅÄÂÀ¼¿ºµ·¹¸º»·¡‡~yvpfYND8/-4:=BFINSX^]\hx~ƒ€„{p�ˆ‚‚„†‰��‘’’‘‘‘‘‘�ŽŒŒŒŠˆ‡…�}~~|ztlhibO?CRcpv{‚†‡††‚xojhlsx|†‡o_]Z^^[_mwqck—ÁÌÇÈÅÃËÍÌÆÊËËËÎÐÏÐÏÏÒÑÏÏÎÎÏÍÔΕjpslv�†ÓÕÔ××ÙØØÙÙÇºÄÆÄÅÃÄÁ¾¾¹¶»½¼¼´°–‚}ytniaVLA5//39>BFKPVZ[_rx{‡�‡ss…ƒ�…†ˆ���‘��ŽŽ�ŽŒŒŒ‹‰ˆˆ‡ƒ€|||{yvmc_\SHBBHUepvxwwwtsqkgipv{~„†n`_\]\YX_lsrffЏÆÅÈÉÊÐËËÎÉÉÊÍËÍÏÏÎÎÐÎÎÎÎÐÑÎÓОopwpj…ÔÚרÙÚÚÚÜØÌËËÆÅÅÄÂÀ¿ÂÀº¹¼¿¼¶¸ª�‚|vqnid^TF:2,.5<@DGJQUWfuoxŠ�†„‚€„†‰���Ž�ŒŒ‹Š‰ˆ‡†††††…‚}{{{}}|vla][YVSLKYippoonouwrihouz}„‚la`]]\ZZ\]`lxocy¦ÆËÆÈÌËÍÌÈÉÊËËÌÍÏÏÏÐÎÎÎÌÍÐÑÎÓÓ¬znul‡ÓÙØÚÛÛÜÜÛÕÌËÉÉÇÅÅÃÃÄÂÁ½¯±¾½¸µ´›ƒzwsoiebVID:/,.7?CEILSZr{x‰‘Ž‹ƒ€�„‡‰�Œ‹‹Œ‹‰‡‡‡†„‚ƒ„ƒƒ‚|||~��€~yqidbbdbcgkmlmmnsx|zqlovy|‚|g_^_`_`][ZY`nwqdj•ÁËÇÉÌÌÌÌÅÇÎÎÍËÍÐÑÐÏÎÎËÊÍÏÑÏÓÚº�ls‡ÔÚÙÚÛÛÝÝÜÑÈÊÉËÊÈÈÈÇÇÅÄ·²¼½¸³´©�‚|yukee`ZSJA6.-2:?EOVSf„‡‹Š†€~€€ƒ†ˆ‹‹‹ŠŠ‰ˆ‡‡‡‡„€�‚�‚�€‚‚‚ƒƒ‚€~zuplkkjihhijjmsx|€yrrvy{�xfea_aa`_[ZZ[_fuwgb…´ÈÈÈËÌÍǾÄÍÌÊÊÍÏÎÏÎÍÎÍÍÏÐÒÑÒÚ¿†n†ÖÝÛÛÜÜÜÚÚÑËÍÍÌËÌÌÉÈÆ¿¿Ãþ»»·¶¶´£ˆ‚|wurmfab_XPH@4//5ELTQTv�‹‡…ƒ†„€‚„ˆ‹‹Š‰ˆ‰‹Šˆ†„ƒ�€�‚�€ƒ††…„„ƒ‚€~|xtqlid`adgkrw{��~yvvvy€tdgb]^[[_`]XWYX`sxk_t¥ÃÈÇÉËȸ³ÉÍÊÈÌÎÏÐÎÍÎÎÍÎÐÏÐÏÑ×Ä�†ØßÜÜÜÝÝÜØÌÊÌÍÎÍÍÍËÈÇÀ¾Ã½¹¸¶¸¹´±•„~xwtqlheea[TLD?85CEJRNc†�‹ŠŒŽ„|�ƒ‰��Šˆ‰‹Œ�‹ˆ…„ƒƒƒ„„„…‡ˆ‡………„„ƒ‚�}{vqkfcbbhpv{~�‚ƒ‚~zvsxpbca^\Y]_bca[WWV]krm`h“½ÉÅÅÅÅÅÉÉÇÇËÏÑÐÍÎÌËÌÍÑÎÎÑÐÐ׿‡ÚàÝÝÜÜÝÜÑÈËËËÌÉÄÈËÉÆÈÇÅ¿¼º¸¸¹µµ¨�„�zusmjjfcZWXSQIBIJDMPUq‰‰ˆ‹‹{lzƒˆŒŒ‹‰ˆŠ��ŒŠ‰†……†‡ˆ‰‹‹Š‡†‡‡†„„ƒ�€~ytnhedfkqw|‚„…ƒ‚xqx~oca^[]]___`a]YYZ\[brufd‚±ÈÅÅËÍÇÄÄÅÊÎÐÑÍÎÎËËÍÏÏÐÒÑÑÓ½‡ÙàÞÝÝÝÝÚÌÊÎÍËËËÇÆÇÇÀÃÉÈÆÆÂ¾º´³´¶¶Ÿ„„}xwplng^VX[[`[QRSNLNO\v„†„€lYqƒ†Š�Œ‹ˆ‰Ž�ŽŒŠˆ††ˆŠ‹�ŽŒ‰‡†‡†……ƒ‚��~zuniddhlrw{�„„���yqz~k___]_a_^]\\]]\[\ZXdt{n]r¤ÃÅÅÄÅÈÅÆËÈÇÏÍÎÎËËÍÍÎÑÑÑÓÕ¹‡ØÙ×ßÜÛÝØÎÌÎÍÌÍÌËËÆÄÂÃÆÉÈÅÃÁ¾·µ¸¸µ­‘…‚~{urqm_^aZW]e^XXYUOKMVm|{r`Xo�…Š�Œ‹‰Œ�’’�Œ‰ˆ‰‹�Ž��Ї…„ƒ‚ƒ„ƒ‚€€ƒ‚{tnihkpuy|€€€ƒ~w€|e\]___`_\^``__^ZWZZ[_lwnaj”¼ÉÆÇÈÄÅÊÉÉÎÍÌËÊÊËÌÎÎÒÒÐÔ½ˆØÙ×ÝÛ×ÚÔÍËÈËËÌÆÆÊÈÈÇÆÆÈǾ¼·º¼½»³¯¤‹†„zxpljifa]\ceba^[ULD>@Pflegq}ƒˆŠ‹ŠŠ�‘””’�‹‰‹Ž�‘�Œ‡„ƒ~�‚‚�‚‰‘�†}xutuvx{||}{{}�…ƒ~„zb[[^^`__]^bb`_^][Z[XVYamrhd‚³ÊÈÆÆÄÈÌÏÎÍÍÌËÉÊÍÎÎÍÍÊÑ¿‡ÖßÝÛÚÖÕÑÏÎÊÍÏÎÎËËÉÉÉÈÈÇÅÄÁ¼¹½¹¸¹ºµ°™‡ƒ}~{tnmkihhedcdea\VOE<44Qmpos}ƒ‡‰Œ‹‹Ž‘••”“Ž‹Ž����ˆƒ€}zyz|€…‰ˆ€wrrstqmkmqtuvux€…†‚…tb^\__^_`_^^``]]^][YWVVSYhuk`w£ÄÊÅÂÈÌÍÎÍÌËÉÊÊÃÇÎÆÉÎÒ¾‡×ÞÛÛÙØÑ¾ÈÒÐÏÑÏÑÏÌÉÂÇÉÈÆÄÇÊĹ´¶¹º¸¬�„~~zxuomjjlifaab_]VNG@72Hjrrv{�…‰‹�Ž�’––—•’���ŽŽŠ„~yuuvvutrrqokea``bb`]\]cjmlls|„ˆ‡‡qcdaa^]ba_aa^^^\[[[\[XTUTUdspdh�¼ÆÁÆÌÌÎÌÅÈÈÉÊÂÅËÌÎÐÔ½†ÖÛÚÛØØÑ·ÂÒÑÐÐÏÏÏÌÌÄÁÈÆÇÇÇÈÇÃÄÄ¿º¸·¶¶œ…„ƒzytpnmolhdba`_ZQHA90?etuz|ƒ‡Š�“’’•™š˜–“��ŽŽ‡€yspomkh_[^^`a][ZXVVWWVSRRWahp{ƒˆ‰†sc_``_ab`\^_\\]\[\]^]ZXWXVR]pteb€¬ÃÄÉËÊËÊÉÈÈÊÊÊÉÍÐÏÒ¾‡ØÝÚÛÛÙÑÌÍÐÓÔÑÐÐÏÏÐÊÇÈÅÆÇÇÄÃÂÃÄÄÃÀ´µµ¥Šƒ…‚|{yusonnkhd`^_]VNC;39`xz~‚…‰’”“’“˜›››™•’‘Œ‡€xkYIGGEKTQIIXba]XUSLBFJ;28I_oy‚‡Š…iZ]]^``WW]][[]^^_a`]\[YWZ[VT[kvoap ÃÌÉÉËÎÊÇÆÈÇÅÈËÍÏÒ½ˆÙÜ×ÝÙÐÊÎÑÑÐÑÑÏÎÎÎÎÍο¼ÅÅÆÅÂÄÄÁÂÄĺ¶¶³¡Š…ƒ�|yywojlmle_[YXSKB966Wz‚€|ƒ‡Ž“”’“—œŸ£¢œ˜–�ˆ€oT?68951/57AJENdt}…Œ…\N[_`aa[\`^\^ba_``_]]\Z[]^_\WZjxsci’¿ÎÉÉÌËÉÄÄÆÅÈÌÌÍÑ»ˆÕÜÖÍÏÅÉÍÐÒÏÐÒÎÌÍÎÍÌÊ»»ÇÅÃÆÅÅÈÇÅÂÂÀ¹º»µ›‰†ƒ}vvwrnmklga]VSMD=<<8Mw‚„€{}�ƒˆ‘•”–™�¡§©¢�œ•ˆxaT[_`_`^ZQC601468;=<5&'In{jU[nzƒ‹€[R]ba^`dea^\^aa`_^__^]^_^^^_]Z\euyic‚´ËÉÉÉÇÆÄÆÉÅÈÌÍл‡ÓÝÚÏÓÊÍÐÎÐÑÕÖÒÏÌÌÍÍÈÃÆÈÆÆÈÇÇÈÉÈÄÃÁ¾¾¾»­‘…}vttsutoligda^TLFBDD>Fq„…‚{y}ƒŒ�‘”˜›ž£ª©¤ —†tgo{{x{„Ž–—ŒwbMBCEHIJD=Kn‹’„nemx‚‰|`\_[WSQUVUVRQZabb`a``____\[\\Z\\`oxqdt£ÇÌÅÃÅÆÉÉÆÇËÍй†ÓÜÝÝÒËÌÏÒÓÒÑÒÐÐÎÈÊÌÊÉÉÉÉÈÈÈÉÈÇÈÇŽ¼¿¼¹Ÿ†y{|zytqqiddc_VPNMKKBBjƒ…ƒ{wy{~‡��‘“—™�¥¬¨¡•…zz€ƒƒˆŽ�‘𢧩¥œ‘†€ylijmyˆ––‹€tqw†ya^YSRROQMJKMMV\ZUTW[_````a^\\Z[\XYfusch”ÀÊÅÃÅÈÇÇÈÇÉк‡ØßÜÖËÊÎÑÏÏÓÎÍÊËÏËËËÌÍÈÈÉÈÈÇÉÉÈÉÈÆÅÁ¼¾½»±•ˆ‡…�{uvuoife_\ZYSTPACf��{vvy{‚‹�Ž�’”–œ¥¥ž”‹†‡‰‡‹—œ˜’��”ž©³µ°­£•‘�‹†Š��Š„{vw|ƒr][XXXVUVSPPTWPNLFDHV^^__ada`_][Z[YW^mria€³ÉÆÁÂÃÄÈÅÇͺ†×ÝÙÕËÎÑÏÀÅÒÓÑÍÌÎÍÎÌÊÉÊÉÉÉÉÉÉÉÊÊÉÅÃÃÀ½½¼½«�І‚|yxutrpkeca][YNBDaz€€zsquwzƒ‹�Œ���‘–š˜––•—™˜˜˜˜–•“���”𠤍¦¡›”‹„ƒƒ†ˆ„}zx{~jZYYZYYWUTUVWYSLIGGP[^^]]_a`aa^\[[[ZV[hsnbs¡ÃÅÀÂÃÇÈËË·‡×ÜØÑÌÐÑÐÊËÒÓÍÎÑÎÎÎÌÌÊËÇÅÊÉÈÊÊÇÇÉż¸¼¾¼¼¼¶š‡†„‚€|ywtrqlfbbb`WOUTGk}zrnpsv|…ŠŠ‰Š�ŒŒ�’”˜ž¢¥§¤�—“����І†‰Œ�ŒŠ…‚€}}~‚ŒŒ{z~wd\[ZYX[\WUVTTTUQLOW__ZWRPQTVTW[]_\Y[[ZY_qteg�»ÊÅÃÇÈÊθˆÙÞÖÍÍÏÑÓÔÏÏÏÍÍÏÐÎÍÎÌÎÌÅÇÇÀÄÈÉÄÅÇȼ·¼¿¼»º·¤‡‡‡…ƒ€|urrplidhh`[Vnw@Rt|{tnkoru{ƒ†„‚‡Š‰‰Œ�–ž¡£¥¥¡š“Œ†‚~}{zzzzyzxvvwxŽ•‰€}~n^^\\[YY[XUUQRVUQUX]ZSLLLMNMLGKVXZ\]\Z[[Y\kvja€µÊÅÃÆÉ͹‡ØÝÒËÍÎÒÓÒÎÎÏÓÎÉÑÍËÍËËÌËÌÈÅÉÊÉÆÈÊÊÄÄý¼¼º·­”Œ�ˆ…ƒ}stxvoighdbc_s‰cFeuxtniknos|‚‚��„‰�“™� ¢¥¦¢š“�†~xtsqomnqrromnqw�Ž˜˜‘…xe]^]\\]][XWTSUWUW_\UQOKKNNPNJGKMKOY^[[\^^Y[gsnbt¥ÃÅÂÇÌ·‰ÕÖÌÊÌÏÓÔÐÏÍËÐÎÊÌËÍÍÎÌÍÎÌÍÍÌÌÌËÊÊÈþÁÀ¾¾½»¶­—�‹‡†‚}|{yslggfhicr……RUjttojiknqv{}}zy}ƒŠ•›ž¡¢¥¦¡š”�Š€ytpmihiiiiggkry„‘˜œ›Œr_^_^\\^^^\[Z[YWY^_XRQSTQPMONLLMJINZ`b`_][Z[X_qxkl‘ºÅÅÌ·ˆÖÓÉÊËÐÓÖÒÏÍÊÌÏÊÂËÏÏÎÎÍËÊËÊÌÎÎÌÊÈÉýÀ¿¾¾À¿»º¤ŽŒ‰†‚�‚~xsnmnpnjfuy�mO`krnkigjmpuxwutuy€Œš£¤¡  žš”‘�…}vqmkjiihggjpv|ˆ“—œœŒm^^__\]\]_^\^]\]]]XTTRQRRQSROPQPNJLX`eb^][YZZ[bq~n`|ªÄÊ·†ÖÔÉÊËÐÓÇÅÎÉÍÏÍËÉÌÍÏÍÍÍÉÉÇÈÌɺÄÊÉÌÌÇÀ½ÀÁÀ»º¼³™Š‡„€ƒ�{rqusqkjws‹ŠZZemnlkhfhkotvspry€Š˜ ¢¢ Ÿ�›˜–’�ƒzuqomjhggkpuy��™œ œ„f__^^]`_]^^]^^]\[XVVUUTSSRSRPRRRPKLQZab`]][YY\_]gvqaoœ¼¶‡ÔÑÊÍÌÌÓÅÀËÆÊÏÊÌÍËÍÍÍËËÌÊÆÈËÇ»ÃÉÊËÊÇÂÃÃÃÁ·´·¼ª�‡„�‚…ƒ‚€{wwusmjyr|•rZcimnlkhiijorpoqv€‹“™žŸŸŸ�œ›˜”‘‹„}vqmifgimqu{Œšž¡¡™{`]_]\^_`_^__^^^[YYYYYYXWUTSSQPORRLJO^dca_^^ZVW\[W`rtgj‹¥ˆÒÍËÐÑÏÐÓÏÐÎÂÂÅÉÌÎÊÌÏËÉËÊÈÈÉËÍËÊËÊÉÈÇÆÃÃÁ¹´·º¹¡�‹ƒƒ…‚€}~~zxunj{yo‘Šb^fjnonkhiijlnoor{†Œ’—›ž�ššœœ™—”�†~vpljknpu~Œšž¡Ÿ›�t]\^]]]_`___^]^__^\[\]\YYXWVWUSSRRMJQZXTX]__[YWWYYVWhtpir‡ÎËÍÑÔÓÒÒÑÌÍÌÄÄÊÌÇÈÐÑÎÊÊÌËÉÉÊÉËËÌËÊÈÅÆÄÅÁÀ¿À»¾³˜�ˆ…„�€}}~~|xqm}‚l‡›s\cglnomggihknnqtw‡Œ“™›œ›šž¢¢Ÿ�›™•�‰…��„‰‘›¡¢¡Ÿœ”‡l\[[_`__^^__^__^^]\\]\[ZYWVYYYZZTQSSPLGIPVZ[^`ZXVVWUWbqpc†ÊËËÎÒÑÐÑѸ»ÓÏËÊÊÆÌÑÎÎÉÁÊËËËËÊÊËÌËÉÇÅÆÇÿÀÂÀ¿¾»¥�Ž‹‡ƒ�||}|{tq~„ll˜�gbfggjmidffilnqrsyƒŠ��“–šœŸ¡¤¤¥§§§¦¤¡žž ¢¥§¤¤£Ÿ˜�‚dYYX]^_^^__^_``_^]]^][Z[[XX[[WVWTQTTMIHPX[\\]a`ZXYYZZUZjq…ÈËÏÏÑÐÍÐϾ¼ÊÏÐÌÉÎÍÍÌËËÅÊÊÌÌËÉÉÊËÉÊÈÇÆÆÁ¼¼»¼ÁÀ½µ›��‹…ƒ€~~}zzxv~„o\zœ~cfedejjcddeijklosz„Š�”™� ¢¤¤£¡£¦§¦¦§¦¥¤¤¢¡¥¤œ’�z]VWWXZ\]^^^__````^]_][\\\\]][WTUWUQNLKIJMPRXYY^^\\[[^]X[gƒÈÌÌÕÓÐÏÉÊÏÎËÌÏÎÏÐÏÍÌÌÎÎÌËÌÌÊËËÊÉÉÌÊÈÇÇÆ¾¼»¼ÁÁ¿¿®•��Іƒ�‚‚~|x}„ta_‹–ldhfddgebbcceghijmu‡�“™œž¡¢¡ žŸ¡¥¥¥¤¥§¦¥¢¤¦ •�‰mVTUVWY[[Z[\^^\]^_`_`_]]]]\]\[YXWVTSPONLJIGDPYZ\_^^[Z[]][XƒÈÎÌÏÏÍÍÆÊÍËËÌËËÐÑÑÏÎÍÌÊËËÌËËÎÍÊÊÉËÊÉÈÇÆ½¼Ã¿½¾»¸¢‘��‡„ƒ„„ƒ‚€{}ƒudZoœˆgfgeabda_`_adeeeiox…ŠŽ’˜™› ¢¡ ¢¥¤¢ £¥¦¥¢ Ÿ—Ž‹�cVWWXZZZ[Z[[[\Z[[[_`a`^^_]Z[\YYZXTTTQQSTSSPINY[^^]]\Z\^][WƒÊÏÑÈÊÎÎÎÎÎÊËÎÍÌÎÑÐÏÍËÎËÇÊËÊËÌÌÌÍÌÌÊÉÈÇÅ¿Àþ¼¿»»²˜��‰†‰ˆ…„ƒ‚€�ve]Z… |cehd^^a][^^_cdfhhmv~‚„ˆ�”˜�ž £¤¢Ÿ››š™��›—”‹„ƒt\WWWXZXWWWZZXWVUVWY[]]\]\\Z[YVWXWWVTSTUVTROMP[^]\\\``bb]ZX„ÎÑÏÏÒÓÎÎÎÏÒÏÎÏÐÑÑÎÌÎÌÉÉËÌÊËÌËËÌËÍÍÈÇÊÉÇÄÄþ¼À¿½¼½§‘މ‰Œ‰………„ƒ�‚zh]Ue•›zbac\Z[ZUZ]]`acefhlsz~€„Š‘•–›žž�›™—–—•‘��Šƒ{eTRSUUVVTSTWXXVURQSTUUSUUX[ZYVTTUVXWXYWTTXTOKR]`\\`__`aa^\[…ÎÑÑÓÔÓÏÍÍÍÏÏÍÏÏÎÏÍÍÏÎÆËÐÎÎÎÎÍÌÊÊÊÇÂÆËÊÆÅÄÆÄ¿ÃÀ¿À¾¸›��ŠŠŠ„…‡†„‚ƒ{j`XSp•™~ic]XWVPOV\^]\`cdfjpvxy{€…�“’”––——˜—�Œ‹ˆƒ}wjPLPQQTVVUUUUWVSUUQOOPQQQSWWURTSQQTZYXXVSSWUROW`]Y[]\YU\aa_Z„ÎÍÌÒÑÐÏÐÏÎÎËÉËÌÏÌËÍÎÏÍÈÌÏÎËÌÌËËÍÌÈÆÆÈÉÆÃÃÃÇÄÁ¾¿Â¿¿­“�Œ‹‹ˆ‰‰‡„„ujbZTXkƒŽ‹|cYUUQJJSZ]\\]_cfgkruusw„…‡Š�’““�‹‹‡€{vqbQJILOSRQSTSQPMKLLLKKOUWVWXVSUXZXUWXVVVUUVURQV^_[\YOQXWZ]^]U„ÐÑÏÔÓÑÑÐÐÐÎËÊÈÈÌÍÎÎÎÏÎÇËÎÍÌÌËÌËÌÎÌÉÅÇÈÄÄÆÃÄÿ¾¿ÀÁ¾¼¤‘��Œ‹ŒŠ†„…{podZUTYclv†q\SRQJBDOY^][Z^`acinpnlosuy~‚„†‡†ƒ€zurqj`a\PHINLLMKJHFIGFFHJJMTSUUVWW[ZZ\[[XYYYUSUUSV^_YY\XRSX_][\XV„ÏÕÔÔÔÒÒÐÍÌÍËÍÎÉÈÍÏÎÍÍÎÊÊËÌÎÏÍÍËÌÍËÊËËÇÆÇÅÆÅÄÀÁÂÁÁ¼¾²˜’�Œ‹Œ‰‡ŒŒˆxphZQQX]][lxfXNOMF?BMWZYXX[]`beiigefgkopsvxyvqnkkeUSU^cZIBFIIEBABFHHKKKKLNPOMORXZYXVVVTVVXUSUVW_a\UVYYXYY\\[ZQKƒÏÕÔÓÑÑÐÉÊÍÏÎÎÐÎÏÏÎÎÎÌÌËËÌÊÉÎÎÉÈÌÌÉÈÊÊÇÆÁÅÉÆÇÀ¿Â¾½·§–’ŽŽ�ˆŠ””‘’ye[SQTZZ`_prcTLMJC<@LSUVVVWZ\^bdedbcddefhjjjgebmdDIIMZfbLAEFECDFDDGIJNPQPSSSSQSVUTRSWVUWWUUUX[aa\WWXWUUYWXWRMK„ÐÒÎÐÐÑÏÈÊÎÎÐÏÏÏÐÏÏÏÐÏÍÍÍÌÉÈÈÉÊÇÈËÉÆÉÉÆÁ»ÆÅ¿ÂÅÂÃÃÂÁÀ¼¸ ’’‘�ЅДЖ�oZRRRWWYcerk_QFHGA:>JRSSRRTVY\]_aaba_^`abba^_j€mA@CGMWejTACIKMNJHIIJLORRRUTPMMQRSUX[[Z\[ZZZ^`dec`_YUUTXWXVVTP„ÐÑËÌÍÑÒÏÍÏÎÐÒÐÎÏÍÍÎÏÎÎÎËÈËÆ¿ÈËÉÊÌÊÈËÇÀÇÆÅ¿ÁÆÃÄÄÂÁÀ½¼­”‘‘��‰�ŠŠ‡“…gOLRSVTZbhsh]KBED>9=HNONNPSUUTUW[\[Z[]]\ZZ`n~‰oA<>CIOWhnV@CHIKLMOPQLLMLKLJHHNQRRUVVXXXX\abbeggghc\YXYXWVTY\S‚ÏÔÌËÌÍÏÍÌÌÊÎÒÑÍÍÍÍÎÎÌÍÍËÈÌÉÆÉÇÊËÊÇÆÉÇÅÇÇÇÈÃÄÁ¾ÅÅÄÃÀ¼º²œ’‘•¢ �w‡‡…„ybJIPRPP[akrcZJ??@>9;CJLLNOSSQPRSRSTSRQPVbn{‚†oB<>@DMU\jrZ=BEJS[blu[<79AECFHILNPSQLQQNOSTQPRSSTTVWY__ZZ[\[ZVTUWVTVSTW†ÐÓÎÌÉËÉÈÎÌËÐÏÎÎÏÐÐÏÎÎÌÎÇÇÈÄÄÆÈÌÌÉÉÉÊÇÇÊËÇÅÃÃÇÈÇÄÅÿ¿·´¶¥Ÿ Ÿ¤Ÿœ‰‡�}ttvhN?FNMQ[bqkZWJ<7:=>AEIHHIJIHHIKKLPV\bhow~�†p@9=DGJSY_eqy]BA=?CEEFIMPRWUUXWUUTPORUVUQOPSY\YVX[[\WUVUTQORW[…ÏÑÌÉÊËÍËÍÍÌÏÐÏÏÏÏÏÐÏÎËËËÌÅÅÇÆÇÊÌÇÇËÌÉÇÈÈÆÃ¿ÃÈÈÆÅÆÆÅÀ¿½¹±©›“�ž¡”‚ŒŒxntvkTA@JMRZbobUTK>68GMTXan]OOKA969BGKMNMNMNOQTX\aekpv{~�…p?59;BLRY`fnt{‰¢šmRD=AHJIIIMPSWYXRIKMMMLMRTRVZURORTNNSYZ[_bbb`„ÎÏÍÌÈÊËÎÉÇÎÏÍÌËÌÍÍÍËÎÏÍÍËËÉÊËËÉÊÉÊ»½ÊÇÉÉÈÄÀÁÅÈÈÇɼ¨¹¾º¯§¢Ÿ”•¢£¦›‰„‰{ofhnueLABKTYcjYOKHB<9DLLKMNQSUVUMHMONMLNNMPOQST[[WV\^^a^VTSWƒÍÐÌËÉÌËÌÌÍÐÏÏÏËÇÌÍËÊÏÌÌÎÐÎÊÊÊËÊÊÈÈÄÅÈÇÉÇÅÇÆÇËÇÂÁÁº¯±©¤¤¤¡¢™”Ÿ¥ª Œƒ‰‡vnhdpogXF@GOUhoXMGDCA=>EMPRRSRSV[_chlrux|~€‚o>06:BMU\_grwxuKDdz†~\JA>DJLLNQRTVUNQXTRUSRSTRW^]\VSTT[^TZz�•h…ÍÌÉËÈÉÊÍÌËÊÊËÎÌÊÎÌÊÍÎÌËÌÍÌÌËÌËÉÆÄÇÎÊÇÇÈÉÉÇůĹ­©§ª¬£›–˜žŸŸ›Ž�‘˜˜‰„‡uxoebdkm`THCHQhdVPIDBA?AIORUTSUW]bfknruz~€��p=/6:BLW\dtƒ‰‡vM65BVlv|fOA;BJMLMPRRTX^\\`]VVXSNPSS[bixu_i—Íáâ©„ËÉÉÊÈÉÊÏÌÇÄÉËËÉÉÌÌÊËÌÌÌËÉËÍÈÅÈÆÅÃÆÇÅÆÆÆÆÂ¹´±®¬¨¦¥žšœ�—�—›œšŠŠˆzsz€ˆ‰|torkacgikcZOJXdVRNIECABHLOQQTX[^cgjntx|}€rA-49BMVayˆŽ�ŒmKIB;6;_�—’oKB=EJILQQSTPPONNNTT^xŒƒs‘¦¦’m„ÄÏÔââÉ‚ÈÊÈÇÄÉËÆÈÇÈÌÎÌÉÆÅÃÇËËÇËÌÊÌÎÈ¿ÃÄÂÂÄÂÃý´­ª¨§«®°¬£™–™�ž‘‹‘›ž�Œ—†z‡�†‰knytid`bdins‚ˆˆwdYNFBCEFHKOSW\`bcglquxz|~~{rG-29BP]vˆŒŒ‹„_CDIMH<;Uy’�‹†hC?ACEHKMOQUY[]\WVU<+0):]gbUO\adkG8<<<=<>?8/.3JswZwœtcagsz~~xpnwwxyz}|x{~~}}~~tƒˆˆ‰‰ˆ‰‰‰‡ˆ‚y{zyxtpwyvtvvvxxxxyyxvspsvuv|€|yywvvwwvzywrqvwxvvvuvysswxwutywpstuuytruruuqv†’’“’”“““‘‘‡yzwssvxvtuvvvwxxyxxvrrstvx|~|zyz{{{{|{ywzyvrswxwwuuuuxttwxwvuyvpsutwysttuvtu€ƒ„ƒƒ‚€�€€�wtsuxwvvvvwwwwwxwtsrsuvz}|{yx{}~€€€€}{{xvttwxwuuvtvxstwvwuuxuqutswxrsutuu~||||zxxyxvsstvwxxvvvwwwwvutrstuwz}|zyyz}€€€€€€€~|ywsswxwvuutvxstwwvuvzuruttyxrttsv€}||zxxxtrsvwstvxwuuvwvvurrstux|}{yyz{}€€€€€€€€€€~yvsswwvvuutuwruxwvtwzsqtttzwrust}|zvstsswvusruwxwutuvtrqrtvy||zyyxz}€€€€€€€€€€}yvsrvwwuutrtwruwvuuxxsrsuwzurtu{vtrswwxvuusswxwwussqrttvz||zxxyy{~€€€€€€|ywsswxvuttstvsuvvvvxyrptvxztqu~vvtwxyvtuvurtwxwtqprsuxz}{yxxxxy{€€€€€€€€€|zyvtsvwwutsruwrtvwwvxyrsuvxxrt~{xvywvuvvvssuwurqqtux|~|yyyxyyx{€€€€€€€€€€zyzwtruwvusstvvruwwwuyyrtvvxxt€zutwwvuvutsttqqqru{}|{yyyyxyyy{€€€€€€€€€€€€€~xyzwtquvvusssvvsvwwvuywruuvxx€ytuwwvvvusqpqqruz}|yxyyyyyyzyz€€€€€€€€€€|vy{xsruvusrttxvrvxwvvyvrtutxxtvwwvvuropqsuy|{yxyyyxxyyyzz}€€€€€€€€€€xvy{wtruutssuvwusvxxwvzvrutwwuwwvtrpqrsv{|zxyyxyxxxyyyzz|€€€€€€€€€€|vuy{wtrtutttvuvvrvxxxwztrtw~wvxurpqrtwz|zyyzzxwxyxyyyyzz~€€€€€€€€€€~€xuvy{xurtvvuvuswuswyyxxytrw}vvsrqsux{{yxyyzzyxwxxyyyyyx{€€€€€€€€€€€{uvux|xtptwvwuttwusxyzywxru}trqtw{}zxxxyyy{yxxxxxyyxutx€�€€€€~€~vuvvy{wsquvwvuutwusxzzwwws|rtx|}|ywxxxxyyzyyxxwxvttuv}�€€€xuvvvx{xtruxwvtttxttyzxuvy|x|}{zzyxxxwyyyyyyxvuttuvvw~�€€€€€{uuvvux|xtruwvustwwruyxwuw}zzzzyyxxxxyyyxxustuuuuux}€€€€€€}vuuuvvx{yurtwwuvxwustwwvw{zz{{yxxxxxxxvtsttuuuwz|}|€~~~~}~~~€yuvvvvvx|zuruwuvxvtvrswvx|z{{zyxwwwwusstuutux{|}{z{€~}|zywvvuuuuuvwwxyzz{{||~{wwwvvvwx{yusstvxvttvrsvy{z|zyyxwtsssstttwz|||zz{z|~|zwurponmljkkkkkmoommoppqrstuvvvwwwwx|zurswwvttuwrsz{z{zxvurqstssuw{}|{{{{{{z}€€}{vsqookgghhikmooooprpmigghjlqqrrrrstvwvx|yuruxvuuuvvqv{yxusrsssttw{|{|{z{{{{zz{~€€|ysnjkiggefkoqrstuuuvtsttqlgdchoqrsttsssvvwx|zusvwuutuutt~wusstssuwz|||zyz{{{{zz{z{~}{xrngcbccehmprstrqqqqqsssstuqojdfnpqrsttttvwwxz}zvttttvutsv|utstuvyz||{{zzzzzzz{zzzzz{zwrjgkdabdinqrppqrpppoppqqppqqpqqlgkqpqrsstvwwwxyz|zvsstvwusu|ttvx{{|zzz{zzzzzz{z{zzzzyxunfbdkhdinrrqrqrrsrssrqqrqpppppprqjkppqrrsvwwwvwyyx{zvssuvwtu|xz{|zyzzzzzz{zzzzz{{zy{zxsmgdbbknnstrqrstuwwwwwussssrrrqrqrrkjqrrqstuwwvvwxwwy|zvstwwuv€|zzzzzyyzzzzzzzzzzzzzyyxrpmfcbcmtsssrstvwxzzyyxvutsssssstutsnlrrruwvstwvvvxwxxx|zvstxuv{zzzzzyyzzzyyzzyzzzzyxwroskeeeksttsrrtvvvvvwxxxwvuttttstuwwwsqrsuz{xwttwvvwwwwwx{zvrtuw|z{zzzyzzzzyzyyzzyzzyxuoqsjefmtuusssuuvuuvuvvwxwwvuuuuttuvvxvstwwxz|zwuuwvwwwwvwxzyuqsx|z{zzyyzyyyzzzyyyyxxuutpqsngltxutstuwvuuttuvuvxwwvuuuutuuttuvuvxwvxz|ywvtuvvvwwwvwyzuqt{yzzyyzyxyyyyzyxvvuvvwvrrtqkpvxuttuvwvuuuuuvvvxxwvvvuttuvuttuuvxxvvxyzywusvwwwwvvwvzxtt{yzyyyyyxyyxwvuuuvvwvuuusrrosxxuuuuvvttvvuvwvwwyzwvttvvvvvusstvwxwvxxxzzwusvwwwvwwwwywv{zzzxyxxwvutuuvwwvvvuvvvutssvxxuuvuuttutuvwyzywxzxuttvxxwwxvrtvwwwwwwwxzzwvsuwwvvwwvvxzzyyywwvttuvvvvvvvwwwvwwvuusvxyxvvvutttttvxyzyywwwutsrvyyyxxvsuwwwwvvwwwwz{xvsuwvvwwvvvyzxwuttuuuvvuuvvvwwxwvwwwvuuuvxwvuuutsstuuvvuvwwwusttsuyyxxzwsuwwvwwwwwwwxxzyvttvwwvwwvx~vuuuuuvuuuuvwwvvvwwwwwwwvtrstvvwwuutsrstssttuvvtsssttuxywuwyuuwvwwwwwwvwwwwzywttvvvwwwx}vuvuvwzzxuvwvwvwvvvvwvvvwrqtstvxvutsrrrrssttsttsstttttwyxwwxwuvvwwvwwwvvwxwwz{wutuvvwvx}wxz{{zzxyxuxzzxxwvwvwwvvwqqtstvxuuusrsrrtstsstsstttttsuyxwxxyvuvwwwwwwvvwxwvx|{vusuvwvy}}}{{zywwxvvy{{yxwwvvvwvwsqtqqvwutttssrsttssstssuvutrqrwwvxxyzvtuwvvwvvwwwwwxyzzwtsuvvx}|{{{zxwxwwvuwz|{xxvvwvvwtrsosvvvuttsrsstsstsssuvvurooptvuwxyyxwttvvwvvvvwwwwyyzzwusstx}{z{zywwwvwvtvyy{|{ywwvvvvsrotuvwvuttssssttssrtvutsqpnouwsuwxyvwxutuvvvwwwvvwxxwxyxtrsw€}{{{{ywxwuuttuyyxy{|zxwwwvusqssuxwvutttsstttssuvttssrppuwssuwyvtwxvtuvvvwvvwwxwwxxywtrt€|{{|ywxyxvvvvuvzzyxz|{zyxvuttssuwwwuutuuttttsstvuvwutssvwsrtwyvtuvwvttuvwwwwwwwwwxwyxtt€}|||zxxxxwwwvutwzzxxy{{{zxvuutrtwxwuuttutttsrtuvwwwvuuwyxtrsvxvuttuwwutvvvuvvwvwwwwwyxv}|||yxyxxwwvvvuvyzyyxxx{|zwwwurrvxwvttttttststuvwwvutuxzyvssvxuuuuuuuxwttvvvuwvwwvvvvwx€~||{xyyxxwvuuvvuwzyyxxxxxywwwvsquywvtttttssttuvvvvvvtuwyxxutvwuvuuutsvxvttuuuuuwwwvvvux€~}|zxzzyxwwwvvvuvyzyyyyxvvutvwtquxxvutsststttuvvvuuvvvwxxwwvvvuutuutttuwwttuvvuvwwvvvux€}|{yzzzyxxwxvvvvvwzzzyxxvttsswwstwxvutrrstvuuvvuutuvvvvvwvvwwvtuuuuttttsuwvtuvuvvvuuutw€}|zx{zzyyxwwwwwwuvy{zzzxuttstxyutwxvutqqruvuuuvwwxxxxxxwutvwxutuvuuttutstuvwutuvvuutttw€}|zz{{zyyxwxvwwvuuvzzzyxvtsstxzvsuxvttqpqsttuxzzz{zyxz{zwttwxttuuuuuututtstvxtsuvvutstv€|{y{{{zyyxwxwwwvvvvxyzzywvtsuxywtuwwutspoqrstvwwwxyyy{zyytrvxttuutuuuutttttsuvutuvutssw€}{z{{{zzyxwxxxxvvvuvxzzxwuuuuvwxttwxvttrpoqrrsstutvuvxyyxurvwttttttuuuttutssstvutuutssv€}z{{{{zzyxxxxxxwvwwuwzzyxwwvvvwzvtuwwutsqponoqrsuuvvuvwxwtsvurssttssttuututuutstuussssv€{y{{{zzzyyxxwxxxwwvuuyzzywvvwv|wttvwvtrrpnlmortuuuutttutqsvtstttssstttsttuttttrtwtrssv€{z||{zzzyyyxwxxwwwwvvwzzzyvvxwƒxtsuvwusrpnklmpsttutttttrotvsstttssttsssutsttttrstuusqu€{z||{zzyxyyxwxwxxwwvvvxz{{yyzw†{tssuuutsqommmlnqrstutsqnntutttttssssssssssssttssstttss{{}|{y{zyyyxxwwyxxwwwwwz{{{{{yˆ‚vttttttssrpnnlkloprsrpomqvutttttttsssssrssttttstsssstu|||{zzyzyyyyxxxyyxwwwwvx{{{{{z~†ˆ}tttsutstsqqomlkmmnoppootvtttttttsttsrsssstttttttrrrqs|{{zzzzzyyyyxxxxyxwwwwwvz{{{{{}„Š…wrstttstutsqonlmmmnnoprvurtttusttstsssrsssrsssstsrrqr€}||{{zzzyyyyyxxxyxxxxxwvx{|{{{|ƒ‰Š�ussutssuutsrpomnooopruwuttttttststsssrsssssrrrtsrrqr€}|{{{zzzzzyyyyyyyxxxxxwwwy|||||‚ˆ‰Š‚xtuvutttutssrqqrqqstwywuttttttsssssssssssssssusrrqr€}|{{{zzzzyyzyyzyyxxxyxwwvw{||}‚‡ˆ‰‹†wtuvvttuuttssstsstu{ƒ�yuututtttttsssrssssrrsssrrqr}|{{{zzzyyzyyyyyyxxxxxwwvwy{|~ƒ‚ƒ†ˆŠŠssuvwutuuttsttuttu}ƒ†…}wvvuttttttssrsrssssssrrrqr|z{{z{zyzyyyyxxxxwwxwwxwwwwz|€ƒ„‚‚†‰Šˆ{qtuwvutsssttuutuw}€‚‡ˆwvuttsstsrrrsrsssrsrqrqpq}zz{{{yyzyxxxxwxxxwxwwxwwvvx‚‚ƒƒƒ‚†ˆŠˆyqtwvutstttttttvw|…‰‰€vttutsssrtsrrsrrqqrqqqqr€|{{{zzyyzzxxxxxxyyxxvwxwwww|ƒƒ‚‚ƒ„„‚ƒˆ‹†wruwvsrrrsssstvwz}€…‡Šˆzqsutsssstsrsrqrrprrqqqq€|{{{zzyyyyyyyyyyyyyywxyxxz}�„ƒ„ƒ„„……‚‚‡‹ƒuruvutrrsrsstuw{}€…ˆˆŠ‚trtttsssssstsrrrrrqnqxw€|{{zzzyxyyyyyyyxyxxyz|~€‚‚‚„„„„„„„†…„‚„†|qtuutsssrsssuwz}…†…ˆ‚vuqttttstsrrqqswtkbl}ƒ�|{{zzyyxxxxxyxwwwy{~��‚‚ƒƒ��ƒƒ„ƒƒ„…†……„ƒ�~vrrsssssssssuvy|~ƒ…‡ˆ}ttuutvwuussj_ht}kX]mohf|||{zyxyxxyyxxx{~�‚‚‚‚‚‚ƒƒ��‚„„…ƒ‚……„ƒ„ƒ‚‚ƒ€zttttuuuuvvwy}~‚ˆŠ„|vvvvxw{|{vuhZhoh^Z[[ZY\xjmhikjhgmkv„‚‚‚‚„…†…„„„„„„„„ƒƒ„„„…††………„„‚‚‚ƒ„„ƒƒ„„…„…„„ƒƒ„„„……„„„„„„„………………†††…„††ˆ†ƒ„sPQNQKMNOSUg†‚ƒ„……†………„„…„„„„„„…………………„„ƒƒƒƒ‚‚‚ƒƒ‚ƒ„…„„„„„ƒƒ„………†…„„ƒ„……††……†††††„†††ˆ†ƒ}ststtusuvuy„ƒ………„…„……„„„…„„„………††…………ƒƒ„‚‚��€€�€��ƒ„„„„…„ƒƒ„„…„††„„„„„……††…††††…………†‡ˆ†�ƒƒ‚�‚ƒƒƒƒƒ„„…†…„ƒ„„„„ƒ„„„„„„……………„„„ƒƒƒƒ�€��€€���€��‚ƒƒ„„„ƒƒƒ„„……………„„„„…††………†…††„…‡ˆˆ€�‚‚‚ƒƒƒ„…………††„ƒ„„„„„„………††……………„„„ƒƒ‚�€€€��€€���€€���‚„ƒ„„ƒ„„„……††…„„„„…†…†………†…†…„†ˆ‡€�‚‚ƒ„„…†††……†…ƒƒ„……„„„…†………„„„„„ƒ„‚‚�€��€€���€€�€�€�€��‚„„„„„„„………†††„„„„†…††…††……‡……††��ƒ„…†……………„……ƒƒƒ„„………†……„…„„ƒ„„ƒƒ‚��€€€€€€€€�€€€€���€€€�ƒƒƒ„„ƒƒ„………†‡……„„………††…††……†……†�ƒ„…„……„…„„„……ƒƒƒ„…†…………„„„ƒƒƒ„„ƒ‚�€�€€€€€�€�€€€���€€€€€€‚ƒ„„„„ƒ„„„…†‡†…„„………††……†…„…‡…†�ƒƒ„……„„„„„……„ƒƒ„…†……„ƒ„ƒƒƒƒƒƒƒƒ‚��€�€€€€€��€€���€�€€€�€€€‚„„„„„„„…†††††………„„………†††…„…‡„€‚„……„„„„„„……„„…………„ƒƒƒƒƒƒƒƒƒ‚‚‚���€��€�€�€�€€�����€€€�€€€�ƒ„„„„…„„…†††††…„„„„…………………„††€‚„…„ƒ„„„„„†…†……„„ƒƒƒ„ƒƒƒƒ„ƒƒƒ‚�€�€��������€€���€€€���€€€€‚„ƒ„ƒ„„„„…††††………„„…„…†††………†�ƒ……„„„„ƒ„…†…†„„„ƒƒƒƒƒƒƒ„ƒƒƒƒƒ�€€€���������€���€��€���€€�€€€ƒ„„„„„„………††……†…„„„„……††…………�ƒ…„ƒ„„„……………ƒƒƒƒƒ‚ƒƒƒƒƒƒƒƒƒƒ‚€€€€����€€��€�������€€€�€��€€‚„„„„ƒ„„…………†…†……„„„„„……………„�„„ƒƒ………………„‚‚ƒƒ‚ƒƒƒƒƒƒƒƒƒƒƒ‚�€€€���€€€�€€�€�����€€�€€€€€€€€ƒ„„„ƒ„„……„………†††…„„ƒƒ„…†………‚…„„………„„ƒƒ‚‚‚‚‚‚ƒ‚ƒƒƒƒƒƒƒƒ‚‚€€€€€����€�€€�€€€€�€€€€€€€€€€€‚„„„ƒƒ„„………„„†‡‡†…„ƒ‚ƒƒ…†…„‚…………„ƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒƒ‚ƒƒƒ€€€€€€�€€�€€€�€€€€€�€€€€�€€€€€€€�„„„„„„„„…„„„…†‡‡‡…„ƒƒ‚„††…‚…„„ƒ‚‚‚ƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚„„„„‚€€€€€€€€��€€€€€€€€�€€€�€�€�€€€€ƒ„„„„…„„„„„„……††‡†…„ƒ‚ƒ…††‚„ƒ‚‚‚‚‚ƒ‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„‚€€€€€€€€�€€€€€€�€€€�€€€€€€€€€€€€‚„„„„„ƒ„„„„„„…†††††…„‚ƒ„……�‚‚�‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„…„„„„„ƒƒ�€€€€€€€€�€€€�€€€€€��€€����€€€€€€�„„„„„„ƒ„„„„…„…†…„††…ƒ„„…„€�‚‚�‚‚‚‚‚‚‚‚ƒƒƒ„„…„„„„ƒƒ‚‚€€€€€€€��€€��€�€€€�€€�����€�€€€€€ƒ„„„ƒ„„ƒ„„„……„…„ƒ†††„„„„ƒ���‚‚‚‚‚‚‚‚‚ƒ„…„„……„„ƒ‚‚‚‚�€€€€€€€€�€€��‚ƒƒ„………„……„„„ƒ‚‚‚‚‚�€€‚ƒƒ„„„„ƒƒƒ„„„……„ƒ…†‡…„„„ƒ�‚‚‚‚‚‚‚‚ƒ„„………„„„ƒƒ‚�‚‚‚‚�€€€€€��€�‚„…‡‰‰Š‹‹ŒŒ‹ŒŒŒ‹ŠŠ‰Š‰ˆˆˆ‡††……„„„„„ƒƒƒ„ƒ…†„„…†††…„„ƒ€‚‚‚‚‚ƒƒ„……„……„„„ƒ‚‚‚‚‚‚‚‚�€€€€��‚…‡ˆŠ‹Œ�����Ž�ŒŒŒŒŒŠ‹����Ž�ŒŠŠ‰‰ˆˆ‡†…ƒƒƒ„ƒ„…„ƒ…†††…†…„€�‚‚ƒ„„„„„„„„„‚‚‚‚‚‚‚‚‚‚‚‚�€€€€�ƒ…ŠŒ�Ž��‘����Ž���ŽŽŽ��ŒŒŒ�‘’‘�‹‰‰‰‰ˆˆ‰‡…„„„„„„„„„…………††„€‚ƒ„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚�€€��ƒ‡Š�‘“’’‘�������’’’“““““’��‘�‘’�ŒŠŠ‰‰ˆˆˆ‡„„„„ƒ„„„„„†…………‡…�ƒ„„„„ƒƒ‚�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†‹�Ž‘“’‘�ŽŽ�����‘‘’’“““”””“““’�‘‘�ŠŠ‰‰ˆˆ‡…„„„ƒ‚ƒ„„„„†…ƒ„…‡†‚„„„ƒ‚�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„…‰�‘’��‘�ŽŽŽ���ŽŽ����‘’’““““’’’‘��‘ŽŠŠŠ‰ˆ‡…ƒƒ„„„ƒƒ„„„„……„„„††‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚�‚‚‚ƒ„†‰Ž‘’’�Œ�����Ž��Œ‹Œ�Ž��‘‘’’’’‘‘‘��Ž�ŽŠŠŠŠ‡……„„„„„ƒƒ„„ƒ„„……„„„…����‚��‚‚‚�‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†‡Š��‘‘�Š�ŽŽŽŽŒ‹‹‹‹‹Œ��Ž��‘‘’‘‘����ŒŽ�ŠŠ‰‡„ƒ„„„„„„„„„„ƒƒ„„„„„„„€�‚�‚‚‚�‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒ‚ƒ†ˆ‡Œ����‹ŒŽŽŽ��Œ����Œ‹ŒŒ�Ž���‘���Ž�ŒŒ‹ŠŠŠ†„ƒ„„„„„„„ƒ„„„ƒƒ„„„„„„„€��‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚ƒ‚‚‚ƒ„ˆˆ‡ŒŽŽ�ŠŒ�ŽŽ�Œ����ŽŽŽŒŒŒ��Ž������Ž�ŒŒ‹Šˆ…„„ƒ„ƒƒ„„„„„„„„„„ƒ„…„……„€��‚�‚‚‚‚‚‚‚‚‚ƒ‚ƒƒƒƒƒƒ„…ˆ‰‡Š�Œ‰‰Œ������Ž������ŽŒŒ�Ž�����ŽŒ�ŽŽ‹ˆ…ƒ„„„ƒƒ„ƒ„„„„„„„ƒƒ„„…„„„„€�‚�‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ„„„„ƒ…‡ˆ‡ˆŒŠ‰Š‹Œ�ŒŒ��Ž�Ž�����Ž���Ž���Ž�Ž����‰…ƒ„„„ƒƒ„„ƒ„„„„„„„ƒ„„„„„…„€���‚‚‚‚‚‚‚‚ƒ‚ƒ„„„ƒƒƒ„„„…‡‡†‰Šˆ‰‹ŒŒ‹‹�Ž�ŽŽ�‘�����‹ŒŽ��Ž�Ž�����‰„ƒƒ„„ƒƒ„ƒƒƒƒ„„„„ƒƒ„ƒ„ƒ„…„€�‚�‚‚‚‚‚ƒƒ„ƒ„„„ƒ„„ƒƒ„„„„„††ˆ‡‡‰‹Œ‹‹Œ����ŽŽ�ŒŒŒŽŽ‹Œ�‘‘Ž�ŽŽŽ���ˆƒ„ƒ„ƒƒƒ„ƒƒ„ƒ„„„„ƒƒ„„„„ƒ„…€����‚‚ƒƒƒƒƒƒƒ„„„„„„„„„„„„…ˆˆ‡‡‰‹‹‹‹Œ�Ž�Ž��‹‹‹ŒŽ����‘’���Œ‹Š�ކƒ„ƒƒƒƒƒ„ƒƒ‚ƒƒƒƒ„ƒ„„ƒ„„„„ƒ€�‚‚ƒ„ƒ„„ƒ„„„„„„„„„„„…„„„„†��Œ‰ŠŠ‹ŒŒ�ŽŽŽŽŽŽ���Ž�Ž�‘‘‘’����‹ŠŒŒ…ƒ„„ƒ„„ƒƒƒƒƒƒ„„ƒ„„„ƒƒƒƒ„„ƒ�‚ƒƒ„„ƒƒƒƒ„ƒ„„„„„„„„„…„„ƒƒ‹”’�‹ŠŠ‹Œ���ŽŽŽ��������‘’‘’“‘��ŽŽ‹Š‰„ƒ„„ƒ„ƒƒ„ƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ�ƒƒƒƒ„ƒ‚‚ƒƒƒƒ„„„„„„„„„„„ƒƒŽ—‘Ž�ŠŠŒ�������‘���‘‘�‘’‘‘’““�Œ‹ŒŒ‹‰„ƒ„„ƒ„ƒƒ„ƒƒƒ‚ƒƒƒƒ„„„ƒƒƒƒƒƒ�ƒ‚‚���‚‚‚ƒƒƒƒƒ„„…„…„„„„ƒƒŽ˜’�Ž‹Š�ŽŽ�‘‘’’’’’’’‘’’’‘’“•–“�ŒŒ��‰…„„„„„„ƒ„„„ƒ‚ƒ„‚ƒ„„„ƒ„ƒƒƒƒ�€€���‚‚‚ƒƒ„„‚�‚„„„„„„„ƒ„ƒ�—’��ŒŠŒŽŽ�‘’“’“““““’““’‘’•™˜˜’ŽŽŽŽŠ…„…„„„„ƒ„„„„ƒƒƒƒƒƒ„„ƒ„„„ƒƒ€€€���‚‚‚‚ƒ„„„‚‚‚‚ƒ„„„„„…„Š•’““ŒŠ‹���‘’“““””“’’’‘’’”™›š™”���Ž‹†‚„„„„„„„ƒƒ„„ƒ‚ƒƒƒƒ„„ƒ„„„ƒ€€���‚�‚‚‚ƒ„„…ƒ�‚��‚ƒ……………ˆ‘”•’�ŠŠ‹�Ž‘‘’’“””““’‘’”•—™››š”���ŽŒ‡„ƒ„„„…„ƒƒƒƒ„ƒƒ„‚ƒƒƒ„„ƒƒƒƒ€�����‚‚‚ƒ„„„…„�‚‚‚‚‚„„………†�””��‹‰‹ŒŽ�‘‘’’““““’’”•””•—˜—‘�‘‘�Œ‡……„ƒ„…„ƒƒ„„„ƒƒ„ƒƒƒƒƒ„„„„„€����‚ƒƒƒƒ„„„„„ƒ‚‚‚ƒƒ‚‚ƒ„……Š’“‘‘�ŠŠ‹Ž���‘‘’’“’’’•–“‘‘’“’�Ž‘‘�Œ‡………„ƒƒ„„„„„„„ƒƒƒƒƒƒƒƒƒ„„„€€����‚ƒƒ‚ƒƒƒƒƒ„‚�‚‚ƒ„‚‚‚„„†Ž‘‘’ŽŠ‰‹�Ž���‘�‘’’’‘’”“’‘‘�ŽŒŽ���‹†……………ƒƒ„„„„„„„ƒƒƒƒƒƒ‚‚„……€€����‚‚‚‚ƒƒƒƒ„ƒ‚�‚‚‚ƒ„„ƒ‚ƒ†ˆ�’“‘‹‰ŠŒ�Ž����‘‘�‘‘������Ž‹ŠŒ��Ž‹†……………†…ƒ„„„„„„ƒƒƒƒƒ‚ƒƒƒƒ„€€���‚‚ƒƒ‚ƒƒƒ„„ƒƒ‚�‚‚‚ƒ„„„„††‹‘”“�ˆŠŒ�Ž����������Ž�����‹‰‹‹ŒŒŠ…………†…††…ƒ„„„…„„„„ƒƒƒ‚ƒƒƒƒ€€���‚‚ƒƒƒ„ƒƒ„„„„ƒ��‚‚‚ƒ„„†‡ˆ‰�“”�ˆŠ‹Œ�������ŽŽŽŽ�Ž�Ž��‹ŠŠŠŠ‹‰†……………†††…„ƒ„…„„„„ƒ‚ƒƒƒƒƒƒ€€€�‚‚‚‚ƒƒƒƒƒƒ„„„„‚���‚‚ƒ…‡ˆ‰ŠŠŒ�Ž‰ŠŒŒŽ����ŽŽ�Œ�Ž�’“‘���Œ‹‹ŠŠˆ………†……††…††…„„„„„„ƒƒƒ„ƒƒƒƒ€€��‚��‚‚‚ƒƒƒ„ƒƒ„ƒƒ����‚„†ˆ‡‰Š‡ˆŒ�ЉŒ�Ž�‘�������“““””“’‘���‹Š†………†……………†††…„„„„„„ƒƒƒƒƒƒƒ€€��‚��‚‚‚‚ƒƒ„ƒƒƒƒƒ‚�€�‚„…‡ˆ‰Š‡‡‹�ЉŒ�Ž�’’�ŽŽ��‘“’�Ž�‘��’‘ŽŒŠ†………………………††††…„ƒ„„„ƒƒƒƒ„ƒƒ€��‚‚�‚‚‚‚‚ƒƒƒƒƒƒ„ƒ„ƒ���ƒ…†‡‰‰ˆ‡ŠŽ‹Š‹�Ž�’“’���’•˜—“�����”���І………†…†……………††††…„„„„ƒ„ƒ„„„€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„‚�‚ƒ…††ˆˆˆˆŠŽ�‹Œ�Ž��“’‘��“˜›œ›š˜–••“ŽŒ�Š…††††††††…††…†††††……„„„„……„€€�‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ„„ƒ„‚��‚ƒ„…††‡‹Ž�ŽŽŽ�ŽŽ�’’“”•”•–˜šœ��œ™’��Œ‰†††††‡‡‡†††……†††††††„„„„……ƒ€��‚‚‚‚‚‚ƒƒƒ‚ƒƒƒƒ„„ƒƒƒ‚�‚ƒ„††††�š�Ž���Ž���’•—™˜”‘‘“–˜˜—”ŽŽ�Žˆ†††††‡†‡††††††…††††‡†„„„……„€���‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒ„ƒƒ‚��‚ƒ„…„„’¥™Ž‘“’‘��‘‘”—š™–’������ŽŽ‘”އ†††††††††‡‡‡‡††‡†††‡†…„„„…„€��‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„ƒƒ‚���‚‚‚‚“«¢’’”””’‘��’–˜™™–“’������“”Œ††…………†††††‡‡‡‡‡‡‡††††††„„„„���‚��ƒƒ‚ƒƒƒƒ„„ƒƒƒƒƒ„„„ƒ�������•®ª™’”––•“’‘‘”•—šš˜—•“’“•–•’Š…†††…†††††††‡‡‡‡‡‡†††‡‡‡††„„���‚‚‚ƒ„‚ƒƒƒƒ„ƒƒƒƒƒ„„„„„ƒ�����’¯¯¤””———–”‘‘‘’•˜™šššš™™š—“Žˆ††††…†††††‡††‡‡‡‡‡‡‡†‡†‡‡‡‡…€��‚ƒƒƒƒ‚‚‚ƒƒƒ„ƒƒƒ„„„„ƒƒ„�����Š«°¬�“˜™™™–“’��‘”–˜™›š™™š–�Ї†††††……††††‡††‡‡‡‡‡‡‡††‡‡‡‡‡€��‚ƒ‚ƒƒƒƒƒƒƒƒ„ƒƒƒ„ƒƒƒƒ„„ƒ�����„¡°¬ª›˜š™›š—“‘�Ž�’•˜™——˜—’Œˆ‡‡†‡‡‡‡†††…†‡‡‡‡‡‡‡‡ˆˆ‡†‡‡‡ˆ‡€�‚‚ƒ‚‚ƒƒƒƒƒƒƒ„„ƒ„„„„ƒƒ„„„‚����€•¬«©¨ ›š›œ™–“�Ž��‘”•”””’�‹�Ї‡†‡‡†‡‡†‡‡‡‡‡ˆ‡‡‡‡‡‡‡‡†‡‡ˆ‡€�‚‚ƒƒƒƒ„ƒƒƒ„ƒ„„ƒ„„„„„„„„„ƒ‚���~‡¢¬§£§Ÿ™››š˜–’�Ž�Ž�����ŽŠ’ œŽ‡‡‡‡‡‡‡†‡‡ˆ‡ˆ‡‡‡‡‡‡‡†‡‡‡‡ˆ‡€�‚‚ƒƒƒƒƒƒƒƒ„ƒ„„ƒƒ„„„„ƒ„„„„‚��€|~‘¨©£¡¡ššš™˜–”’�ŽŽŽŽ�Ž��‹—¥¨£“ˆ‡††‡‡‡‡‡‡‡ˆ‡‡‡‡‡‡†‡ˆˆˆˆˆˆ€‚ƒƒƒƒ‚ƒƒƒƒƒ„ƒ„„ƒ„„„ƒ„„„„„„ƒ‚€}{{‘£¥ŸŸž˜™˜—–”“‘������ŽŽ‹–¤§ª§—‰†‡†‡‡†‡‡‡‡‡‡‡‡‡†††‡ˆ‡‰ˆ‡€�‚‚ƒƒ‚ƒƒƒƒƒƒƒ„„„„„„ƒƒ„„„„„„‚}{{{|}ŠšŸŸŸœ———–““’‘������Œ‹•¢¤ª­©˜ˆ†††‡†††‡‡‡ˆˆ‡ˆ‡‡ˆ‡ˆˆ‰ˆ†€�ƒƒƒƒƒƒƒƒƒƒ„ƒ„ƒ„„„ƒ„„„„„„„„€{{{{{{|„‘œ�Ÿœ–•••”“’’‘��Ž��Œ“ ¥ª¬­¦Žƒ†‡‡††‡††‡ˆˆ‡ˆˆ‡ˆˆˆˆˆ‡‡‚ƒƒƒƒƒƒ„„„ƒ„ƒ„„„„„„„„…„ƒƒ‚€}zz{{z{{|€‹—�Ÿš••••”“’‘���ŽŽŒ“Ÿ§««¯¯–‚ƒ„…†‡‡‡‡‡‡‡‡ˆˆˆˆˆ‰Šˆƒ…€‚ƒƒƒ„„„„…ƒƒ„„„…„„„„ƒ‚�€~~}}|{z{{{{{{{|ƒ�˜š”””••“’‘��ŽŽ��‘�¦ª®»·•……„ƒ…†‡‡‡‡ˆˆ‰‰‡…‡�—��|€€‚ƒƒƒ„ƒ„„„„„„„„„…„ƒ‚}|||{|||{{{z{{zz{z{|�‡ˆŒ�“”“’����ŽŽ�’ž¥¬ºÂ¯Œ…††„ƒƒ‚…†‡…Ž™‘†�’ œŽŒ‘‘�‚ƒƒƒ„„„„„„„„„„ƒ‚€~}|}|{||{{||{zz{|{{{|{|}}}~ƒŠ�‘�������Œ�›¡¬³³Ÿ…†…†……„€€…„�ž“�“›�œœœ�š+×þùûþþýûüþþþþþýûþþþþþùîÞßááßÞááàßáåãÛ·˜žªÄØÚ×ÖÚÜÜÙØÙÚÜÙÜÜÜßÜÛÝÝÞÙÕÔ×Ûß×ɪ‘’“‘Œ�†vu‚ªÙàÞÞßÝÝÖÐÙÙÑÐÒÔÔÚËŠs‡„y€µÑÏÑÓÔÙ×ÔÖÕÑÎÒÑÉÀÀʳ‰‡¸ÛÒÔÕ×ÛØÒÏÎÏÌÊŸq†»ÌÏÒÏÎÑÊÆÒ»}~¹ÎÌËÁ¹ºÈµ|p¯ÅËÃ1ÆÁÓäÍÕ¹ÓϺøÆËзØÄÆîкÕíáàáááàßßâææÙº˜‘§¼ÍÓÓÔÒÕÙÚØ×ÙØÚÜÚÛÜÝÞÞÝÞßÜ×ÔÝßÕÁ¦˜““—š�vvy‡£ÊÝÞÝÝÛÚÙÜÇ¿ÙÓÎÑÐÑÑÌÓÅŒxˆ†v‚¸ÐÐÔÒÖÖÒÔÔÑÎÐÐÊÄÈͼ¡…‡½ÙÓÔÖÙ×ÓÐÎÎÇɸˆqйÍÑÑÏÏÍÉÍЩv�ÄÐËÿ½ÇÄœp~¶Ï¼0±«Ä­¹ˆ¿Ãгް²‡Ê°Š»Ë¦´çãàâàÞßâäâÔº�’ž³ÍÙÛ×ÔÔÕ×ÚÑÎÙÙÔÚÜÛÜÛÜÜÝØ×ÙÚÝÛÓ» ’��—˜Š{sx‘³ÑßâàÜÛÛÛÛÛÛÖÕÚÒÑÑÐÐÑÌÑÒºˆwŠ�k~´ÐÑÕÖ×ÓÒÓÒÏÏÌÌÎÍ、{‡ÂÚÑÔØØØÒÎÎÌÍËÀ’q’ÃÐÏÎÍÎÌÊÏÏœq–ÌÑÈÆÂÊɱŠe‡Ç»-Öݦµ¾ÄžÌѰ¥­Ä¾œÑ˯¢åÏ¡ÐåßÞÝâåÝѸ�š¦½ÕÚÙ×ÈÈÖÖØÛÙÍÐÛØÖÚÚÛÛÙÜÖÓÕØÝÜͱ–ŠŠ—�“‡{w�™¿×áãÞÛÚÜÜÜÝÝÜÚÛÚ×ÓÒÒÏÐÑÑз²º…u‡‚q€¯ÉÎÓÖÕÕÕÑÒÓÌËÐÍÏÆ¿À�w‰ÆØÓרØÖÏÌÐÐÉÏÊ›z�ÄÅÊÌÍÆËÎÒÊ’p¤ÒÍÄÅÍ̹®�i”¹(¶Ú¼ÙçÑÎÝáããâàÒÝâæÚåÛÕàÞÝáåàͳ š©ÄÖÔÔÓÕÕÄÊÕÖØÚØØØØ×ÚØÕÚÛÚ×ÓØàÛɬ‘…‹—™‘�ut…§ÇÚââßÛßÞÝÞÝÝÜÚØÛÛÛÞÝßàßßÞÛØÉ¿ÐÀ†s…†u~®ÌÏÓÓÕ×ÔÒÔÎËÉËÓȾļ–xŽÊÖÑÖÕ×ÔÐÐÏÉÉÐÖxŸ¼ÇÍÎËËÐÏÔɉp«ÐÊÉÏÑÆ¾ºˆo”‡Å±½ÛåÜÑáæäâãããßàáæàÞåãáæá̬™˜•·ÖÛÖÒÒÓÖØ××ÕÙ×Ô×ÚÚ×ÖØØÙÙ×ÛÛÛצ‘„…“œ’rv�²ÏÙÙÜÚ×ÍØØÙÝÝÛÝÞÞàäçéëëììíììëëçåÞßÌ�m€‹~„²ÐÑÒÕÔÕÔÎÏÎÇÏÕÇÁÁɘt�ÆÕÒÔÖÕÖÒÑÏÍÊÈ¿ˆu ÃËÍÎÊËÐÎ×Àys³ÐÌÏÐǼ¾¯}j}­ÄØÏÖÜáàÝÜÛÙÙÛÝÛÛ×ÖÞââÝË®›š¤­½ÖÚÙר×ÙÙÙÚÖÖØÙ××ÙÛÚØÙÖ×ÛÝÝ϶žŽ‹Ž—�~{u~š¾×áß×ÔÙÝÒÅÔÍØÞÝàäçéëìììììëëëëëëìíìëèíÙšx€Š�…²ÑÒÖÒÒÕÍÐÐÏÔÕÌÅÇÊÊ»�s�É×ÓÖÒÔÔÑÐÍÏÈȹ�x²ÎÎÌÊÌÍËÎÖ°o{ºÍÎÏǽº·¡y!u®ÝÞÛáâáááàÝÜÝÞÞÝÝàãäÕ¾­››ª½ËÏÙØÔÛÝÛÙÙØÙÙרÛÝÙÖ×רÖ×ÕÙÛÊ­’‡‰’—Œ}po†£ÅÙÝÝÙ×ÚÛÛÜÛÜÜÛßãçêëììëëëëëêêëëëëêëëëëìëðèÀ—†…€‚®ÐÔÒÔØÓÆÉÒÎÎÌÈÌÆ¼¼±Šr”ÎÖÓÔÓÔÑÏÏÎÍËκ{„ÃÒÌÌÎÌÌÍÐÒ¦k„ÂÐÏʾ¾¸º¢}ÌÞÞââààááÜÙÜÝÛÜßãáÒ¸��š°ÅËÌÑÖÖÙÛÝÜÚÙÕÕÒÓ×ÙÚ×ÕÖÕÕÖÜÛÒÁ¨‘ƒˆŽ—ˆunrްÅÖá×ÏØÛÜÛ×ÚÜÞßáçèéììëëëëëëëëëëëìëëììììëëëéîóã¼”…~©ÎÑÓÙÖÈÊÓÎËÊÉÍ̺¾²ŠtœÒ×ÓÔÖÒÏÎËÏÍÊЬu’ÇÍÌÎÍÍÍÍÑÒši–ËÒËÃÇ¿¾°‰ÛàßßáâáßÜÚÞÜÛÞáÞʰ›”Ÿ¬½ÑÓÎÍÍÔØÛÜÛÙÖÔרÓÔØÙÔÓÔÔØÛÙÒºŸŽ‰Œ”™ˆxmw“³ÍÞÒÒ××ÛÝÜÜÜÛÝßáåéëìëìëëëëìëëëììëëëëëëìëëëìíìèéðñتˆ|{©ÐÑ×ÔÐÓÔÓÐËÌÍÍËÅÁ°‡qœÑÔÑÕÖÓÑÐÏËÊÉ̦w—ÄÊÍÎÍÌÍÌÓÍ‘oŸÍÑËȾ¾­‡ØáßààßÞÜÙÚÒÑáÝʬ”‘š¯ÇÐÓÔÌÊÍÑ×ÚÛÜØ××ÖÓÓ×ÖÚÙÕÐÙÜÙ˲šŽŠ�—‘†wn|ž¿ÐÔÔÙרÜÞÝßÝÛÜÞâçêììëëììëëëìëëëëìëëëëëëëìëëëìììëêçëò縋|~ªÑÔÑÊÑÕÓÓÎÌÌÉÊÈÀ¼À©€o ÔÔÒÕ××ÓÎÌÌÌÊÉœt™ÄÌÏÊÊÎÎÏ×ȇk§ÒÎÌÂÁ®‡ÙáÞÝßßÞÛʨ�¸Ê°œ�™§½ÐÐÏÖÔÉÌÍÑÔÚÝÜÜÙØÕÁÉÖÐÒÖÙÙÚɯš��“•‹~rq„¤ÅÚÞÙÔÖÛÝÜÔ×ßßÜÜáæêìëëêëëëêëìëëëëëëìëëëëëëìììììììëëêêéèîí¿‘|x¤ËÏÉÐÔÒÑÎÍÌÌÊÉÅÀ¿·¨†t©ÖÕÑÓÖÒÎÍÍÎËÊ‘sŸÄÍÇÈÎÍÒÒÖ¾{tµÒÏËŲ‡ÖßßäåâÞÅ«”u‘›”š«»ÀÈÒÑÒÙÑÍÏÎÒ×ÚÛÚÚÙÚÔÍÑÐÒ×ÚÑ앎”˜“„tmw�±ÎßßÚ×ÙÛÛÛÛÙÏÖÞÜÞäéëëìëëëëëëëëìëëëìëìììëëëëëëììììëëëëëêëêèìí¿ŒzvžÇÐÒÔÔÑÏÎÍÍÊÉÉÅ´¯·¬‡v¨ÕÒÎÒÒÏÏÍÍÏÌȾ�v¡Ç¿¿ÌÍÑÒÑÖ¹v{¾ÑÊÈ·†ØäáØ¼®«œ‹•�”¯¿ÌÔÏÅÐÑÔØÏÐÎÒÚÜÚÛÛØ××Õ×ÔÔÙÔ¼¡’�•�–„qo}›¾ÔßàÛÖÔÙÜÛÚÜÝØÚÝÝáçêëëëììëëëëëìëëìëëëëëììììëëëëëìëëëëëëëëëêêèìꮇ€wžÏ×ÔÖÖÑÏÐÎËÈÆÇ¸°´½³Šv¬ØÎÐÔÑÏÎÏÍÌÊÊÀ‰t©Á¾ÉÎÏÒÒÒØ°o‡ÆÌȸˆÞÒ®—‹ƒ€Œ��Œ ¼ÎÑÒÔÒÔÖÈÓÕÍÎÍÖÛÚÚÛÛÙÕÒÖÓÐɳ��‘–—–…ss‡¦ÆÛßÛ××ÙÚØÛÕÒÜÝÝÝÞÞäêìëëëëëëëëëëëìëëìììììììíìëìëìììììëëëëëëêêëêêéïÚ˜Š�t�ÐÕÓÖÓÐÑÏÌÊÃÃȾ»½»´†w±ÖÒÔÓÑÓÓÏÌÎÉȼƒz¢³ÅÌÍÑÓÒÕÖ¤p—ɼ­�²ž”š¥…jp¦¾ÂÓØÕÏÐÑÖØÑÑÖÏÌÉÐÙÙÚÛÚÕÖ××ÔÀ§‘ˆ�˜˜�{sz”·ÐÝÝÚØ×ÚÞÜÚÙÚÔÓÞÞÜÝàæëëëëëêëëëëëëëëìëëìììììììììëììëììëìëëëëëëêêêêêêèî¿…Š{mšÍÒÑÓÑÑÐÌÌÆÂÅÁÁ¿¸±¤†x²ÖÌÁÎÖÔÒÐÎÍÆËº}m’ÀËÍÐÑÒÑÕÒ›s¢½«s™¨ÆÔÒ§qƒº×ÚØÖÕÔÖÖ×ÒÓÚÒÌÏÌÕØØÚÚÖØÛÒ¼¡�ˆ‹•™‡qp€”µÙáÝÚרÝÜÛÔÕÚ××ÜÞ××Ûßçëëëëëëëëëìììëëëììëììììììëëëëììëìììììëëëëêêéêêéééìä˜xˆzošÌÓÎÐÑÑÌÊÊÈÄÂÁÿ°®¯}x·ÑÀÍÓÒÔÕÐÍÊÆÎµwv²ÈËÎÏÐÑÒ×Αuªµ~ÆÓÚÞÛͼÊÓÎÐÓ×ÔÓר×Ô×ÖÎÎÍÒÖÕÕÚÜÙÑ»ŸŒ‡Ž•�€qj|©ÊØÜÞÙÛÑÏÜØÚÚÍÒÛÛÛÛÛÓÕáçêêëëìëììëììëëëëëììììììëììëììììììììììëêêêêêêéêéééêéîÊ~yŠ}p–ÆÊÉÑÓÎËÉÈÄÁÃÅŹ»¢z|¼ÒËÑÓÔÖÔÏÍÈÉÓ­q‡½ÊÌÏÏÐÒÒØÉ‡{¡‡×ÛÒ×ÑÌÙÖÓÖÕÔÕÐÐÕ×ÕÕØÏËÍÎÒÔ×ÛÚÍ·žŒ‰’–Šrer‹©ÌÞßÝÙÚÝßÓÐÚרÙÙÚÜÝÜÛÛÝáèêêëëëëëìëëëëëëëëëëëëììììììììììììììììëëêêêééééééééêêêë¸qs‡~o’½ÆÎÓÐÍÉÅÇÁ¿ÄÉÊü³¦|½ÒÐÔÓÓÓÒÏÊÉÌÌ q“ÃÌÍÏÎÐÓÒØ¿€v…ÒÛÐÎÏÊÍÐ×ÕÓ××ÐÐ××ÐÖÕÊËËÏÕÚØÈ±šˆ†ŒŽ‚mdr’»ÕÞÝ×רÚÛÜÜÛÛÚÙÙÛÜÛÝÜÛÜÜáçéêêêëêëëëëëëëëìëëëëëëëìììëììëìììììììëëëêêêêééèéèééééééÞ¨on„}q‘ÁÍÌÐÐÍËÊÄ¿ÂÄÊȺ§¶®z…ÁÖÒÓÔÓÓÑÊÊËÌË¢sžÈÉÎÐÏÒÓÒÕ³z†ÖÛÐÍÊÁÌÓØÖÔÒÔÑÒÙÕÏÔÑËÍÐÕÓÀ¦“ŠˆŠˆ|j^ršÃÜà×ÑÓÚÝÜÚÙÚÚÙÙÚÙÚÜÛÝÔÔÝÛßæèéêêêêêëëëëëëëëëëêìëëëëìíìëììììììëëëìëëëêêêêéééééèèèèéçâÙ³vl‚~q�ÄÎËÏÏÏËÆÁ¿¾Ç˽¨¶Æ«w†ÃÕÑÒÓÔÓÌÌÐÌÌÌ™w¦ÈËÎÏÐÒÑÐÏ©‡ÖÕÐÑËÈÑÕÔÕÕÑÒÑÕ×ÓÔÓÐÐÐ̼¢�‰ŒŒ†wkiyœÉßßÙÖÕÔÛÕÒÛÛÛÛÚÙÚÚÛÚÙÜÝÔÔÜÝäèèéêêêëëêëëëëëëëìëëëëëëëìíìììììëëëëìëëëëëëêêéêééèéèèèèèèåØ×ºwh~~o�ÃÎÌÌÍÊÈÃÀÀÄÉÆ±¸ÈÆŸqˆÅÓÏÓÓÒÏÍÎÌÉËË’z±ÍÍÐÐÐÒÐμ‰ÔÓÑÐÍÏÕÙÔÓ×ÖÒÒÖÔÓÖÕÓDzœŽ‹‘“†uik�¤ÇÞßÙÕÖÙÚÛÜÕÔÛÜÙ×ÛÚÚÚÚÚÚÛÛÜÛÝäççèéêêêëëêêëêëëëëëëëëëëëëììëììëìììììëëëëëëëêêêéééééèèèèèèçÜÏÕ¹|h{|n‰¿ÐÊËÊÉÅÀÂÃÃɼÀÏǸ™rŽÉÕÒÕÔÓÏÏÏÍËÏÈ’¸ÑÍÏÑÒÒ˳ˆÒÕÑÍÌÎÖÖÓÕ×ÓÑÒÕÖÛׯ¬’ŠŠ��‚tkmƒ­ÎÜÝØÕÖÖÙÚÚÚÙÜÜÕÕÙ×ÚÛÚÛÚÛÜÛÛÛÜâæçèèéêêêêëêêêëëëêêêëëëëììëëëëëìììììììëëììëêêêêêéééééèèèèèèçãÕÌÔÂj~}o†¾ÒÉÇÈÇÆÄÁÃÊÄÈÓʹ¶šr’ÍÔÑÒÓÕÔÒÍÎÊÐÈ�„½ÏËÐÐÑ͵„ÎÑÍÌÍÓØÑÑÖÒÐÓØÚÔÄ©’††’•†ofr�¸ÈÕÞÖÓØÛÚ×ÚÛÛÚÚÚÚÖÖרÚÛÛÛÚÜÛÚÛÛàåæççèééêêêêêêëëëêêêëëëììììëëëìëìììììëìëëëëëëêêêëêééééééèèèèçäÛÎËÓ¿vf€~nƒ¿ÏÇÈÇÈÇÅÆÆÁÊÑÐĬ³�m•ËÐÍÒÖ×ÔÎÏÏÊÏËŒ‡¿ÌÍÎÎй„ÎÐÍÌÏ×ÕÑÒÒÏØÜÓ¸žŠ‚‡““‚ts€£ÀÑà×Ò××ÙÛÜÛÚÚÚÚÙÙÙÚÛÛרÚÚÚØØÜÜÛÛÝãæçèçèééééêêêêêêëêêëìëëëëëëëëëëëëììììììëëëëëëëëêêêééééééèèèèèåàÓÌÉͬzn{xg¸ÌÅÉÉÈÊÉ¿¸ÇÐÎÈ´±¬‘r˜ÏÒÐÔÖÕÒÓÔÏÊÔÆ‚ŠÁÎÍÍÏ·†ÑÒÎÍÐÔÐÑ×ÙØÏ·™…‡’‰{nn…«ÎßàÜÖ×ÙØÚÚÛÚÚÚÚÙØØÙÙÚÚÚÚÙÛÚÚØ×ÛÜÛÛÞâåæççèèééééêêêêêêêëëëêëëëëëëëëëìëììëëëëëëëëëêëëêéêêêééèèéèèèèæâØÍËÉÒÃixyl{®ÉÍÍÆËÎǺÂÒÐÆ¼²®¸’p ÍÑÒÒÒÔÕÕÒÐÎÔ³z�ÅÏÎиˆÏËÊÎÐÑÕÚÙÍ´•��ŠŒ~qlr�³ÒàÞÖÕ×ÚÛÙÙÚÙÛÖ×ÙÙØØÚÚÚÚÙÙÙÙÚÙÙÚÙ×ÖÙÜàâåææççèéééééêêêêêêêëêëëëëëëëëìëëëëìëëëëëëìëêêêêêêéêêéééèéèèèèæâÜÏÉËÌÕÅ�u}zix°ÈËÊÌÎÎÄÆÓÑÊÀº²¹´ŒsŸÎÓÐÒÔÔÖÓÔÓÍͯ}–ÆÎз…ÄÃÇÐØÚÕÀ¦‘�ƒ‹ˆxhf{�¿×àÞÙÕ×ÚÚÚÜÛÜÛÚÚØÙÙÙÙØÙÙÙØØÙÚÚÙØØ×ÖÖØÙßääææåçççèéééêêêêêêêëëëëëëëëìëëëëëëëììëëìëëëëëëêêêêééêééééèèèèçæãàÕÊÌÌÊÖÑ–mvwly¨ÈÌÌËÍÈËÓÏÊÅ¿·²·µ�x¨ÓÓÓÓÓÖÕÔÔÐÊЬz�ÊÒ¶x­¯ÌÜÖº—…‚†ˆ„ygg‚ªÏÞáÜ×ÖØÚÚÚÚÛÜÜÜÛÚÙÜÚÙÙÙÙØ×ÕרÙÚÚÙØÙÝßßÕÖßãäåååæççèééééêêêêêëëëëëëëëëììëëëëëëëëëëìììëëëëêêêéêêêééééééèèçæäáÚÎËÌÊÊÓÈ‹ovzt}¨ÅÊÍÐÎÍÔÑËü¸³®¸¶�{¯ÕÒÓÖÖ×ÖÖÖÏÊʤ~¥Ð¶s•–Áºœ‡€‰Ž…tjx’µÔßÞÚÕÔÙÛÙÙÛÚÙÚÛÛÚÚÚÙÙÖըרÚÙרØ×רÛßßÚȱ¶ÓÛáâäååææèèééééêêéêêêêëëëëìììëëìëëëììëëëëììììëëëëëëêêêééééééééèèçåâÝÑÊËÉËÌÔÊ‘oz‚v�«ÌÐÐÍÊÒÓÎŽ»½¶¶·°Š{²ÔÔÔÖרØÖÔÌÉË�z­º}²Ÿ‘Œˆ�Œ~to}¨ÊÜâÜÖÕ×ÙÙÚÚÙÚÜÚÚÚÜÝÚØÚÙ×ÖרÖ×ÚÙØÖÕÖÛÞÜϺ¡Š†¹×ÚââääåææççèèééêêêéêêëêëìëìììëëëìëìíìëììëëëëëëëëëëëêêêééééééèéèèèæãßÕÌËÊËÌÎÖÊ’o}‚y€¬ÍÐÊËÑÓÏËú¿¿¾µ³®‹�µÓÑÓÖÖ×ÕÓÏËÌÈ•�¥yÊ®�Œwgo�°ËãâÜÕÏØÙØÚÚÙØÚÜÜØÛÝÞÞÛÙÚØ×ØÙרØ×ÖÖÚÜÛÓÁª–Œ‰�©ÖÚÞâããäåææçççèèéêêêêëêëëëëëëëëììëëìëëììììëëëëëëëëëëêëêëêêêéééèèèèèæäàÙÎÌÉÊÇÇËÏÊ“kv{v~­ÓÎÌÒÓÏÊÆ¿¼½Á¼±¸¿‘ƒ¶ÖÔÒÕØÖÓÏÎËÎÆ�{qº²‚mlw“·ÕâßÙר×ÕÙÙÙÙÙØØÙÕ×ÙÛÜÜÙØÚÙÙ×ÖÖÖÕÔÖÜÞÚÆ®šŽŠ“�¢ŸÁßÝàáããäåååçèèèééééêêêêêëìëëëëìììëìììëëììëëëëëëëìëëëëëêëêéêéééééèèèçäáÜÒÍÊÉÇÇÌÉÎÈŽhy‚v~¯ÐÍÐÕÑÊÉÆÂÂÄÀ³ºÍ¸ƒ‰ºÓÒÔØÖÓÏÎÌÊÎÀŒw£�w~�ÃÚÜÙ×ÖÙÜÚÚÚØÙÚÚÙ×ÙÙÔÖÙ×ÙÙ×ÖØÚÙ×ÔÓÖÙÛÚп¦ˆ„Œ™Ÿœ•‰�ËâßßáâããääåæçèèèéééêêêêêêëëëëììììëëëëìëììëìëëëëëëëëëëêêêêéêêééééèèèçäâÞÕÍËÊÉÊÈÌÍÓОru{nu¬ÐÏÑÓÍÊÉÄÀÀÁ¸¼È¿¡�„ºÔÑÕÖÔÐÐÏÍËдg‹Œ¥ÎÜÝÚÕÖÚÜÜÛÚÛÙØØÙÚØÕÙÚÚÙØÖØÙØØ××ÕÕÙÜÛÓï˜�‹‹–›–‰~vžÛßßàáâãâãååææçèèèéééééêêêëëììëììëëëëëìëììëìëëëëëëëëëêêêêééêéééééèèèçåãàÙÎÊËËÅÀËÆÈÖÓ pwuiz«ÎÑÑÒÏËÆÀ½¾»ÀÊÀ¬š~‹½ÔÑÓÓÑÒÐÍËË·nµÓÛÜØÖ×ÚÙÙÛÛÚÚÚÖØÙÙÙ××ÙÚÙÙÙÚÙÙØ×ÕÖÛÝ×ȯš�Œ“šš“ˆ€zwxx~½àÝßàááâããäååææçèèééééêêêëëëëëëëëììëëëììëëëëìëëêêëêëëêêêéééêéééééééèçæäàÛÏÊËÃÇÊË´±ÍÏÔ¢qswqt£ÏÐÊÈÍÌÅÿ¼ÂÌȯ –zŠÇÖÐÑÐÏÑÎÌ̶‡×ߨÓÖØÚÚÛÚÛÜÛÛØ×ÙÙÙÙרØÙÚÙÙÙ×Õ×ÜÞØË¹ �Š’��•Šwuurtyƒ¡ÓÞÞßàááâããäååææçèèèèééêêêêëëëëëëëìëëëëëêêêêëëëëêêêëëëëêéééééèéêéééééèæäâÝÔÎÌÅÉÍËľËÊÒÓ¥xsxpp¢Í¿®ÉÐÇÄÅÇÈÌι£¢›s‰ÈÔÐÑÏÐÐÎζ†Ñ×ÖÖרÙÛÝÝÜÚØÙÙÚÙØÚÙ×Ø×ØÚØÔÖÙÜÚÓ¾£‘‰Œ—�Ÿ—„wttrqt€”«ÈØÛÞÞßàáááãääääåææççèèéêéêëëëëëìëëêëêëëëëëìììììííìëëëêëëëëìëëêéééèéèèèèæåâàÔÉÍÍËÊËÏÎÊËÌÒÖ²{s}mr Â¿ÈÏÈÃÈÍÍÍÏÁ¯¦®˜o‰ÆÓÎÑÒÒÏй…ÓÙÕØØØÚÜÛÛÜØÐÖÚÙÕÖ×ÖרØÖÕÔÙÞÜÎ²š†…“œŸ—Š�xvuuvyŠ¥ÃÖßßÙÚÞÞßàáââãääääææçççèéêêêêëëëëëëëëëëìííííìêéèåäáßÝÜÜÛÛÛÛÝßáåçéëìëêëêéééçåãâÖÊÈÈÍËËËËÊÊÍËÍ×¶yuzpršÂÊÎÌÆÆÉÏÏÎÆ´¨ª­–p‰ÉÕÐÓÕÑѼ…ÔÚØÙÙÙÚÛØÚÛÚØØÙ×ÖÖÕÕÖÕÕØÛÛÓ¿§•Œ�™¡�‘†}yqsxŠ£ºÏÜßÜÚÐÒÝÞÞßááâãããäååæççèèèêéêêêêêêëëëííìëéæâÞÚÕÐÌÇÃÀ½¼»º»¼¼½¿ÁÃÄÆÊÎÓÙÝáæéêëêéèäáÛÐÇÆÌÎËÉÌËÉÎÍÊÎ×´|txrr�¾ÌÉÇÄÁÌÑÏȽ·´¨¤˜o�ÉÐÐÓÒÒ½…ÔÛØ×ØÚÚÚØÙÙÚÚÚÙ×ÙÖÒÔÙÚÛÙË·Ÿˆ‡–  ˜Œ�}|zwx‚—³ÅÙãÙÖ×ÖØ×ÙÞßÞàááâãäääåææççèéééééééêëìíìêæáÚÔÏÉÄÀ½º·´²°®­¬«¬®®¯°±±±±²²²²µ·¼ÃÊÒÙßäæçæáØÐÍËËÊÉÉÆÄÌÍÍÍÎ׸~oyww›ÃžÄÅÊÒÐÈÂǽ¯ª±›nˆÄÑÐÓÔ»†ÔÚØØ×ØÙÙÚÙÙØ×ØØÖÕÓÕÛÜÑ¿¬›”—š¡ž‘…}{yx|ˆ“ªÇÚàÒÔÖÎÔÚÙØØÛÞßÞàâââãäåååæçççèèèèêêìíìêæàÙÒËÆÁ¿½¹¹¹·´²¯«§£Ÿœ™˜˜—˜š™––𡦍©©¥¡¢£§¯¸ÀÈÐÕÙÛÛÚØÔÒÐËÿÅÊÍÐÍÎ׺�r{yw™¿¹ÃËÉÍÐÈÁÀ»·³²· v•ÌÔÐÔ»†ÔÚרÙÚÙÙÙØÙ×ÕÕÖØÚ×ÒdzŸ’”ž¤¡—‹�zxxwzЧÇÖÝßÛÖÔÕÔØÚÚÚÙØÜßßßàáâãäååæåææçèèêêëíìéåÝÕÎÈÂÀ½»¹¶²¬¦¡œ—‘Œ‡�|ywvtsrqrrstw|‚Š“˜™™›žžŸ ¡¥§®´»ÂÉÎÓ×ÙÙÔÍÊÊËÌÍÎÏ×½zixsn”­½ÉÊÌÎÌÁ¼À¿¶º¾Æ¦yœÏÓÓ½…Ó×ÕÖÚÜÛÚØ×ÖÕÖÛÞÛγœ�“˜Ÿ¥ž�ƒ~|{ws|—´ÍÛÞÚØØ××ÙÙÙÚÛÚÚÚØÝàßßàáâãääåæåæçééêëéæáÜÕÍÇÁ»·³®¨¡›–‘Œ†�|vpljigffddddbadedfit{}~}�Š“œ¢£¥¤££§ª®´¹½ÂÉÏÒÕÖÕÒÐÏÊÌÖ¶|ozoj‡·ÉÍÑÎÎÅÀÁÀ½ÄÂÄ¿—rœÎÔ¼†Ñ×רØÙÙÖÕ×ÚÛÚÒ®—Љ‘ž¡™�€{yxvz}“¾ØàÞÚÖÒ×ÛÚÚÙÙÙÚÛØÚÙÙÞààààâããååææèééèäáÜØÓÎÆ¾´ª¡›˜’Œˆ…‚�}{yvsld_]\\\[Z[\^]YZ\[\bospjcdjs~Š”œ¥«¬¬®±³´³°°³·¿ÇÎÓÖÕÓÐÍÔ¾�kwpl—ÈÎÏÒÏÆ¿Ã½¾ÄÁÄŶŒnœÒ½†ÒØÙÙÕÕÖØÚÜÕŰŸ•�‹”š˜�ˆƒzrsy†—®·ÊáÜØÖÓÙÚÚÚÙÚÚØÙÛØØ×ØÚßáááâäææçççåãßÚ×ÔÒËû°£—އƒƒ‚��ƒƒ€}xtpmjgbYOLJNTSMLLJLMMOMLXeihaVV_hlqy€‡’£®³¶¶¶¶³°­«­°´ºÃÊÒ×Ôǽ´wh|nl›ÊÍÏÎÇÃÆ¿¼ÈÅÉÊÁ´�t©½…Ò×ÒÕÚÜÜÕÆµ¥˜—š�˜‘�‰„|wvv|›¶ÆÚÜÚ×ÖÖØ×ÑØÜÚØÛÜÚÚÔÊÒÚÕÖÛßáããääãâàÞÚÕÑÏÏÎȼ® ’‡ƒ‚‚„……ƒƒ�~zuqmiedbcdaZXXZ]YSSSNMNNNKIPVVXXRRV\djpwzwƒž¯±²±±²°¯®®­­®²¶ºÁÐ͹ͼvduqm›ÉÐÌÆÇÊÄÀÇÇÌÍÅÁº”z˜…ÔÚÕÙÙÌ·¡•’—šž—Œ…�~wsy‹�£ÅÙáßÛØÕÒ×ÚØÙÚÚÛÙÙÚÙÛÛÔÌÖÜØ×ÝáââßÜÚØÕÐÌÌÎÑÏŲŸ‘‰†‚‚…‡‡†ƒ€}zuqnkhfffhkmoqrqqrpliikjjfb_]ZYXRPOJGJNVaipy{|Š ­¯±³´³²²°¯°°°²´´ºÊÍË׺td{vo”ÄÏÄÃÉÆÄÃÀÅÌÈÁº¸�p†ÐÐÅ»ª›•”–š—Ž†|wvw}ˆ—´ÏÔÙâÚÕÖÔ×××ÚÚÚÛÜÛÚÚÜÕÒÛÙÚÛÚÛØÙßàÛ×ÔÑÏÍÌÎÑÓ̽¥Ž~~…ˆˆ‡††„�~zuqmkihkllmoqtttuutvxxvspmmoonmkgc`\XSH>?HOU^eny~„�¥¯°³µµ¶µµ¶¶´³²¶·¶ÃÍÎÍÖ¿vc~ul‘ÄÉÁÅÁÃÊ¿½ÉÌô·®€�³š‘•˜š›–Œ„zwux…˜¯ÉÛâáßÙÔÔ×ÖØÚÙÙÚÚÚÚÚÚÚÚÚÙØÚÛÛÙÙÙØÚÛÕÒÐÎÍËÏÔÔǰ—„xwz„ŒŒˆ„‚€|xtpmkjjjlqsrrrrsttustvvuuusqnmnpppokhgd`[TPRXVW^epx€ˆ•¦¬¯´···¹ºº¹····¾ÇÍÐÐÎ׿wfzuj’Äļ»ÀÎÊÆÌÌÈ»¹²—n˜ŠŽ™˜Ž€{yxuu~‘«ÃÓÝßÚÙØ×ÚÖÖÙØÛÜÙÕרÚ×ÕÙÙÚÚÜÛÙÙÙÚÙÚÛÙÓÏÍÌÍÓÖϽ¥�|wz}€ƒˆ‡…�{vronmkjlmqssstttuutsqpomiggikmmnopnnoonlkgdcbbfeWYcju€†Ž ®´¸»¼½¼»»º»º¹ÁÊËÌÏÒÐÍÙÃ}h|yo–Ä¿·¾ÊÍÍÏÌÊÀÀ»œoŸš‹‚zxywtz�©¾ÎÝÞÛÚÖËÖÛÙÙÚÛÙÛÜÛÚÚ××ÛÚרØÕØÚØÙÒÓÚÛÚ×ÑÍÌÌÑÔÑ»™�xx}�‚}}ƒƒ‚{qooonnooqrrqqqstsplifdd`YTTWZ_cfjnqommonkjjhfgjkodPVeq{€ŠŸ®·º¼¿ÁÀ¾½½¼»ÀÊÍÌÎÐÑÑÐÎÓ¾€o†}rœÀº¾ÈÆËÐÎÍÄÀ£u�ˆzvtrw•²ÐààÝÖÔÖÙÛØÚÛÙÒØÜÛÚÛÚÚÜÛÖÔÛØ×ÙÕ×ÚØØØ×ÚÛÔÌÊÊÐÖÒ¿¢~pw~�‚}~~}{}~~zplnppqssspnpqoljga^ZVTQOLMNRVZ\`djmomlllkjlljknpsuZK[jw‰œ«´¹½ÁÂÁÁÀ¾ÀÇÉËÍËËÐÑÐÑÏÈË»…s�|s�Ÿ³ÈÈÉÏÑÒËÄÅ«h„usx�‰¡½ÖàÕÑ×××ÙÙÙÛÝÜÚÛÚÚÚÛÙØÙÚÚÛ×Õ×ÕØÚÛÚÕÑÙÛÚÙÑÊÈÌÓÖŧ‘}oy€~||}}yssxzwpkpstuttpkmolfa`\WSPMGDGJMOSXZZ\_eglnmlklllmllnoqto\[eu��ž«³¸½¿¾¾¿¾ÂÉÎÍÌÍËÈÍÑÐÏÐÎÈÍĆl~vp}¦ÅÉÍÎÑÑÍÊÈ«_x|—­ÀÐÛÞÚÖÍÒÙÙÚÙØÚÚÙÛÙÛÜÜÚÛÛØÙÚÙÚÚÚ×רÙÚÛÖÎÒØÖÏÈÉÍÓ̲”…Œ„u{}~~}|{wrmkkmommptuvvusomlfa]\[YXZ[ZXTTVWTUZ[[\`dfjmnnlnpoookhfdgnlgjvƒ‘¢¬²µ¶º¿½¼ÃÊÊÊÇÉÍÍÌËÎÏÍÎÏÏÌÕÇŒo{~v’¿ÇËÍÐÑÎË̱o©ÀØààÞÚÕÕ×ÛÜÙØØØÙÜÚÚÛÚÛÚÚÚÚÛÙÚÙÙÛ×ÓØ×ØÚØØÚÕÑÖÌÇÌÏÒÕw‚‘”ƒx|}}}|xqkhfdcfilosuuvusqpmfcccdghkmnornhgec`^]__`eiiknnnprrqnha^ZY_lqr}‰—¦®°¯´·¯ºÉÈÉÊÉÅÄÌÌÍÌÌÏÍÍÍÐÏÍ×ËŒmzxu”ÁËÍÐÑÍÉηˆÚâÍÏ×ÕÖÙÙÚÚÙØ×ØÙÚÚÛÛÙÚÚÛÚÚÙÙØÙÙÙÙÖÓ×רØ×֨רÒÇËÒÓÁ�jq���xz{}{ytkeca[V_jmpstvvusqpniimpstuxxtqrtspommlheedbdgiknmnorsrnfc_XOO\oxƒ’¡­®®³±�~Œ¾ÍÇÈÉËÉÉÈËÍËÍÍÍÍÏÎÍËÓȉgyzo’ÃÐÏÑÍÇ͹ˆÕÖÁÌÚØØÙÙÙØÙØØ×ÙÚÙÛÚרÚÕÖÚØØ×ØØÖÓרÕÖÕÓÖ×Ö×ÖÎÊÎÏÄ–qhy‹uyzyzvmd`^UKLVemprtvuttqpomqtuy{yxxvsrqrpnoooonmkjighiknnnnpssmfc_XPIJ_}� ®²¯­�ŒqkƒµËÇÆËÊÈÇÊÌÌÊÊÊÍÍÌÎÍÊÔÊ‹k€xk–ÈÎÐÐÅÊ»†ÒÖÑÖÚØØÙÙÙØÙÚÓÓ×ÖØÛÚÙÚÚÓÔØÖÖ××ÖÔÒÖ×ÖÕÔÕØÒÒÕÑÍÏÏÈ¢}wgguyy{yupg_[WM@AQ^hmrtuuutsqqruxwy{{{vsrqpopnllmmnnnnnmkkknppoonqpkgcb]UKHSt™­²´»»ˆh{‚xk|®ÈÆÇÈÇÈÉÊËÊÊÊÎÍÌÍÍËÌÓÉŽm|yt™ÇÏÍÈʺ†ÒØØÙÙ××ÙÙ×ØÙØÑÓÖÓØÙØÙÚÔÖÖÔÒÕÙ×Ö××ÖÖÓÒÖÙÙÒÔ×ÐÍÑÎ¹Ž‚zgdq{zyumbZXQC9:LZbkqstuttusstw{{{|}}zsqpolllkgefikmnppmklmnpomnnmmjhhhbYNHJe™²¶ÂÌ͹“w|‚{mv¥ÃÆÆÈÊÎÍÊËÊÊÎÏÌÌÍÊÍÍÐÈ�m~�v�ÈÊÇϺ…ÓÙÕ×ØØØØ×ÖØØ×ØÙØÙÙØØØ×ÒÔ××ÔÕØØ×Ø×××ÒÒØØÖÕÔÕÑÌÏÆª�‰}mjs{yskc\WK;89CR_gnstuvvuuttx{}~~|ytrpmjgeda^\]`eilnonnonnnlllmlmkijjhd\SL`œÀËÎÐÑ×Μzu||nsžÄÊÈËÃÂËÊÊÊÌÍÌÌÍËÍÏÈÎÆ‹l�‚xŸÇÉͽ…ÕÚ×××ÙÙ×ר×ÕÖÙÙÙÙØ×Ø×Ö××רÙÖÖ×××רØ×ÕÔÒÓÖרÓÍÍ¿¨–�‡untyukb]\Q<9>AJUajostuvwwvvwz}~~~}ytqle^ZWTQQRUVW\bgjmnooooomlkmlllijmnmjieg¦¾´ÌÎÍÐÐ̯zp€st˜ÂÉÆµ¶ÉÉÊËÌÍÍÍËÈÍÐÌÈÍÆ”p|~w™Â˹‡ÕÙØ×Ö×ר××ØØØÖØØÙÙØ×Õ××ÕÕר×ÖÕÕÔÖÖÕÔÒÖØÛÛÑÄ®µÎ¿¬œ—�ypvuoe`cXD@AADKUblpstuwxxzz|}€|xtnf]XUSQMHEEJOQT[`eilmopoqpnmnnmmlnonlnpsr¢¾¬ÎÐÌÏÐÓØ¹‚o|‚rl�¿Ç¼ÂÇÇÉËËÍÍÌÌËÌÌÉÊÊÍÌŸt}~t‘¾¸…ÓÙØÖ××רØÙÙÙÙÚÙÕÖÖÕÙ×××ÖÖØ×Ö××ÕÒÓÖ×ÙÛ×ÍÀ± “†“¼Åµ§ž‘xvrqi`aM=?A?BKXckqtvvy{{{}€~|wrk`ZZ\YVURNH@>DKOTY]chlnpqqrqppqomnmiefkosyŸÐÐÌÍÎÑÐÎÓÖ¹‚m}�rk�¾ÆÄÇÄÇËÊËÍÍÍÎÌÇÆÈÌÈÌÓ©v|„v“±…ÑÖÔÔÔÕרØ×ÔÓÙÙØ×ÖÓÕØØ×ÖØ××ÖÔÔÔ×ÚÚ×ÑÆ¸¢•Ї‹Ž‘’¢¾Å¸¢Ž…�yplhZL=9@CADP[ckqvxz|~~€€~|xsj^[]]\ZZ[[VQH>D@=DKTY`lvy}€‚ƒ‚��€~zuoc^_`a`\VQNLC60126?JQV[afjntwz{|}p[OF?<=ETajvŸÊÎÍÍÏÐÏÏÐÐÎÍÕÔ¥v{„xh|¬ÃÅÈÈÉÍÎËÍÍÊÊËÍÎÌÍÏÎÒ«vy‡„ÐÙ×ØÚØ×ØÙÚÕÖÚÙ×ÖÔÓÒÔØÚ×ËÉ´¡”Šˆ‹‹•’ˆŠƒ{urnhgfdeadz›±¡‰ƒpQ<:??;?DKOU`nz�…‡ˆ‡ˆ‡†�|wtrppolljie`\XWVPICDO\a_^cknptwy~‚…€bHDA@FUZT`ˆÀÏÎÍÎÌÎÎÏÏÏÎÑÑÏÌÐÔµ€jx}psšÁÊÉËÌËÊÉÊÉÍÌÇÌÎÊÌÎÍÔ±†ÒÚØÖÖÔÓÔÔÖ×ÚÚÒȹ¦•Šˆ‰Œ�Ž‘��‰skfehjjjkklmnmnponnonpl_nƒ„€t`K>?ELOPW`p~ƒ†ˆ‰‰ˆ‰ˆ‡‚}~|zxtpnljhge`ZURSWXXY_hnpruy|€„……pJBE:-3CNeœÉÏÏÏÌÆÊËÏÏÏÐÐÐÍÏÑÑÜÇ‹kv~ro‘¾ÌËËÊÉËÌÉËÍÊÍÌÉÇÇÍϾ…Ï×ÕÓÔררÕÍñ£•�Œƒˆ™—––”Œ~smhfeiiillllmmmoppoopponnim~wrwztdNKSSPRXbt~…ˆˆˆ‰ˆ‰‹‹‰ˆ‡†…‚|yuqonkgb\WUUWWVY`gnpqvy|}…††^LLE879Di«ËÎÎÍÎËÅÈËÍÏÏÍÎÏÌÏÓÓÚÏœss{qlˆ¹ÍÉÊÉÉÌÍËÌÌÎÎÍËÊÍϺ„ÎÑÖÙÚÛÓõ§™’Ž’˜œ˜Šƒ�Œ…~xmgfhikllmnnlkmonmonoqqqpponp}rfkotwsleaWNQXhz�ˆŠŠŠ‰ŠŒŽŒŒ‹‹Š‡†ƒ�~yuokheb`_]^_``elrstwz}€�…‡ŠˆpYXWVSLQ{¶ÅÁÊÌÍÏËÍÍÎÎÎÎÎÒÍÌÒÓÎÔÓ«wr|wn…¶ÊËÉÉÌÎÌÊÌÎÎÎÍÐÎн†Ó×ÓÌ¿­œ�‰�”—�¢Ÿ›„ty{skjheflmppnmnnnnnprpopopsrqoopnuxiknquvwvpi`TRau‚‡Š‹��Œ�����Œ��Šˆ‡„|zuqonljjhhikotxzyz~~�‚�‚…ˆŒ‹|a^dhkad•ÂÆÀËÎÍÎÍÎÏÐÎÎÎÍÏÏÐÒÒÐÌÏÔ´|n|xm€«ÇÇÇÍÍÊÊÌÎÍÎÎÐÎ̼„ô ‘ŠŠ�—œ ¡›’Œ|qhfmmhhiillmmnmllljmnmnpppqrqpqpooooxsimku|vqwtqkggu‚‡ŒŒ‹ŒŒ�Ž�’’‘���ŽŠ‰‡‚€~{ywuusrstv{}|}}~�ƒƒ‚��…Š��‡lY\cmlt¬ÆÇÎÏÏÏÐÐÍÏÏÌÏÍÌÈËÑÒÒÐÒÐÐØ¹~lwxmx¢ÂÈÉËÉËÌÎÏÎÐÑÌÊ»o•‹Œ’š£¥œ“†{tols‚Œƒm\[abdfcdijjikkjmnmmnopqpoopnnoonzskno}ƒwlvwuutx�†Š��‹‰Š��’““”’‘‘�ŽŽ�‹ˆ†„ƒ�~~{z{|~~~~�ƒƒ�€€ƒ‹�’�|e^`ip‚µÈÇÏÎÎËÈËÍÍÊËÐÎÏÌÍÎÑÓÑÑÒÑÒÙÊkuxou�¾ÆÇÊËÊÌÎÎÐÐÎϺnœ ¥£��rlkq�œ¹ÌȾ°‡\PW[[Z\`cfhijjlllmnooppnopomlmm|vmqt‚ƒzv}|xzz|‚ˆŒŒŽ�‰ŠŽ�“””““•”’“”““��Ї†„‚‚€~€‚�€�€€�‚‚�€�…Œ“•“ˆtmkls…´ËÌÊÌÌ̾¾ÏÏÌÎÏÏÌÏÐÎÏÓÓÒÒÒÎÐÙÊ“puxor–½ÃÅÊËËÌÐÐÎÎÑ»w¥•„xqor}� ±ÀÈÍÙÑÁËÜÒ bJJLPTWZ]`cfffghijlmlllmnopnlk{znsx…‡…ˆ€y|}~~„ŠŒ�ŽŽŒŒŽ�“••”•˜˜˜˜˜—•“�ŽŒŠ‡†…„ƒ��‚ƒ�€€��„ƒ��‚ƒ‡‹�–•Ž~urrv‚«ÉÊÉËÌÌÊÌËÊÏÎÎÍÉÎÏÍÐÒÓÒÒ̾ÇÐ×Óœmsxps—½ÅÅÊÍÌÏÐÎÍѾbzopz‹Ÿ³ÄÑ××ÔÊÉÐÊ¿ÅÎÒÑ«nG>BIMPSVY]`abdfiklihkkjlopomx{pszˆ‹Ž‰eg|‚„‰Š‹���Œ��“””–˜š››š™—–•’‘�ŒŠˆ…„…ƒ�€�€€�‚ƒƒƒƒƒ†‰‹Ž•™“†{xy{�¢ÆÇÉËÍÌÏÒÈÆÏÏÐÍËÏÍËÎÑÏÐÏËÇÌÓÒØÒ›oqwpt•¸ÆÇÊÍÎÐÐÏѽb�œ´ÆÔÚÝÝÛ×ÔÒÏÏÕɾ¾ÄʪuR>9?FJMPTW[]_behjijkjjjlmons|rt|‰‹ŠqOcz„€‚†ˆŠŒ�ŒŒŽ‘•™›žž��œ›š˜˜—––”‘�Œ‡„†…„‚�€�€€~~€�„‰�‘™¥«¥’�}}„˜ÀÊÅÊÌÊÊÍÍÊÌÏÒÍÎÑÏÌËÎÎÏÎÏÐÏÐÓÑ×Ö¢omxupН¿ÄÉÌÎÐÏÏ»uÂÛàÞÜÛØÖÖÕÖÕÔØÑÁÀÂÿº½½¯‰`C58?EIMPQVX[_cffhhhiijjkkjxwv~‰‰z]Veuƒ‡‚€„†ˆ‰‹Š‹�—¡§©««¬¨¤£žš——™˜–•’ŽŠ‡………ƒ€~€~~}}€ƒˆ�š®»º³¤‰~~�‡�—¹ÊÉÊÊÊÌÍÉÉÎÏÎÅËÑÎÍÎÏÏÏÑÎÍÏÎÐÑÖÙ¬uo~vn‚§½ÄÇÊÏÏϺ|É×ÕÕÖÖØÙ×Ö×ÔÕÕÅÀÀ¿¾¾»½¹»­ŠkM938@EHJMPV]_aabcdfefhiiclxx~ˆ„kZaezŽ‹…€€‚„†‡ˆ‹”£¬­­®³µ³±ª£Ÿ›™š˜”‘ŽŒŠˆ…ƒ�}~~~|}€€„Š”§¸»µ°«•}�‡‹s~°ÌÉÇÉÉÉËËËÍÎÃÇÐÎÏÑÌÌÏÏÐÐÏÎÑÒÍÕÚµzlvsr†¦ÀÅÅËÏÑ»†ÔÒÑØÙÖÔÓÐÖÔÐÔʺ»¼¹¹Ã´³»´µ£ƒoXB327>CEJQUWZ\]_bdcdefgb_v{‡d]fm‡’Œ†€€�‚„†ˆŒš¦¨©«­°²²³¯¬ª¥Ÿ™—•‘Ž‹ˆ…ƒ�|}}{yy|‚‚ƒˆ“ ©¯²°¬¨™ƒ}€†ŒzeqžÃÉÅÈÊÊËÌÎÌÌÍÍÍÏÐÌÌÐÏÏÐÏÐÒÒÒÏÑØº‚ksxv�žÀÆÄÌÒ»ƒËÙרÕÑÒÐÍÔÑÑÔɽ»¼½»»²²½º¹´–|naN:018>CGJMRWY[^abbbcdcYm~}‡~ffr{Š�‹†���‚„…†�™¡¤¦¨«­¯­¯°²°­¦ž˜”‘�‹‡ƒ€€|}|xw{‚†…†ˆ�™Ÿ¡£©ª¦£™„}„‰ƒwddŒºËÉÈÇÊÎÍÉËÎÍÍÍÍÏÏÎÏÐÑÐÏÑÓÓÒÐÏ×È™ppwpuœÀÃÅκ‚ÌÜÙÙÔÏÖÖÒÏÒÕÓÁ»ÁÀ»°º½½½º´¥‹{siXD5/16=BGJNTVX[^^]`cd^ezyƒ�mn|{��‹‡ƒ€€‚„…†�–�£¦¦©««¨ª­¯¯®ª£š”�Œ‰†„€~€|xx~…Љ††Œ”™� ¢£ Ÿ™ƒy~�ˆwwja|®ÉÇÅÈËËËËËÍÏÏÎÍÌÌÍÎÐÎÍÐÒÐÐÑÏÏ×Ò¢olupl‹­¼Çµ†ÖÚÖ×ÖÕÖÖÔÐÔØÐ¼·¿ÀÂú°¸½»»³®Ÿ†}tj^N?3/29?CGKPSVYYZ]adb`s|‡|wvq†Ž‰„�‚ƒ…†‹“˜ ¤¥§¨§¤¦©ªª©§¢œ–�Ї†ƒ~�ƒ€ytvyzzz{~�ƒ‡�–››šœ—�v{€†{fmwp_n�ÂÊÅÈÌÍËÊÎÎÑÑÊÇÍÏÎÌÊÎÐÑÐÐÐÎÏÎÒÓ®whvneƒ²Ç²…ÕÛØ×ÕÕÔÔ××ÙÕÈÃÁÀÁÀ¿½²¸»¹¹¹¶±‘~zsmdWH90-3:ACHKOTVWZ^bb]e||„‰‹�…mu‹‹„‚‚�„†…‰�”™ž¢£¢¡¡¡¤¥¤£¢¡�–�‹‰†‚€�„„€ulmmgO?I[ltuz„�‘���{sy~…}a]hvsdh�ºÊÉÊËÊÈÉËÆÊÌÇÉÎÐÎÌÏÐÐÑÑÏÎÐÑÎÏÔ´|kysp‡°¶…ÔØÕÖÕÕÖÕÔØ×¿»ÇÅÄ¿¹½»¶·º¸¹º·£‡~zvogYLB6..4:>DIMPSUY\^_\q|u~Š”‘~o�‹„‚�‚†‡‡‹Ž�’•˜™™™™›�žžž�›˜“�‹‰…€~‚„ƒ‚xh`b[?.2;I^lqv}€€}qpx}…y`^\drvkd{ªÈÉÇÉÅÀÊÇÊÈÇÊËÍÎÏÎÏÏÏÑÐÏÐÐÎÌÍÔÁ‚hvsj~Ÿ†ÒÔÔ×רÙ××Ú͸ÀÇÄÅÄÄÀ¾¾¹µ¹¼¼½µ±™ƒ}xsnh_UK>2-.4;@CHMOSUV\\bxvr}Ž•‘‰ˆ‡„��ƒ…‡Š�Ž��Ž�‘“’’’“•••”‘�ŽŒ‡„�}}�ƒ…„€tcYTLEEE=?Ujoqsrtqjnv}„v^^[Y`qvobnžÄÇÄÇÆÊÐÍÈÍÌÊÉÌÌÎÏÏÍÏÐÎÎÍÍÏÐÐÖ‡jstmq†ÓÙÖØÙÙÚÙÚÚÎÈËÇÃÃÅÂÁ¿ÁÀ»¹½¿½·¶«�‚|wqnic\QE91,/7<8;d€„‡…�€zvx|zx{…”žŸš–—™™œ£¤ •†}‚�™ž�š•�Š…ƒ„‚€„…ƒ€}wqr{�vlq}uYRQNOONONKU^`][\]_`aa`^]]\Z[]Y_nxobx«ËÊÂÄÆÈÈÇÇÉËϼ†×ßÛØÍÉÎÑÐÐÒÎÌÉËÎÊÊËÌÍÉÈÉÈÈÈÉÉÈÉÈÅÅÀ»½½»°”‡…„€|zrsurnkhfc^WPF@>:;Z{‚†„€€{srxywv|Š˜Ÿž˜••—–˜š—‘��™  žžžš•”“‘�ˆ…„ˆˆ…ƒƒƒ~|‚ƒzss|mVVUSTROMPSQTSLHKU^___`b`_]ZZ\ZWYfsocl™ÂÉÅÃÅÅÅÈÅÅλ…×ÞØÕÌÎÐÑÅÇÒÑÑÌÊÍÌÎÍÊÊÉÉÈÈÈÇÉÉÉÉÉÆÅÅÀ½½¼½«�‹ˆ‚~{wvvuqolid]^XFAED2Eq~ƒ„�}toruusu€�šœ—��”•’“’Ž‘˜›Ÿ¡žšœ�™––“މ‡‡†„ƒƒ�~z|‚„{wvxgZ[XVVSTTVZSLJFDIV^_`_`cbba^\ZZ[YU_otgdˆ¶ÆÂÀÁÂÇÅÇ̹‡×ÝØÒËÏÐÐÈÈÒÓÎÎÑÎÎÐÍÊÉÊÈÅÊËÇÉÌÇÇÊÆ¿»½½½½¼¸œ‰‡„‚~{wurplieehZG@Vy]8]z�†…�}xqpstsqv‚‘™—‘����‘‘�”˜›��œ™˜™—’‘ŽŠ‡ƒ~zxvtsqqv~‚~xzu`ZYZ[WTVUUVUOJKPX_][ZWWZ\[]\\]\Z[YW]gunbw¦ÄÅÂÃÅÈÌ͹‡ÙÞØÍÌÐÑÒÓÎÎÏÌÍÏÐÎÍÎÍÎÍÆÇÈÁÄÇËÅÄÈȽ¶»¿½»º·¦‰†‡…„�~wturookkgZRB`�–XIq†‡„€{topttqpxˆ”–‘‹†ˆŽ‘•™šš�Ÿž›–�Ž�Œˆ„~|vrommmlou}�€}}n\ZXZ]YUVTSVVSQU[]YQOMNNOPLNX\]]]\\\YXbrqcl™ÄÊÃÃÇÉι†ØÞÓËÌÎÑÓÒÍÌÏÒÎÊÑÍËÎÌÌÌÊÌÈÂÆÈÉÅÇÉÊÄÃý»¼»µ­“ŠŒˆ†„vuz{uoljd^XDd€�H`y…Šˆƒ€zsopqqpuŠ�އ‚�…‰‘œžžœž¢ž—�‡‰Šƒ|xsqpmjjjiiow~�€�{e\[[[ZXVUTSWVU[]YTNIJMNOOKHJRQQY^[Z[]^Y_ntfdŒºÇÂÂÆÌ¸†ÖØÎÊÌÍÑÓÐÎÍËÐÎËÎËÍÍÍÌÌÍËÊÍËËÊÉÉÊÈÄÁÃÀ¾¾¼¹´©–�‹‡†�||{{vnjjga[Ps†~�]Qo‚Љ„‚|uopqpqx‚‹�„~|„Œ—£¨¢ žœš“‹ŠŠ†€yspnjgedfkry~€ƒ…wc]\]]\[YYXXWW[a]UPQQNOLNNJJKJINX^]]]]]\Z[fsnez©ÄÅÄ˺‡ÖÔÉÊËÏÒÔÒÏÍÉÌÏËÃÉÎÏÎÍÍËËËËÌÍÎËÊÉÈùÁ¿¾¿¿º¹¤ŽŒ‰‡ƒ€�~ytpmomdcd€Šw‘�Tg}ˆŠ„�€€|uqqpoqy„‰„{y~†Œ“ž¥¨¥ œ˜˜—’�Œ‡€zqjfc`bgms{}�Ž‹sa]]]]_^\\[[[[^\VTRQSROPQONONLJNXadb_]YY[YYewzfk–¼ÆÉ¹†ÖÕÈÉÉÎÒËÈÎËÍÎÍËÉÌÍÎÍÍÌÉÊÈÉËʾÃÊÉËËÆÁ¾ÀÀ¿¼º»´™‹‰…€€‚€~ysqsphfkƒ�x—jg{„Š…ƒ…ƒ�}tqrqmrz‚‚|wx�‹’•�¥¥¦¡š˜˜•‘�ŽŠ„�}{zwy|€‚~‚�Œn^]__]^^]]^^^]YUUTTSRSRTTPRSRPKKRZaa_^]ZY[\]csyfbƒ°Æµ†ÔÒÊËËËÒÇ¿ÊÇËÐËÌÍÊÍÍÌËÊËÉÆÈÊȹÀÉÉËËÉÁÁøµ·ºª�ˆƒ�‚„‚�€zuvslfg‚�}m•†k|�‡‰‡‰Š…‚|vvsoory~xvz‡�‘–œ£§¥Ÿ™–••––˜š���›——™›šŠ�ˆ„i\_``^^__^__[YWWXWWWUTSSRPQRSRMKO[bca_^[YXX_\Yjxncx¢°†ÓÎÊÐÑÎÏÑÎÏÍÂÃÅÈÌÎÊËÎËÈÊÊÇÈÉÊËÊÊËÊÉÆÄÄÃú³´¸¸ �‰‚‚…‚€~~}zwpkg}Ž‚h†�xxƒ†ŠŠŠ��‡€ywvsnow|}}yw}‰�‘—žŸ ¡žž�œœž¢§¨¦ œš›šš›•…€„|d[]_````_]]^^\[ZZ[[YWVUTUSOQSRMIP]a^_`_^ZWWXYYXarrioˆ„ÏÌËÑÔÓÒÓÒÏÎÉÀÂÈÌÈÇÍÐÎÊÊËÊÈÈÊÊËÊËÊÉÇÅÅÃÄÁ¿¼¾»½²—�ˆƒ„‚€}|~~{tomzŠƒii—“w�……†‡�‘Žƒ{xwupntz||xvw�ŠŽ‘“–—� ¢¢¢¡¢¢Ÿ ž™••–““•™Ž�†zb_^``__`_^^^_]\Z[][ZYWWWXYWWUSPNPQNLPW[]]]ZWUWWR[ktlcƒËÌËÍÒÒÒÑѽ»ÑÎÊËÊÅÉÏÏÎËÂÈËÊÊËÊÊËËËÊÇÅÅÆÄÀÀÂÀ¾¾»¥�ŽŠ‡ƒ€~||~|yspy†‚l[uœ‡}‡†�‚†Ž‘‰}wvtrmouxusssxƒˆ�“—œ¢¡¡£¢¢¡›˜—˜”�“–””–�†‰t_``_^^_^^_`_]]]]][ZZ[XUZZYYYUQTVQJFKRWZ\_c`ZXVVWWWaok†ÊËÎÎÐÑÎÐѾ¹ÊÏÐÌÈÍÍÎÍËËÄÉÊÌÍËÊÊËËÊÊÈÇÆÆÁ¼¼¼»ÀÀ½´™�ŽŠ„‚€~}}z{wrw……p`\…œƒ‡Œ…€‚ˆ‘Ž�ywtqmlnqsqnmnsz„ŒŽ“˜œžžžžŸžš˜”“��Ž�•’�‹‹‡jY[]^_^^^_`a`__^^^[]\]ZZ\\YTUVSRQNKIMUYZ\Z\a^[[Z[^ZU^lƒÉÌÌÔÓÐÐÌËÍÍËÌÏÍÌÐÏÎÍÌÌÍÍËÌÌÊËÌÊÉÉËÊÈÇÆÄ¾»¹»ÁÁ¾¿®”��Šˆƒ‚ƒ�~}zww‚†tc[i˜–‡�‹ƒ�ƒ‹�Š~xurmhhkqnihiou}†‰ŒŽŽ•˜™�š——™“ŽŒŠŠ‹ŽŒ‰ˆ‰€bWY\\\\]___^_a_]^^\]]]]_][ZWWXVRPNLJHHHIRXX[]]]\[]^\Z^€ÈÏÍÐÐÌÎÇÉÍÌËÌËÌÑÑÐÏÎÎÌÊËËÌËÌÎÌÊÉÉËËÉÉÇǽ»Á¿¾¾¼¸¡‘��ˆ…„„„‚�€{{ƒve_Y{ ’ˆ‰…‚€‚ŠŠƒzrpnhgfikifhmos|„ˆŠˆŒ�“˜”’“‘‘�Œ‡‰Œ‡‡‡††t]YZ[\ZZ\\\[[]]_```^\^][\\[ZZXUSSRQPOONLFLW[\]^^[Z\\]\W�ÉÏÒÉÈÎÎÍÌÍÊÊÎÍËÏÒÐÏÍËÎËÈËËËÌÍËËÌËÌËÉÈÈÆ¿ÀÄþ»¿»º±˜�Žˆ†‡†„„„ƒ€~ƒzf\Xb‰ –Œ„€��„†}okljgdchiggklouz�…†…‡‰ŠŒŽŠˆ‹�‹‰Š‰†…‚ƒ�iZ[YXYY[[YYXXXX[^_^]^][XYZXXYXVUSRRTVUSPMOY^^^^]]^_`][Y‚ÎÒÏÎÐÓÎÎÎÎÐÏÍÎÐÑÒÏÌÍÍÊÈËËÊËËËËËËÌÍÊÈÉÉÇÄÅþ¼¾¿¾¼¼¨’�ŠˆŒŠ†……„ƒ€�„|g\XWg†—š•ˆ�}{‚|ofeggedecacgjkpu{ƒ††ƒƒ‡‡�€†ˆŠŒˆ„€{‚}_WXVVUVYYYWVSRTUXXXYYYZZZZVUVVVUVVVTUVRMJP[`_^__`aaa_\ZƒÎÒÑÓÓÑÎÎÍÌÏÏÎÎÐÏÏÎÍÏÎÅÉÏÍÍÎÍÌËÊÉËÈÁÅÉÊÇÅÄÅþ¿½¿¿·›ŽŒŠ‹‹„…‡†„€}xk_XV]dp�‹‘ˆ}uxzyl]Z`ccefb^_`cgjptx}ƒ†ƒ~~yvx|€…ˆ‚yxx~pVVVVUUTUXXVWVQPQQQPRSXZXUUTQQSXXXXWSRXWRLR]^\]a`[Z]`_]]ƒÌÎÍÒÑÏÏÐÎÍÎÌÊËÍÏÌÊÍÍÏËÉÌÎÎËÌÌÌËÌÌÆÃÆÉÉÆÄÃÄÆÃÁ¿¿Á¿¿«’ŽŒŠ‹‡ˆ‰‡ƒ†|pxn`XWZ_`cb{‰€vquwr^SW]`aedb_\]befjotz‚~xuutsruyyuppsv`QSSSTVUTSPPRRNLLNSTSTWURQUWURTYXUVVTTVTQQY`^[[WVWTX__^X…ÑÑÍÒÒÐÑÑÐÐÎËÈÈÉÍÍÍÍÎÎÍÆÈÎÎÌÌËÌËÌÎËÊÅÆÈÄÃÅÃÅÄÀ¾ÀÁ¿º¡��‹‹‹ŒŠ‡‰“ŒrsqcWTV]^ba`}‡}rosuiSMV]^^adb]YY]`ejlsy|}xsqqljjmmmkjniOKPNMONOLJJHGHIJJNUVWXXWUXZ[\ZZYXXWUTVTQRY`][\YPOX\ZZ\[W„ÏÔÓÔÓÑÒÒÎÌÌËÍÎÉÉÍÏÎÍÌÎÊÉÌÎÏÎÌÌËÌÌËÊÈÉÇÆÆÆÅÄÄÁÁÂÁ¾¾²–‘�Œ‹ŒŠˆ——•ŽxodYTTYZ[fai…†xjjpn]NMU[Z[]`^ZWX[]achmpppplhddeddefihcXHFJKJFDBCFHGIKLJLPPPQQUYZZYYYXVXZYVTUTU\a_VW[YVXY^^[]WS‚ÍÔÕÕÑÐÐÊËÌÍÍÎÏÍÎÏÏÎÌËÍÌËËÊÉÍÎÊÉÌËÉÉËËÇÇÄÄÈÆÆÀ¿ÃÂÿ½º¦–’ŽŒŒ‰‹™˜‹›™}bYVVWZVZhaq‰ƒqahphZOMTYXWZ[ZXWWWY\`bdfeffbabaaaafaVYe^JBHGDBACDGHJKMNOPQQPQQVXWVSTVUTUVUUVWY`bZTUYYVXYYZYXQK„ÏÒÏÐÏÏÏÇÊÍÎÐÏÎÎÐÑÐÍÎÎËËÌÌÉÉËËÊÇÇËÉÇÉÊÇÃ»ÄÆÁÃÃÁÃÃÂÁÀ¼¶Ÿ’’��Љ‹™‹‰ž�tWRWVVWT_ebzˆ�k\dg_XOKRXYWVUUTSVWXZ[\]ab`_aa`]\]UIEKVffNAEHIJKGEGHHLPRRSVWUPOSTRSUZZY[[XWXZ\ab_[[YVUSWWXWTPO…ÏÑÌÍÍÐÑÎÌÏÏÏÑÑÎÏÎÌÍÏÏÍÌÌÊÌÈ¿ÈÌÉÈÌËÈÊÇÁÅÄÄÁ¾¿ÆÅÅÃÁÁ¾»«”’‘Œ’’‚…‘†‰›‹gROTTVST_bf}†�dT^]YVMIOUTTQOOPRTVUVVVY\ZYZXTSUJ;:@GMWghN>EKMMLLONNKMOOOOMJJKORSTWYZ[[[[^``bddfdc\XVVYXWVYZRƒÏÔÍÊËÎÐÎÍËÊÍÑÒÍÌÌÌÍÍËÌÌËÉÍÈÁÉÉÉËÉÇÆÉÆÃÆÇÆÆÃÃÂÀÆÅÃÂÁ¼º²œ‘�—¦¥Žs…�…‡��iQJOSQQU_`k�…|^PVUVUMHJOUTPPPNPUSPQRQRSPNNSdeA5:=BKS[jmO:?CEGIMPSPOMIGHIIIKOQRSSSSVXX\bccfggefd]YWYZWUSW\W„ÐÑÌËÉÈÇÇËÉÇÊÎÏÌÊÎÏÏÎÍÎÍËÈÍËÉÆÆËËÇÆÆÉÇÈÆÆÈÈÄÄÂÂÈÆÄÃÀ¼·²¨––¤­©ŸŒ‚‹�ƒƒ‚ymTEGOOPV]ar�€y[KKMRSNIHKPRSQOOPPMMMOOMNR]n~sC68>CIRZ`npP9?DHJKKJNSVYZ[TLLNPOOQSTUY\WVUTWTRSRTVX[`fc„ÎÏÌÊÇÊÊÌÉÅÍÎËËÌÌÌËÍÍÍÏÍÍÊËÊÊËËÉÉÊ̽¼ÊÈÈÇÇÄÀÁÅÈÇÆÈ¾­·½º¯¨¥£•—¦ª­£‘‡‹—Œpkfpym^LDGNUXn|ka]YNDCLQOKJKMLKMPUYZ]elpsw|pB039CJRY_fmptw‚¡”ubJ=AGKLJKOQUXXSIGJLMMKPQNPSRQOUXSPW^^`d_ZX\‚ÎÐÌÊÈÌËÌÌÌÐÏÍÎÊÈÌÎËÉÎÍÌÏÑÎÈÊËÌÉÊÉÉÂÂÈÆÉÇÅÄÄÆÊÉÆÅžª©©¦¥¦¥¤™’›œ££�†…“�}vifhmofVLEHO\~‚k[YYULILPPQOOOMPSVY]bhlotwzqC.28CLUY^jv|}b@]~ЇtQA>CJLKMORSSUSKLRPQQOOOQPU\[^]YXXY^^YZ`hZƒÍÌÉËÉÉÊÌÌÍËÊÊÍÌÉÍÍËÌÎÍËÌÏÌËËËËÊÇÄÇÍÉÅÅÈÉÇÇÇÈɽ±°¯®¬£�—𢡡›Š�‰„„‚ƒ‡��…vspddllmh[RJIbyfYXWUPMOSVSRPQSWX\aehlptxyrE-18DNUZj}‰Œ‡a:0EJJHIJKIJNUWT[n Ã­‹¡°¢€vªßÔËÚØÂ�ÇÉÃÃÄÈÊÉÈÄËÍËËÊÉÇÆÉÍÍÉËÌÊÉÌÌÆÄÄÀÀ¾¼½¸°­¬©©­´°£™•˜�¥§¡‘�‡‘¢˜�–˜¡¦“„wuy}zsrx~qg^ahnpw}‰’™Ÿ�zdMHKKOSVXZ]^adfhknqqmjN.,5CXw„ˆ‹ˆ†wSAADHLH<6Hh}�žŠ\DA=:CJP`et‡“|Pa|ÀéÀ¡§—wv±ÓË»¸»·¡‚ÈÇÃÃÆÊÌÍÌÅÉËÅÂÈÈÉËÌÌÍÉÇÈÉÆÈËÈÆÄÀ»¶³¯®°«®¯«­³°¤•�‘— §§¡’ŠŠ‚�—�ŒŒ˜ž£¬†{Œ•�…‚‹‘yu‚‹……„|ww‚�š£ª‘h\[\^abbdfhkosvz{xusY:17Sz����‘‹•{PLNQRSTL>?Nd�¤œreŽ’‰�’�·ÉÆ©“�ŠÄÙÁ»»²­½Æºµ·µ²³§‚ÇÆÆÄÁÇÉÊÉÉÉÉÄÃÉÉÊÊÊÉÈÉÈÈÈÈÊÇÁ¼·³¯¬©«¯®«­¯±¶µª›ŽŠ�›£¦§¤—xƒ‡zŒ�Šˆ�—~la\gg`ZU[^RNMX`ahplbZPIT[p{ZEDCCDDDFHHJNQSUURQP?,()C_c[MS_\ib?8:;;<=@=2+/=Usv_e’|ggdi{„�|ˆsm�€|}|ƒ~vy{{|}~vƒˆˆ‰‰ˆ‰‰‰‡ˆ‚yzzzyvptzxuvuvwxxyyzxvuppuvuy€~yyxvwxxw{xvsrvxxwvwuuysswxxutywqsttuxssustuqv†’““’”“““‘‘‡xzxusuwwuuvwvwwxyxxwtsstuvz}}{yyzxxxzzyxzyvrrwxwwvuuuxttxxwuvzvpsutvxstttvtu€‚„ƒƒ‚€��€�xurswxvuvvvwxvvxxutsstux||{yxyz{|}~~~~{vstwxxuuvtuxstwwvuuytqusswxrtutuv||||zxyzxvtstvwwwwvvwwvwwvurrsuvx|}{yxyz{}€€€€�ƒ�ztswxvuvutuxstwwvuvxtsutsxxqttsv}||{xxyvrsvwttvxxvuvwvvvsrrsuw{}|zyyzz|~€€€€€‚„~tsxwvvuutvxsuwvvuvysrtttzvrusu}|{wstsruwvtruwxxutuvutrrtuw{|{zyxyz|~€€€€€„€tsvwwuutsuwruwwuuwxrqstwztrtv€|wurrvwwvuvtswxxwutsrrstuy||{xxyyy{~€€€€€€€€€€€ƒ~sswxvuutsuvruvvvuxxrqtvxztrv~wutvxyxuuvvrtwxxurqqrtvy||zyxxxyz|€€€€€€€�‚zsswwvutssuvsuvwwuxxrruvyyru~zyvxxvuuvvtsvwvsqrstv{}|zxyxxyyy|€€€€€€€€€€€€€‚wtsvwvusstvvruwwwvyyquvvxwtzutvvvuvvustusqprty||{yyzyyyyyz|€€€€€€€€€�{vtrvwvtsttvwsvwwwvzwruuuwx€zuuxwvvvvtqqqqrsx}}zxxyyyyyzyy|€€€€€€€€€€~{xtrvwussttxvrvxwvvyvruuux~ytvwwvvvsppqrtw{|zxyyyyxxyzyyz€€€€€€€€}z{wtsvutstuvxuswxxwvzurtuv~xtwwwusqqrruy{{yxyyyxxyyyyyzz}€€€€xxzwtrtuuttvuvvsvxxxwzsqtw~vuxvsqpqsvz|zyyyzyxxxyxyyyyy{€€€€{vy{xtruvuuvutwurwxyxxxrrw|uvtrqstw{{zxyzzzyyxxxxxyzzxx}€€€€€€wuy|xtruwvwuttwusxzzyxwrv}urrsvz|{yxyxyy{zxxxxxyyxwuuz€€€€€€zvvy{wsquwwvtttwttyzzwwwt~rsw{}}zxxxyyyzzyxyxxxwuttuy€€€€€€€€€}wvvy{wtruxwvuttxttyzwuwy|v|}{zzzyxyxyyyyyxywvtttvvu}�€€€€€€€€xuvvy{xtrvxvvttvwruyxwux|{zzzzyxyyxyyyyxvttutuuux{€�€€€zvvvwy|xtruvwuvwvusuxwvw€{zz{{yyxxxxyxwutttuutvx{}}€~~}|zzyyyyz{|}~€|uvvwwy{yuruxuvxvtvstwwy|z{{zyyxwwxvsstuuuuw{|||{{~}|zxvutsrqqqrqrrstuvy{}}xwvvvvx|zuruuuxvtuvstwy{z{zyyyxusssstttwz{||{z{{}€€€~}zwtrqpnkkkiiiijijknpqqqrstuvwwwwwy|yvrsvwuttuvsty{z{yxwvsqrtsstwy}}{z{{{{{~€~}|yuqljjiihfegjklnooomknmihilopqrrstvwwy{yusuyvtttvwrw{zyvtssssttuy{||{z{{{{zz{~€~~}|zxurmfcabceghknprtsstutttrrohddfmrrsssrrsvx|yusvwuuuuvts~wussststvy{|}{zz{{{{{{zz{~}{zywsmgjib`bcgkprrqqrrqqqqqrssstqkeemprrstssrsvz~zutuuuvuusv|ttsttuxz{{{zzzzzzzz{zzzz{{yyvpjdabhkeejnrsqppqrrqpqopopqqqqrpjemqqsssttsuwyz}yvsstvvvsu|tsuw{|{{zz{z{{zzzzz{zzz{zywskdca``hpnpttsrqrrsuuuutsrqqqpppoppjlqrrssttuvwyxy{yussvwxtv|wz{|{zzz{{zz{{zzyyz{yzzywtqqicbabdmtssssqqstuwxyyywuusrrrrqqppmnqrrrstvvvvxxwy|yvstwwuv€|{{z{zzz{z{zzzzzyzzzyyywrosoecccipttsssrstvvvvwxyyxxvttsrssssspprrrssuwvwvxxxxy|yvstxvw€{z{z{zyy{{{zyzzzzyyzyxxsnomfddgmuvutssrstvvutttuvwxxwvutttttvvtrrsvwwttvwvwwxxxy|zurtuw€|zzzzzyzzzyyyyzzzyyzyxupppkefjqwyvttssstvvwutttuuwxxwvututtvvwwssvz{ywuuwvvwwxwwxzytrsw|zzzzzzzyzyyyyyyzyxxwutprrmglrwzxttttstuvwvuuuuwvuwxvvututtuuvwuvxxz|zwutvvvvxwwwwzyuqu{yzzzzzyxyyzzyyxwvuuvvvrrtpkpvyywtuttuuuuutuvwvwxwxywuuvvuttttuuwvwxz{ywutuvwwwwwwwzytt{zzzxyzyyyyyxwuuuvwwwvvusttqrxzzwtutuuuuttuuvwxy{zyy{yvutvvvusstwwvxxx{zwusvwwwwwwwwyxv{zzzyyyyxvuuuuvwwwvvvvvvvsssvyyzwuuuuuttstuuxxz{|{wxzxvttwxxxvrsvwwwwwxzzwusuwvvvwwvvxy{yyyxxvutuuwwwvvvwwvwwvvvttuuwyxvutututssttuvvvuvxwxxutttvyyzyttxwvwxwwwzzwvsvwwwwxwvvyzxxvuuuuuwvuuvvvwwwvwwwwvvrrstuuuvuuttssrrstssstuwxwvsstttxwzzuuwwwwxwwwxzzxvttvwxxwwvx~vuvuvuvvuvvvvwvvvwwwwwwvwuqsssttvwvttsrrqrrrrsstttuuttutttxvuxuuwwwwwwwwxwxzywttwwwwwvx}vvvuwwyzxvvwvwvvwvwwwwvvxuqsrsssvwutttsrrqqrrsssstttttuttuwzwwuuwwwwwwwvwxww{zvttvwwwvx}vwyz{zzyyxuxyyywvvvvvvvvwupsspqsuvusstsrqqrrrsssttttttutttuxxxvvwwwwwwwvwwvvy|ywttuvwwy~|}}|{zyxxwvvy{{yxwwvvvvvvvqsqostuvuttsrqppqrrssstttstvvttrruxwxuuwvvwwwvwwwvwy{zwtstvvy}|{{{zxwxwwvux{|{yyvvwvuvvsrppustvwuurponnoqrstttsstuvutrposwvyxtuvvwwvvwwwwwyyzzwtrtux}|zzzzwxwvvvtuyy{|{xwwwuuussrrtrsvwvurppoonoqrtttssuvttsqporvuxywttvwvvvwwvwwyxwzzwtrsw}{zz{ywywuuttuxyxy||ywwvvuttrssrsuwvvtrqqpppprsssssvuuussrqrutwwwwutuvvvwwvwxxxwxyyvtqu|z{{zwxxwwuuvvvyyyy{}|zxwwuustsrsuwvvvttsrrrrrsssrtvuvyxvutuuswwtvxvtuuvwwvwwxwwwxwywtt|{||zxxwwwwwvvtxzyyyy{|{zxvuuusqruwwvvvutsssssssssuvvwwwutvxurvwutuxwttvvvvvwwvwwwwwxwv€}|}|yxyyxwwwwvuvyzyxxxy|{yvuvvtrqswwvuuvtsttssssttuvvvwwtuy{wtvvuutuvxutuvvvvvvwwwwwvxy€~}}|yyyyywwvvvvuwzzyyxwxvvuutvusprvvvttutstssrqrtuuuuuvvuvyzyvvvuutttwxvttuuuvvwwwvvvux}||{yzzyxwwwvuvvvyzzyxxxusstuxxsqsvvvutttssrqppqstuutttuwwxyxxxvututttuwwuuvvvuvwvvvvuw}|{zyzzyxwwwvvvwuwyzzzxxutrrux{urstuvusttsspoqrstuutsstuwwwwwxwuuuutttutvwutuvuvvvuuutx€}|zy{{zzyxwwwwvvvvxzzzywtssruz}vssuvuusrrsronqstuvvvvvvwxyyvvxwuuuuuuutttuwvuuuvvvutttx€}|zz{{zzzxxxwvvwvvwz{zywvsssuz|xsstvuvtrqrqnnpstuxxwwxwwxz}wsxwuuuuututttttwwttuvvutttw€|{y{{{zyzxxxxwwwvvux{yyxwuttvxzzussuuvvsqrrompssrsuvvwwvw{}wswwttuuuuuuuttssvwusuvuuttw€}{z{{{zzyyxxxwwvvvvvxyyxwvttvvxzwrstuvwuqrrqopqppprsuvvvvxzwsvusttuuuuutttsstuvutuutssw}zz{{{zzyyxxxxxwvwvvwzyxwwvvvtz}xtsstuvvtqrqponnpqrsututtuwwuutsssttttuuuttttttvvutsssv€|z||z{{zyyyyxxxxvwwvvyzyxwvuus~„ztrssuuvurrrpmllnqstuuuuuuvvvusssssstttututttusruvusssv{z}|{{{zyyyxxxxxwwwvuwzzzywvvu~†~tqqrstuusrsroklmnpsstsuuuuuvussttssttttsttutttsstvusrv€{z||{zzyxyyxxxxxxwwwvvyzzzyyyv~‡„vppqrsttsrrrpnmllmnooprssuuvuttttstsssssssttttssstuurt{{}|{z{zxyyxxxxxxxxwvwwz{{zzzx~…ˆ}ppqpqstsrqrrqonmlllmpqrruvvuutttstssrsrsrrtttsttsrsut||}{zzyzzyxyxxxxxxxxwwvx{{{{{y}„ˆ‡voqporsssqrsrqpnmmmmpqqrtvvttttttssrssrsssssttttrqrrs|||zzzzzzyyyxxxxyxxwwwwwz||||z{ƒ‡Š‚rnppqrrsrrtssrqpoooprrruwuttttuutsstssssssssuttsrqqp€}|{z{zzzzyyyxxxxyxwxxxwvx{|||{{‚ˆ‰Š€tppqqrrrrsssrrqqppqrstvwustsstsstsstssssssrssssrrqq€}}{{{zzzyyyyyyxyxxxxxxwvwz|||||�‡ˆŠŠ‡zpqqrssrsssssrrrrsstuvvtsttttsssssssssssssssstsrqr€}|{{{zyzzyyyyyyyxxwxxxwvwx{}|}�…‡‰ŠŠ…soqrttsrsssssrssstuuzyutuuuttttssrsssssrrrsssrrqr€}{{{zzzzzyyxxyyyxxwxxxxwwwy||}‚‚€…ˆ‰ŠŠ~oprsutsssssssssstuyƒ„{vvvuttststssrsssrrsrrrrqqr€}z{{{zzzzzzyyyyyxxxxxxxxwvwz|„„ƒ�„‰ŠŠ‰znqsttttstsststutx‚‡‡wvvuuttttssrrrssssssrrqqr€}zz{{zzyzyyyxxxxyxxxxwwwwvvz€‚‚„ƒƒ‚ƒ‡Š‹†umstrststttttutw{~€…‰ˆwuuutttsrssrrssrsrrqqqpr|zz{zzzzzyyyxxxxyyxxwwxwwvv}ƒ„ƒƒƒƒ„„‚…‰‹‚rnssssssuuuttuwz}€…‰‹‡wruvtttsstsrsrrqrqqrqrqq€}{|{zzzzzyyzyyyxyyyywxyxx{}�„„…„„„„†„‚ƒ‡Š~nqstrrstttttuw{}†ˆˆ‰}sstuuussstttsrrrrrrpquu€}{{{zzyyyyyyyzzxxxxzz|~~‚‚ƒ„„„„…„„†……ƒ‚ƒ€roqsssttssstuw{~€…††ˆ~vuqtuutsttsssrstsnfjzƒ�€|{|{zzyxyyyxyyxwxy{�‚‚‚ƒƒ�‚ƒ„„„ƒ„………„……‚�}xtrrtsssssuvvz}~ƒ…ˆ†zuuuvtuwuussnejr~p[\owrp€|||{zzyxxyxxyyy{}�‚ƒ‚‚‚‚„ƒ�€ƒ„…†„ƒ„ƒ„„„…ƒ‚�ƒ�ztstuuuuvwxy}ƒ‰‰ƒyvvvwxw{{ytujZhrpbZ]_][^xjmhikjhgmkv„‚‚‚ƒƒ…†…………„„„„„ƒƒ„„„„††……„…„ƒƒƒƒ„„„ƒƒ„„„„…„ƒƒ„„„…†…„„„ƒ„…………………†…†„„††ˆ‡ƒ„sPQNQKMNOSUg†‚ƒƒ„……………………„„„„„„„………†………„ƒƒƒƒƒƒƒƒƒƒƒ„„ƒ„……„„ƒ„………†…„„ƒƒ„……†……†††††……††ˆ†ƒ}ststtustvuy„ƒ„……„„„……„„„„„ƒƒ„…………………„ƒƒƒ‚‚‚‚‚�€�€€‚‚ƒƒ„…„„ƒƒ„………†…„„ƒ„„……†…†…††…†„……‡ˆ…�ƒƒ‚‚‚‚ƒƒ‚ƒ„…………„ƒ„„„„ƒƒ„„„„…†…………„„ƒƒƒƒƒ‚‚���€€�€€€€���ƒ„„„ƒ„„„„…………„„„……†………††…†…„…†ˆˆ�‚‚‚‚ƒƒ„ƒ„………††„ƒƒƒ„„„„„„……†……………„„„ƒƒƒ‚���������€€�€�€�€‚„…ƒ„„„…„…†…„…„„………†…†††…†…„†‡†€��‚ƒ„………………„†…ƒƒƒ„…„„…………………„„„„ƒƒƒ‚‚�€�€€���������€���€€‚„„„„„„……††……„„„……†††††……†……††€�ƒƒ…†……„……„……„ƒƒƒ„………†…………„„ƒƒ„ƒƒƒ‚��€€���€��€������€�€�€�‚„„ƒƒ„„…†††……„„………††…†………†………�ƒ„„……………„„„……„ƒƒ„……†……„„„„„„ƒ„„ƒ‚‚�€�€�€€���€€�€�€��€€�€€€€ƒ„„„„„„…†††………………†††………„…†……�ƒƒ„……„„„„„„…„ƒƒ„…†………„ƒƒƒƒƒƒ„„ƒƒ‚����€��€€����€€€���€€�€€€€‚„„„„„„…††††………„„…†††…†…„…†…€�„……„„„„ƒ„„„„„…………„„ƒƒƒƒƒƒƒƒƒƒ‚‚����€€€€€€����€€€���€€€€€€€�ƒƒ„…„„……†…††……„„„…………†……„††€‚„…„ƒ„„„„„…†…………„ƒƒƒƒƒƒƒƒƒƒ‚ƒƒ‚���€€��€�€€€��€€€�€€€�€€€€€€€ƒ„„„„„„…††…††…„„„………†……………†€‚„„ƒƒƒ„ƒ„……†…„„ƒƒƒƒƒ‚ƒƒ„ƒƒ‚‚ƒ‚�€�€€�€€€€€€���€€��€���€€€€€€€�ƒƒƒ„„„…††…†…†…„„„„……†……………€ƒ…„ƒƒ„……………„ƒ‚ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚�€€€€€�€�€€€€�€�€€€�€���€€€€€€€€‚„„„„„……††……††…„„ƒ„„…………†„€„„ƒƒ„……………„‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ‚ƒƒ‚€€€€€€€€€€�€€���€��€€���€€�€€€€€�„ƒ„„„…………†…†‡†…„„ƒ„„……………�…„„……†…„ƒƒƒ‚ƒƒ‚‚‚‚ƒ‚ƒƒƒ‚ƒ‚ƒƒ‚€€€€�€€€€€�€���€€��€����€€�€€€€€ƒ„„ƒ„………„…„†‡‡†…„„ƒƒ„…††…‚…………„„ƒ‚‚‚‚‚‚‚‚‚ƒ‚ƒƒƒƒƒ‚‚ƒ„ƒ�€€€€�€€€€€�€�€€€€€��€€€€€�€€€€€€€‚„„„„„……„„„…‡‡‡‡…„ƒ‚ƒ„††„‚……„ƒ‚‚ƒƒƒ‚‚‚ƒ‚‚‚ƒ‚ƒƒƒƒ„„„„„�€€€€€€€�€€€�€€�€�������€€€�€€€€€€�„„„„„„„„„ƒ„††‡‡……„ƒ‚ƒ…††‚„ƒ‚‚‚‚‚ƒƒ‚ƒ‚‚‚‚‚ƒƒƒƒ„…„„„„‚€€€€€€�€€€€��������€��€�€€€��€€€€ƒ„…„ƒ„„„„„„…†††††„ƒƒ„„……��‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ‚ƒƒ„„„„„„ƒƒ�€€€€€€€�€€€€€�€€���€€€�€�€€€��€€€€‚„„„„ƒ„„„„………………††„ƒƒ„…„��‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„ƒ‚‚€€€€€€€�€€€€€€������‚‚ƒ‚ƒ‚‚��€€�€€�„ƒ„„„ƒ„ƒ„…„„…„„†‡†„„„„„€���‚‚‚‚‚‚‚‚‚„„„„„„„„ƒƒ‚‚‚�€€€€€€€€€€€€€€��‚ƒ……†‡‡‡ˆˆˆˆ‡‡††…ƒƒ�€�„„„„„„„ƒƒ„„„†…ƒ…†††„„„ƒ€�‚‚‚‚‚‚‚ƒƒ„„…„„„„„ƒ‚‚‚‚‚‚�€€€€€€€€€€��‚ƒ…‡ˆ‰‹Œ����ŽŽ����‹Š‰ˆˆ‡‡†……„„„„„ƒƒ„„„†…„…†††……„ƒ€�‚�‚‚ƒƒ„……„„†…„„ƒ‚�‚��‚‚��€€€€€�€�‚‚„†ŠŒŒ�Ž��‘���ŽŽ���ŽŽŒŒŽŽ�ŒŒŠ‰‰ˆ††…ƒƒƒ„„„…„ƒ„…†…†…„„€�‚‚ƒ„„……„„„„„‚ƒƒ‚‚‚‚‚‚‚‚‚€€€€��‚ƒ„‡ŠŽ‘“’’‘‘�����Ž���ŽŽŽŽ�ŒŽ�’‘�‹Š‰‰‰‰ˆ‡†…„„„„„ƒ„…………††…€‚ƒ„„…„„„„ƒ‚‚‚‚‚‚‚�‚�‚‚‚‚�€�‚‚ƒ„†‰�Ž�’““’�����‘‘‘‘’’’““’““‘ŽŽ�’�ŒŠŠ‰‰‰ˆˆˆˆ„ƒƒ„„„„……………‡†�ƒƒƒ„„„ƒ‚‚‚�‚‚‚‚‚‚‚‚‚‚‚�‚�‚ƒƒ„‡‹Ž‘’�Ž‘‘��ŽŽ�������‘‘‘’““””“’‘‘’‘‹‰Š‰‰ˆˆˆˆ†ƒ‚‚ƒ„ƒ„……„„…‡†�„ƒƒƒ‚‚���‚���‚‚‚‚‚‚‚‚‚��‚ƒ„†‰Ž‘’’’�Œ�Ž�Ž���Ž�����Ž���‘’““’’’’��ŒŠŠ‰ˆˆˆ‡†„„ƒƒƒƒƒ„„…„ƒ„†…�ƒ‚����‚‚����‚�‚‚‚‚‚‚‚‚‚ƒ„…‡ˆ�‘’’‘�Ž‹ŒŽŽŽ�Ž��Œ‹Š‹‹Œ����‘’’‘‘’���ŒŠŠˆ‰ˆ†…„„ƒƒƒ„ƒƒƒ„„„ƒƒ„…����‚��‚‚‚�‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†ˆˆŠ��‘�ŽŒŒ�Ž�ŽŽŽ����ŒŒŒ‹‹Œ�����‘‘‘��Ž�‹ŠŠŠˆ†…„„„„„„ƒƒƒƒ„„„„ƒ„„€�‚�‚��‚‚‚�‚‚‚ƒ‚‚‚‚‚‚‚ƒ„†ˆˆŠŽ���Œ‰‹�ŽŽ�ŽŽ���ŽŽŽŽŽ�ŒŒŒŒŽ���‘��ŽŒ‹ŠŠˆ‡„„„ƒ„„„„„ƒƒƒƒ„„„„„„„€�‚�‚��‚‚�‚‚‚‚‚‚��‚‚�‚‚„‡ˆˆŒŽŽŒŠ‡ˆŒ�ŽŽŽ���Œ�����ŽŽ�Œ�ŒŒ�����ŽŒ‹Š‰‡„ƒƒƒ„ƒ„„„ƒ„ƒƒ„ƒƒ„„„„„ƒ€�‚����‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ…‡‡‡‹Œ‹ˆˆ‡‰ŒŒ�ŽŽ�Œ��Ž�������Ž��Ž����ŽŒ‹‹‹ˆ„ƒƒƒƒƒƒ„„……„ƒƒ„ƒƒ„„„„„„€��‚‚‚�‚‚‚��‚‚‚‚ƒƒ„ƒƒ„ƒ…‡‡†‰‹Šˆ‡ˆ‰‹���ŒŒ��Ž������ŽŽ���ŽŽ����ŒŽ��ˆ„„ƒƒƒƒƒƒ„…„„ƒƒƒƒ„„„„„„„€���‚‚‚‚‚‚‚‚‚ƒƒ„„„„ƒƒ„ƒ„…‡††ˆ‰‡‡ˆŠ‹�Ž��Œ�Ž�����Œ‰‰‹ŽŽŒŒŽ��Ž�����‰ƒ„„„„ƒƒ„ƒ„„„„ƒƒƒ„„„„„„„€���‚‚‚‚‚‚‚ƒƒ„„ƒƒƒ„„ƒ„„„„„…†ˆˆ‡‡ˆ‰‹ŒŽ����Ž���Ž�Œ‰ˆŠ��‹Œ��‘���ŽŽ�Š„ƒƒ„„ƒ‚ƒ„ƒ„„„ƒƒƒ„„ƒƒƒ„„€�‚‚‚‚‚ƒƒƒƒƒƒƒ„„ƒ„„ƒ„„„„„„…‰��Œ‰‰Š‹Œ����Ž��ŽŽŽ���ŽŽ����‘‘’��‹‰‹Žˆƒƒ„ƒƒƒƒƒƒƒ„ƒ„„„„ƒƒƒƒƒƒƒ€�‚‚ƒ„„„ƒƒ„ƒ„„„„……„„…„„„„„†‘–’��‹ŒŒ�ŽŽŽ�������������Ž�‘‘‘‘‘Ž�Š‹‹†„„„„„ƒ„ƒƒƒ„„„„„„ƒƒƒƒƒƒƒ�‚ƒƒƒƒƒ„ƒƒ„„„„„„……„„„…„„„ƒˆ–•��ŽŒ‹Œ������’‘‘‘‘��������‘�‘‘’���Љ„„„„„ƒƒƒ„ƒƒ„„„„„„„ƒƒƒƒƒ„�‚‚ƒƒƒƒ‚‚‚ƒ„ƒ„„ƒ„„„„„„„…„ƒ‰–”����‹‹Ž����‘’’““’’‘‘‘��‘‘‘‘’““‘��‹‡ƒƒƒ„ƒƒƒƒ„ƒ‚ƒƒƒƒ„„„ƒƒƒƒƒƒ€‚‚‚����‚�‚ƒƒƒƒƒƒ„„„„„„„„ƒ‰•”‘��Ž‹‹�����‘’““”“““’’‘‘’’‘‘’”•”���ˆƒƒ„ƒ„ƒƒƒ„ƒ‚ƒƒ‚‚ƒƒ„ƒƒƒƒƒ‚€€€€€���‚‚ƒƒƒƒ‚ƒƒƒƒ„„„„„„ƒˆ“”““’Ž‹ŠŒŽ��‘“••••”“““’’’“’‘’“•—˜”Ž�‰„„ƒ„„ƒƒƒ„ƒƒƒƒƒ‚ƒ„ƒƒ„„ƒƒƒ€€€��‚‚‚‚ƒƒƒ„„‚‚‚‚ƒ„„„„„„„†�””•‘��Š‹�Ž�“•–——–•”“““’’‘’““”—™š—�ŽŠ„ƒƒ„„ƒƒƒƒƒƒƒ‚ƒ‚‚ƒ„ƒƒ„ƒƒƒ€€€��‚‚‚‚ƒƒ„ƒ„ƒ�‚��‚ƒ„…„„……Œ“•“�‘Ž‹‹Œ��“”––——–””““’’’”••–˜š›—�ŽŒ…ƒ„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„ƒƒƒ€€���‚�‚�‚ƒ„„…„��‚���ƒ„„„„…‰�•’’’ދЋŒŽ‘“””•–—”“’’’’“–“‘’’•—”��Œ†ƒƒ„„„ƒƒƒ„ƒƒƒƒƒƒƒ‚ƒ„„„„ƒ€����‚ƒ‚‚‚ƒ„„„„ƒ��‚ƒ‚‚‚ƒ„„…†Œ”’““�ŒŠ‹ŒŒ�‘’’“””“‘‘’“’”–”���‘‘���Œ‡…„ƒ„„„„„„„ƒƒƒƒƒƒƒƒƒ„……„€€����‚‚ƒ‚ƒƒ„„„„‚€�‚‚ƒ‚�ƒ„……ˆ�’””’�Š‹ŒŒŽ���’’‘‘‘‘‘’‘’’“’���ŽŒ��‹†…†…ƒ„„„„„„„ƒƒƒƒ‚ƒƒƒƒƒ„„€€€€€�‚‚‚‚ƒƒƒ„ƒ„ƒ��‚�ƒ„ƒ‚ƒ…†‡Š‘”•”�Š‹Œ���Ž�����‘‘‘‘‘‘�ŽŽŽ�ŽŠ‰�ŽŠ†…………„„„„„„„„ƒƒƒƒ„ƒ‚ƒ‚‚ƒ€€���‚‚‚ƒƒƒƒƒƒ„„„‚�‚�‚ƒƒ„…†‡‡‡Œ“––’‹‹Œ��������’“’‘�������ŒŒ‰ˆ‰‹‰††……†…„„„„„„…„„ƒƒ‚ƒƒ‚ƒƒƒ€€���‚�‚ƒƒƒƒƒƒ„„„„����‚ƒ„†ˆ‰‰‰‰�““�‹Š‹�ŽŽŽ��‘’“”“�Ž�����Ž�Œ‰ˆ‰‰‡…††…††……ƒ„„„„„„„„‚ƒƒƒƒƒƒ€€���‚�‚‚‚‚ƒƒƒƒƒƒ„ƒ����‚„†ˆ‰‹Šˆˆ�ŽŽ‹‹‹���Ž�‘’““’‘Ž�ŽŽ�’’’�ŽŒ‰Šˆ†……†………†………ƒ„„„„„ƒƒƒƒƒƒƒƒ�€��‚�‚‚‚‚‚ƒ„ƒƒƒƒƒƒ�€��‚„‡ˆŠŠŠ†…‹Ž�Œ‹‹�����‘””“‘�ŽŽ�“””•”’�ŽŒ‹‰†……………†††††…„„ƒ„„ƒƒƒƒƒ„„ƒ€€��‚�‚‚‚‚‚ƒƒƒ„ƒƒƒ„‚���‚„†ˆŠŠˆ†…‰Ž��ŒŒ��‘��‘”•“��‘“–———™˜•‘��Œˆ………†……††††††…„„„„„ƒƒƒ„„„ƒ€�‚‚‚‚�‚‚‚‚ƒƒƒ„ƒ„„„ƒ‚�‚‚„…‡ˆ‰ˆ‡‡ˆ��Ž����‘‘��“”“��“–™šššœ›˜“�ŒŽˆ…………………†††††††…„„„ƒƒƒ„„„ƒ€��‚�‚�‚‚‚‚ƒƒƒƒƒƒƒ„ƒ„‚�‚„…†‡ˆˆˆˆˆ�‘����Ž�‘��’“’�’•—˜˜˜™šš™”�‹�‰…††††………††…††††…„„ƒƒƒ„„„ƒ€€���‚‚‚‚�‚ƒƒƒƒƒ„„ƒƒ„‚��‚„……†‡‰�“��‘‘‘����‘‘’’“”•–•”’‘’’’’�‹‹‹ˆ†††††…†…††……†††††„„ƒƒ„„„ƒ€€���‚‚‚‚ƒ‚‚ƒƒƒƒ„„ƒƒƒƒ‚�‚ƒ„…‡ˆˆ’¥›‘”“’’�����‘‘“–˜˜•’�ŽŽŽŽŽ�‹ŒŠ†††††††††††††…†††††…ƒ„„„„ƒ€�����‚‚‚ƒ‚‚ƒƒƒƒƒƒƒƒƒƒ‚��‚ƒ……†…•¬¥–––”““’‘‘���’–˜˜—”’�����ŽŒŒ‰†††††††…‡††‡†††‡††††…„„…„„€�‚‚�‚‚‚ƒƒƒ‚ƒƒƒƒƒƒƒƒƒ„ƒ‚���‚‚ƒ„–±¬œ–™–”“’’’���’”—˜˜—––––””’�Œ‰……††††††‡†‡‡†‡‡‡†††††…„„„„€�‚��‚ƒƒ‚ƒƒƒƒƒ„ƒƒ„ƒƒƒƒ„ƒ�����‚‚’³°£™™˜—”“““‘��‘‘“•—˜˜™™š™˜–�Šˆ………†††††††‡‡‡‡‡††††††††…„„���‚‚‚ƒ„ƒƒƒƒƒƒ„ƒƒ„ƒƒ„„„„‚����‚�Œ¯³©¡™š™–”””“‘����‘”–—˜˜™——–�‰‡††…†††††††‡†‡‡‡‡†‡††††‡‡†…���‚‚‚ƒƒƒ‚ƒƒƒƒ„ƒƒ„ƒ„„„ƒ„ƒ������…¦´ª© š™˜••–•“‘�����’“•––••”�ˆ††††††………††††‡‡ˆ‡†‡††‡‡‡‡‡‡���‚ƒ‚‚‚‚‚ƒƒƒƒ„ƒƒƒ„„„ƒƒ„„ƒ�€��€�›²«¨¨¢›˜—•——”’‘�ŽŽŽ��’““’“�‹‡…†‡††††††††…†‡‡‡†‡‡‡‡‡‡‡†‡‡€��‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒ„„„‚����€�ª®©£§¤™˜–˜˜•“’��Ž�ŽŽ������Ї†††‡†††‡‡‡††‡‡‡‡‡ˆ‡‡‡‡‡‡‡‡‡€��‚ƒƒƒƒƒƒƒƒƒƒƒ„ƒ„„„„ƒƒ„„„ƒ�€��~„�­ª¤ £�˜——˜–”“’��Ž�Œ��Ž�ŒŒ‘އ†††††‡‡‡‡‡‡†††‡‡‡‡‡†‡‡‡‡‡‡€�‚ƒƒƒ‚ƒƒ‚‚ƒƒƒ„„ƒ„„„„„ƒƒ„„„‚�€€||‰ ©¦¢Ÿ ›™—––•“’‘���Ž�����“¢¢‘‡†††‡††‡‡‡‡‡‡†‡‡‡‡‡‡ˆˆ‡ˆ‡‡€‚ƒƒƒƒƒƒƒƒƒƒƒ„„„ƒ„„ƒ„„„„„„„„‚€}|{|…™¥£ ŸŸ™™˜”•”’‘‘�������’Ÿ¦ª¦”‡†††‡‡‡‡‡‡‡ˆ‡‡‡‡‡‡‡ˆˆˆˆˆ‡€‚ƒƒƒƒƒƒƒ‚ƒƒƒ„„„„…„„„„„„„„„…‚}{{{{|��œ¡Ÿ œ–™–•”’‘‘‘��‘�ŽŒ“ ¤©¬§”‡†††‡‡†‡‡‡ˆˆ‡‡‡‡‡‡ˆˆˆˆˆ‡€‚ƒƒƒƒƒƒƒƒƒƒ„ƒ„„„„„„„„…„„„…„€{{{{{{{}‡–ŸžŸ˜•––”’‘‘‘‘����‹‘ž¤ª«¬£‹„††‡†††‡‡‡ˆˆˆ‡‡ˆˆˆ‡ˆˆˆ‡€‚ƒƒƒ„ƒ„„ƒƒ„„ƒ„„„„„„„……ƒƒƒ‚€}z{{{{{{{|‚�˜Ÿ�•””•”“’‘‘����Œ�œ¥ªª±¬�‚ƒ…‡‡†‡††‡‡‡ˆˆˆˆ‰ˆ‰‰ˆ††€‚ƒƒƒƒ„„„„„ƒƒ„„„…„„…ƒ‚‚€~|}|zz{{{z{z{{}ƒŒ•“’“”““’‘���ŽŽ��™¥©°¾°�…„„„…†‡‡‡‡‡ˆˆˆˆ†‡Œ“�„|~€‚ƒƒƒ„„„„„„„„„„……„ƒ‚}||||{||{{z{{{{{z{{z}‚†Š�’“’���Ž����™£®½Á¥ˆ†††„ƒƒƒ††‡†Œ”�‡€�œœ�†Š‹�ƒƒƒ„……„„„…„„„„ƒ‚€~}}|||||{|}|{{{{|{{{||{|}}}~ƒŠ��ŽŽŽ�‹‹ŒŽ—¡®³±–‚………†„‚€�‚†„Ž�’‰Œ˜�›˜šœ™ \ No newline at end of file diff --git a/bin/foreman_part_qcif_422.yuv b/bin/foreman_part_qcif_422.yuv new file mode 100644 index 0000000..ed359e4 --- /dev/null +++ b/bin/foreman_part_qcif_422.yuv @@ -0,0 +1 @@ ++Øþùûþþýûüþþþþþýûþþþþþùîàââáßáâáßàãåß¿›œ¨¾ÖÛÖ×ÛÛÛØ×ÛÝÜÙÝÝÜÞÜÜßßßÛÖÕØÝáÔħ‘“””Œ�…tu†µßÞÝßÞÝÞÔÌÙÙÑÑÑÒÓ×Ô˜o�†}y§ÏÏÏÔÔØÖÔ××ÑÐÔÒËÀ¾Éº�€¢ÖÓÐÖ×ÙÙÕÐÎÏÉÌ®ww§ÈÍÒÐÏÏÈÃÏÉ“r¦ÑÏÊÁººÈÀ�i—ÀÆÖ¾1ÆÁÓäÍÕ¹ÓϺøÆËзØÄÆîкÕíâááâáààâæçÞÁ�’£¸ÉÑÔÕÒÔÙÛÙ×ÚÙÛÝÛÜÜÝÝÝÞßßÜØÔÝàÕÀ¤—““—šŒuv{Œ©ÐÞÝÝÜÜÛÚÛÇ¿ØÒÎÑÐÑÑÈÑΘu…ˆvvªÎÏÒÓ××ÒÓÓÑÎÏÏËÆÌν¬Ž~ªÖÕÔÖØÙÕÑÎÏÉÉÁœvyªÊÑÑÏÎÎÎÌѼ‚}´ÑÍÅÃÀÈÆ¦xn¦ÍÒ¾0±«Å­¹ˆ¿Ãгް±‡Ê°Š»Ë¦´çãááàßáäåÚÁ¢‘—¬ÉØÜÙÕÔÕ×ÙÓÎØÙÔÙÜÛÜÜÝÛÝÙØÙÙÝÛÓºŸ‘�‘——Š{qx”·ÖáãßÜÜÜÜÝÜÛÙÙÙÔÑÒÐÏÐÍÐͼ’t…„ms¤ÊÏÓ×ÖÓÓÔÒÑÐÌÌÏÎÏÂÀ¯„|­×ÓÔÙÙØÔÍÎÎÎÌÌ«z‚·ÎÌÍÍÏÊËÎÓ²w€ÀÓÊÆÄË˵˜os´Ô¼.Öᩱ½Æ Ëб¥­Ä¿œÑË®¡åΡÐçàÝáæàÖ¾¢™¡·ÐÙÙØËÉÖÖØÜÙÍÏÛØÖÛÚÛÛÛÝÖÓ×ÙÝÝͰ–‰‰—�’†{xƒ�ÁÙâáÞÛÜÝÝÜÝÝÛÚÜÚÖÔÓÒÏÑÑÒѸ°Â�o�†stŸÅÌÒÕÕÕÖÒÒÔÍÊÎÌÑȼé~z²ØÔÖØØ×ÐÍÐÐÈÌÒ±}‹¹ÂÉÍÎÆËÐÐÓ¬sŠÇÏÆÇÎп¶£o~ý)¹Ð´ËäâÈÖâáãäáàÒÝâçÚåÝÕßàáæãÔº¥›£½ÕÖÖÕÖÖÃÈÖÖØÚØ×ÙÙØÛÚÖÛÝÚÙÔØáÜˬ�…Š—™‘�tu‰«ÉÜâáÞÛÞÝÝÝÞßàßÞàßÛØÓÍÌÎÑÐÐÑǼÌË”p}…wv ÈÐÓÓÔ×ÖÒÓÏËÉÌÓÉ¿ÃÂ¥~·×ÒÕÕ×ÖÓÑÐÍËÌȨv�´ÅÌÍÍËÏÐÒÕ£k’ÉÏÌÏÒÇ¿À›n�²‚­²×æÝÔÜåãäåãââßâãèáàææååÕ´›™”²ÒÚ×ÔÔÓ×ÙרÖÙ×Ó×ÚÚØÖØØÙÚÙÛÛÜ×ç’……“œ’sw“¶ÑÚÙÝÛÙÍÖ×ÙâäæèéëêëêéèãÝÚØÔÏÐÏÑÉÄÓÏšmzŠ€|£ÌÒÑÖÔÕÕÎÐÐÊÐÖËÃÂÊ˨{·ÖÔÔÖÕÖÒÐÐÍËÆÆœqŽ¿ÌÍÍÊËÎÌÕÑ‘i›ÍÍÎÐǽ¼¶ŒlˆwÂØÓÕÛÞáßÜÛÚÚÚÚÝÜÚÔÜäãàÔ¶Ÿ˜�¨·ÒÛÚ×ÙÙÙÙÙÜ××ÙÙØØÙÚÛÙÙÖ×ÛßßѸ �‹�˜�~{v›¿Øáߨ×ÛÝÕÇÔÔáêëììëìììììíííìêäÜÖÍÏÓÏÍÐÏžq{Œ�{ ÌÒÕÓÒÖÏËÎÐÓÔÍÇÉÉÈÁ x~¸ØÔÕÓÒÔÑÐÍÏÊÈÈ™tŸÌÑÍËÍÍÌÍÔăl£ËÎÏʽº·°Šq~ÛàÙàãããâáàÜÜÝÞÝÝÞâæÝɶž˜¤¸ÈËÖØÕÛÝÛÙÛÙØÙÖØÛÞÛ××ר××ÖÙÜͱ“†ˆ‘–Ž}qp„£ÆÚÝÝÙØÜÝÛÜÜâåèëêëëëëëëëëëêêêëíìëçßÔÒÓÐÊÐÓ§wzŠ�x�ÊÓÒÕ×ÕÅÆÒÎÌËÈÌǼ¹·šu�¾ØÔÔÓÕÒÏÐÍÎÌÍË�s¯ÒÍÌÐÎÌÍÎÓÀ|p²ÑÎËÀû¾³ƒƒ×ßâááááâßÛÝÝÛÜÞâãÛä‘—©ÀÉÌÒ×רÛÝÝÛÙÖÖÓÓ×ÙÛÙÔÕÖÕÖÛÛÓĬ“ƒˆ�–‰uoqŒ±ÅÕáØÐÙÝÞÝØÛâçêìíëêëëìëëëëëìëëëëêëìíìå×ÐÐ˾ÉÓ¶|vˆu—ÆÑÑØÕÍÎÓÑÍÊÊÎÎÇ¿¿¼™x‡ÂÙÓÓÕÓÏÏÍÏÍÉÍÀ‡€¶ËËÏÎÍÎÎÎÖ¶u~½ÒÎÈÈÁ¼¿¡ˆØâßàááàÝÙÝÞÛÜâäÕ»¤•™£µÏÔÎÎÍÓÙÜÝÜÛ×Ô×ÙÓÔÙÛÕÓÕÕÙÛÚÕÀ£�‰‹“›Šzmw’³ÍÞÕÑØØÛÞÞÝÜßåêëëëêëëëììëìììììììëëëììëëíèÚÐμ½È¿¨qr‡~q•ÊÓÕÓÏÔÕÔÓÍÍÎÌÍÉÀÀ¹–r…ÂÖÐÔÖÖÔÒÏÍÌÉ´ÊÍÏÌÌÎÎÐ×­r„ÁÓÎÊ¿½½®ˆØãààáßÝÚÝØÓààÓ¸�‘–¦ÁÎÒÕÏËÎÑ×ÚÜÝÙØØÖÔÔØÖÙÚÕÐÙÝÛζŸ�ŠŽ–“‰yny›¿ÒÔÕÙØØÝßÞÞÝÝâéìëëëëëìëëëëììììììììëëììììììíçØÏÌÉǭ®sr…u–ÉÓÑÈÏÕÓÔÐÍËÊËÉý³�rˆÈ×ÒÖØÙÔÎËÍÎÊͱzƒ·ÊÏÊÈÏÎÒÖÔ£g‹ÊÑÐÈÂÀ«‡ÙáÞÝÞÞÝѵ›ºÒº¤�” ¶ÍÒÑ×ÖÊÍÎÑÕÛÝÞÝÚÙÙÃÅÖÒÓÕØÙÜδœŽŒ’•Œup€ ÂÚßÚÕ×ÜÝÝÕÖÞÞáæêëëëìëëëììëëëëëìëëìëëìëìëìììëëìå×ÐÍÍÅÂÓ«kqˆ~o�¿ÎÉÎÔÔÒÏÍÌÌËÊȽ·±—t�É×ÑÒÖÔÏÍÎÎÎÌɪx‡¶ËÅÄÎÍÒÒÔЖk˜ÌÐÌÇÅ«†Øàâææãα’q•¢“–£µ¼ÇÔÑÐÙÓÌÐÏÑÖÚÛÛÜÚÚÖÍÏÑÑÖÛÔȲ˜�”˜•‡xmtŒ¬ÌÞàÛ×ÙÝÜÜÝÛÑÕàäéëêêëëëëììììëëëëììëëëëëëìììëëëììëëå×ÎÍýÊÑ¥ns†}nнÑÓÕÖÔÏÎÍÎÌÈÈdz¬¶¶švŽÊÖÌÑÓÏÑÎÎÎÎÉÇ©wнÁ¾ËÏÏÒÑÖÏŽj¤ÐÉÈ̱‡Ûçáɾ¹£�™Œ�¥¸ÈÑÏÄÎÒÔÙÐÐÐÓÚÜÚÛÛØÖØÖØÕÔÚ×ħ“�“�šˆto{˜»ÓßáÛ×ÓÙÜÜÛÜÝÙÛãçêëêëëëëëëììëëëììììììëëììììììëëëëëëêéäØÏÈÊÌÏÓ¨qq…‚t‹ÂØÔÖ×ÑÐÐÏÍÉÅÇ¿³µ½ºžv‘ÎÔÏÖÓÑÐÑÎÌÌÈÇ¢s‘º½ÈÎÏÑÒÑØÈƒs´ÏÃdz‹ÒÀ¥Ž†…���Š–²ÉÏÓÖÑÐ×ÊÒÖÏÐÎÖÜÛÛÜÛÙÖÒÖÓÑͺ£’‘”——ˆurƒ¡ÃÚàÝ××ÙÚÙÜÖÒÜÝÝÞäéëëëëìëëëëëìëëëëëììëëëììììììììëëëëëëëèèä×ÎÎÎËÌѬonˆ„o…ÃÖÑÔÓÑÑÏÌËÅÂÉÀ½¾¸¸–u•ÎÖÒÐÑÕÔÑÍÍÌÇÈ�r‡¥ÃÌÎÐÒÓÓÙ¿€½¼¼²}¦‘�š„ov¡¯´ÌÖÕÑÐÑÕÙÔÏÖÒÍÉÏÙÙÚÜÜÖÔר֯®—Š‹”š�~tv�°ÍÜÞÚØ×ÙÞÝÛÚÛÕÓßÞÞåêëêëëìììëëëëëëëëììëëëìëëìëëìëëëëëëëëëëêèèäÕÌÏÍÊÌЯzp„€j‚¾ÓÐÑÑÑÑÌËÉÃÄÁ¿Àº®¨šs”ÎϽËÕÔÔÒÎÎÈÉÊ—i�ºÊÌÏÏÒÒÒÙ¹{ˆ·Ã°m¢¹ÉË¢ju²ØÚÚÖÔÓÔÕ×ÔÑÚÔÍÏÊÓØØÚÚ××ÛÖ锈ˆ’š�uoz�®ÕáßÛØØÜÜÜÕÔÛ×ÖÜÞרåéêêëëëììëìëëëëëëëìììëëììììêëëëëëëëëëëëêêéèéâÔÎÎÏÍËѹ|nƒ€kƒ¼ÔÍÏÑÑÎËÊÉÅÃÁÃÁ¶¯¸�o™ÏÈÊÓÓÕÖÒÎËÆÌÊ’oŸÅÊÍÎÑÑÒÕØ°vŽÅµÌÛßÜÊ­½ÐÏÑÓÖÔÒ×××ÔרÏÍÏÒ×ÖÕÙÜÛÖĨ�†‹’’†vju ÃÔÝàÚÛÓÐÜØÙÛÏÒÜÛÜÜÜ×ÞéêëëëëëëëëëëìëëììëëìììëìëìëëëëëëëëëëëëëëêéççèáÓÎÏÏÌÊм„o„„p�¸ÉÆÐÔÐÌÉÈÅÁÂÄÆÇ¾»®�qŸÐÎÐÔÔÖÕÒÏÊÆÑĆsªÉÌÏÐÑÒÓÕÖ¥r›´ŠÖØØÓÍ×ÙÔÕÖÕÖÑÐÖ×ÖÖØÑËÍÎÓÔ×ÛÜÓÀ§�ˆ�–�yhn„ŸÅÝáßÛÛÝßÕÑÜØ×ÚÙÛÜÝÞÜÝåêêëëëëëëìììëìììëìììëìììììëëëìììëìëëëëëëëëêéèèèèàÑÍÏÏÍÊо{fƒp~­ÆÍÒÒÏËÆÈÿÂÈËŽ°°’q¡ÏÓÔÓÕÕÔÐËÊËμƒ{´ÌÌÐÐÐÔÔÖЙu�†ÔÕÑÐËÎÏÔÖÔרÑÐÖØÓ××ÌËÎÏÕÛÜл¡Œ†Š�‡rej†¯ÑßàÚØÙÛÝÝÝÜÛÛÛÛÜÜÝÞÞÜÞäêëëëëëëëëììììëìëìììììëìììììììëìììììëëëëêëëëêééèéçÝÑÎÎÌÌËÏ»€d{‚p~²ÌËÐÑÏÎÌÆÂÁÁÉʼ¦²½�v¦ÒÔÔÖÕÕÒËËÎÌÏ¿€…¾ÊÍÏÐÒÔÓÔÉ’q‡ÕÔÎÌÃÌÓØÖÔÓÔÒÒØ×ÐÔÔÍÍÐÖØÌ´š�ˆ‰Šƒp]gŒ·ØâÛÔÕÛÞÝÜÛÜÜÚÚÚÚÛÝÜßÖÓÞãèêëëëëëìëëëìëëëëëììììììììììììììììëìëëëëëêëëëêééééèæÛÐÎÍÏÐËÓÉ‹ex‚t{¯ÏËÍÐÐÌÇÂÁ¾ÄÌì³Ç¿‹t¨ÑÒÒÓÓÔÏÍÑÎËи|‹ÂÍÌÐÐÑÒÑÐÇ�‰ÐÒÐËÆÏÖÖÖ×ÓÒÒÕÙÔÔÔÏÏÐÎÆ®•Š‹Œ‰~nhp�»ÚàÜØÖÔÛ×ÒÚÝÜÝÜÛÛÛÛÜÛÛÝÕÒáèéêëêëëëìëëëëëëëëëììëììììëëëìëëìììëëìëëëêëëëëêéèèèèçãÖÏÏÏÐÍÉÔÍ�dv€qy®ÌÌÌÎËÉÄÁÂÄÇË·¸É˱t¬ÓÓÔÔÔÓÍÎÎÍËÒ±|–ÈÎÏÑÑÒÒËͱˆÎÓÐÍÏÔÚÖÔØ×ÓÒØ×ÔÖÖÕÏ»¤’ŠŽ’‹{mfv—½ÙáÜ×ÕÙÛÜÝÖÑÜÝÚÙÛÜÚÚÜÜÛÜÛÝßåèéêëêêêëëëëëëëëëëëëëëëìëìëëëëëëìììëëëëëëëëëëëêéèèéèçæÝÐËÎÏÎÍËÓË–hr€rv§ÍÌÉÊÊÇÃÃÅÃÊÂÂÑË»«‚x³×ÔÕÕÖÓÑÑÏÍÌÒ³|›ÌÎÌÑÓÓÌǵ†ÐÔÎÍÎÖÙÔÖÙÕÒÔÕÖÛÛϹžŽ‰‹�Š{liwœÅÚßÛÖÖ×ÛÛÛÛÜÜÝØÕÚØÚÜÚÛÛÛÜÝÜÝãèèééêêêêêëëëëêëëëëëëëëëììììììëëëììëììëëëëëëëëêêêéééèçåâÕÊÌÍÎÎÎËÐÑ�hs€vw¨ÐÌÇÉÇÈÅÂÄÊÇÈÔÏ¿³¬w³ÓÐÒÔ××ÔÎÍÍÌÒ±{žËÊÎÑÑÎк†ÏÐÌÌÒØÔÒÔÕÑÒÖÛÙзž‰‚Ž–ŒuekªÁÔáÙÔ×ÚÚØÜÜÛÛÛÜÛÖÕÙÙÚÛÛÛÛÜÝÛÜàæèééêêêêêêëëëëëëëìëëëëëììëëëìëììëëëëììëëëëëëëêêêéééèèææåßÑÌÎÎÎÎÌÊÎÍ‹ax�rq¤ÏËÆÇÈÆÇÇÄ¿ÇÐÐË®²¦wxµÓÏÑÕØÖÐÏÒÎÌׯz£ÊÍÍÍÌм…ÍÏËÍ××ÒÓÓÏÔÜÚǬ”„„�•‹{st�²ÉßÚÔ×רÜÜÜÝÜÛÛÚÚÚÚÜÛØ×ÚÛÛØ×ÝÝÜÝãæèééêêêêêêêëëëëêëëëëëëëëëëëëëëëëëëììììëëêëëëëêêêêéèèèèçæäÙÎÏÏÍÌÌÍÉÌÁ•oqylmžÆÆÊÍÈÊËÄ·ÀÐÏÈ»²®§}{½ÓÐÓÖÕÕÖÖÒÎÏמv¨ÍÎÏÍÏ»…ÎÒÍÏÖÒÑÕÙØÖÆªŒ~ƒ�Ž„tlx™ÁÛáߨÖÙÙÚÛÜÜÜÛÚÚÚÛÚÙÚÛÛÛÚÛÛÛÙØÜÝÜßäæçèêêêêêêéêêêëêêêëëëëëëëëëëëëëìëëëìëëëëëëëëëëêêéééèèèèçæäßÑÌÎÌËÌËËÊÑÔ ms}ql“ÃÎÎÈÊÏÎÀÁÓÔʾ¶­º©w�¹ÒÓÒÓÖ×ÖÔÔÐÐÉ”|¯ÎÎÎи…ËÍÎÑÑÒÙÜ×Ĥˆ~†�‡{pl} ÃÛáÛÖØÛÜÛÙÛÜÝ××ÚÙÚÙÛÜÛÛÚÛÛÛÛÙÚÚÚÙØÜâåçèèééééêêêêêêëëêëêêëëëëëëëììëëìëëëëëëëëëëëëëëêêêééèèèèçæåãÖÍÎÍÍÌËÊËÊÏÕ®}v|qj–ÂÌËÍÎÏÇÇÓÑÌľµ´º¦yƒ¾ÖÒÔÕÕ×ÖÔÔÏÍÉ•~²ÍÍÑ·ƒÇÉÍÕÛÛ϶ ‰‡‹ƒrdm‰­ÍßáÝÖÖÚÛÚÜÝÜÜÛÛרÛÚÚÚÚÚÚÚÙÚÚÚÚÙÙØÖרÝäæççèééééééëëêêêëëëêëëêëëëëëììììììììëëëëëëëëëìëëëêêééèèççææäÞÔÏÍÍÌÌËËÌÉÐÙ°qpyqo’½ËËÌÎÊËÓÏÉÆÀ¸±³¹§|ŠÅØÒÕÖ××ÕÕÕÍÎË„¹ÏѶ|·ÉÙÞË«‘ƒ‚…Š‚nbp’¾ÖááÛØÙÜÜÛÛÜÜÝÞÜÚÚÛÜÛÛÛÛÙÙØØÙÚÙÛÚØÚÝàÞÛàäæçèéèéééêêëëëëëëëëëëëëëëëëììììíëìíìììëëëëëëëëëëëêêêééèççæåäâÛÓÎËËËÊÊËËÊÎÒ©uq{zt‘ºËÎÒÐÍÔÔÍżº·¯³º¥{ŽÈÕÔÖ×ÙØØØÔËÊÁŒˆ¼Ò¸k˜Å̰‘„�‹~ml|ŸÆÛáÞØÕÙÜÜÛÜÜÛÜÜÝÜÛÛÛÚØ×ÙØØÛÚÙÙÙØØØÛÞáÞËÃÙâäææççèéééêêëëëëìëëëêëëëëëëëëëëììëììììëëëììëëëëëëêêêêêèéççææåãÝÕÏÊËÊÊËÊÉËÍÒׯys‚{x•ÂÒÑÎÊÒÔÐÊ»¿¼¹¶´¡z‘É×ÓÕÙØÙÖÔÐÊÏ»ƒ�Ƽsžž•†‹�‡{oq�µÐááÚÕ×ÙØÛÛÚÛÜÛÚÚÜÞÛÙÛÛÙØÙÚ×ÖÙÚÙ×ÖÖÛßßÔÁ¨Ž©ÝâäåæççèéééêêêêêêêêëëêêëëëìëëêëìììëëëëëëëìëëëëëëëêêêêêéèéèççæåãßÕÍÍÌÊÉËÌÊËËÍÑÔ±yr�{u“ÂÓÌËÒÓÐÍȼ½¾À¹°µ§�–ÇÔÓÖרÖÓÐÍÊη—¶…¯€Š’ƒni~˜·ÝåáÙÑÖÚÚÛÛÛÚÚÜÝÙÚÝßÞÜÚÛÚÙÚÙØØØ××ÖÙÞÝ×DZ›Žˆ”ÆááäåæçèèéééêêêêêêéêëëëëëëëëìëëëëìëëëëëëìëëììëëëëëëêêêêééèèçææåäâÙÏÍÍÌÅÈÍÉÊÇÅÉËÒ±sl{|u“ÈÒËÑÔÑÊǽ¾ÄÀ²¶É­}˜ÌÖÑÔØ×ÔÐÎËËЭ‹�µˆwql|ŸÈÞãßÙØ×ÔÙÚÚÚÛÚÚÛרÛÜÝÞÜÚÛÚÙÙØ×ÖÕÔÕÜàÞζŸ�Š�œŸ±ØàáäåæçèèéééêêêêêëêêëêëëëëëëëëëììëëëììëììëëìëëëìëëëêêêêéèèççææåäãÞÔÍÍÍÇÈÎÊÉÉÈÌËÌѱwq�zs‘ÃÐÏÔÔÌÊÉÄÃÄô¸ÊÄ—~šÈÕÓרÕÐÐÎÌËЬwv¡zm…¬ÎÛÛÜØÙÜÜÚÚÙÙÛÛÚÙÚÚÕÖÛ×ÙÜØ×ÙÚÚÙÖÔÖÙÜÜÕÈ±Žƒ‰•Ÿ�˜Š®Ýßâäåæçèèéêéêêêêëëëëëêëëëëëëêëììììëëëììììëëëëëëëëëëêêêêêèèèçææåãâà×ÏÎÌËËÍÌËËÊÅÌÏÐÙ¿‚m{si�ÃÒÑÔÑÌËÇÁ½Á»¼Èì’zŸÍÔÓÖÕÒÒÑÎËËΤiˆ�¹ÔÝßÚ×ÙÜÝÝÜÝÜÙÙÛÛÚØÙÛÛÚÛÖØÛÙÙÙÙÖÖÙÜßÙ˸Ÿ’�‰’œ™Ž�zƒÀàßâäæççèèéêêêêêêëëëêëêëëëëëëëëìììëëìììììëëëëëëëëëëëêëêêééèèèçææäããÚÌÍÍÊËÌÊËÈÆÂÌÂ½ÏØÁƒqxqpŒ¾ÓÑÒÑÍÊÅÀ¾¼ÀËÆ°¢Œ|ŸÒÔÓÓÑÑÑÏÍÉ;u¾ÓÞÞØÖÚÜÛÝÝÛÜÜØÚÚÚÛØØÚÛÚÚÛÛÚÚÚÙ××ÛßÜÑ»¢‘Œ‘™›–Œ„}xw|®ÚÜàâäåæççéêêêêêêéêëëëêêëëëëëììëëììëëìììììììëëëëììëëëëëêêêéèèèçççåäãÞÐÅÈÉÊÌËÌÁÅÍË»¬ÈÌׄpyuk„¼ÒɽÉÐÉÅ¿ÄÊÍ· ž‹u¥ÔÔÑÐÏÑÑÎÍ͸†ÜßÔÕÙÙÙÛÚÜÝÜÛÚØÚÛÛÚØÚÚÚÚÚÚÚÙרÛàÝÒë•‹Ž™ž™�„yuvtsuˆÂÜÜàâäååæçèééêêëëêêëëëëêëëëëëëëëëììëìììëëëìëëëëëìëëëëëëëêéééèèèèçæåãáØÈÇÊÌÌÌÎÊÊÌÊÊÆÊËÍׯ�pvxi‚»Ç®ÂÒÉÄÇËËÌÑÁ­¥©ˆn¦ÒÒÐÒÐÑÏÍÍ·†ÓÙÖØÙÙÚÝÝÜÜÙÙÚÛÛÚÛÛØÙÙÙÙÙÖÖ×ÛÝÙÊ²šŠŠ’œ¡�Šzuusps{Œ¢ÀÑØÞàâäääæçèéêêëëëêêêêêêëëëìëëëëëëëììììììëëëëëìëëëëëëëëëëêééééèèçççåäãÜÐÊËÏÊÃÊÍÍÌÌÍÏËÊÌÏÖÌ—qzuk‚³ÈÊÎÌÄÆÌÏÏÐȶ¦««…q£ÑÐÐÓÕÒÏи…ÔÙ×ÙÚÛÜÜÝÝÛÓÖÛÚØØÙØØÙØØ×Ô×ßßÖ¿¥�„Ž™Ÿœ�…{vuuuvƒœºÑÞÞÖÚÞáããååæçéêëëêêëëêëêëëëëëëëììëìììììëëììëëëìëëëëëëëëëëëëëêêêéèèèççæåäßÑÈËÎÍÈÇÆÍÍËËËËÊÍÍÈÒÑ•pzvmªÆÍÍÈÆÄÌÑÏʺ¬­«¤…o¨ÕÑÒÕÒÐÔ»†ÕÚÚÚÚÜÜÚÛÝÜØØÚØÖ××Õ××Õ×ÛÜÛ̵žŽ‹“œŸ˜‹ƒ~zssu‚™°ÉÚßßÝÒÐÜßáãäåæçèêêêëëêëëëëëëêêëëëëëëëìììëëìëëëëëëëëêêêêêëëëêêëêêêêéèèèèçææåâÖËÌÎÏÎÌÊÍÎÌÈÊËÈÍÏÌÌÔÏšsuxszªËÉÅÅÀÈÑÑËÁÀ½­¤ª‰r§ÌÏÑÓÑÖ¿‡ÖÝÙÙÛÜÜÙÚÛÛÜÙÙØØØÓÓ×ÙÜÝÔĬ�…�œ¡œ’„~~|xv{Œ©¾ÔãÜÙØ×Ù×ÕÜßàâääæçèéêêëëêëêêêêêêêëêêëëëëëëëëëìëêêêêëëëêêêéêëëëëêëëëëêééèéèçææäâÙËÈËËËÎÎÎÌÌÌËÆÁÉÍÎÐÍÔÑžqu}vƒ¯Ç¼ÁÈÉÐÒÌÃÇÀ³°²°‡o¥ÐÒÒÒÕ¼†ÕÛרÙÙÚÛÛÛÚÙÙÙØ×ÕÓÙÞÙ̹¥•’”�¢™‹{zyz�Šž¼ÔáÕÒÙÐÔÛÚÙÖØÜÞàâäååçèêêêêëêééêêêëëëëììííììëìììíììíííííííîíííìììëìëëëêëëëêêêêêêéèæàÒËÍÌÊËËÌÌÍÏÍÆÂÈÌÍÐÎÍÓÒ¡qszs|¬¹½ÌÊÌÑËþ½»µ´¸º‘|±ÖÒÑÖ»†ÔÚØÙÚÙÚÚÚÚÙ×ÖÕÖÙØ×Ò«—’˜¡£œ’†}yxvx‚š¼ÐÚàßÙÔÕÕ×ÛÛÛÚÔ×ÝßàâäæææéêêééêëììëëéèæäáßÝÜÜÜÜÜÜÛÚÚÙÙØØÙÙÙÙØÖÕÓÒÐÎÍËÌÌËÊÉÉÉÉÊÌÏÑÔÕ×ÚÚÛÚØÚÙÖÖÓÏÎÎÍÎÌÅÄÈËÎÐÑÎÒÔšiszkxš·ÈËÎÎÎÆ¿Âº¾Áƽ‰|´ÕÑÔ»†ÓÙ×ÚÝÝÛÙÙÙÕÔÙÝÞØÃ¬š””›¤£™‰~|wswŠ¥ÁÖàÞÛÙ××ÚÛÚÛÛÚÛÛÕØÝßáãäåæçééêëììëèãÝØÑËÆÁ¿½¼¼¼º¸´¯¬«ª¥Ÿ™—˜—™››™—“���’”•˜›œžŸ £¥¥§¨ª®±³¶¸½ÀÃÈÌÑÕ×ÖÑÍÌÌÉÅÆÊËÎÐÏÍÓÏ¢utwir¥ÈÍÑÑÐÈÀÂÀ¿ÄÂÂÄ®w±ÓÓº…ÓÙÙÙÛÛÙÖØÙÚÝÛп§‘ˆ‹š£ •‡{ywyy…®ÏÞàÜØÒÖÜÚÚÛÚÛÛÜÚÚÚÖÚÞßáâäåæçéììéäÝÓÊÁºµ²¯¬©§¥£ž™“އ„|{vrppoopvxxtmkkmqux{…‰�’—œ¡¥§§¨§¦¨ª«ªª­±µºÀËÒÐÌÊËÊÈÌÍÌÍÍÏÍÏÌ¡lo{ky°ÐÍÑÐȿÿ»ÅÂÄÈ¿¨}xºØ¼„ÔÝÚØÕÖ×ÙÞÜÒÁ«œ�‰�˜›”�†~vsw~‹ ¯¿ÞßÚ×ÔØÙÚÛÙÛÛÙÙÜÛÙØÙÖÛÞàáãäæèééäÛÑÆ½·´²³³°¬¥�”Œ…zwsppojhihhhjkntvuoe_]adfjmruy}�„…‰’�©¯±±¯±±°°¯®¯¯°´ÂÍÎÌÊÉÈÌÍÌÌÍÎÎʶágrui{²ÐÏÍÈÆÇüÈÈÊËÄ¿¯‚�¾¿…Ó×Õ×ÛÝÜÓÅ´¡––š—’�މ�ywuvŠ¥·ÑÛÙÙÙרÙÑ×ÜÚÙÚÜÛÚØÌÐÛ×Ö×ÜÞßáãåèèâ×Ê¿¹¸¸¹¹µ¯¦œ’ˆ€ytrpmlkjkigc_\[[[\bhijd[Z[[Z[[`ehnqux{zxz…•¢®²±±³µ¶µ´´·´·ÆÍÍÍËÉËÍÌÍËÊÎÐÃÉÖ dlzmz°ÍÍÆÅÉÇÃÆÅÊÍÈþ°€…©†ÔרÞÙɲ ••˜žž”‹†�{uu€…’´ÐßààÛØÔ×ÚÙÚÚÛÛÙØÛÚÚÛ×ÌÓÜÚÖÙÜßàáäçâÖÇ¿½½½»¶¬¢˜�‡ƒ~wqlkhfdcb^[WTQOPSSOMSXWVSOONLMRUWUX^diouy{vx�„�£±µµ·¹¸¸¸º¸¸ÆÎÍÍÌÊËÎÍÍËËÏÏÏÌÑÕ empv¨ÎÈÀÇÆÃÇÁ¿ÈË÷¹«yy†ÔÓÉ»§™‘“™œ•�„|yxz~‡Ÿ¿ËÓâßÙÙÕ×Ù×ÙÛÛÜÝÜÛÛÜØÓÙÚÛÜÛÛÜ×ÙÞßáåäÙÊ¿½¿¾¸®¡•Œ†ƒ�}ypg^WRSX]ZTSWWVWZ^`^^a`][ZWND@BMX[WSPT\bhmsv~‰†�‚•®µ¸º¹º»¼¸¹ÇÌËÊËËÌÍÎÍÌÍÏÌÌÏÏÒÖ¤eq~ms¦ÉÃÁ¿ÀÍÈ¿ÇÌȹµ¶—s­ž™–—››•Œ†zwv|‰�¸ÎßãâÞ×Õ×רÚÚÙÚÜÛÛÚÛÜÛÜÚØÚÜÜÛÚÛÛØÚßáäßÎÁÀÀ¹«œ”Žˆ„ƒ‚€|xsoid]WVZaffglorsqpnmljihfedb]WTU^gigbUKKR\chms{„ˆ‚{�«µ¹»º»½¹»ÇËËËÌËÌÍÍÎÎÍÍËÍÑÓÏÑÙ©ko|ns©Ç½¹½ËÐÉÍÍËÁ½º¦•rŽˆ—œ˜Š�}zxvwƒ˜±ÆÕßáÝÚØÙ×ÕÚØÛÜÜÖ×ÙÛÙ×ÛÛÚÛÜÜÛÚÚÚÚÚØØÞâà×Ǿ¿¸¥�„�ƒ„„…‚~yrmjjjmpqtwywtuutvxyxwtrolmnljgeccfjjmlmhYHEKU`fkns}†|t’®³¹ºº»·ÁÌÈÊËÊËÌÍÌÍÍÌÍÍÎÐÒÒÏÒÙªorƒux­Å¼½ÈËÌÑÎÌÆÀÁ«žsž�‰‚{yyus~•ª¾ÖÞÝÝÙÍÓÝÛÚÛÛÛÛÜÜÜÛØ×ÜÛ×ÙÚÖÙÛÙÛÕÓÚÙÚÛÜÞÙÎÄ¿¶£�€„‡‡…‚zunjikosvy{}~}|zvuwxxxwwxwsqrpnmkijnnmnnool^QJMV_goqsvwr}¡¯³¸¹¸²£·ÌÇÈËËÎÌÌÍÆÉÎÌÍÑÑÑÑÏÎШsz‡v}©´¸ÉÇÈÑÑÑÌÃöŸs–�xutwy„š»×ßàÜ×רÛÖØÜÜÖÙÞÜÛÛÛÛÜÛØÕÛÚ×ÚרÜÚÙÙ×ÚÜÞÜØÑÉŽ¥‡{~‚†ˆ‡ƒ€zuqlimpruwyz{}||||{ywwxyyvuwxvsppqrompssttttqojcZSSYajqsstvx“¬¯²¶¸ª|²ÊÉÉÉÎÍÌÎËËÎÍÉÎÒÒÐÑÌÇ̬xtƒsvФÄÊÊÎÒÓÐÉÈ»§i�uvyzЦÄÜÜ×ÚÙ×ÙÛÚÛÞÜÛÛÚÚÜÜÚÙÛÚÛÜÙÕØÖØÛÜÛ×ÑÙÜÛÜÛÕÐÌË̹”wq~‡†„„�|wrnllptttvxzzyxuqpopqprtwyvstuurqqrpnnpqqqpnpqpmid\Z\aflsuvxx�§®°µµ™|o{¯ËÇÇËËËÍÍÌÎÍÉËÐÑÎÏÏÌËÕ²us|uu”ÀÇÌÏÑÑÏÌ̽ª^x�•©»ÏÜÞÜÏÍÚÚÚÚÙÙÚÚÜÛÛÜÛÛÛÛØÙÛÛÚÛܨרÙÛÛ×ÐÒ×ÖÒÍËÌÏϳƒot|„‡„�}xtqommruuvwxwusmd_^`begjmpsuvttsrrrrqqsqnmjgdcdhlmmjfa^aeiqsvz{�¥±¶µ˜‚{qz«ÌÉÆÉËÊÆÄÍÍÎÌÍÏÍÍÍÏÏÐØ¸}q�y|¦ÅÊÎÐÐÏËÌÆ°j¦ÈÛÞáßÙÕÖÙÚÛÚÙÙÙÛÛÙÜÛÛÚÚÚÛÜÛÚÚÚÚÙÔØÙØÚÙÙÙØÐÕÐÉÌÑÒήyiv||‚‡�|vrqppqstsuxvqjdc\VTV\_`bejmmqsrsrrstuuuuqkgc^YVTX_eikkhaaejmsy~ƒ‘¤²µ¼šn{ƒrx§ÊÊÉÊÊÈÅÉËÌÍÌÎÎÎÍÏÐÍÏØ¹zlyuu¤ÈÎÑÑÎÉÌ̵ˆÜÚÖÛØÖÙÚÚÛÛÙØÙÙÛÜÜÛÚÚÛÛÜÛÚÚÙÙÙØÚØÓ×ÙÙÙÙ×רØÖÎÐÒÒÌ­�ks}}|€ƒ�xnopprvuqqqng_XTPNPSUY^aachlknpprsstvxwusmhfb\WOJIKS]eijgcbfpy�„�—¤¯·ÈÄ—s{�znrŸÇËÈÈÌÌÉÉÊÍÌÌÎÍÎÐÎÍÍÍ×¹xk�tr¤ÎÐÐÐÇÊÏ´ŠÙÆÄÙØÚÚÚÚÙÚÙÙÙÙÛÜÜÛ×ÙÛ××ÚÙÙØÙÙØÕ×ÙÖרÔÖÙרØÔÏÒÓͳ�€xx}~~}€…}qllquvsqngbZSQOKOTWXZ^bcehlmnoqrrssuwxvrkhfb[VRLFCFNW^che`iyˆ‹’ ¬³ÃÎËÌ¥ro}|po”ÁËÆÊÊÈÉÉÊÌÊÌÊÍÏÌÍÎÌÎØ»|r�px«ÌÏÒÉÇε…ÓÒÒÙØÙÚÚÚÙÚÚ×ÕØØÙÛÚÚÛÜÖÔÙØ×ØØ×ÖÒÖØÖ××Ö×ÔÒ×ÖÑÎÒнž�‰{y~xy��sjpvxwqkd_][]bddcefdcddffhkmnprrqrrsvxvqkgdc^ZWNGFEEHQ]eigty|Œ’�«´¿ÌÎÎÓÓ¡su�€tm�»ÈÆÇÈÊËËËËËËÎÐÍÌÍÌÍÏÕ½€q€{{«ÍËÉËϹ…ÓÛÙÙÙØÚÚÙÙÙÚÓÒ×ÓÖÛÙÚÜØÖØ×ÓÓØØÖ××רÖÔ×ÚÚÓÓ×ÖÏÎÓÈ­˜Ž‡yw€}xqntsjnuwyumdabhmsuvyvtrppmkklmmmopssqqrrttsojgffb]ZVSRPNORW^hillz”£¯µÀÊËÑÑÏÐϸ‡u€vl„²ÈÇÈËÍÌËÌÌÊÍÏÎÌÎÌÌÏËÑ»~o†}~­ËÉÌѺ‡ÔÚ×ÙÙÙÙÙÖØÙØØØÙÙÙÙÙÙÙÕÔÙØÔÕÙÙ×ØÙØØÕÒØÚ×ÖÖÕÕÎÎϽ¤‘Œ‰xwxqlihcltvwxqkkpuz}|xx{ywutttrqrsrqrsutrrqrrqqnkiiheeggddfggfa_ceck‰¨±¹ÄÍÎÉËÌÏÒÓØ»�st€ym€±ËÊÊÀ·ÉÊËÊÌÍÎÌÍÊÌÑÌÈϸqƒ{€¬ÉÊι‡ÕØ×ÙØÚÙØÙÙ×ÖÙÚÙÚÙÖØØØØ×ØÙÚÙ×רÙÙØØØ××ÔÒÔרØÏÌ˸Ÿ‰ŒŠxz|rkfe]druwxuqrw~}{xxxvsrsrrsttssrstutqooqqppoljiiiklkjloooqspiii|¦¶»ÅÎÎÏŪÄÑÎÎÐÒÍ›sx‚}oy¨ÇȺ¶ÅÈÊËÌÍÍÌÌÉÌÏÎËËϾ‰o{y¡Äʶ†ÕÚ××ØØØÙÙÙÖØ××ÙØÙÙÙרØÖÓØÙØ×ÕÖÔÖØÖÕÓÕØÛÝ×˺©ÀÍ»£��ˆz{xnebZTiswyxuxz~€|zyvuutpmmnoqrssttttttqoooppnomjikkjhhiklmnquxwrwš¹ÂÌÐÎÎÐ̺ÊÔÍÏÑÒØÓ¤rqƒ|ls¡ÈÃÃÇÅÆËÊÌÍÌÍÎÍÊÇÇËÉÎÉ”s}w�È·†ÕÛ××ØØØØØÚÚØØÙ×Ö××ÙØØØÖÔØ××××ÖÒÒÕÖÙÜÚÔÊ»ª™Œ…¨È½¬šŽ…�}sh`]OXnvxyxx|}�~wuusrpnjebcfkmqsttttvvtqooppponkjkjfbaeiklorsw|z�¸ÉÎÐÐÌÌÐÓÕËÈÎÒÑÐÐÒͨwp‚}lr ÃÄÆÄÅÊÊÊÌÍÍÍÌÊÈÉËËÆÔÑ•oƒ�z¡´†ÔØÖÔÕØØØÙ×ÖØÙÙ×ÖÓÒØØØÖØÙØØÖÔÔÕÙÚÚÕÎŰŸ‘‰ŠŒ�‘›½Æµ¡�‡ˆ�pd]ULarxyzz{}~~yuspkgdb_\[YY^cilpqtuuvtrppqqqolige`YV[bhjloqqty}”ÂÏÌÎÑÍÍÎÐÎÄÂÊÑÑÏÐÐÑÖ¸|k|}no”¾ÇÁÇÊÉÉËÌÌÌÌÌÏÍËËÇÊÕÊ’o�ƒyއÏÒÕÑÑØÙÖÌÒÖÙÕÖÚØ××ÖÖ×ÕÖÖÔÖØØÚÚÖÍ»§™�…‡‹�”™™”‘˜·Â¯š�Œƒnc\PQdsy{zz~€}xtqkfcbcb^[XVUUX^cinqtvvvusrrqqkeb^WOLQVXYZ`ejlpw}’½ÊÉËÏÑÐÏÏÐÎÈÈÏÐÎÏÒÐÏØÂ†n€rj�»ÃÃÉÈÉÌÌËÌÍÊÊËÌÍÊËÏÒË–q�…u…ÑÖÖÖÖ×ÙÕÍÕØÙØÙÚרØÖÖÕ×ÚØØÛÚÓÆµ¢“‰‡Š�”™˜•�‡�ytn{£¹´¥•…pc[OTcsz||}€~zuogadhiijd^YUSSQTZ_diouxxwwwusnb\XOHHMSTURLJS^flu|•¾ÌÎÂÆÐÐÏÎÑÒÍÍÐÑÏÑÑÎÎÏÙÌ“t�qj‡µÅÇÉÈÌÍÌÍÍÊÉÊÊÏÎÍÑÍÐÎ�q~„…ÔÙרØ×ÙÙÚÕÖÚÛÙØ×ÕÓÓÖÚÝÔÏÌÁ¯ž�ˆ‰‰�•‹ŒŠ€yvrkggeeak�¬¸±�ŠvYKTcr{~�€€|uoe`cgiiigc^YQMOOOSX]bipwzzzzzwhXSKCDHNSW[]XOMT`hpz—ÁÉÉÇÉÎÊÍÏÏÐÑÐÐÐÐÏÏÌÏÐÎ×Кqu}ui~°ÆÆÉÊÌÌÌËÉËÊÈÌÌÍÏÎËÏΟov‡Ó×רÙÙÚÚÙÖÖÙ×ÓÓÕØÖ×ÖϽ¦¤Ÿ“‹‹�”™’Žƒwtnhigffghijljiv�£¤”uTLVcq}€�‚€~yrh`bedbcb`^ZTMFGLORW[aflu{||{|yeSJB@?CJQX]bc^SNXemx�ÄžÍÍÉËËÏÏÎÐÑÏÎÏÎÎÍÐÒÐÎÔÑ›nq|vi|ªÄÉÈÌÌËËÈÉÉËÌÈËÏÌÌÏÐÑ¥o‡ÕÙÖÕÖØÙÙØÔÑÕ×ÙÛÛØÉ¸®ŸŒ�ˆŒ“˜™—�‚wsmmjjlomjjllnnmqojlrzp[QNYao~‚ƒ‚|wodbdabcbcc`[UMHEHRXZ^agmtz}}~{iSGA>=ACBBCDEGNY][^iorw{ƒƒƒƒ|jYQHA??@@>>CDDLZcn…³ÇÈËÊÈÈËʾÆÎÍÐÎÎÏÐÐÎÎÎÑÐÍÑÕÑÎÔÍ�su}vo�ºÉÉÈËÌÍÊËÍÎÎÍÐÑÎѽ‡ÒÙÙÑIJŸ�‹�’˜Ÿ¡£’|x{{qkkgeimnonnnnnmmnqpopoorssqoopomkbUIKQVmƒ††„}vqmkie]TQTUVYYVRRRUVW[empty~�ƒ…†…‚ubSNLHFIOQUZ`e^]gq†±ÅÆÉÊÊÈÉËÅËÏÏÏÎÎÏÑÐÏÏÍÌÍÑÒÔÒÐÎÓÔ§qp{un†²ÇÇÊÍËÊÍÏÏÎÏÐÐÉν…ƹ¥•Œ‰�“› ¢›—Š{pfoqkgihkmnnonlllklmnopppqrqpqqooponq|hSJQWn†‰ˆ…€xvvvtqoljhhgd`[VVWY[`hmpty}€�ƒ‡‰‰†}obXTPLKOW^bgoqlpw„œ¹ÇÆÈËÊÉÈÎÏÑÏÏÑÎÎÐËÏÐÎÌÈÏÑÔÑÑÓÑÔÖ¬xlyun€«ÅÇÊÉËÌÍÏÐÏÑÏËλp”‰‰Ž˜¡¡ž•Šuonp{zk_]cedffdhlkjjjjknnmnnopqooponnonnwzxubSTXp‡‰‰ˆ…€~~}zyusolifb^[[[]bgnsuwz}€�ƒ†Š�‹ˆ�xqlb]ZUQRW\dkpuy~‡�‰·ËÈÆÉÊÊÍÎÎÍÇÄÌÏÌÊÑÐÐÎÏÎÐÓÓÒÑÓÓÕÚ»�mxwmz¤ÂÄÇÌËÊÎÐÐÐÐÐлnš�£¦ “�umkp|ˆž¼¿´¦„\RX]][\`cfhijikklmmonpqpppnnklmpwihsrhZXu‰‰ˆŠˆ…„‚�}}yrokfedbcdfimsxyz|€�€„ˆŒ��‹…~utpieb`\[\clqw~‚Šƒi|¯ËÊÆÈÌÌÌËÌŽÌÐÍÎÑÐÌÌÐÎÏÒÓÒÒÓÉÊÒØÃ‹nvwnx¢¿ÄÆÊÌÌÏÐÎÎÎѺx¦˜ˆ}uopx‡—­½ÄÔÚÇÆØÐ¡dKKORUY[^adffggijjkmnmmmmopnlkqshgmwte^z‹‹‹‹ˆ††…‚€~zvtqnnnoonqsvy{{{~���€‚ˆ�“”�‰�yuurnkkkkklpvz„ŠŠqcn—ÄÍÅÈÉÊÍÍÍÏÍÇÎÎÎÏÊÍÏÌÏÓÒÑÑÏ¿ÃÐÑÚɉlvxoy¢ÀÄÇËÌÍÏÏÎÏÓºezmnt†—¬ÀÍÔÔÏÈÐÍÀÂÐÖÓ­qK?CJORSVZ^`bcdehjllijkjlnpomsriioxwpn‚Œ‹ŒŒ‹‰ˆ‡…ƒ�}|zxwvvwwwxyz|}}~‚ƒ‚�‚…Š�’”�Š„yvvutrqqqrvy}€„‰Œ|p^]‡ºËÈÆËÌÍÍÐÌÇÍÎÐÎÌÏÎÌÌÑÐÐÎÌÍÏÐÔÒÙÊ�krvpw—»ÅÅÊÍÎÏÏÏѽ`„”«¿Ï×ÜÝÚØÔÍÌÓÐÁÁÄÀÆÍ±yQ?;AGJLQTV[]_behjijkjjkjlonssihs{tsyˆŠŠ�Ž�ŒŠˆˆ‡†…ƒ€|{|||{|~~€‚„„ƒ‚ƒ‡‰�›¡™Ž†€{wwvvxwvwwz}‚„…‹Švrrhc{«ÆÆÇÍÌÊÍÎËÉÎÑÏÌÏÐÏËÍÑÐÎÐÏÎÏÒÑÑÚÏ–mq|sq�¯ÀÃÉÌÏÐÍλyÈÚÝßßÜÙÕÖÖÖÔÖ×Ƚ¿ÂÀ¼½¿®ŒbE47@DHLOSUZ]`befghhhihilkpsiiv|x{~‰Š‰��Ž�Œ‹‹‹‹Š‡„„‚�‚�€~~€€€€‚ƒƒ„ƒ„‡‰�žµ»°Ÿ�‚|ywwuwz{}}}�…†‡�ŒmbpwpanšÁÌÉÊÊÊËËÉÌÍÏÇÄÏÐÎÎÏÎÏÐÎÍÏÏÏÓÏØÕ£rr|qp‹«ÀÆÇËÐÏй‚×Ý×Õ×ÖØÙ××ÖÓØÏÃÂÂÀ¾»½º»±ŽnO947>DIKMQUZ^acbceeefgihmthjx‚ƒ}}Š‹‰Ž���‘‘��Ž‹‰‰ˆ†…ƒƒ‚‚���€�ƒ�€€‚…‹’¢µÂû­š‡}ywwuvz{}�‚„‡ˆ‰Ž�oWYgvugiŒºÉÆÇÈÈËÌÌÌÎÉÆÎÏÎÑÎËÏÐÏÐÐÐÒÔÑÏÖØ¬tjuuv‰ªÂÅÃËÐÑ»…ÎÒ×ÚØÖÖÔÕ×ÓÓÒÀ»¼½ºÂ¼µºµ´©‰r[D427>CEINUXZ]__accdfffjtjiz†ƒin‰‹‹Ž��‘““’���ŒŒŒŠŠ‡…„……„ƒƒƒ�~~€‚ƒŒž®»ÁÀº°¤Ž~wttvyzz}�„…ˆ‹‹ŽŽpXQTetwmbx©ÆÈÆÉÉÊÍÎÌÌÏÎÎÎÐÐÍÎÑÐÑÏÏÒÓÔÓÐÓ×µ„ntxt|¦ÆÄÈÍÑ»…ÓÙרÔÒÓÍÔÓÏÕÏ¿º»»ºÀ·­ºº¸·Ÿ€paP<106=AGLOQVZ[]`abcbcdsni|‚uYb…‹‹Ž‘‘‘’““‘�������‹‡††…„„‚�~€�‚ˆ—¥¬´»½¸¯¥“€vqptz{|�…‡‰Š‹�ŽrZVRT\n{p^kšÂËÇÆÉÌÍËÊÍÍÎÍÍÐÐÍÍÏÑÐÏÐÓÔÓÓÏÑ×È“kqunw�»ÀÅͺ�ÕÞÙ×ÎÒÖÔÓÒÔ×ɼÁÁÀ¾²·¾¼¾º·«�}tk[F5/27=BFJOSVX[]^^^a`mpl}|jWg…ŠŠŽ’“”””•“‘‘’‘�ދЉ†…„‚‚€}}��…“¡¤©±¶·±ª¢•…xomptw|€�…ˆ‰Š‹�ŽpXYZYX]kvufd†¶ÉÆÄÉËÌÌËÌÏÐÑÏËËÍÍÎÍÎÐÒÒÑÑÑÐÏÔÍ›nlujiаÄǹ…ÕÚØØÔרÖÑÒÖÔó½ÁÂýµ¸¼¼»·®£‹vl`Q@4/18>BFKOSVXYYZ\_clo{xcZv‰ˆ‹�““•–”’““““‘��Šˆ‡„ƒ‚€€~z}„…„Œ™žž¤¬°¯ª¦¡˜�‚tlkmqw|€ƒ†‰Œ‹�Œr`cea\\\bqxi^v§ÇÈÆËÌÌÈÌÏÍÏÏÉÊÎÎÎÉÍÑÑÑÐÏÎÐÐÎÒѦokxol‘·Çµ†ÕÜ××ÖÖÕÖÖÖÙО¾Á¿²²»º¹¹¶³š�|smeXJ:0/28>CFKORTVWY^[dqzvba~‰ˆ��‘“““’‘“”‘‘‘�ŽŠ‡…‚‚€}zz€†††Œ“–𠦧§¦¤ š“Œ|mihmsy€ƒ„†Š‰‹Šviifd_\[[^kwpcm–¿ËÊÊËÉÅËÆÅÌÈÈËÎÏÎÏÐÑÑÒÑÏÐÑÐÌÏѰxkyrm…¶·…ÔÚ×ÖÔÖÖÖ×ÛͽÄÇÅù»º¶·º¸¸º¹ªŒzvqi\NC8/-39>AFJNQUXZYaqyvcd~†‡Œ�‘’“’’””“‘��Ž‹ˆ‡…�€}}zux}€‚„†‡ˆ�™¢¢ ¡ ›”އ|mgehpx}‚ƒ‚†‡Š‹tfgd`]ZZ^[]gtvic�±ËÈÇÈÁÇÌÍÈÇÍËÌÍÎÐÏÐÏÐÒÏÏÏÎÏÍÎ׸{juolƒŸ…ÏÔÖÖרØÖÙÕ¼·ÅÄÅÃÄÿ¿ºµ¸»»½¸±Ÿ…~yvph`VL?4-.3:>CFJQWWX_nyxji{…‡‹��‘“‘‘’’‘Ž�ŽŒ‰†…‚}}zvqorrhenx{~ˆ•˜”“’ކxoqmgdfnv{~�ƒ…†‹Špbdd`^]\][XYerulau¦ÄÆÆÈÉÎÏÊÏÌÉÊËËÌÎÏÎÎÏÏÍÍÍÏÑÑÏÕ¾ƒmsuju…Ó×ÕØÚÙÚÙÜÐÃÈÈÅÄÅÄÄÀÀÁ»·¼¾¿¹´°”‚}xsojc^SG:0,/5;?DJQXXZhx}}~w‡‰Ž‘‘’�����‹ŒŒŠˆ‡„€|{zyvngfcVJLXju{�„ƒ‚‚l[anqlgekt{~€�ƒ†‹†j`ddcb_]\[Y[]`gtufi’»ËÈÇÊÌÌÎÊÇÉÊÊÌÍÎÎÐÏÏÎÎÌËÐÑÐÎÖÆ•pqsj†ÓÚØÚÜÛÛÜÛÓÍÌÉÆÄÅÃÁÁ¿µ²»¿º¶µ¦‰�}xtokgbYJ@:1,06=BFOUWaty…‹zvƒ‡��‘�ŽŽŽŒ‹‹Š‰‰‰‡ƒ~ywxxxtlb]ZWPLRapuvuuvnXWfqwvojkry|~�„Š„h`cca^^``_]\ZX[guvid¯ÊÈÆÌÌËÌÊÄËÏÍÌÌÎÑÐÏÎÎÍÊËÍÏÐÏØÒ¡rot†ÓÛÛÛÜÜÝÝÙÍÊÊÊÊÈÆÇÇÆÆÅú­µ¿»´²°•‚�|yuoedcZRJA6-,184.-3:?DM^u|‹‹‡€ƒ�‘��‹‰ˆˆ‡„ƒ„ƒƒ�~|||~~~{vpkhhllkmmllicfmquz}€|wtwyz|~ƒŠyecb`fg_]][^`_[XXWYjytce�ºÈÈÇËÉð¼ÍËÉÊÍÎÐÏÌÍÎÍÍÐÐÏÑÏÕÕ°{‡×ÞÜÝÝÝÛÛÔÊËÍÏÍÍÎÌÈȼÀÃÁ½º¸´¸´´¡‡‚zutsnhddd^UME<30/4@PVs‡ˆ…~|�‹��‹Š‰ˆ‡†ƒ‚‚€�€€‚‚�€}|zxtpnmmkhfffdgmtx}€��‚€}{wvvx{�‡raaaacc_^ZY_`ba^ZWVYdprg_{«ÆÇÆÄÄÄÆÈÉÇÈÍÐÒÏÍÎËÌÍÏÐÍÏÑÏÒØ´‡ØßÝÝÜÜÝÛÏÉÊÊÍÍÉÈÌÊÈÇÅÄÅ¿»¹¹¶º·³®•…�|vsokihe`XWSKB:21>LPb‡‰ƒ€ƒ‚ˆ�Œ‹ŠŠ‰‡†„‚�€‚ƒ‚„…„‚‚�€€~}zxsnkhebbcgnuz~�ƒƒƒ„ƒ��|vtuz�…l^_bcb`]\\^_^ab`\YX[[^jvnbošÀÇÅÇÍËÄÃÄÇÍÏÑÏÎÏÎÌÍÏÏÏÑÒÑÑÓÁ‡×àÝÜÜÝÞÖÊËÍÌÊËÆÅÇÊÅÂÈÇÅÄþ»¸¶¶µ¶¨Šƒ€yvqkljd\SZ[VPIDAGGJP{އ‰Š���ŠŒ�‹ˆ‡„„„……‡ˆˆ‡„ƒ„„ƒƒ‚€~|vrlgeccfkqx}€�ƒ…†‡„„„zqs|ƒ…k_`aa_^]]_`__]]]]\Z\\W\lzyda‰·ÇÅÅÄÇÆÃÇÌÆËÐÎÏÌËÌÍÍÏÒÑÒÓÔº‡ÖÜÝÝÝÞÜÓÊÍÏÎÌÍËËÇÇÄÀÅÇÈÈÅÿº³´¸¸µ›„ƒ~|xqpof[]\XWZYROUONHb‰††…tt�ŽŠŠŒ‹‰ˆ…„†‡ˆ‹Œ‹‡„……„ƒƒ‚�€~ysld``chnsx|�„„„……�ƒƒ�~su~…�h``_\[\^__`^]_``__\YXZZ\euvf`|ªÅÈÅÈÇÄÇÊÇËÏÌÍËÊËËÎÏÑÒÐÑÕ½ˆÕÖÛÞÙÚÙÏÌÊËÌÍËÅËÉÆÆÆÇÈÈÅÀÁ¼º¹»»¸°ª’†ƒ�|xsokdeb[V[caZZXWNQuƒ�|gfˆ�‹‰‹Œ‹‰‡†ˆŠ‹Œ‹Š†ƒ„ƒƒ„„‚�€€}xrkdbfksy|€ˆ�‡‚���‚………}{‚‡}d_`_\Z]^^`_]]acb`_][Z\ZWV\hsocn›ÄÊÆÆÅÅÊÎÏÍÍÎÌÊÈÌÏÏÍÎÌËÔ¾ˆ×ÝÜÜØÖØÑÎÊÊÎÌÌÊËÉÉÉÈÉÉÇÄÁ½¸¹¼»»º²²¢‰†€|}xpnmifc_]`cb_\\YQWnvqee„�‹‹�Ž�‹‰‰‹Ž��‹‡…ƒ�‚ƒƒƒƒ†‰…~{xsqsux{~ƒ��ˆ}|„……‡ƒ€…ˆ{c`^]_\^`__``^```_]^\\ZYWWST`qtdf�¸ËÈÃÅËÍÎÍÍÍÊÉÊÆÃÌÊÆÍÏÓ½‡ØßÛÛÙ×ÎËÑÑÏÑÐÐÑÍÌÆÆÊÊÉÆÅÇĿ¾µ¶¹º·³˜‰�||ywrnljgdb__eec_\VJHMRdn�ŠŠ‹��ŒŠŠ��ŽŽŠ„�€}||~���…ƒxooprttrnmos|�~yurx‚…ˆ†ƒ‡ˆxb]X]baa`^_c`^b`]_^\Z[ZZZWUUT[mtjcy©ÇÄÃÊÌÌÎÇÅÊÉÊÆÀÉËÌÏÑÔ½†ÖÝÛÚÙÙÀ¶ÏÒÐÐÑÏÐÍËÈÀÇÇÇÈÇÈÉÆÄľ¹¸¹·¹ªŒƒ�{zvqomlihebcdd`ZSM@8>_r}ŒŠ‰Š‹‹�‹‹���Œ‡�{wvwwvtroliea]\__^\\\[]bikllmrz‚‡Š‰‡‰‰wda^ca^_^`bb^]__\^][\\]]\YWXYSVhuoal˜»ÄÆËËÌÊÈÈÆÈÊÉÉËÎÐÐÒ½‡ÖÞÚÙÚÖÉÅÎÑÓÒÑÐÐÏÏÎÄÆÇÆÇÇÅÅÄÃÅÅÂÀ¹µ·°’‚…ƒ{zurpolihfc`a`[RMH??\s|ЋЋ‹‹ŒŒ�ŽŒŽŠƒ}uqonle^Z[]a^[ZXSQRRTXVPOKHM[gpy�‡ˆŠ‰‰ˆuc`\[[[^`b^UZ^[[]^^^aa_^\ZWW[YUVcsugd…²ËËÉÉÌÍÉÆÇÉÆÇËÌÎÏÒ¼‰ÙÜÛÞØÐÎÒÑÒÔÒÑÐÎÎÏÎÍÉ¿ÂÄÆÆÃÃÃÂÃÅÆ¾µ¶´§�†…�|zywsjighjie``^YRLF@Yw}ˆ‹‹ŠŠŒŒ�Ž��Œˆ‚zqbPFCFJS]acbtxmffih`_aVG11;>Ibt}‚…‰Š‰‡pXRNJS^`ab^X]^]]`ca__^^^][Y[^_]XW`rykbx©ÉËÈÊËËÈÄÆÆÅÊÌÍÎÒ¼‡ÖÚÖ×ÎÇËÍÑÑÏÑÑÍÍÍÍÍÏŵ¿ÇÅÅÅÄÅÆÅÅź¹¹¹¤Œ‡…‚ywxummjiligb][YTMH?Ry�…‹‹ŠŠ‹ŒŽŽŽŽ‰†‚xcH:8:?ANZMI[{€tijmgWIEEGJY\UMUky…Š‹‹†kVQNLUaba_bed`]]`ba`^]__]^_^_^^^[Y_nyscl™ÂÍÉÉÈÇÇÄÇÆÅÊÍÏÑ»†ÔßÎÎÐÈÎÏÑÑÑÕÒÎÍÎÎÎÍÄ¿ÅÇÄÆÇÅÇÉÉÅÿ¾¾¼´›‰„}usttutoljhgd\YUPJDDFIKOMHIJIJNPRRTUSPLNRSRTX\[[\ZZZ]_bdda`^WUTVYXWWWRM…ÐÎÍÎÐÑÏËÍÏÐÐÑÐÏÐÎÍÐÏÎÎÍÌÊËÆÄËËÇÊÍÉÇÊÃÄÃÃÅ¿¾ÃÇÅÅÂÂÀ¿½¸Ÿ‘“��Œ†{‰‚iWRRQUUZbfjI10/16AIPUWZ^_ab```aabbba]YX]enu}…ŠƒVAEHMR]lfG:AEHJLKNQQMJNMLLLIHIMQRTUWXYYXY^cbcggfggb\XXYXVTU\YP…ÐÑÌËÎÑÑÍÎÍÍÑÒÐÏÍÌÍÏÎÎÎÌÉÉÌÃÄÊÊËÌÊÇÉÊÂÃÉÇÆÅÂÃ¿ÂÆÃÄÁ¿¼º©•‘��Œ„{||…�€cNMQSTR[biiD30//2:ELOPQSVYXXYYZ[YWQPW`fjpx†‹‚T?CCIOU`olM:>@@DGILQPOPKHHHKLLMQRSTTRSVWZ_bbdeddbc_[WVYZVTTXZV…ÏÐÊËÊÉÈÊËÈÊÎÑÏËÌÎÏÐÎÍÎÎÊÊÍÊÈÆÈÍÉÇÆÈÉÈÇÅÆÈÇÃÄ¿ÃÇÅÅþº¶¯ ”��Œ‚yrƒ„„ƒv]IINSQQ\akb@3///06;DIJKLNPRQQPOMLLV`dgntz‚‡Š‚SDLMQ[bnU972./125;BFGGHIILPSY^aekpu|�…†ˆ‚R:@AEJRZ_fkyyhtyM8;@FGILMLRVWZZYWRPOQSSTRRTW[\XXWYYXWTRTTPS^ca…ÎÏËÉÊÌÌÊËÍÎÎÍÐÏÍÍÏÑÐÏÌËÍÉÈÈÇÈÊÊÊÉÊÊÊËÈÈÇÄ¿½ÅÈÈÇÇÆÆÃ¾À½¼²§š’šœœ�ƒŒŠtnsvjS@?IMSZcjM9930024;BJOQRQSVY[]`elosy~ƒ†‡ˆ�R8=ACISX^ekq~�—¤Š^K@>EIKJHIORVYYXNGJLNNMOTTRWYSQPUSPQUY[]aa`aa…ÎÏÍÉÈÉËÌÆÊÏÌËÍÎÎËÌÐÎÏÎÍËÉËÉÊËËÉÊÌÉ»ÅÊÈÇÈÆÁÀÄÇÈÆÅÆ´°ÀÁ¾·«¦š�•œ�™�†‰nkloo\E>FNTXagG7753126=FMRTTVY[^afjnrx}�„‡‡ˆ�R6:=AHRX^gmq|�…›�|iK>@GLKLNPSUVWSIGMONMLONNOPSSU]ZXY\]_a[TUUY„ÏÏÍÉÊÌÌÎÊÍÐÏÎÌÈÊÎÎÊÊÎÌÎÏÐËÈÊËËÉÊÉÆ½ÅÈÈÈÆÆÄÃÅÈÈÇÇȶ±Àºµª¥¢ž“•¡¡£–‡ƒˆznegnvdNAAKSWcaB7645448@IOTWZ[^aejmpw|�ƒ†‡‡€Q49<@IRX_ekv‡”ƒMRs�†sQD?@GKKMPQSUWSNTWRSTSSUUSZ][ZUTTV^ZRg‡œ“[ƒÎÎÌÊÉÌÌÍÍÏÍÌÍÏÈÉÍÍËÎÎÌËÎÏÌËÊÌÌÉÆÅÉËÈÇÈÉÆÅÇÇÌÌþ½»º¹°£ž¡¢  —’ž¤§œŠ‚ˆ„tngcongYG@ENUh_?967788;CLTY[[^afkoty|~�„†††O28;?ISZadn„�‘„O3;J`ryv[I<><:99:?HPTVY]chlqtw|€ƒ†‡‡†P/5:?GS\al€Ž��xRG=77Dt™”Š^D>@HKJNQQTSQQNONPUTf�Ž}{›§£ƒožÒÎÚÝâȃÉÊÉÆÈËÊÉÉÅÇÍÍÊÇÇÉÈÊËÉÊÍÊÊÍÍÃÂÇÄÄÄÆÄÄÄÅÆÄ»´±¬©©§¥£�˜™›–Ž•™›™ˆˆ†xqy�‰‡ysntl`behkd\SP^[?:9;<=>?DJOV[_ehlpty~‚ƒ„†…ƒ~V/3;?HU_iŽ�ŽŠfCFJKC9Ce…–‹†zX<>DEAEEJQQZhr]Rh‘Öஞ¬Ÿyw²ÞÛÄÉÌÆ­‚ÉÈÅÃÃÊÈÇÆÆÍÍÍËÈÇÃÅÊÎËÈÍËÊÌÍÈÄÆÂÀÂÁÀÁº¯©¦¥¦ª®®¨ž–”—œ›�Š�™�ŽŒ˜†|Š‹†yglvpfa[]^ekt…ІoYK?98:?AFMUZ_eilpuxz|~‚€|wZ726=HR`yˆ‹‹‹VBCFILI=4AZt‹š‰iWG?P\`lx€œ¬§{^k�ÒÒ®§¤�…©Ä·®­ª§¥”‚ÉÅÁÅÈÊÍÎÇÅÌÊÆÈÊÉÉÊËÎÌÈÈÉÈÈËÉÇÅÃÃÀ½½»·´¬©ª¨¥¨®°¦˜‘‘•œ£ “‡…Žž”Œ—™›¢–‚„|q}€zy‚xjefjy�”œ¢¢˜ŠvaTMKOU[agntx|€�„ˆ‹��‹„‚fC=9?Md�“–˜˜•�jPOOQQSVPA>E[q•² t�½ ™–•§ÁǺ°¬‹¤ÇÁ¹º¹¸¿¼²±³´´´¶©�ÆÆÄÂÅÊÌÍÊÈÉÆÂÆÉÉËËËÊÉÈÇÈÈÈÉÆÅľ¸³¯«¨ª©©«ªª¯²©™ŒŠŽ— ¤ “‰…�•Š‹�š�u`WRSUQQRVSMHCGMNRSYgmzzmZA89@NW[iw|€ƒƒ�€}yumfcaadfda]XQG;5434@O]bachmqvy{|€mPEDDFKPW`g^OVeƒ¸ÈÉÉÌÏÎÍÐÐÎÎÎÎÎÎÑÑÎÎÖ»jw|nm’»ÉÈÉËÊÌÉÈÊÉÌÉÉÍÎÊÍÎÒ¿…‡ÔÙÕÕÔÖÙÙÖÕÒÔÙÛÚ×Óê�–‹��‹‘šš’‰qmkjjjkmmkjjlmnlmpqpkgeYECB:ALRXhyƒƒ„„�|ysmhda`YOHC?>:620002AVdc`cinrvy|€‚‚vVA>=?BFNYfiVTf”ÄÆÊÍÎÎÎÐÍËÏÎÏÏÐÎÑÐÎÎÐÖÇ�js~tnŒ¹ËÊÊËËÊËÊÈÍÌÈÍËÈÊËÌÔ·…ÑÚ××ÖÔÔÕÕØØÛÖË¿¬š‹‡‰‰�“‘�‹‰‚wlgddiljlkkllllopomoonqshSG?AB:AJOWiy�„………�|wrmjgfaVKEDCDFHIGEDIT\\[_glosw{‚„„~dC987987:I^YWo¨ËÊÉÌÏÑÏÏËÄÆÊÍÎÏÏÎÎÎÐÒÒÜÒŸrs}sj‚²ËÊÊÊÉËÌÊËÎÌÎÍÊÈÈÎμ…ÏÖÓÓÖÙÙÙ×ÑÅ·¦š�ŽŒ„�š–•”�„wmiffhjiimlllmmloonooooonmkkpkYMF@CLPWhz�„†ˆ†ƒ~wtsssqmid_\\\][WSPPRTUV\elprvz}€ƒ…†„tYHD@>=716BO\€ºÊÈÉËÊËÎÍÏËÆËÍÏÏÎÍÏÏÊÎÔÒÖÖ¯}oytl}­ÊÊÊÈÉÍÍËÌÍÎÐÎÍÍÎк…ÎÓ×ÚÛØÌºª�”��•œŸ•„�Œ‡~yrhefjjklnnmnllnqnnonoqppooomly�ucNCJQRWi}…†‡‰ˆ†„}~~|ywtqmkigc_ZVUUVVY_florvz}�ƒ†ˆˆ~fTMKLLIJOKK^ŽÅÉÇÉÌÿÌÍÎÏÎÏÎÐÎÎÍÏÐÎÏÓÓÎÐÔºƒoz|oy§ÆËÈÉÌÍËÊÌÍÍÍÍÑÏÑ»‡Ô×ÏÄ´¢”‹Š‘—› ¢›“ypyxnhhheimnpnmnmmmnnprpopoqrrpnoqoxxlqvqcUVTQYn€‡ˆ‡ˆ‰‰ˆ†…„‚}{wsokheb`]\[\^aekqsux{~€�‚„‡ŠŠ…r_UQQUY_gi^e”ÅÊÉÈËÈÇÎÏÏÎÍÍÎÐÎÎËËËÎÑÓÑÑÏÏÖĈjwzou�ÁÈÈÌÌÊËÍÎÍÍÎÑËÊ»ƒ»©—‹ˆŒ”›Ÿ¡�”ŠƒslgfkiehhhkklnnkklkklmmoopppqppqoonoqxkeksuslcXO]v„ˆ‰‰‰‹‹‰‰ˆ‡…‚�~{vqmjihgefggjmrvwy|}€€�ƒ†‰‹Œ‰pd\USY`iqqr—ÂÈÉÊÇÊÐÏÐÍÐÐÌÏÍÌÐÍÌÉÌÐÒÑÐÒÑÑÙÈŽmszor•½ÇÈÈÉËÌÏÏÍÐÐË̺o‘Š�–ž¥¡—‹~vpmn|�•†n[Z_abcabhiijkjjlnnnnopppnoonmmlrtjjkrvvsmd\k�‰ŠŠŠ‹�Œ‹‹‰‰‡„ƒ�}zxvtssrrqqsvxz{{|}€‚�€�‚†Œ�‘ކ{qid^X[dnu{šÄÆÆÉÊÌÎÎÌÉÁÇÏÎÊÏÑÐÏÎÏÏÑÓÒÑÒÓÓÙÑœorypp޶ÄÄÊËÊËÎÐÐÐÏкo ¤¥ –†xnkmx‹šªÇÒÇÄ·‰\OTXXY[^beghijkklmnnoponooollkttiijx{wtrpp|ˆ‹Š‰Š�Ž��ŽŒ‹‰‡†…‚€~}|{{{yyz|}}~~~‚ƒ‚�€‚‡Ž“•’‹�ytpmigipx‘¹ÎÈÆËÍËÌÊË¿ÅÐÎÍÐÐÎËÎÐÎÑÒÓÒÔÍÆÎÖÔ©vqyrnŒµÃÅÈËËÍÐÏÍÍмwž‹|snqxˆ›­»ÉÉÏÚÌÀÏÝÓŸ`IGKPSVZ\^adfffghjmnkkmmnppnkutijo~|stvux‚‰‹ŠˆŠ��‘��Ž�‹‹‹Š‰ˆ†„‚��€}~~€€€€‚„„‚�‚…‰�‘”“Ž…}zxttssuz‚ˆŠ«ÍÊÇÉÊÌÍÍÏÐÈÊÏÎÏÍÊÏÎÍÑÒÑÑÑȾËÐÕÛ«spyrpŒµÄÆÊÍÌÎÐÏÏÒ½avnu„—­¾ÏÖØ×ÓÉËÐÈÀÇËÑЩnG>AHLOQUY\_abceilmiikkklnonvwjlt€}z}|y{ƒ‹Œ‹ˆŠŽ�’‘�‘‘�‘���Œ‰ˆ†…„„„ƒ€€��€�‚„…„ƒƒ…‡‰Œ” ¢˜Š{{{zyyz}ƒŒwjžÇÌÆÈÌÍÌÎÐÈËÎÏÐÌÎÐÌËÏÐÏÐÍÍÏÏÓÓÔØ®umvsq…­ÃÅÈÌÍÐÐÐÑ»e–©ÀÏÚÝÞÝÚÔÔÓÐÒÔļ¿ÆÉ¨vT>8>EHLORVY\_behjijijjikmntxlmvƒ…ˆzp{}„‹ŒŒŠŠ��‘‘’”•••“‘�ŽŒŒŠˆ‡…„„ƒ‚‚‚��ƒ„„‚�ƒ„‡ŠŽš®»¹¬™„{{|~~~�…ŽˆihŽ»ÊÆÉÌÊËÎÍÉËÐÐÌÌÐÏÌÍÏÐÏÏÐÎÍÐÑÑÖÛµ{kyyn~¡ºÃÆÊÍÏÎϺvÊßáÝÛÙØ××Ö×ÔÔØÎÁÀÂý¹½¼¯ŠbD67>DHKNQUY\`cfefgghhijjoxmlx…‡„b^y~„ˆŠ‹Š‹Ž‘’“••——–•“‘‘��Œ‹Š‡……†……„ƒƒ‚�~�ƒ†‹š¯ÀĽ´¥�}yx{~€‚ƒ‡Œ�|ib}­ÊËÈÊÊÊÌÉËÍÍËÂËÑÏÎÏÎÎÐÐÎÍÏÍÒÑÒÛ¾ƒmyxm}žºÄÆÊÎÎк{Ì×Õ××רØ×רÓ×ÒÃÀÁ¿¾½º¼¹¹«‰lP:26?DGILPV\_a`aceedfhhkxqm{…‚qT\u€ƒˆŠ‹‰‹Ž�“•••———–”“”•“‘��‹ˆ‡†…„„„ƒ�~}€€€‚‡“¤³»½¹´ª•xy{}ƒ„ˆ��|wqer ÅÉÇÈÉÊÌÌÍÎÍÆËÐÎÐÑËÌÐÏÐÒÐÑÓÒÏÑÚÆ‰jqvt~›ºÄÄÉÎѹ‡ÓÔÔÚÙÖÕÒÐ×ÓÑÖǺº»¹½Â±´º´´ ƒpYD416BFJOSVYXZ]_]bsx€rcixˆ‰„�‚…ˆŠ�‘’“””“”••””’‘�ŽŒ‰†…ƒ�€}zxz~‚……†ˆ‹�“œ¡¡¢¡ ž•onsx}€„ŠŒv`^]]hvtbd‰¸ËÆÉÌÌÉÊÎÍÍÏËÈÍÏÏËËÏÐÐÑÐÏÎÑÐÏÕÀ†huwi~ªÃ´‡ÕÝÙ×ÕÖÕÕרÚÑÅÅÃÂÃÀ¿»²¹»¸¸¹·¯�ztndYI;2/19@AFKORUX[\]`ox€{kov~‰†€�…‡Š��’’““’’“’“��ŽŽ�‰‡…ƒ€~~~|wssttmiov{|�‹•˜—––”Šxljouz€ˆ‰ta]\\[cqtic|ªÇÌÉËËÆÅÊÄÊÉÇÊÎÐÎÎÐÐÏÑÒÏÎÑÑÎÌÓÅ‘ktxov¡´†Ô×Õ×ÕÖØÖÔÚÒ¸¼ÇÅÄÂÀ¼¿ºµ·¹¸º»·¡‡~yvpfYND8/-4:=BFINSX^]\hx~ƒ€„{p�ˆ‚‚„†‰��‘’’‘‘‘‘‘�ŽŒŒŒŠˆ‡…�}~~|ztlhibO?CRcpv{‚†‡††‚xojhlsx|†‡o_]Z^^[_mwqck—ÁÌÇÈÅÃËÍÌÆÊËËËÎÐÏÐÏÏÒÑÏÏÎÎÏÍÔΕjpslv�†ÓÕÔ××ÙØØÙÙÇºÄÆÄÅÃÄÁ¾¾¹¶»½¼¼´°–‚}ytniaVLA5//39>BFKPVZ[_rx{‡�‡ss…ƒ�…†ˆ���‘��ŽŽ�ŽŒŒŒ‹‰ˆˆ‡ƒ€|||{yvmc_\SHBBHUepvxwwwtsqkgipv{~„†n`_\]\YX_lsrffЏÆÅÈÉÊÐËËÎÉÉÊÍËÍÏÏÎÎÐÎÎÎÎÐÑÎÓОopwpj…ÔÚרÙÚÚÚÜØÌËËÆÅÅÄÂÀ¿ÂÀº¹¼¿¼¶¸ª�‚|vqnid^TF:2,.5<@DGJQUWfuoxŠ�†„‚€„†‰���Ž�ŒŒ‹Š‰ˆ‡†††††…‚}{{{}}|vla][YVSLKYippoonouwrihouz}„‚la`]]\ZZ\]`lxocy¦ÆËÆÈÌËÍÌÈÉÊËËÌÍÏÏÏÐÎÎÎÌÍÐÑÎÓÓ¬znul‡ÓÙØÚÛÛÜÜÛÕÌËÉÉÇÅÅÃÃÄÂÁ½¯±¾½¸µ´›ƒzwsoiebVID:/,.7?CEILSZr{x‰‘Ž‹ƒ€�„‡‰�Œ‹‹Œ‹‰‡‡‡†„‚ƒ„ƒƒ‚|||~��€~yqidbbdbcgkmlmmnsx|zqlovy|‚|g_^_`_`][ZY`nwqdj•ÁËÇÉÌÌÌÌÅÇÎÎÍËÍÐÑÐÏÎÎËÊÍÏÑÏÓÚº�ls‡ÔÚÙÚÛÛÝÝÜÑÈÊÉËÊÈÈÈÇÇÅÄ·²¼½¸³´©�‚|yukee`ZSJA6.-2:?EOVSf„‡‹Š†€~€€ƒ†ˆ‹‹‹ŠŠ‰ˆ‡‡‡‡„€�‚�‚�€‚‚‚ƒƒ‚€~zuplkkjihhijjmsx|€yrrvy{�xfea_aa`_[ZZ[_fuwgb…´ÈÈÈËÌÍǾÄÍÌÊÊÍÏÎÏÎÍÎÍÍÏÐÒÑÒÚ¿†n†ÖÝÛÛÜÜÜÚÚÑËÍÍÌËÌÌÉÈÆ¿¿Ãþ»»·¶¶´£ˆ‚|wurmfab_XPH@4//5ELTQTv�‹‡…ƒ†„€‚„ˆ‹‹Š‰ˆ‰‹Šˆ†„ƒ�€�‚�€ƒ††…„„ƒ‚€~|xtqlid`adgkrw{��~yvvvy€tdgb]^[[_`]XWYX`sxk_t¥ÃÈÇÉËȸ³ÉÍÊÈÌÎÏÐÎÍÎÎÍÎÐÏÐÏÑ×Ä�†ØßÜÜÜÝÝÜØÌÊÌÍÎÍÍÍËÈÇÀ¾Ã½¹¸¶¸¹´±•„~xwtqlheea[TLD?85CEJRNc†�‹ŠŒŽ„|�ƒ‰��Šˆ‰‹Œ�‹ˆ…„ƒƒƒ„„„…‡ˆ‡………„„ƒ‚�}{vqkfcbbhpv{~�‚ƒ‚~zvsxpbca^\Y]_bca[WWV]krm`h“½ÉÅÅÅÅÅÉÉÇÇËÏÑÐÍÎÌËÌÍÑÎÎÑÐÐ׿‡ÚàÝÝÜÜÝÜÑÈËËËÌÉÄÈËÉÆÈÇÅ¿¼º¸¸¹µµ¨�„�zusmjjfcZWXSQIBIJDMPUq‰‰ˆ‹‹{lzƒˆŒŒ‹‰ˆŠ��ŒŠ‰†……†‡ˆ‰‹‹Š‡†‡‡†„„ƒ�€~ytnhedfkqw|‚„…ƒ‚xqx~oca^[]]___`a]YYZ\[brufd‚±ÈÅÅËÍÇÄÄÅÊÎÐÑÍÎÎËËÍÏÏÐÒÑÑÓ½‡ÙàÞÝÝÝÝÚÌÊÎÍËËËÇÆÇÇÀÃÉÈÆÆÂ¾º´³´¶¶Ÿ„„}xwplng^VX[[`[QRSNLNO\v„†„€lYqƒ†Š�Œ‹ˆ‰Ž�ŽŒŠˆ††ˆŠ‹�ŽŒ‰‡†‡†……ƒ‚��~zuniddhlrw{�„„���yqz~k___]_a_^]\\]]\[\ZXdt{n]r¤ÃÅÅÄÅÈÅÆËÈÇÏÍÎÎËËÍÍÎÑÑÑÓÕ¹‡ØÙ×ßÜÛÝØÎÌÎÍÌÍÌËËÆÄÂÃÆÉÈÅÃÁ¾·µ¸¸µ­‘…‚~{urqm_^aZW]e^XXYUOKMVm|{r`Xo�…Š�Œ‹‰Œ�’’�Œ‰ˆ‰‹�Ž��Ї…„ƒ‚ƒ„ƒ‚€€ƒ‚{tnihkpuy|€€€ƒ~w€|e\]___`_\^``__^ZWZZ[_lwnaj”¼ÉÆÇÈÄÅÊÉÉÎÍÌËÊÊËÌÎÎÒÒÐÔ½ˆØÙ×ÝÛ×ÚÔÍËÈËËÌÆÆÊÈÈÇÆÆÈǾ¼·º¼½»³¯¤‹†„zxpljifa]\ceba^[ULD>@Pflegq}ƒˆŠ‹ŠŠ�‘””’�‹‰‹Ž�‘�Œ‡„ƒ~�‚‚�‚‰‘�†}xutuvx{||}{{}�…ƒ~„zb[[^^`__]^bb`_^][Z[XVYamrhd‚³ÊÈÆÆÄÈÌÏÎÍÍÌËÉÊÍÎÎÍÍÊÑ¿‡ÖßÝÛÚÖÕÑÏÎÊÍÏÎÎËËÉÉÉÈÈÇÅÄÁ¼¹½¹¸¹ºµ°™‡ƒ}~{tnmkihhedcdea\VOE<44Qmpos}ƒ‡‰Œ‹‹Ž‘••”“Ž‹Ž����ˆƒ€}zyz|€…‰ˆ€wrrstqmkmqtuvux€…†‚…tb^\__^_`_^^``]]^][YWVVSYhuk`w£ÄÊÅÂÈÌÍÎÍÌËÉÊÊÃÇÎÆÉÎÒ¾‡×ÞÛÛÙØÑ¾ÈÒÐÏÑÏÑÏÌÉÂÇÉÈÆÄÇÊĹ´¶¹º¸¬�„~~zxuomjjlifaab_]VNG@72Hjrrv{�…‰‹�Ž�’––—•’���ŽŽŠ„~yuuvvutrrqokea``bb`]\]cjmlls|„ˆ‡‡qcdaa^]ba_aa^^^\[[[\[XTUTUdspdh�¼ÆÁÆÌÌÎÌÅÈÈÉÊÂÅËÌÎÐÔ½†ÖÛÚÛØØÑ·ÂÒÑÐÐÏÏÏÌÌÄÁÈÆÇÇÇÈÇÃÄÄ¿º¸·¶¶œ…„ƒzytpnmolhdba`_ZQHA90?etuz|ƒ‡Š�“’’•™š˜–“��ŽŽ‡€yspomkh_[^^`a][ZXVVWWVSRRWahp{ƒˆ‰†sc_``_ab`\^_\\]\[\]^]ZXWXVR]pteb€¬ÃÄÉËÊËÊÉÈÈÊÊÊÉÍÐÏÒ¾‡ØÝÚÛÛÙÑÌÍÐÓÔÑÐÐÏÏÐÊÇÈÅÆÇÇÄÃÂÃÄÄÃÀ´µµ¥Šƒ…‚|{yusonnkhd`^_]VNC;39`xz~‚…‰’”“’“˜›››™•’‘Œ‡€xkYIGGEKTQIIXba]XUSLBFJ;28I_oy‚‡Š…iZ]]^``WW]][[]^^_a`]\[YWZ[VT[kvoap ÃÌÉÉËÎÊÇÆÈÇÅÈËÍÏÒ½ˆÙÜ×ÝÙÐÊÎÑÑÐÑÑÏÎÎÎÎÍο¼ÅÅÆÅÂÄÄÁÂÄĺ¶¶³¡Š…ƒ�|yywojlmle_[YXSKB966Wz‚€|ƒ‡Ž“”’“—œŸ£¢œ˜–�ˆ€oT?68951/57AJENdt}…Œ…\N[_`aa[\`^\^ba_``_]]\Z[]^_\WZjxsci’¿ÎÉÉÌËÉÄÄÆÅÈÌÌÍÑ»ˆÕÜÖÍÏÅÉÍÐÒÏÐÒÎÌÍÎÍÌÊ»»ÇÅÃÆÅÅÈÇÅÂÂÀ¹º»µ›‰†ƒ}vvwrnmklga]VSMD=<<8Mw‚„€{}�ƒˆ‘•”–™�¡§©¢�œ•ˆxaT[_`_`^ZQC601468;=<5&'In{jU[nzƒ‹€[R]ba^`dea^\^aa`_^__^]^_^^^_]Z\euyic‚´ËÉÉÉÇÆÄÆÉÅÈÌÍл‡ÓÝÚÏÓÊÍÐÎÐÑÕÖÒÏÌÌÍÍÈÃÆÈÆÆÈÇÇÈÉÈÄÃÁ¾¾¾»­‘…}vttsutoligda^TLFBDD>Fq„…‚{y}ƒŒ�‘”˜›ž£ª©¤ —†tgo{{x{„Ž–—ŒwbMBCEHIJD=Kn‹’„nemx‚‰|`\_[WSQUVUVRQZabb`a``____\[\\Z\\`oxqdt£ÇÌÅÃÅÆÉÉÆÇËÍй†ÓÜÝÝÒËÌÏÒÓÒÑÒÐÐÎÈÊÌÊÉÉÉÉÈÈÈÉÈÇÈÇŽ¼¿¼¹Ÿ†y{|zytqqiddc_VPNMKKBBjƒ…ƒ{wy{~‡��‘“—™�¥¬¨¡•…zz€ƒƒˆŽ�‘𢧩¥œ‘†€ylijmyˆ––‹€tqw†ya^YSRROQMJKMMV\ZUTW[_````a^\\Z[\XYfusch”ÀÊÅÃÅÈÇÇÈÇÉк‡ØßÜÖËÊÎÑÏÏÓÎÍÊËÏËËËÌÍÈÈÉÈÈÇÉÉÈÉÈÆÅÁ¼¾½»±•ˆ‡…�{uvuoife_\ZYSTPACf��{vvy{‚‹�Ž�’”–œ¥¥ž”‹†‡‰‡‹—œ˜’��”ž©³µ°­£•‘�‹†Š��Š„{vw|ƒr][XXXVUVSPPTWPNLFDHV^^__ada`_][Z[YW^mria€³ÉÆÁÂÃÄÈÅÇͺ†×ÝÙÕËÎÑÏÀÅÒÓÑÍÌÎÍÎÌÊÉÊÉÉÉÉÉÉÉÊÊÉÅÃÃÀ½½¼½«�І‚|yxutrpkeca][YNBDaz€€zsquwzƒ‹�Œ���‘–š˜––•—™˜˜˜˜–•“���”𠤍¦¡›”‹„ƒƒ†ˆ„}zx{~jZYYZYYWUTUVWYSLIGGP[^^]]_a`aa^\[[[ZV[hsnbs¡ÃÅÀÂÃÇÈËË·‡×ÜØÑÌÐÑÐÊËÒÓÍÎÑÎÎÎÌÌÊËÇÅÊÉÈÊÊÇÇÉż¸¼¾¼¼¼¶š‡†„‚€|ywtrqlfbbb`WOUTGk}zrnpsv|…ŠŠ‰Š�ŒŒ�’”˜ž¢¥§¤�—“����І†‰Œ�ŒŠ…‚€}}~‚ŒŒ{z~wd\[ZYX[\WUVTTTUQLOW__ZWRPQTVTW[]_\Y[[ZY_qteg�»ÊÅÃÇÈÊθˆÙÞÖÍÍÏÑÓÔÏÏÏÍÍÏÐÎÍÎÌÎÌÅÇÇÀÄÈÉÄÅÇȼ·¼¿¼»º·¤‡‡‡…ƒ€|urrplidhh`[Vnw@Rt|{tnkoru{ƒ†„‚‡Š‰‰Œ�–ž¡£¥¥¡š“Œ†‚~}{zzzzyzxvvwxŽ•‰€}~n^^\\[YY[XUUQRVUQUX]ZSLLLMNMLGKVXZ\]\Z[[Y\kvja€µÊÅÃÆÉ͹‡ØÝÒËÍÎÒÓÒÎÎÏÓÎÉÑÍËÍËËÌËÌÈÅÉÊÉÆÈÊÊÄÄý¼¼º·­”Œ�ˆ…ƒ}stxvoighdbc_s‰cFeuxtniknos|‚‚��„‰�“™� ¢¥¦¢š“�†~xtsqomnqrromnqw�Ž˜˜‘…xe]^]\\]][XWTSUWUW_\UQOKKNNPNJGKMKOY^[[\^^Y[gsnbt¥ÃÅÂÇÌ·‰ÕÖÌÊÌÏÓÔÐÏÍËÐÎÊÌËÍÍÎÌÍÎÌÍÍÌÌÌËÊÊÈþÁÀ¾¾½»¶­—�‹‡†‚}|{yslggfhicr……RUjttojiknqv{}}zy}ƒŠ•›ž¡¢¥¦¡š”�Š€ytpmihiiiiggkry„‘˜œ›Œr_^_^\\^^^\[Z[YWY^_XRQSTQPMONLLMJINZ`b`_][Z[X_qxkl‘ºÅÅÌ·ˆÖÓÉÊËÐÓÖÒÏÍÊÌÏÊÂËÏÏÎÎÍËÊËÊÌÎÎÌÊÈÉýÀ¿¾¾À¿»º¤ŽŒ‰†‚�‚~xsnmnpnjfuy�mO`krnkigjmpuxwutuy€Œš£¤¡  žš”‘�…}vqmkjiihggjpv|ˆ“—œœŒm^^__\]\]_^\^]\]]]XTTRQRRQSROPQPNJLX`eb^][YZZ[bq~n`|ªÄÊ·†ÖÔÉÊËÐÓÇÅÎÉÍÏÍËÉÌÍÏÍÍÍÉÉÇÈÌɺÄÊÉÌÌÇÀ½ÀÁÀ»º¼³™Š‡„€ƒ�{rqusqkjws‹ŠZZemnlkhfhkotvspry€Š˜ ¢¢ Ÿ�›˜–’�ƒzuqomjhggkpuy��™œ œ„f__^^]`_]^^]^^]\[XVVUUTSSRSRPRRRPKLQZab`]][YY\_]gvqaoœ¼¶‡ÔÑÊÍÌÌÓÅÀËÆÊÏÊÌÍËÍÍÍËËÌÊÆÈËÇ»ÃÉÊËÊÇÂÃÃÃÁ·´·¼ª�‡„�‚…ƒ‚€{wwusmjyr|•rZcimnlkhiijorpoqv€‹“™žŸŸŸ�œ›˜”‘‹„}vqmifgimqu{Œšž¡¡™{`]_]\^_`_^__^^^[YYYYYYXWUTSSQPORRLJO^dca_^^ZVW\[W`rtgj‹¥ˆÒÍËÐÑÏÐÓÏÐÎÂÂÅÉÌÎÊÌÏËÉËÊÈÈÉËÍËÊËÊÉÈÇÆÃÃÁ¹´·º¹¡�‹ƒƒ…‚€}~~zxunj{yo‘Šb^fjnonkhiijlnoor{†Œ’—›ž�ššœœ™—”�†~vpljknpu~Œšž¡Ÿ›�t]\^]]]_`___^]^__^\[\]\YYXWVWUSSRRMJQZXTX]__[YWWYYVWhtpir‡ÎËÍÑÔÓÒÒÑÌÍÌÄÄÊÌÇÈÐÑÎÊÊÌËÉÉÊÉËËÌËÊÈÅÆÄÅÁÀ¿À»¾³˜�ˆ…„�€}}~~|xqm}‚l‡›s\cglnomggihknnqtw‡Œ“™›œ›šž¢¢Ÿ�›™•�‰…��„‰‘›¡¢¡Ÿœ”‡l\[[_`__^^__^__^^]\\]\[ZYWVYYYZZTQSSPLGIPVZ[^`ZXVVWUWbqpc†ÊËËÎÒÑÐÑѸ»ÓÏËÊÊÆÌÑÎÎÉÁÊËËËËÊÊËÌËÉÇÅÆÇÿÀÂÀ¿¾»¥�Ž‹‡ƒ�||}|{tq~„ll˜�gbfggjmidffilnqrsyƒŠ��“–šœŸ¡¤¤¥§§§¦¤¡žž ¢¥§¤¤£Ÿ˜�‚dYYX]^_^^__^_``_^]]^][Z[[XX[[WVWTQTTMIHPX[\\]a`ZXYYZZUZjq…ÈËÏÏÑÐÍÐϾ¼ÊÏÐÌÉÎÍÍÌËËÅÊÊÌÌËÉÉÊËÉÊÈÇÆÆÁ¼¼»¼ÁÀ½µ›��‹…ƒ€~~}zzxv~„o\zœ~cfedejjcddeijklosz„Š�”™� ¢¤¤£¡£¦§¦¦§¦¥¤¤¢¡¥¤œ’�z]VWWXZ\]^^^__````^]_][\\\\]][WTUWUQNLKIJMPRXYY^^\\[[^]X[gƒÈÌÌÕÓÐÏÉÊÏÎËÌÏÎÏÐÏÍÌÌÎÎÌËÌÌÊËËÊÉÉÌÊÈÇÇÆ¾¼»¼ÁÁ¿¿®•��Іƒ�‚‚~|x}„ta_‹–ldhfddgebbcceghijmu‡�“™œž¡¢¡ žŸ¡¥¥¥¤¥§¦¥¢¤¦ •�‰mVTUVWY[[Z[\^^\]^_`_`_]]]]\]\[YXWVTSPONLJIGDPYZ\_^^[Z[]][XƒÈÎÌÏÏÍÍÆÊÍËËÌËËÐÑÑÏÎÍÌÊËËÌËËÎÍÊÊÉËÊÉÈÇÆ½¼Ã¿½¾»¸¢‘��‡„ƒ„„ƒ‚€{}ƒudZoœˆgfgeabda_`_adeeeiox…ŠŽ’˜™› ¢¡ ¢¥¤¢ £¥¦¥¢ Ÿ—Ž‹�cVWWXZZZ[Z[[[\Z[[[_`a`^^_]Z[\YYZXTTTQQSTSSPINY[^^]]\Z\^][WƒÊÏÑÈÊÎÎÎÎÎÊËÎÍÌÎÑÐÏÍËÎËÇÊËÊËÌÌÌÍÌÌÊÉÈÇÅ¿Àþ¼¿»»²˜��‰†‰ˆ…„ƒ‚€�ve]Z… |cehd^^a][^^_cdfhhmv~‚„ˆ�”˜�ž £¤¢Ÿ››š™��›—”‹„ƒt\WWWXZXWWWZZXWVUVWY[]]\]\\Z[YVWXWWVTSTUVTROMP[^]\\\``bb]ZX„ÎÑÏÏÒÓÎÎÎÏÒÏÎÏÐÑÑÎÌÎÌÉÉËÌÊËÌËËÌËÍÍÈÇÊÉÇÄÄþ¼À¿½¼½§‘މ‰Œ‰………„ƒ�‚zh]Ue•›zbac\Z[ZUZ]]`acefhlsz~€„Š‘•–›žž�›™—–—•‘��Šƒ{eTRSUUVVTSTWXXVURQSTUUSUUX[ZYVTTUVXWXYWTTXTOKR]`\\`__`aa^\[…ÎÑÑÓÔÓÏÍÍÍÏÏÍÏÏÎÏÍÍÏÎÆËÐÎÎÎÎÍÌÊÊÊÇÂÆËÊÆÅÄÆÄ¿ÃÀ¿À¾¸›��ŠŠŠ„…‡†„‚ƒ{j`XSp•™~ic]XWVPOV\^]\`cdfjpvxy{€…�“’”––——˜—�Œ‹ˆƒ}wjPLPQQTVVUUUUWVSUUQOOPQQQSWWURTSQQTZYXXVSSWUROW`]Y[]\YU\aa_Z„ÎÍÌÒÑÐÏÐÏÎÎËÉËÌÏÌËÍÎÏÍÈÌÏÎËÌÌËËÍÌÈÆÆÈÉÆÃÃÃÇÄÁ¾¿Â¿¿­“�Œ‹‹ˆ‰‰‡„„ujbZTXkƒŽ‹|cYUUQJJSZ]\\]_cfgkruusw„…‡Š�’““�‹‹‡€{vqbQJILOSRQSTSQPMKLLLKKOUWVWXVSUXZXUWXVVVUUVURQV^_[\YOQXWZ]^]U„ÐÑÏÔÓÑÑÐÐÐÎËÊÈÈÌÍÎÎÎÏÎÇËÎÍÌÌËÌËÌÎÌÉÅÇÈÄÄÆÃÄÿ¾¿ÀÁ¾¼¤‘��Œ‹ŒŠ†„…{podZUTYclv†q\SRQJBDOY^][Z^`acinpnlosuy~‚„†‡†ƒ€zurqj`a\PHINLLMKJHFIGFFHJJMTSUUVWW[ZZ\[[XYYYUSUUSV^_YY\XRSX_][\XV„ÏÕÔÔÔÒÒÐÍÌÍËÍÎÉÈÍÏÎÍÍÎÊÊËÌÎÏÍÍËÌÍËÊËËÇÆÇÅÆÅÄÀÁÂÁÁ¼¾²˜’�Œ‹Œ‰‡ŒŒˆxphZQQX]][lxfXNOMF?BMWZYXX[]`beiigefgkopsvxyvqnkkeUSU^cZIBFIIEBABFHHKKKKLNPOMORXZYXVVVTVVXUSUVW_a\UVYYXYY\\[ZQKƒÏÕÔÓÑÑÐÉÊÍÏÎÎÐÎÏÏÎÎÎÌÌËËÌÊÉÎÎÉÈÌÌÉÈÊÊÇÆÁÅÉÆÇÀ¿Â¾½·§–’ŽŽ�ˆŠ””‘’ye[SQTZZ`_prcTLMJC<@LSUVVVWZ\^bdedbcddefhjjjgebmdDIIMZfbLAEFECDFDDGIJNPQPSSSSQSVUTRSWVUWWUUUX[aa\WWXWUUYWXWRMK„ÐÒÎÐÐÑÏÈÊÎÎÐÏÏÏÐÏÏÏÐÏÍÍÍÌÉÈÈÉÊÇÈËÉÆÉÉÆÁ»ÆÅ¿ÂÅÂÃÃÂÁÀ¼¸ ’’‘�ЅДЖ�oZRRRWWYcerk_QFHGA:>JRSSRRTVY\]_aaba_^`abba^_j€mA@CGMWejTACIKMNJHIIJLORRRUTPMMQRSUX[[Z\[ZZZ^`dec`_YUUTXWXVVTP„ÐÑËÌÍÑÒÏÍÏÎÐÒÐÎÏÍÍÎÏÎÎÎËÈËÆ¿ÈËÉÊÌÊÈËÇÀÇÆÅ¿ÁÆÃÄÄÂÁÀ½¼­”‘‘��‰�ŠŠ‡“…gOLRSVTZbhsh]KBED>9=HNONNPSUUTUW[\[Z[]]\ZZ`n~‰oA<>CIOWhnV@CHIKLMOPQLLMLKLJHHNQRRUVVXXXX\abbeggghc\YXYXWVTY\S‚ÏÔÌËÌÍÏÍÌÌÊÎÒÑÍÍÍÍÎÎÌÍÍËÈÌÉÆÉÇÊËÊÇÆÉÇÅÇÇÇÈÃÄÁ¾ÅÅÄÃÀ¼º²œ’‘•¢ �w‡‡…„ybJIPRPP[akrcZJ??@>9;CJLLNOSSQPRSRSTSRQPVbn{‚†oB<>@DMU\jrZ=BEJS[blu[<79AECFHILNPSQLQQNOSTQPRSSTTVWY__ZZ[\[ZVTUWVTVSTW†ÐÓÎÌÉËÉÈÎÌËÐÏÎÎÏÐÐÏÎÎÌÎÇÇÈÄÄÆÈÌÌÉÉÉÊÇÇÊËÇÅÃÃÇÈÇÄÅÿ¿·´¶¥Ÿ Ÿ¤Ÿœ‰‡�}ttvhN?FNMQ[bqkZWJ<7:=>AEIHHIJIHHIKKLPV\bhow~�†p@9=DGJSY_eqy]BA=?CEEFIMPRWUUXWUUTPORUVUQOPSY\YVX[[\WUVUTQORW[…ÏÑÌÉÊËÍËÍÍÌÏÐÏÏÏÏÏÐÏÎËËËÌÅÅÇÆÇÊÌÇÇËÌÉÇÈÈÆÃ¿ÃÈÈÆÅÆÆÅÀ¿½¹±©›“�ž¡”‚ŒŒxntvkTA@JMRZbobUTK>68GMTXan]OOKA969BGKMNMNMNOQTX\aekpv{~�…p?59;BLRY`fnt{‰¢šmRD=AHJIIIMPSWYXRIKMMMLMRTRVZURORTNNSYZ[_bbb`„ÎÏÍÌÈÊËÎÉÇÎÏÍÌËÌÍÍÍËÎÏÍÍËËÉÊËËÉÊÉÊ»½ÊÇÉÉÈÄÀÁÅÈÈÇɼ¨¹¾º¯§¢Ÿ”•¢£¦›‰„‰{ofhnueLABKTYcjYOKHB<9DLLKMNQSUVUMHMONMLNNMPOQST[[WV\^^a^VTSWƒÍÐÌËÉÌËÌÌÍÐÏÏÏËÇÌÍËÊÏÌÌÎÐÎÊÊÊËÊÊÈÈÄÅÈÇÉÇÅÇÆÇËÇÂÁÁº¯±©¤¤¤¡¢™”Ÿ¥ª Œƒ‰‡vnhdpogXF@GOUhoXMGDCA=>EMPRRSRSV[_chlrux|~€‚o>06:BMU\_grwxuKDdz†~\JA>DJLLNQRTVUNQXTRUSRSTRW^]\VSTT[^TZz�•h…ÍÌÉËÈÉÊÍÌËÊÊËÎÌÊÎÌÊÍÎÌËÌÍÌÌËÌËÉÆÄÇÎÊÇÇÈÉÉÇůĹ­©§ª¬£›–˜žŸŸ›Ž�‘˜˜‰„‡uxoebdkm`THCHQhdVPIDBA?AIORUTSUW]bfknruz~€��p=/6:BLW\dtƒ‰‡vM65BVlv|fOA;BJMLMPRRTX^\\`]VVXSNPSS[bixu_i—Íáâ©„ËÉÉÊÈÉÊÏÌÇÄÉËËÉÉÌÌÊËÌÌÌËÉËÍÈÅÈÆÅÃÆÇÅÆÆÆÆÂ¹´±®¬¨¦¥žšœ�—�—›œšŠŠˆzsz€ˆ‰|torkacgikcZOJXdVRNIECABHLOQQTX[^cgjntx|}€rA-49BMVayˆŽ�ŒmKIB;6;_�—’oKB=EJILQQSTPPONNNTT^xŒƒs‘¦¦’m„ÄÏÔââÉ‚ÈÊÈÇÄÉËÆÈÇÈÌÎÌÉÆÅÃÇËËÇËÌÊÌÎÈ¿ÃÄÂÂÄÂÃý´­ª¨§«®°¬£™–™�ž‘‹‘›ž�Œ—†z‡�†‰knytid`bdins‚ˆˆwdYNFBCEFHKOSW\`bcglquxz|~~{rG-29BP]vˆŒŒ‹„_CDIMH<;Uy’�‹†hC?ACEHKMOQUY[]\WVU<+0):]gbUO\adkG8<<<=<>?8/.3JswZwœtcagsz~~xpnwwxyz}|x{~~}}~~tƒˆˆ‰‰ˆ‰‰‰‡ˆ‚y{zyxtpwyvtvvvxxxxyyxvspsvuv|€|yywvvwwvzywrqvwxvvvuvysswxwutywpstuuytruruuqvƒˆˆ‰‰ˆ‰‰‰‡ˆ‚y{zyxtpwyvtvvvxxxxyyxvspsvuv|€|yywvvwwvzywrqvwxvvvuvysswxwutywpstuuytruruuqv†’’“’”“““‘‘‡yzwssvxvtuvvvwxxyxxvrrstvx|~|zyz{{{{|{ywzyvrswxwwuuuuxttwxwvuyvpsutwysttuvtu†’’“’”“““‘‘‡yzwssvxvtuvvvwxxyxxvrrstvx|~|zyz{{{{|{ywzyvrswxwwuuuuxttwxwvuyvpsutwysttuvtu€ƒ„ƒƒ‚€�€€�wtsuxwvvvvwwwwwxwtsrsuvz}|{yx{}~€€€€}{{xvttwxwuuvtvxstwvwuuxuqutswxrsutuu€ƒ„ƒƒ‚€�€€�wtsuxwvvvvwwwwwxwtsrsuvz}|{yx{}~€€€€}{{xvttwxwuuvtvxstwvwuuxuqutswxrsutuu~||||zxxyxvsstvwxxvvvwwwwvutrstuwz}|zyyz}€€€€€€€~|ywsswxwvuutvxstwwvuvzuruttyxrttsv~||||zxxyxvsstvwxxvvvwwwwvutrstuwz}|zyyz}€€€€€€€~|ywsswxwvuutvxstwwvuvzuruttyxrttsv€}||zxxxtrsvwstvxwuuvwvvurrstux|}{yyz{}€€€€€€€€€€~yvsswwvvuutuwruxwvtwzsqtttzwrust€}||zxxxtrsvwstvxwuuvwvvurrstux|}{yyz{}€€€€€€€€€€~yvsswwvvuutuwruxwvtwzsqtttzwrust}|zvstsswvusruwxwutuvtrqrtvy||zyyxz}€€€€€€€€€€}yvsrvwwuutrtwruwvuuxxsrsuwzurtu}|zvstsswvusruwxwutuvtrqrtvy||zyyxz}€€€€€€€€€€}yvsrvwwuutrtwruwvuuxxsrsuwzurtu{vtrswwxvuusswxwwussqrttvz||zxxyy{~€€€€€€|ywsswxvuttstvsuvvvvxyrptvxztqu{vtrswwxvuusswxwwussqrttvz||zxxyy{~€€€€€€|ywsswxvuttstvsuvvvvxyrptvxztqu~vvtwxyvtuvurtwxwtqprsuxz}{yxxxxy{€€€€€€€€€|zyvtsvwwutsruwrtvwwvxyrsuvxxrt~vvtwxyvtuvurtwxwtqprsuxz}{yxxxxy{€€€€€€€€€|zyvtsvwwutsruwrtvwwvxyrsuvxxrt~{xvywvuvvvssuwurqqtux|~|yyyxyyx{€€€€€€€€€€zyzwtruwvusstvvruwwwuyyrtvvxxt~{xvywvuvvvssuwurqqtux|~|yyyxyyx{€€€€€€€€€€zyzwtruwvusstvvruwwwuyyrtvvxxt€zutwwvuvutsttqqqru{}|{yyyyxyyy{€€€€€€€€€€€€€~xyzwtquvvusssvvsvwwvuywruuvxx€zutwwvuvutsttqqqru{}|{yyyyxyyy{€€€€€€€€€€€€€~xyzwtquvvusssvvsvwwvuywruuvxx€ytuwwvvvusqpqqruz}|yxyyyyyyzyz€€€€€€€€€€|vy{xsruvusrttxvrvxwvvyvrtutx€ytuwwvvvusqpqqruz}|yxyyyyyyzyz€€€€€€€€€€|vy{xsruvusrttxvrvxwvvyvrtutxxtvwwvvuropqsuy|{yxyyyxxyyyzz}€€€€€€€€€€xvy{wtruutssuvwusvxxwvzvrutwxtvwwvvuropqsuy|{yxyyyxxyyyzz}€€€€€€€€€€xvy{wtruutssuvwusvxxwvzvrutwwuwwvtrpqrsv{|zxyyxyxxxyyyzz|€€€€€€€€€€|vuy{wtrtutttvuvvrvxxxwztrtwwuwwvtrpqrsv{|zxyyxyxxxyyyzz|€€€€€€€€€€|vuy{wtrtutttvuvvrvxxxwztrtw~wvxurpqrtwz|zyyzzxwxyxyyyyzz~€€€€€€€€€€~€xuvy{xurtvvuvuswuswyyxxytrw~wvxurpqrtwz|zyyzzxwxyxyyyyzz~€€€€€€€€€€~€xuvy{xurtvvuvuswuswyyxxytrw}vvsrqsux{{yxyyzzyxwxxyyyyyx{€€€€€€€€€€€{uvux|xtptwvwuttwusxyzywxru}vvsrqsux{{yxyyzzyxwxxyyyyyx{€€€€€€€€€€€{uvux|xtptwvwuttwusxyzywxru}trqtw{}zxxxyyy{yxxxxxyyxutx€�€€€€~€~vuvvy{wsquvwvuutwusxzzwwws}trqtw{}zxxxyyy{yxxxxxyyxutx€�€€€€~€~vuvvy{wsquvwvuutwusxzzwwws|rtx|}|ywxxxxyyzyyxxwxvttuv}�€€€xuvvvx{xtruxwvtttxttyzxuvy|rtx|}|ywxxxxyyzyyxxwxvttuv}�€€€xuvvvx{xtruxwvtttxttyzxuvy|x|}{zzyxxxwyyyyyyxvuttuvvw~�€€€€€{uuvvux|xtruwvustwwruyxwuw|x|}{zzyxxxwyyyyyyxvuttuvvw~�€€€€€{uuvvux|xtruwvustwwruyxwuw}zzzzyyxxxxyyyxxustuuuuux}€€€€€€}vuuuvvx{yurtwwuvxwustwwvw}zzzzyyxxxxyyyxxustuuuuux}€€€€€€}vuuuvvx{yurtwwuvxwustwwvw{zz{{yxxxxxxxvtsttuuuwz|}|€~~~~}~~~€yuvvvvvx|zuruwuvxvtvrswvx{zz{{yxxxxxxxvtsttuuuwz|}|€~~~~}~~~€yuvvvvvx|zuruwuvxvtvrswvx|z{{zyxwwwwusstuutux{|}{z{€~}|zywvvuuuuuvwwxyzz{{||~{wwwvvvwx{yusstvxvttvrsvy|z{{zyxwwwwusstuutux{|}{z{€~}|zywvvuuuuuvwwxyzz{{||~{wwwvvvwx{yusstvxvttvrsvy{z|zyyxwtsssstttwz|||zz{z|~|zwurponmljkkkkkmoommoppqrstuvvvwwwwx|zurswwvttuwrsz{z|zyyxwtsssstttwz|||zz{z|~|zwurponmljkkkkkmoommoppqrstuvvvwwwwx|zurswwvttuwrsz{z{zxvurqstssuw{}|{{{{{{z}€€}{vsqookgghhikmooooprpmigghjlqqrrrrstvwvx|yuruxvuuuvvqv{z{zxvurqstssuw{}|{{{{{{z}€€}{vsqookgghhikmooooprpmigghjlqqrrrrstvwvx|yuruxvuuuvvqv{yxusrsssttw{|{|{z{{{{zz{~€€|ysnjkiggefkoqrstuuuvtsttqlgdchoqrsttsssvvwx|zusvwuutuutt{yxusrsssttw{|{|{z{{{{zz{~€€|ysnjkiggefkoqrstuuuvtsttqlgdchoqrsttsssvvwx|zusvwuutuutt~wusstssuwz|||zyz{{{{zz{z{~}{xrngcbccehmprstrqqqqqsssstuqojdfnpqrsttttvwwxz}zvttttvutsv~wusstssuwz|||zyz{{{{zz{z{~}{xrngcbccehmprstrqqqqqsssstuqojdfnpqrsttttvwwxz}zvttttvutsv|utstuvyz||{{zzzzzzz{zzzzz{zwrjgkdabdinqrppqrpppoppqqppqqpqqlgkqpqrsstvwwwxyz|zvsstvwusu|utstuvyz||{{zzzzzzz{zzzzz{zwrjgkdabdinqrppqrpppoppqqppqqpqqlgkqpqrsstvwwwxyz|zvsstvwusu|ttvx{{|zzz{zzzzzz{z{zzzzyxunfbdkhdinrrqrqrrsrssrqqrqpppppprqjkppqrrsvwwwvwyyx{zvssuvwtu|ttvx{{|zzz{zzzzzz{z{zzzzyxunfbdkhdinrrqrqrrsrssrqqrqpppppprqjkppqrrsvwwwvwyyx{zvssuvwtu|xz{|zyzzzzzz{zzzzz{{zy{zxsmgdbbknnstrqrstuwwwwwussssrrrqrqrrkjqrrqstuwwvvwxwwy|zvstwwuv|xz{|zyzzzzzz{zzzzz{{zy{zxsmgdbbknnstrqrstuwwwwwussssrrrqrqrrkjqrrqstuwwvvwxwwy|zvstwwuv€|zzzzzyyzzzzzzzzzzzzzyyxrpmfcbcmtsssrstvwxzzyyxvutsssssstutsnlrrruwvstwvvvxwxxx|zvstxuv€|zzzzzyyzzzzzzzzzzzzzyyxrpmfcbcmtsssrstvwxzzyyxvutsssssstutsnlrrruwvstwvvvxwxxx|zvstxuv{zzzzzyyzzzyyzzyzzzzyxwroskeeeksttsrrtvvvvvwxxxwvuttttstuwwwsqrsuz{xwttwvvwwwwwx{zvrtuw{zzzzzyyzzzyyzzyzzzzyxwroskeeeksttsrrtvvvvvwxxxwvuttttstuwwwsqrsuz{xwttwvvwwwwwx{zvrtuw|z{zzzyzzzzyzyyzzyzzyxuoqsjefmtuusssuuvuuvuvvwxwwvuuuuttuvvxvstwwxz|zwuuwvwwwwvwxzyuqsx|z{zzzyzzzzyzyyzzyzzyxuoqsjefmtuusssuuvuuvuvvwxwwvuuuuttuvvxvstwwxz|zwuuwvwwwwvwxzyuqsx|z{zzyyzyyyzzzyyyyxxuutpqsngltxutstuwvuuttuvuvxwwvuuuutuuttuvuvxwvxz|ywvtuvvvwwwvwyzuqt|z{zzyyzyyyzzzyyyyxxuutpqsngltxutstuwvuuttuvuvxwwvuuuutuuttuvuvxwvxz|ywvtuvvvwwwvwyzuqt{yzzyyzyxyyyyzyxvvuvvwvrrtqkpvxuttuvwvuuuuuvvvxxwvvvuttuvuttuuvxxvvxyzywusvwwwwvvwvzxtt{yzzyyzyxyyyyzyxvvuvvwvrrtqkpvxuttuvwvuuuuuvvvxxwvvvuttuvuttuuvxxvvxyzywusvwwwwvvwvzxtt{yzyyyyyxyyxwvuuuvvwvuuusrrosxxuuuuvvttvvuvwvwwyzwvttvvvvvusstvwxwvxxxzzwusvwwwvwwwwywv{yzyyyyyxyyxwvuuuvvwvuuusrrosxxuuuuvvttvvuvwvwwyzwvttvvvvvusstvwxwvxxxzzwusvwwwvwwwwywv{zzzxyxxwvutuuvwwvvvuvvvutssvxxuuvuuttutuvwyzywxzxuttvxxwwxvrtvwwwwwwwxzzwvsuwwvvwwvvxz{zzzxyxxwvutuuvwwvvvuvvvutssvxxuuvuuttutuvwyzywxzxuttvxxwwxvrtvwwwwwwwxzzwvsuwwvvwwvvxzzyyywwvttuvvvvvvvwwwvwwvuusvxyxvvvutttttvxyzyywwwutsrvyyyxxvsuwwwwvvwwwwz{xvsuwvvwwvvvyzyyywwvttuvvvvvvvwwwvwwvuusvxyxvvvutttttvxyzyywwwutsrvyyyxxvsuwwwwvvwwwwz{xvsuwvvwwvvvyzxwuttuuuvvuuvvvwwxwvwwwvuuuvxwvuuutsstuuvvuvwwwusttsuyyxxzwsuwwvwwwwwwwxxzyvttvwwvwwvxzxwuttuuuvvuuvvvwwxwvwwwvuuuvxwvuuutsstuuvvuvwwwusttsuyyxxzwsuwwvwwwwwwwxxzyvttvwwvwwvx~vuuuuuvuuuuvwwvvvwwwwwwwvtrstvvwwuutsrstssttuvvtsssttuxywuwyuuwvwwwwwwvwwwwzywttvvvwwwx~vuuuuuvuuuuvwwvvvwwwwwwwvtrstvvwwuutsrstssttuvvtsssttuxywuwyuuwvwwwwwwvwwwwzywttvvvwwwx}vuvuvwzzxuvwvwvwvvvvwvvvwrqtstvxvutsrrrrssttsttsstttttwyxwwxwuvvwwvwwwvvwxwwz{wutuvvwvx}vuvuvwzzxuvwvwvwvvvvwvvvwrqtstvxvutsrrrrssttsttsstttttwyxwwxwuvvwwvwwwvvwxwwz{wutuvvwvx}wxz{{zzxyxuxzzxxwvwvwwvvwqqtstvxuuusrsrrtstsstsstttttsuyxwxxyvuvwwwwwwvvwxwvx|{vusuvwvy}wxz{{zzxyxuxzzxxwvwvwwvvwqqtstvxuuusrsrrtstsstsstttttsuyxwxxyvuvwwwwwwvvwxwvx|{vusuvwvy}}}{{zywwxvvy{{yxwwvvvwvwsqtqqvwutttssrsttssstssuvutrqrwwvxxyzvtuwvvwvvwwwwwxyzzwtsuvvx}}}{{zywwxvvy{{yxwwvvvwvwsqtqqvwutttssrsttssstssuvutrqrwwvxxyzvtuwvvwvvwwwwwxyzzwtsuvvx}|{{{zxwxwwvuwz|{xxvvwvvwtrsosvvvuttsrsstsstsssuvvurooptvuwxyyxwttvvwvvvvwwwwyyzzwusstx}|{{{zxwxwwvuwz|{xxvvwvvwtrsosvvvuttsrsstsstsssuvvurooptvuwxyyxwttvvwvvvvwwwwyyzzwusstx}{z{zywwwvwvtvyy{|{ywwvvvvsrotuvwvuttssssttssrtvutsqpnouwsuwxyvwxutuvvvwwwvvwxxwxyxtrsw}{z{zywwwvwvtvyy{|{ywwvvvvsrotuvwvuttssssttssrtvutsqpnouwsuwxyvwxutuvvvwwwvvwxxwxyxtrsw€}{{{{ywxwuuttuyyxy{|zxwwwvusqssuxwvutttsstttssuvttssrppuwssuwyvtwxvtuvvvwvvwwxwwxxywtrt€}{{{{ywxwuuttuyyxy{|zxwwwvusqssuxwvutttsstttssuvttssrppuwssuwyvtwxvtuvvvwvvwwxwwxxywtrt€|{{|ywxyxvvvvuvzzyxz|{zyxvuttssuwwwuutuuttttsstvuvwutssvwsrtwyvtuvwvttuvwwwwwwwwwxwyxtt€|{{|ywxyxvvvvuvzzyxz|{zyxvuttssuwwwuutuuttttsstvuvwutssvwsrtwyvtuvwvttuvwwwwwwwwwxwyxtt€}|||zxxxxwwwvutwzzxxy{{{zxvuutrtwxwuuttutttsrtuvwwwvuuwyxtrsvxvuttuwwutvvvuvvwvwwwwwyxv€}|||zxxxxwwwvutwzzxxy{{{zxvuutrtwxwuuttutttsrtuvwwwvuuwyxtrsvxvuttuwwutvvvuvvwvwwwwwyxv}|||yxyxxwwvvvuvyzyyxxx{|zwwwurrvxwvttttttststuvwwvutuxzyvssvxuuuuuuuxwttvvvuwvwwvvvvwx}|||yxyxxwwvvvuvyzyyxxx{|zwwwurrvxwvttttttststuvwwvutuxzyvssvxuuuuuuuxwttvvvuwvwwvvvvwx€~||{xyyxxwvuuvvuwzyyxxxxxywwwvsquywvtttttssttuvvvvvvtuwyxxutvwuvuuutsvxvttuuuuuwwwvvvux€~||{xyyxxwvuuvvuwzyyxxxxxywwwvsquywvtttttssttuvvvvvvtuwyxxutvwuvuuutsvxvttuuuuuwwwvvvux€~}|zxzzyxwwwvvvuvyzyyyyxvvutvwtquxxvutsststttuvvvuuvvvwxxwwvvvuutuutttuwwttuvvuvwwvvvux€~}|zxzzyxwwwvvvuvyzyyyyxvvutvwtquxxvutsststttuvvvuuvvvwxxwwvvvuutuutttuwwttuvvuvwwvvvux€}|{yzzzyxxwxvvvvvwzzzyxxvttsswwstwxvutrrstvuuvvuutuvvvvvwvvwwvtuuuuttttsuwvtuvuvvvuuutw€}|{yzzzyxxwxvvvvvwzzzyxxvttsswwstwxvutrrstvuuvvuutuvvvvvwvvwwvtuuuuttttsuwvtuvuvvvuuutw€}|zx{zzyyxwwwwwwuvy{zzzxuttstxyutwxvutqqruvuuuvwwxxxxxxwutvwxutuvuuttutstuvwutuvvuutttw€}|zx{zzyyxwwwwwwuvy{zzzxuttstxyutwxvutqqruvuuuvwwxxxxxxwutvwxutuvuuttutstuvwutuvvuutttw€}|zz{{zyyxwxvwwvuuvzzzyxvtsstxzvsuxvttqpqsttuxzzz{zyxz{zwttwxttuuuuuututtstvxtsuvvutstv€}|zz{{zyyxwxvwwvuuvzzzyxvtsstxzvsuxvttqpqsttuxzzz{zyxz{zwttwxttuuuuuututtstvxtsuvvutstv€|{y{{{zyyxwxwwwvvvvxyzzywvtsuxywtuwwutspoqrstvwwwxyyy{zyytrvxttuutuuuutttttsuvutuvutssw€|{y{{{zyyxwxwwwvvvvxyzzywvtsuxywtuwwutspoqrstvwwwxyyy{zyytrvxttuutuuuutttttsuvutuvutssw€}{z{{{zzyxwxxxxvvvuvxzzxwuuuuvwxttwxvttrpoqrrsstutvuvxyyxurvwttttttuuuttutssstvutuutssv€}{z{{{zzyxwxxxxvvvuvxzzxwuuuuvwxttwxvttrpoqrrsstutvuvxyyxurvwttttttuuuttutssstvutuutssv€}z{{{{zzyxxxxxxwvwwuwzzyxwwvvvwzvtuwwutsqponoqrsuuvvuvwxwtsvurssttssttuututuutstuussssv€}z{{{{zzyxxxxxxwvwwuwzzyxwwvvvwzvtuwwutsqponoqrsuuvvuvwxwtsvurssttssttuututuutstuussssv€{y{{{zzzyyxxwxxxwwvuuyzzywvvwv|wttvwvtrrpnlmortuuuutttutqsvtstttssstttsttuttttrtwtrssv€{y{{{zzzyyxxwxxxwwvuuyzzywvvwv|wttvwvtrrpnlmortuuuutttutqsvtstttssstttsttuttttrtwtrssv€{z||{zzzyyyxwxxwwwwvvwzzzyvvxwƒxtsuvwusrpnklmpsttutttttrotvsstttssttsssutsttttrstuusqu€{z||{zzzyyyxwxxwwwwvvwzzzyvvxwƒxtsuvwusrpnklmpsttutttttrotvsstttssttsssutsttttrstuusqu€{z||{zzyxyyxwxwxxwwvvvxz{{yyzw†{tssuuutsqommmlnqrstutsqnntutttttssssssssssssttssstttss€{z||{zzyxyyxwxwxxwwvvvxz{{yyzw†{tssuuutsqommmlnqrstutsqnntutttttssssssssssssttssstttss{{}|{y{zyyyxxwwyxxwwwwwz{{{{{yˆ‚vttttttssrpnnlkloprsrpomqvutttttttsssssrssttttstsssstu{{}|{y{zyyyxxwwyxxwwwwwz{{{{{yˆ‚vttttttssrpnnlkloprsrpomqvutttttttsssssrssttttstsssstu|||{zzyzyyyyxxxyyxwwwwvx{{{{{z~†ˆ}tttsutstsqqomlkmmnoppootvtttttttsttsrsssstttttttrrrqs|||{zzyzyyyyxxxyyxwwwwvx{{{{{z~†ˆ}tttsutstsqqomlkmmnoppootvtttttttsttsrsssstttttttrrrqs|{{zzzzzyyyyxxxxyxwwwwwvz{{{{{}„Š…wrstttstutsqonlmmmnnoprvurtttusttstsssrsssrsssstsrrqr|{{zzzzzyyyyxxxxyxwwwwwvz{{{{{}„Š…wrstttstutsqonlmmmnnoprvurtttusttstsssrsssrsssstsrrqr€}||{{zzzyyyyyxxxyxxxxxwvx{|{{{|ƒ‰Š�ussutssuutsrpomnooopruwuttttttststsssrsssssrrrtsrrqr€}||{{zzzyyyyyxxxyxxxxxwvx{|{{{|ƒ‰Š�ussutssuutsrpomnooopruwuttttttststsssrsssssrrrtsrrqr€}|{{{zzzzzyyyyyyyxxxxxwwwy|||||‚ˆ‰Š‚xtuvutttutssrqqrqqstwywuttttttsssssssssssssssusrrqr€}|{{{zzzzzyyyyyyyxxxxxwwwy|||||‚ˆ‰Š‚xtuvutttutssrqqrqqstwywuttttttsssssssssssssssusrrqr€}|{{{zzzzyyzyyzyyxxxyxwwvw{||}‚‡ˆ‰‹†wtuvvttuuttssstsstu{ƒ�yuututtttttsssrssssrrsssrrqr€}|{{{zzzzyyzyyzyyxxxyxwwvw{||}‚‡ˆ‰‹†wtuvvttuuttssstsstu{ƒ�yuututtttttsssrssssrrsssrrqr}|{{{zzzyyzyyyyyyxxxxxwwvwy{|~ƒ‚ƒ†ˆŠŠssuvwutuuttsttuttu}ƒ†…}wvvuttttttssrsrssssssrrrqr}|{{{zzzyyzyyyyyyxxxxxwwvwy{|~ƒ‚ƒ†ˆŠŠssuvwutuuttsttuttu}ƒ†…}wvvuttttttssrsrssssssrrrqr|z{{z{zyzyyyyxxxxwwxwwxwwwwz|€ƒ„‚‚†‰Šˆ{qtuwvutsssttuutuw}€‚‡ˆwvuttsstsrrrsrsssrsrqrqpq|z{{z{zyzyyyyxxxxwwxwwxwwwwz|€ƒ„‚‚†‰Šˆ{qtuwvutsssttuutuw}€‚‡ˆwvuttsstsrrrsrsssrsrqrqpq}zz{{{yyzyxxxxwxxxwxwwxwwvvx‚‚ƒƒƒ‚†ˆŠˆyqtwvutstttttttvw|…‰‰€vttutsssrtsrrsrrqqrqqqqr}zz{{{yyzyxxxxwxxxwxwwxwwvvx‚‚ƒƒƒ‚†ˆŠˆyqtwvutstttttttvw|…‰‰€vttutsssrtsrrsrrqqrqqqqr€|{{{zzyyzzxxxxxxyyxxvwxwwww|ƒƒ‚‚ƒ„„‚ƒˆ‹†wruwvsrrrsssstvwz}€…‡Šˆzqsutsssstsrsrqrrprrqqqq€|{{{zzyyzzxxxxxxyyxxvwxwwww|ƒƒ‚‚ƒ„„‚ƒˆ‹†wruwvsrrrsssstvwz}€…‡Šˆzqsutsssstsrsrqrrprrqqqq€|{{{zzyyyyyyyyyyyyyywxyxxz}�„ƒ„ƒ„„……‚‚‡‹ƒuruvutrrsrsstuw{}€…ˆˆŠ‚trtttsssssstsrrrrrqnqxw€|{{{zzyyyyyyyyyyyyyywxyxxz}�„ƒ„ƒ„„……‚‚‡‹ƒuruvutrrsrsstuw{}€…ˆˆŠ‚trtttsssssstsrrrrrqnqxw€|{{zzzyxyyyyyyyxyxxyz|~€‚‚‚„„„„„„„†…„‚„†|qtuutsssrsssuwz}…†…ˆ‚vuqttttstsrrqqswtkbl}ƒ�€|{{zzzyxyyyyyyyxyxxyz|~€‚‚‚„„„„„„„†…„‚„†|qtuutsssrsssuwz}…†…ˆ‚vuqttttstsrrqqswtkbl}ƒ�|{{zzyyxxxxxyxwwwy{~��‚‚ƒƒ��ƒƒ„ƒƒ„…†……„ƒ�~vrrsssssssssuvy|~ƒ…‡ˆ}ttuutvwuussj_ht}kX]mohf|{{zzyyxxxxxyxwwwy{~��‚‚ƒƒ��ƒƒ„ƒƒ„…†……„ƒ�~vrrsssssssssuvy|~ƒ…‡ˆ}ttuutvwuussj_ht}kX]mohf|||{zyxyxxyyxxx{~�‚‚‚‚‚‚ƒƒ��‚„„…ƒ‚……„ƒ„ƒ‚‚ƒ€zttttuuuuvvwy}~‚ˆŠ„|vvvvxw{|{vuhZhoh^Z[[ZY\|||{zyxyxxyyxxx{~�‚‚‚‚‚‚ƒƒ��‚„„…ƒ‚……„ƒ„ƒ‚‚ƒ€zttttuuuuvvwy}~‚ˆŠ„|vvvvxw{|{vuhZhoh^Z[[ZY\xjmhikjhgmkv„‚‚‚‚„…†…„„„„„„„„ƒƒ„„„…††………„„‚‚‚ƒ„„ƒƒ„„…„…„„ƒƒ„„„……„„„„„„„………………†††…„††ˆ†ƒ„xjmhikjhgmkv„‚‚‚‚„…†…„„„„„„„„ƒƒ„„„…††………„„‚‚‚ƒ„„ƒƒ„„…„…„„ƒƒ„„„……„„„„„„„………………†††…„††ˆ†ƒ„sPQNQKMNOSUg†‚ƒ„……†………„„…„„„„„„…………………„„ƒƒƒƒ‚‚‚ƒƒ‚ƒ„…„„„„„ƒƒ„………†…„„ƒ„……††……†††††„†††ˆ†ƒsPQNQKMNOSUg†‚ƒ„……†………„„…„„„„„„…………………„„ƒƒƒƒ‚‚‚ƒƒ‚ƒ„…„„„„„ƒƒ„………†…„„ƒ„……††……†††††„†††ˆ†ƒ}ststtusuvuy„ƒ………„…„……„„„…„„„………††…………ƒƒ„‚‚��€€�€��ƒ„„„„…„ƒƒ„„…„††„„„„„……††…††††…………†‡ˆ†}ststtusuvuy„ƒ………„…„……„„„…„„„………††…………ƒƒ„‚‚��€€�€��ƒ„„„„…„ƒƒ„„…„††„„„„„……††…††††…………†‡ˆ†�ƒƒ‚�‚ƒƒƒƒƒ„„…†…„ƒ„„„„ƒ„„„„„„……………„„„ƒƒƒƒ�€��€€���€��‚ƒƒ„„„ƒƒƒ„„……………„„„„…††………†…††„…‡ˆˆ�ƒƒ‚�‚ƒƒƒƒƒ„„…†…„ƒ„„„„ƒ„„„„„„……………„„„ƒƒƒƒ�€��€€���€��‚ƒƒ„„„ƒƒƒ„„……………„„„„…††………†…††„…‡ˆˆ€�‚‚‚ƒƒƒ„…………††„ƒ„„„„„„………††……………„„„ƒƒ‚�€€€��€€���€€���‚„ƒ„„ƒ„„„……††…„„„„…†…†………†…†…„†ˆ‡€�‚‚‚ƒƒƒ„…………††„ƒ„„„„„„………††……………„„„ƒƒ‚�€€€��€€���€€���‚„ƒ„„ƒ„„„……††…„„„„…†…†………†…†…„†ˆ‡€�‚‚ƒ„„…†††……†…ƒƒ„……„„„…†………„„„„„ƒ„‚‚�€��€€���€€�€�€�€��‚„„„„„„„………†††„„„„†…††…††……‡……††€�‚‚ƒ„„…†††……†…ƒƒ„……„„„…†………„„„„„ƒ„‚‚�€��€€���€€�€�€�€��‚„„„„„„„………†††„„„„†…††…††……‡……††��ƒ„…†……………„……ƒƒƒ„„………†……„…„„ƒ„„ƒƒ‚��€€€€€€€€�€€€€���€€€�ƒƒƒ„„ƒƒ„………†‡……„„………††…††……†……†��ƒ„…†……………„……ƒƒƒ„„………†……„…„„ƒ„„ƒƒ‚��€€€€€€€€�€€€€���€€€�ƒƒƒ„„ƒƒ„………†‡……„„………††…††……†……†�ƒ„…„……„…„„„……ƒƒƒ„…†…………„„„ƒƒƒ„„ƒ‚�€�€€€€€�€�€€€���€€€€€€‚ƒ„„„„ƒ„„„…†‡†…„„………††……†…„…‡…†�ƒ„…„……„…„„„……ƒƒƒ„…†…………„„„ƒƒƒ„„ƒ‚�€�€€€€€�€�€€€���€€€€€€‚ƒ„„„„ƒ„„„…†‡†…„„………††……†…„…‡…†�ƒƒ„……„„„„„……„ƒƒ„…†……„ƒ„ƒƒƒƒƒƒƒƒ‚��€�€€€€€��€€���€�€€€�€€€‚„„„„„„„…†††††………„„………†††…„…‡„�ƒƒ„……„„„„„……„ƒƒ„…†……„ƒ„ƒƒƒƒƒƒƒƒ‚��€�€€€€€��€€���€�€€€�€€€‚„„„„„„„…†††††………„„………†††…„…‡„€‚„……„„„„„„……„„…………„ƒƒƒƒƒƒƒƒƒ‚‚‚���€��€�€�€�€€�����€€€�€€€�ƒ„„„„…„„…†††††…„„„„…………………„††€‚„……„„„„„„……„„…………„ƒƒƒƒƒƒƒƒƒ‚‚‚���€��€�€�€�€€�����€€€�€€€�ƒ„„„„…„„…†††††…„„„„…………………„††€‚„…„ƒ„„„„„†…†……„„ƒƒƒ„ƒƒƒƒ„ƒƒƒ‚�€�€��������€€���€€€���€€€€‚„ƒ„ƒ„„„„…††††………„„…„…†††………†€‚„…„ƒ„„„„„†…†……„„ƒƒƒ„ƒƒƒƒ„ƒƒƒ‚�€�€��������€€���€€€���€€€€‚„ƒ„ƒ„„„„…††††………„„…„…†††………†�ƒ……„„„„ƒ„…†…†„„„ƒƒƒƒƒƒƒ„ƒƒƒƒƒ�€€€���������€���€��€���€€�€€€ƒ„„„„„„………††……†…„„„„……††…………�ƒ……„„„„ƒ„…†…†„„„ƒƒƒƒƒƒƒ„ƒƒƒƒƒ�€€€���������€���€��€���€€�€€€ƒ„„„„„„………††……†…„„„„……††…………�ƒ…„ƒ„„„……………ƒƒƒƒƒ‚ƒƒƒƒƒƒƒƒƒƒ‚€€€€����€€��€�������€€€�€��€€‚„„„„ƒ„„…………†…†……„„„„„……………„�ƒ…„ƒ„„„……………ƒƒƒƒƒ‚ƒƒƒƒƒƒƒƒƒƒ‚€€€€����€€��€�������€€€�€��€€‚„„„„ƒ„„…………†…†……„„„„„……………„�„„ƒƒ………………„‚‚ƒƒ‚ƒƒƒƒƒƒƒƒƒƒƒ‚�€€€���€€€�€€�€�����€€�€€€€€€€€ƒ„„„ƒ„„……„………†††…„„ƒƒ„…†………�„„ƒƒ………………„‚‚ƒƒ‚ƒƒƒƒƒƒƒƒƒƒƒ‚�€€€���€€€�€€�€�����€€�€€€€€€€€ƒ„„„ƒ„„……„………†††…„„ƒƒ„…†………‚…„„………„„ƒƒ‚‚‚‚‚‚ƒ‚ƒƒƒƒƒƒƒƒ‚‚€€€€€����€�€€�€€€€�€€€€€€€€€€€‚„„„ƒƒ„„………„„†‡‡†…„ƒ‚ƒƒ…†…„‚…„„………„„ƒƒ‚‚‚‚‚‚ƒ‚ƒƒƒƒƒƒƒƒ‚‚€€€€€����€�€€�€€€€�€€€€€€€€€€€‚„„„ƒƒ„„………„„†‡‡†…„ƒ‚ƒƒ…†…„‚…………„ƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒƒ‚ƒƒƒ€€€€€€�€€�€€€�€€€€€�€€€€�€€€€€€€�„„„„„„„„…„„„…†‡‡‡…„ƒƒ‚„††…‚…………„ƒƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒƒ‚ƒƒƒ€€€€€€�€€�€€€�€€€€€�€€€€�€€€€€€€�„„„„„„„„…„„„…†‡‡‡…„ƒƒ‚„††…‚…„„ƒ‚‚‚ƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚„„„„‚€€€€€€€€��€€€€€€€€�€€€�€�€�€€€€ƒ„„„„…„„„„„„……††‡†…„ƒ‚ƒ…††‚…„„ƒ‚‚‚ƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚„„„„‚€€€€€€€€��€€€€€€€€�€€€�€�€�€€€€ƒ„„„„…„„„„„„……††‡†…„ƒ‚ƒ…††‚„ƒ‚‚‚‚‚ƒ‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„‚€€€€€€€€�€€€€€€�€€€�€€€€€€€€€€€€‚„„„„„ƒ„„„„„„…†††††…„‚ƒ„……‚„ƒ‚‚‚‚‚ƒ‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„‚€€€€€€€€�€€€€€€�€€€�€€€€€€€€€€€€‚„„„„„ƒ„„„„„„…†††††…„‚ƒ„……�‚‚�‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„…„„„„„ƒƒ�€€€€€€€€�€€€�€€€€€��€€����€€€€€€�„„„„„„ƒ„„„„…„…†…„††…ƒ„„…„�‚‚�‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„…„„„„„ƒƒ�€€€€€€€€�€€€�€€€€€��€€����€€€€€€�„„„„„„ƒ„„„„…„…†…„††…ƒ„„…„€�‚‚�‚‚‚‚‚‚‚‚ƒƒƒ„„…„„„„ƒƒ‚‚€€€€€€€��€€��€�€€€�€€�����€�€€€€€ƒ„„„ƒ„„ƒ„„„……„…„ƒ†††„„„„ƒ€�‚‚�‚‚‚‚‚‚‚‚ƒƒƒ„„…„„„„ƒƒ‚‚€€€€€€€��€€��€�€€€�€€�����€�€€€€€ƒ„„„ƒ„„ƒ„„„……„…„ƒ†††„„„„ƒ���‚‚‚‚‚‚‚‚‚ƒ„…„„……„„ƒ‚‚‚‚�€€€€€€€€�€€��‚ƒƒ„………„……„„„ƒ‚‚‚‚‚�€€‚ƒƒ„„„„ƒƒƒ„„„……„ƒ…†‡…„„„ƒ���‚‚‚‚‚‚‚‚‚ƒ„…„„……„„ƒ‚‚‚‚�€€€€€€€€�€€��‚ƒƒ„………„……„„„ƒ‚‚‚‚‚�€€‚ƒƒ„„„„ƒƒƒ„„„……„ƒ…†‡…„„„ƒ�‚‚‚‚‚‚‚‚ƒ„„………„„„ƒƒ‚�‚‚‚‚�€€€€€��€�‚„…‡‰‰Š‹‹ŒŒ‹ŒŒŒ‹ŠŠ‰Š‰ˆˆˆ‡††……„„„„„ƒƒƒ„ƒ…†„„…†††…„„ƒ�‚‚‚‚‚‚‚‚ƒ„„………„„„ƒƒ‚�‚‚‚‚�€€€€€��€�‚„…‡‰‰Š‹‹ŒŒ‹ŒŒŒ‹ŠŠ‰Š‰ˆˆˆ‡††……„„„„„ƒƒƒ„ƒ…†„„…†††…„„ƒ€‚‚‚‚‚ƒƒ„……„……„„„ƒ‚‚‚‚‚‚‚‚�€€€€��‚…‡ˆŠ‹Œ�����Ž�ŒŒŒŒŒŠ‹����Ž�ŒŠŠ‰‰ˆˆ‡†…ƒƒƒ„ƒ„…„ƒ…†††…†…„€‚‚‚‚‚ƒƒ„……„……„„„ƒ‚‚‚‚‚‚‚‚�€€€€��‚…‡ˆŠ‹Œ�����Ž�ŒŒŒŒŒŠ‹����Ž�ŒŠŠ‰‰ˆˆ‡†…ƒƒƒ„ƒ„…„ƒ…†††…†…„€�‚‚ƒ„„„„„„„„„‚‚‚‚‚‚‚‚‚‚‚‚�€€€€�ƒ…ŠŒ�Ž��‘����Ž���ŽŽŽ��ŒŒŒ�‘’‘�‹‰‰‰‰ˆˆ‰‡…„„„„„„„„„…………††„€�‚‚ƒ„„„„„„„„„‚‚‚‚‚‚‚‚‚‚‚‚�€€€€�ƒ…ŠŒ�Ž��‘����Ž���ŽŽŽ��ŒŒŒ�‘’‘�‹‰‰‰‰ˆˆ‰‡…„„„„„„„„„…………††„€‚ƒ„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚�€€��ƒ‡Š�‘“’’‘�������’’’“““““’��‘�‘’�ŒŠŠ‰‰ˆˆˆ‡„„„„ƒ„„„„„†…………‡…€‚ƒ„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚�€€��ƒ‡Š�‘“’’‘�������’’’“““““’��‘�‘’�ŒŠŠ‰‰ˆˆˆ‡„„„„ƒ„„„„„†…………‡…�ƒ„„„„ƒƒ‚�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†‹�Ž‘“’‘�ŽŽ�����‘‘’’“““”””“““’�‘‘�ŠŠ‰‰ˆˆ‡…„„„ƒ‚ƒ„„„„†…ƒ„…‡†�ƒ„„„„ƒƒ‚�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†‹�Ž‘“’‘�ŽŽ�����‘‘’’“““”””“““’�‘‘�ŠŠ‰‰ˆˆ‡…„„„ƒ‚ƒ„„„„†…ƒ„…‡†‚„„„ƒ‚�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„…‰�‘’��‘�ŽŽŽ���ŽŽ����‘’’““““’’’‘��‘ŽŠŠŠ‰ˆ‡…ƒƒ„„„ƒƒ„„„„……„„„††‚„„„ƒ‚�‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„…‰�‘’��‘�ŽŽŽ���ŽŽ����‘’’““““’’’‘��‘ŽŠŠŠ‰ˆ‡…ƒƒ„„„ƒƒ„„„„……„„„††‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚�‚‚‚ƒ„†‰Ž‘’’�Œ�����Ž��Œ‹Œ�Ž��‘‘’’’’‘‘‘��Ž�ŽŠŠŠŠ‡……„„„„„ƒƒ„„ƒ„„……„„„…‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚�‚‚‚ƒ„†‰Ž‘’’�Œ�����Ž��Œ‹Œ�Ž��‘‘’’’’‘‘‘��Ž�ŽŠŠŠŠ‡……„„„„„ƒƒ„„ƒ„„……„„„…����‚��‚‚‚�‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†‡Š��‘‘�Š�ŽŽŽŽŒ‹‹‹‹‹Œ��Ž��‘‘’‘‘����ŒŽ�ŠŠ‰‡„ƒ„„„„„„„„„„ƒƒ„„„„„„„����‚��‚‚‚�‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†‡Š��‘‘�Š�ŽŽŽŽŒ‹‹‹‹‹Œ��Ž��‘‘’‘‘����ŒŽ�ŠŠ‰‡„ƒ„„„„„„„„„„ƒƒ„„„„„„„€�‚�‚‚‚�‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒ‚ƒ†ˆ‡Œ����‹ŒŽŽŽ��Œ����Œ‹ŒŒ�Ž���‘���Ž�ŒŒ‹ŠŠŠ†„ƒ„„„„„„„ƒ„„„ƒƒ„„„„„„„€�‚�‚‚‚�‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒ‚ƒ†ˆ‡Œ����‹ŒŽŽŽ��Œ����Œ‹ŒŒ�Ž���‘���Ž�ŒŒ‹ŠŠŠ†„ƒ„„„„„„„ƒ„„„ƒƒ„„„„„„„€��‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚ƒ‚‚‚ƒ„ˆˆ‡ŒŽŽ�ŠŒ�ŽŽ�Œ����ŽŽŽŒŒŒ��Ž������Ž�ŒŒ‹Šˆ…„„ƒ„ƒƒ„„„„„„„„„„ƒ„…„……„€��‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚ƒ‚‚‚ƒ„ˆˆ‡ŒŽŽ�ŠŒ�ŽŽ�Œ����ŽŽŽŒŒŒ��Ž������Ž�ŒŒ‹Šˆ…„„ƒ„ƒƒ„„„„„„„„„„ƒ„…„……„€��‚�‚‚‚‚‚‚‚‚‚ƒ‚ƒƒƒƒƒƒ„…ˆ‰‡Š�Œ‰‰Œ������Ž������ŽŒŒ�Ž�����ŽŒ�ŽŽ‹ˆ…ƒ„„„ƒƒ„ƒ„„„„„„„ƒƒ„„…„„„„€��‚�‚‚‚‚‚‚‚‚‚ƒ‚ƒƒƒƒƒƒ„…ˆ‰‡Š�Œ‰‰Œ������Ž������ŽŒŒ�Ž�����ŽŒ�ŽŽ‹ˆ…ƒ„„„ƒƒ„ƒ„„„„„„„ƒƒ„„…„„„„€�‚�‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ„„„„ƒ…‡ˆ‡ˆŒŠ‰Š‹Œ�ŒŒ��Ž�Ž�����Ž���Ž���Ž�Ž����‰…ƒ„„„ƒƒ„„ƒ„„„„„„„ƒ„„„„„…„€�‚�‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ„„„„ƒ…‡ˆ‡ˆŒŠ‰Š‹Œ�ŒŒ��Ž�Ž�����Ž���Ž���Ž�Ž����‰…ƒ„„„ƒƒ„„ƒ„„„„„„„ƒ„„„„„…„€���‚‚‚‚‚‚‚‚ƒ‚ƒ„„„ƒƒƒ„„„…‡‡†‰Šˆ‰‹ŒŒ‹‹�Ž�ŽŽ�‘�����‹ŒŽ��Ž�Ž�����‰„ƒƒ„„ƒƒ„ƒƒƒƒ„„„„ƒƒ„ƒ„ƒ„…„€���‚‚‚‚‚‚‚‚ƒ‚ƒ„„„ƒƒƒ„„„…‡‡†‰Šˆ‰‹ŒŒ‹‹�Ž�ŽŽ�‘�����‹ŒŽ��Ž�Ž�����‰„ƒƒ„„ƒƒ„ƒƒƒƒ„„„„ƒƒ„ƒ„ƒ„…„€�‚�‚‚‚‚‚ƒƒ„ƒ„„„ƒ„„ƒƒ„„„„„††ˆ‡‡‰‹Œ‹‹Œ����ŽŽ�ŒŒŒŽŽ‹Œ�‘‘Ž�ŽŽŽ���ˆƒ„ƒ„ƒƒƒ„ƒƒ„ƒ„„„„ƒƒ„„„„ƒ„…€�‚�‚‚‚‚‚ƒƒ„ƒ„„„ƒ„„ƒƒ„„„„„††ˆ‡‡‰‹Œ‹‹Œ����ŽŽ�ŒŒŒŽŽ‹Œ�‘‘Ž�ŽŽŽ���ˆƒ„ƒ„ƒƒƒ„ƒƒ„ƒ„„„„ƒƒ„„„„ƒ„…€����‚‚ƒƒƒƒƒƒƒ„„„„„„„„„„„„…ˆˆ‡‡‰‹‹‹‹Œ�Ž�Ž��‹‹‹ŒŽ����‘’���Œ‹Š�ކƒ„ƒƒƒƒƒ„ƒƒ‚ƒƒƒƒ„ƒ„„ƒ„„„„ƒ€����‚‚ƒƒƒƒƒƒƒ„„„„„„„„„„„„…ˆˆ‡‡‰‹‹‹‹Œ�Ž�Ž��‹‹‹ŒŽ����‘’���Œ‹Š�ކƒ„ƒƒƒƒƒ„ƒƒ‚ƒƒƒƒ„ƒ„„ƒ„„„„ƒ€�‚‚ƒ„ƒ„„ƒ„„„„„„„„„„„…„„„„†��Œ‰ŠŠ‹ŒŒ�ŽŽŽŽŽŽ���Ž�Ž�‘‘‘’����‹ŠŒŒ…ƒ„„ƒ„„ƒƒƒƒƒƒ„„ƒ„„„ƒƒƒƒ„„ƒ€�‚‚ƒ„ƒ„„ƒ„„„„„„„„„„„…„„„„†��Œ‰ŠŠ‹ŒŒ�ŽŽŽŽŽŽ���Ž�Ž�‘‘‘’����‹ŠŒŒ…ƒ„„ƒ„„ƒƒƒƒƒƒ„„ƒ„„„ƒƒƒƒ„„ƒ�‚ƒƒ„„ƒƒƒƒ„ƒ„„„„„„„„„…„„ƒƒ‹”’�‹ŠŠ‹Œ���ŽŽŽ��������‘’‘’“‘��ŽŽ‹Š‰„ƒ„„ƒ„ƒƒ„ƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ�‚ƒƒ„„ƒƒƒƒ„ƒ„„„„„„„„„…„„ƒƒ‹”’�‹ŠŠ‹Œ���ŽŽŽ��������‘’‘’“‘��ŽŽ‹Š‰„ƒ„„ƒ„ƒƒ„ƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ�ƒƒƒƒ„ƒ‚‚ƒƒƒƒ„„„„„„„„„„„ƒƒŽ—‘Ž�ŠŠŒ�������‘���‘‘�‘’‘‘’““�Œ‹ŒŒ‹‰„ƒ„„ƒ„ƒƒ„ƒƒƒ‚ƒƒƒƒ„„„ƒƒƒƒƒƒ�ƒƒƒƒ„ƒ‚‚ƒƒƒƒ„„„„„„„„„„„ƒƒŽ—‘Ž�ŠŠŒ�������‘���‘‘�‘’‘‘’““�Œ‹ŒŒ‹‰„ƒ„„ƒ„ƒƒ„ƒƒƒ‚ƒƒƒƒ„„„ƒƒƒƒƒƒ�ƒ‚‚���‚‚‚ƒƒƒƒƒ„„…„…„„„„ƒƒŽ˜’�Ž‹Š�ŽŽ�‘‘’’’’’’’‘’’’‘’“•–“�ŒŒ��‰…„„„„„„ƒ„„„ƒ‚ƒ„‚ƒ„„„ƒ„ƒƒƒƒ�ƒ‚‚���‚‚‚ƒƒƒƒƒ„„…„…„„„„ƒƒŽ˜’�Ž‹Š�ŽŽ�‘‘’’’’’’’‘’’’‘’“•–“�ŒŒ��‰…„„„„„„ƒ„„„ƒ‚ƒ„‚ƒ„„„ƒ„ƒƒƒƒ�€€���‚‚‚ƒƒ„„‚�‚„„„„„„„ƒ„ƒ�—’��ŒŠŒŽŽ�‘’“’“““““’““’‘’•™˜˜’ŽŽŽŽŠ…„…„„„„ƒ„„„„ƒƒƒƒƒƒ„„ƒ„„„ƒƒ�€€���‚‚‚ƒƒ„„‚�‚„„„„„„„ƒ„ƒ�—’��ŒŠŒŽŽ�‘’“’“““““’““’‘’•™˜˜’ŽŽŽŽŠ…„…„„„„ƒ„„„„ƒƒƒƒƒƒ„„ƒ„„„ƒƒ€€€���‚‚‚‚ƒ„„„‚‚‚‚ƒ„„„„„…„Š•’““ŒŠ‹���‘’“““””“’’’‘’’”™›š™”���Ž‹†‚„„„„„„„ƒƒ„„ƒ‚ƒƒƒƒ„„ƒ„„„ƒ€€€���‚‚‚‚ƒ„„„‚‚‚‚ƒ„„„„„…„Š•’““ŒŠ‹���‘’“““””“’’’‘’’”™›š™”���Ž‹†‚„„„„„„„ƒƒ„„ƒ‚ƒƒƒƒ„„ƒ„„„ƒ€€���‚�‚‚‚ƒ„„…ƒ�‚��‚ƒ……………ˆ‘”•’�ŠŠ‹�Ž‘‘’’“””““’‘’”•—™››š”���ŽŒ‡„ƒ„„„…„ƒƒƒƒ„ƒƒ„‚ƒƒƒ„„ƒƒƒƒ€€���‚�‚‚‚ƒ„„…ƒ�‚��‚ƒ……………ˆ‘”•’�ŠŠ‹�Ž‘‘’’“””““’‘’”•—™››š”���ŽŒ‡„ƒ„„„…„ƒƒƒƒ„ƒƒ„‚ƒƒƒ„„ƒƒƒƒ€�����‚‚‚ƒ„„„…„�‚‚‚‚‚„„………†�””��‹‰‹ŒŽ�‘‘’’““““’’”•””•—˜—‘�‘‘�Œ‡……„ƒ„…„ƒƒ„„„ƒƒ„ƒƒƒƒƒ„„„„„€�����‚‚‚ƒ„„„…„�‚‚‚‚‚„„………†�””��‹‰‹ŒŽ�‘‘’’““““’’”•””•—˜—‘�‘‘�Œ‡……„ƒ„…„ƒƒ„„„ƒƒ„ƒƒƒƒƒ„„„„„€����‚ƒƒƒƒ„„„„„ƒ‚‚‚ƒƒ‚‚ƒ„……Š’“‘‘�ŠŠ‹Ž���‘‘’’“’’’•–“‘‘’“’�Ž‘‘�Œ‡………„ƒƒ„„„„„„„ƒƒƒƒƒƒƒƒƒ„„„€����‚ƒƒƒƒ„„„„„ƒ‚‚‚ƒƒ‚‚ƒ„……Š’“‘‘�ŠŠ‹Ž���‘‘’’“’’’•–“‘‘’“’�Ž‘‘�Œ‡………„ƒƒ„„„„„„„ƒƒƒƒƒƒƒƒƒ„„„€€����‚ƒƒ‚ƒƒƒƒƒ„‚�‚‚ƒ„‚‚‚„„†Ž‘‘’ŽŠ‰‹�Ž���‘�‘’’’‘’”“’‘‘�ŽŒŽ���‹†……………ƒƒ„„„„„„„ƒƒƒƒƒƒ‚‚„……€€����‚ƒƒ‚ƒƒƒƒƒ„‚�‚‚ƒ„‚‚‚„„†Ž‘‘’ŽŠ‰‹�Ž���‘�‘’’’‘’”“’‘‘�ŽŒŽ���‹†……………ƒƒ„„„„„„„ƒƒƒƒƒƒ‚‚„……€€����‚‚‚‚ƒƒƒƒ„ƒ‚�‚‚‚ƒ„„ƒ‚ƒ†ˆ�’“‘‹‰ŠŒ�Ž����‘‘�‘‘������Ž‹ŠŒ��Ž‹†……………†…ƒ„„„„„„ƒƒƒƒƒ‚ƒƒƒƒ„€€����‚‚‚‚ƒƒƒƒ„ƒ‚�‚‚‚ƒ„„ƒ‚ƒ†ˆ�’“‘‹‰ŠŒ�Ž����‘‘�‘‘������Ž‹ŠŒ��Ž‹†……………†…ƒ„„„„„„ƒƒƒƒƒ‚ƒƒƒƒ„€€���‚‚ƒƒ‚ƒƒƒ„„ƒƒ‚�‚‚‚ƒ„„„„††‹‘”“�ˆŠŒ�Ž����������Ž�����‹‰‹‹ŒŒŠ…………†…††…ƒ„„„…„„„„ƒƒƒ‚ƒƒƒƒ€€���‚‚ƒƒ‚ƒƒƒ„„ƒƒ‚�‚‚‚ƒ„„„„††‹‘”“�ˆŠŒ�Ž����������Ž�����‹‰‹‹ŒŒŠ…………†…††…ƒ„„„…„„„„ƒƒƒ‚ƒƒƒƒ€€���‚‚ƒƒƒ„ƒƒ„„„„ƒ��‚‚‚ƒ„„†‡ˆ‰�“”�ˆŠ‹Œ�������ŽŽŽŽ�Ž�Ž��‹ŠŠŠŠ‹‰†……………†††…„ƒ„…„„„„ƒ‚ƒƒƒƒƒƒ€€���‚‚ƒƒƒ„ƒƒ„„„„ƒ��‚‚‚ƒ„„†‡ˆ‰�“”�ˆŠ‹Œ�������ŽŽŽŽ�Ž�Ž��‹ŠŠŠŠ‹‰†……………†††…„ƒ„…„„„„ƒ‚ƒƒƒƒƒƒ€€€�‚‚‚‚ƒƒƒƒƒƒ„„„„‚���‚‚ƒ…‡ˆ‰ŠŠŒ�Ž‰ŠŒŒŽ����ŽŽ�Œ�Ž�’“‘���Œ‹‹ŠŠˆ………†……††…††…„„„„„„ƒƒƒ„ƒƒƒƒ€€€�‚‚‚‚ƒƒƒƒƒƒ„„„„‚���‚‚ƒ…‡ˆ‰ŠŠŒ�Ž‰ŠŒŒŽ����ŽŽ�Œ�Ž�’“‘���Œ‹‹ŠŠˆ………†……††…††…„„„„„„ƒƒƒ„ƒƒƒƒ€€��‚��‚‚‚ƒƒƒ„ƒƒ„ƒƒ����‚„†ˆ‡‰Š‡ˆŒ�ЉŒ�Ž�‘�������“““””“’‘���‹Š†………†……………†††…„„„„„„ƒƒƒƒƒƒƒ€€��‚��‚‚‚ƒƒƒ„ƒƒ„ƒƒ����‚„†ˆ‡‰Š‡ˆŒ�ЉŒ�Ž�‘�������“““””“’‘���‹Š†………†……………†††…„„„„„„ƒƒƒƒƒƒƒ€€��‚��‚‚‚‚ƒƒ„ƒƒƒƒƒ‚�€�‚„…‡ˆ‰Š‡‡‹�ЉŒ�Ž�’’�ŽŽ��‘“’�Ž�‘��’‘ŽŒŠ†………………………††††…„ƒ„„„ƒƒƒƒ„ƒƒ€€��‚��‚‚‚‚ƒƒ„ƒƒƒƒƒ‚�€�‚„…‡ˆ‰Š‡‡‹�ЉŒ�Ž�’’�ŽŽ��‘“’�Ž�‘��’‘ŽŒŠ†………………………††††…„ƒ„„„ƒƒƒƒ„ƒƒ€��‚‚�‚‚‚‚‚ƒƒƒƒƒƒ„ƒ„ƒ���ƒ…†‡‰‰ˆ‡ŠŽ‹Š‹�Ž�’“’���’•˜—“�����”���І………†…†……………††††…„„„„ƒ„ƒ„„„€��‚‚�‚‚‚‚‚ƒƒƒƒƒƒ„ƒ„ƒ���ƒ…†‡‰‰ˆ‡ŠŽ‹Š‹�Ž�’“’���’•˜—“�����”���І………†…†……………††††…„„„„ƒ„ƒ„„„€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„‚�‚ƒ…††ˆˆˆˆŠŽ�‹Œ�Ž��“’‘��“˜›œ›š˜–••“ŽŒ�Š…††††††††…††…†††††……„„„„……„€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„‚�‚ƒ…††ˆˆˆˆŠŽ�‹Œ�Ž��“’‘��“˜›œ›š˜–••“ŽŒ�Š…††††††††…††…†††††……„„„„……„€€�‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ„„ƒ„‚��‚ƒ„…††‡‹Ž�ŽŽŽ�ŽŽ�’’“”•”•–˜šœ��œ™’��Œ‰†††††‡‡‡†††……†††††††„„„„……ƒ€€�‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ„„ƒ„‚��‚ƒ„…††‡‹Ž�ŽŽŽ�ŽŽ�’’“”•”•–˜šœ��œ™’��Œ‰†††††‡‡‡†††……†††††††„„„„……ƒ€��‚‚‚‚‚‚ƒƒƒ‚ƒƒƒƒ„„ƒƒƒ‚�‚ƒ„††††�š�Ž���Ž���’•—™˜”‘‘“–˜˜—”ŽŽ�Žˆ†††††‡†‡††††††…††††‡†„„„……„€��‚‚‚‚‚‚ƒƒƒ‚ƒƒƒƒ„„ƒƒƒ‚�‚ƒ„††††�š�Ž���Ž���’•—™˜”‘‘“–˜˜—”ŽŽ�Žˆ†††††‡†‡††††††…††††‡†„„„……„€���‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒ„ƒƒ‚��‚ƒ„…„„’¥™Ž‘“’‘��‘‘”—š™–’������ŽŽ‘”އ†††††††††‡‡‡‡††‡†††‡†…„„„…„€���‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒ„ƒƒ‚��‚ƒ„…„„’¥™Ž‘“’‘��‘‘”—š™–’������ŽŽ‘”އ†††††††††‡‡‡‡††‡†††‡†…„„„…„€��‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„ƒƒ‚���‚‚‚‚“«¢’’”””’‘��’–˜™™–“’������“”Œ††…………†††††‡‡‡‡‡‡‡††††††„„„„€��‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„ƒƒ‚���‚‚‚‚“«¢’’”””’‘��’–˜™™–“’������“”Œ††…………†††††‡‡‡‡‡‡‡††††††„„„„���‚��ƒƒ‚ƒƒƒƒ„„ƒƒƒƒƒ„„„ƒ�������•®ª™’”––•“’‘‘”•—šš˜—•“’“•–•’Š…†††…†††††††‡‡‡‡‡‡†††‡‡‡††„„���‚��ƒƒ‚ƒƒƒƒ„„ƒƒƒƒƒ„„„ƒ�������•®ª™’”––•“’‘‘”•—šš˜—•“’“•–•’Š…†††…†††††††‡‡‡‡‡‡†††‡‡‡††„„���‚‚‚ƒ„‚ƒƒƒƒ„ƒƒƒƒƒ„„„„„ƒ�����’¯¯¤””———–”‘‘‘’•˜™šššš™™š—“Žˆ††††…†††††‡††‡‡‡‡‡‡‡†‡†‡‡‡‡…���‚‚‚ƒ„‚ƒƒƒƒ„ƒƒƒƒƒ„„„„„ƒ�����’¯¯¤””———–”‘‘‘’•˜™šššš™™š—“Žˆ††††…†††††‡††‡‡‡‡‡‡‡†‡†‡‡‡‡…€��‚ƒƒƒƒ‚‚‚ƒƒƒ„ƒƒƒ„„„„ƒƒ„�����Š«°¬�“˜™™™–“’��‘”–˜™›š™™š–�Ї†††††……††††‡††‡‡‡‡‡‡‡††‡‡‡‡‡€��‚ƒƒƒƒ‚‚‚ƒƒƒ„ƒƒƒ„„„„ƒƒ„�����Š«°¬�“˜™™™–“’��‘”–˜™›š™™š–�Ї†††††……††††‡††‡‡‡‡‡‡‡††‡‡‡‡‡€��‚ƒ‚ƒƒƒƒƒƒƒƒ„ƒƒƒ„ƒƒƒƒ„„ƒ�����„¡°¬ª›˜š™›š—“‘�Ž�’•˜™——˜—’Œˆ‡‡†‡‡‡‡†††…†‡‡‡‡‡‡‡‡ˆˆ‡†‡‡‡ˆ‡€��‚ƒ‚ƒƒƒƒƒƒƒƒ„ƒƒƒ„ƒƒƒƒ„„ƒ�����„¡°¬ª›˜š™›š—“‘�Ž�’•˜™——˜—’Œˆ‡‡†‡‡‡‡†††…†‡‡‡‡‡‡‡‡ˆˆ‡†‡‡‡ˆ‡€�‚‚ƒ‚‚ƒƒƒƒƒƒƒ„„ƒ„„„„ƒƒ„„„‚����€•¬«©¨ ›š›œ™–“�Ž��‘”•”””’�‹�Ї‡†‡‡†‡‡†‡‡‡‡‡ˆ‡‡‡‡‡‡‡‡†‡‡ˆ‡€�‚‚ƒ‚‚ƒƒƒƒƒƒƒ„„ƒ„„„„ƒƒ„„„‚����€•¬«©¨ ›š›œ™–“�Ž��‘”•”””’�‹�Ї‡†‡‡†‡‡†‡‡‡‡‡ˆ‡‡‡‡‡‡‡‡†‡‡ˆ‡€�‚‚ƒƒƒƒ„ƒƒƒ„ƒ„„ƒ„„„„„„„„„ƒ‚���~‡¢¬§£§Ÿ™››š˜–’�Ž�Ž�����ŽŠ’ œŽ‡‡‡‡‡‡‡†‡‡ˆ‡ˆ‡‡‡‡‡‡‡†‡‡‡‡ˆ‡€�‚‚ƒƒƒƒ„ƒƒƒ„ƒ„„ƒ„„„„„„„„„ƒ‚���~‡¢¬§£§Ÿ™››š˜–’�Ž�Ž�����ŽŠ’ œŽ‡‡‡‡‡‡‡†‡‡ˆ‡ˆ‡‡‡‡‡‡‡†‡‡‡‡ˆ‡€�‚‚ƒƒƒƒƒƒƒƒ„ƒ„„ƒƒ„„„„ƒ„„„„‚��€|~‘¨©£¡¡ššš™˜–”’�ŽŽŽŽ�Ž��‹—¥¨£“ˆ‡††‡‡‡‡‡‡‡ˆ‡‡‡‡‡‡†‡ˆˆˆˆˆˆ€�‚‚ƒƒƒƒƒƒƒƒ„ƒ„„ƒƒ„„„„ƒ„„„„‚��€|~‘¨©£¡¡ššš™˜–”’�ŽŽŽŽ�Ž��‹—¥¨£“ˆ‡††‡‡‡‡‡‡‡ˆ‡‡‡‡‡‡†‡ˆˆˆˆˆˆ€‚ƒƒƒƒ‚ƒƒƒƒƒ„ƒ„„ƒ„„„ƒ„„„„„„ƒ‚€}{{‘£¥ŸŸž˜™˜—–”“‘������ŽŽ‹–¤§ª§—‰†‡†‡‡†‡‡‡‡‡‡‡‡‡†††‡ˆ‡‰ˆ‡€‚ƒƒƒƒ‚ƒƒƒƒƒ„ƒ„„ƒ„„„ƒ„„„„„„ƒ‚€}{{‘£¥ŸŸž˜™˜—–”“‘������ŽŽ‹–¤§ª§—‰†‡†‡‡†‡‡‡‡‡‡‡‡‡†††‡ˆ‡‰ˆ‡€�‚‚ƒƒ‚ƒƒƒƒƒƒƒ„„„„„„ƒƒ„„„„„„‚}{{{|}ŠšŸŸŸœ———–““’‘������Œ‹•¢¤ª­©˜ˆ†††‡†††‡‡‡ˆˆ‡ˆ‡‡ˆ‡ˆˆ‰ˆ†€�‚‚ƒƒ‚ƒƒƒƒƒƒƒ„„„„„„ƒƒ„„„„„„‚}{{{|}ŠšŸŸŸœ———–““’‘������Œ‹•¢¤ª­©˜ˆ†††‡†††‡‡‡ˆˆ‡ˆ‡‡ˆ‡ˆˆ‰ˆ†€�ƒƒƒƒƒƒƒƒƒƒ„ƒ„ƒ„„„ƒ„„„„„„„„€{{{{{{|„‘œ�Ÿœ–•••”“’’‘��Ž��Œ“ ¥ª¬­¦Žƒ†‡‡††‡††‡ˆˆ‡ˆˆ‡ˆˆˆˆˆ‡‡€�ƒƒƒƒƒƒƒƒƒƒ„ƒ„ƒ„„„ƒ„„„„„„„„€{{{{{{|„‘œ�Ÿœ–•••”“’’‘��Ž��Œ“ ¥ª¬­¦Žƒ†‡‡††‡††‡ˆˆ‡ˆˆ‡ˆˆˆˆˆ‡‡‚ƒƒƒƒƒƒ„„„ƒ„ƒ„„„„„„„„…„ƒƒ‚€}zz{{z{{|€‹—�Ÿš••••”“’‘���ŽŽŒ“Ÿ§««¯¯–‚ƒ„…†‡‡‡‡‡‡‡‡ˆˆˆˆˆ‰Šˆƒ…‚ƒƒƒƒƒƒ„„„ƒ„ƒ„„„„„„„„…„ƒƒ‚€}zz{{z{{|€‹—�Ÿš••••”“’‘���ŽŽŒ“Ÿ§««¯¯–‚ƒ„…†‡‡‡‡‡‡‡‡ˆˆˆˆˆ‰Šˆƒ…€‚ƒƒƒ„„„„…ƒƒ„„„…„„„„ƒ‚�€~~}}|{z{{{{{{{|ƒ�˜š”””••“’‘��ŽŽ��‘�¦ª®»·•……„ƒ…†‡‡‡‡ˆˆ‰‰‡…‡�—��|€€‚ƒƒƒ„„„„…ƒƒ„„„…„„„„ƒ‚�€~~}}|{z{{{{{{{|ƒ�˜š”””••“’‘��ŽŽ��‘�¦ª®»·•……„ƒ…†‡‡‡‡ˆˆ‰‰‡…‡�—��|€€‚ƒƒƒ„ƒ„„„„„„„„„…„ƒ‚}|||{|||{{{z{{zz{z{|�‡ˆŒ�“”“’����ŽŽ�’ž¥¬ºÂ¯Œ…††„ƒƒ‚…†‡…Ž™‘†�’ œŽŒ‘‘€‚ƒƒƒ„ƒ„„„„„„„„„…„ƒ‚}|||{|||{{{z{{zz{z{|�‡ˆŒ�“”“’����ŽŽ�’ž¥¬ºÂ¯Œ…††„ƒƒ‚…†‡…Ž™‘†�’ œŽŒ‘‘�‚ƒƒƒ„„„„„„„„„„ƒ‚€~}|}|{||{{||{zz{|{{{|{|}}}~ƒŠ�‘�������Œ�›¡¬³³Ÿ…†…†……„€€…„�ž“�“›�œœœ�š�‚ƒƒƒ„„„„„„„„„„ƒ‚€~}|}|{||{{||{zz{|{{{|{|}}}~ƒŠ�‘�������Œ�›¡¬³³Ÿ…†…†……„€€…„�ž“�“›�œœœ�š+×þùûþþýûüþþþþþýûþþþþþùîÞßááßÞááàßáåãÛ·˜žªÄØÚ×ÖÚÜÜÙØÙÚÜÙÜÜÜßÜÛÝÝÞÙÕÔ×Ûß×ɪ‘’“‘Œ�†vu‚ªÙàÞÞßÝÝÖÐÙÙÑÐÒÔÔÚËŠs‡„y€µÑÏÑÓÔÙ×ÔÖÕÑÎÒÑÉÀÀʳ‰‡¸ÛÒÔÕ×ÛØÒÏÎÏÌÊŸq†»ÌÏÒÏÎÑÊÆÒ»}~¹ÎÌËÁ¹ºÈµ|p¯ÅËÃ1ÆÁÓäÍÕ¹ÓϺøÆËзØÄÆîкÕíáàáááàßßâææÙº˜‘§¼ÍÓÓÔÒÕÙÚØ×ÙØÚÜÚÛÜÝÞÞÝÞßÜ×ÔÝßÕÁ¦˜““—š�vvy‡£ÊÝÞÝÝÛÚÙÜÇ¿ÙÓÎÑÐÑÑÌÓÅŒxˆ†v‚¸ÐÐÔÒÖÖÒÔÔÑÎÐÐÊÄÈͼ¡…‡½ÙÓÔÖÙ×ÓÐÎÎÇɸˆqйÍÑÑÏÏÍÉÍЩv�ÄÐËÿ½ÇÄœp~¶Ï¼0±«Ä­¹ˆ¿Ãгް²‡Ê°Š»Ë¦´çãàâàÞßâäâÔº�’ž³ÍÙÛ×ÔÔÕ×ÚÑÎÙÙÔÚÜÛÜÛÜÜÝØ×ÙÚÝÛÓ» ’��—˜Š{sx‘³ÑßâàÜÛÛÛÛÛÛÖÕÚÒÑÑÐÐÑÌÑÒºˆwŠ�k~´ÐÑÕÖ×ÓÒÓÒÏÏÌÌÎÍ、{‡ÂÚÑÔØØØÒÎÎÌÍËÀ’q’ÃÐÏÎÍÎÌÊÏÏœq–ÌÑÈÆÂÊɱŠe‡Ç»-Öݦµ¾ÄžÌѰ¥­Ä¾œÑ˯¢åÏ¡ÐåßÞÝâåÝѸ�š¦½ÕÚÙ×ÈÈÖÖØÛÙÍÐÛØÖÚÚÛÛÙÜÖÓÕØÝÜͱ–ŠŠ—�“‡{w�™¿×áãÞÛÚÜÜÜÝÝÜÚÛÚ×ÓÒÒÏÐÑÑз²º…u‡‚q€¯ÉÎÓÖÕÕÕÑÒÓÌËÐÍÏÆ¿À�w‰ÆØÓרØÖÏÌÐÐÉÏÊ›z�ÄÅÊÌÍÆËÎÒÊ’p¤ÒÍÄÅÍ̹®�i”¹(¶Ú¼ÙçÑÎÝáããâàÒÝâæÚåÛÕàÞÝáåàͳ š©ÄÖÔÔÓÕÕÄÊÕÖØÚØØØØ×ÚØÕÚÛÚ×ÓØàÛɬ‘…‹—™‘�ut…§ÇÚââßÛßÞÝÞÝÝÜÚØÛÛÛÞÝßàßßÞÛØÉ¿ÐÀ†s…†u~®ÌÏÓÓÕ×ÔÒÔÎËÉËÓȾļ–xŽÊÖÑÖÕ×ÔÐÐÏÉÉÐÖxŸ¼ÇÍÎËËÐÏÔɉp«ÐÊÉÏÑÆ¾ºˆo”‡Å±½ÛåÜÑáæäâãããßàáæàÞåãáæá̬™˜•·ÖÛÖÒÒÓÖØ××ÕÙ×Ô×ÚÚ×ÖØØÙÙ×ÛÛÛצ‘„…“œ’rv�²ÏÙÙÜÚ×ÍØØÙÝÝÛÝÞÞàäçéëëììíììëëçåÞßÌ�m€‹~„²ÐÑÒÕÔÕÔÎÏÎÇÏÕÇÁÁɘt�ÆÕÒÔÖÕÖÒÑÏÍÊÈ¿ˆu ÃËÍÎÊËÐÎ×Àys³ÐÌÏÐǼ¾¯}j}­ÄØÏÖÜáàÝÜÛÙÙÛÝÛÛ×ÖÞââÝË®›š¤­½ÖÚÙר×ÙÙÙÚÖÖØÙ××ÙÛÚØÙÖ×ÛÝÝ϶žŽ‹Ž—�~{u~š¾×áß×ÔÙÝÒÅÔÍØÞÝàäçéëìììììëëëëëëìíìëèíÙšx€Š�…²ÑÒÖÒÒÕÍÐÐÏÔÕÌÅÇÊÊ»�s�É×ÓÖÒÔÔÑÐÍÏÈȹ�x²ÎÎÌÊÌÍËÎÖ°o{ºÍÎÏǽº·¡y!u®ÝÞÛáâáááàÝÜÝÞÞÝÝàãäÕ¾­››ª½ËÏÙØÔÛÝÛÙÙØÙÙרÛÝÙÖ×רÖ×ÕÙÛÊ­’‡‰’—Œ}po†£ÅÙÝÝÙ×ÚÛÛÜÛÜÜÛßãçêëììëëëëëêêëëëëêëëëëìëðèÀ—†…€‚®ÐÔÒÔØÓÆÉÒÎÎÌÈÌÆ¼¼±Šr”ÎÖÓÔÓÔÑÏÏÎÍËκ{„ÃÒÌÌÎÌÌÍÐÒ¦k„ÂÐÏʾ¾¸º¢}ÌÞÞââààááÜÙÜÝÛÜßãáÒ¸��š°ÅËÌÑÖÖÙÛÝÜÚÙÕÕÒÓ×ÙÚ×ÕÖÕÕÖÜÛÒÁ¨‘ƒˆŽ—ˆunrްÅÖá×ÏØÛÜÛ×ÚÜÞßáçèéììëëëëëëëëëëëìëëììììëëëéîóã¼”…~©ÎÑÓÙÖÈÊÓÎËÊÉÍ̺¾²ŠtœÒ×ÓÔÖÒÏÎËÏÍÊЬu’ÇÍÌÎÍÍÍÍÑÒši–ËÒËÃÇ¿¾°‰ÛàßßáâáßÜÚÞÜÛÞáÞʰ›”Ÿ¬½ÑÓÎÍÍÔØÛÜÛÙÖÔרÓÔØÙÔÓÔÔØÛÙÒºŸŽ‰Œ”™ˆxmw“³ÍÞÒÒ××ÛÝÜÜÜÛÝßáåéëìëìëëëëìëëëììëëëëëëìëëëìíìèéðñتˆ|{©ÐÑ×ÔÐÓÔÓÐËÌÍÍËÅÁ°‡qœÑÔÑÕÖÓÑÐÏËÊÉ̦w—ÄÊÍÎÍÌÍÌÓÍ‘oŸÍÑËȾ¾­‡ØáßààßÞÜÙÚÒÑáÝʬ”‘š¯ÇÐÓÔÌÊÍÑ×ÚÛÜØ××ÖÓÓ×ÖÚÙÕÐÙÜÙ˲šŽŠ�—‘†wn|ž¿ÐÔÔÙרÜÞÝßÝÛÜÞâçêììëëììëëëìëëëëìëëëëëëëìëëëìììëêçëò縋|~ªÑÔÑÊÑÕÓÓÎÌÌÉÊÈÀ¼À©€o ÔÔÒÕ××ÓÎÌÌÌÊÉœt™ÄÌÏÊÊÎÎÏ×ȇk§ÒÎÌÂÁ®‡ÙáÞÝßßÞÛʨ�¸Ê°œ�™§½ÐÐÏÖÔÉÌÍÑÔÚÝÜÜÙØÕÁÉÖÐÒÖÙÙÚɯš��“•‹~rq„¤ÅÚÞÙÔÖÛÝÜÔ×ßßÜÜáæêìëëêëëëêëìëëëëëëìëëëëëëìììììììëëêêéèîí¿‘|x¤ËÏÉÐÔÒÑÎÍÌÌÊÉÅÀ¿·¨†t©ÖÕÑÓÖÒÎÍÍÎËÊ‘sŸÄÍÇÈÎÍÒÒÖ¾{tµÒÏËŲ‡ÖßßäåâÞÅ«”u‘›”š«»ÀÈÒÑÒÙÑÍÏÎÒ×ÚÛÚÚÙÚÔÍÑÐÒ×ÚÑ앎”˜“„tmw�±ÎßßÚ×ÙÛÛÛÛÙÏÖÞÜÞäéëëìëëëëëëëëìëëëìëìììëëëëëëììììëëëëëêëêèìí¿ŒzvžÇÐÒÔÔÑÏÎÍÍÊÉÉÅ´¯·¬‡v¨ÕÒÎÒÒÏÏÍÍÏÌȾ�v¡Ç¿¿ÌÍÑÒÑÖ¹v{¾ÑÊÈ·†ØäáØ¼®«œ‹•�”¯¿ÌÔÏÅÐÑÔØÏÐÎÒÚÜÚÛÛØ××Õ×ÔÔÙÔ¼¡’�•�–„qo}›¾ÔßàÛÖÔÙÜÛÚÜÝØÚÝÝáçêëëëììëëëëëìëëìëëëëëììììëëëëëìëëëëëëëëëêêèìꮇ€wžÏ×ÔÖÖÑÏÐÎËÈÆÇ¸°´½³Šv¬ØÎÐÔÑÏÎÏÍÌÊÊÀ‰t©Á¾ÉÎÏÒÒÒØ°o‡ÆÌȸˆÞÒ®—‹ƒ€Œ��Œ ¼ÎÑÒÔÒÔÖÈÓÕÍÎÍÖÛÚÚÛÛÙÕÒÖÓÐɳ��‘–—–…ss‡¦ÆÛßÛ××ÙÚØÛÕÒÜÝÝÝÞÞäêìëëëëëëëëëëëìëëìììììììíìëìëìììììëëëëëëêêëêêéïÚ˜Š�t�ÐÕÓÖÓÐÑÏÌÊÃÃȾ»½»´†w±ÖÒÔÓÑÓÓÏÌÎÉȼƒz¢³ÅÌÍÑÓÒÕÖ¤p—ɼ­�²ž”š¥…jp¦¾ÂÓØÕÏÐÑÖØÑÑÖÏÌÉÐÙÙÚÛÚÕÖ××ÔÀ§‘ˆ�˜˜�{sz”·ÐÝÝÚØ×ÚÞÜÚÙÚÔÓÞÞÜÝàæëëëëëêëëëëëëëëìëëìììììììììëììëììëìëëëëëëêêêêêêèî¿…Š{mšÍÒÑÓÑÑÐÌÌÆÂÅÁÁ¿¸±¤†x²ÖÌÁÎÖÔÒÐÎÍÆËº}m’ÀËÍÐÑÒÑÕÒ›s¢½«s™¨ÆÔÒ§qƒº×ÚØÖÕÔÖÖ×ÒÓÚÒÌÏÌÕØØÚÚÖØÛÒ¼¡�ˆ‹•™‡qp€”µÙáÝÚרÝÜÛÔÕÚ××ÜÞ××Ûßçëëëëëëëëëìììëëëììëììììììëëëëììëìììììëëëëêêéêêéééìä˜xˆzošÌÓÎÐÑÑÌÊÊÈÄÂÁÿ°®¯}x·ÑÀÍÓÒÔÕÐÍÊÆÎµwv²ÈËÎÏÐÑÒ×Αuªµ~ÆÓÚÞÛͼÊÓÎÐÓ×ÔÓר×Ô×ÖÎÎÍÒÖÕÕÚÜÙÑ»ŸŒ‡Ž•�€qj|©ÊØÜÞÙÛÑÏÜØÚÚÍÒÛÛÛÛÛÓÕáçêêëëìëììëììëëëëëììììììëììëììììììììììëêêêêêêéêéééêéîÊ~yŠ}p–ÆÊÉÑÓÎËÉÈÄÁÃÅŹ»¢z|¼ÒËÑÓÔÖÔÏÍÈÉÓ­q‡½ÊÌÏÏÐÒÒØÉ‡{¡‡×ÛÒ×ÑÌÙÖÓÖÕÔÕÐÐÕ×ÕÕØÏËÍÎÒÔ×ÛÚÍ·žŒ‰’–Šrer‹©ÌÞßÝÙÚÝßÓÐÚרÙÙÚÜÝÜÛÛÝáèêêëëëëëìëëëëëëëëëëëëììììììììììììììììëëêêêééééééééêêêë¸qs‡~o’½ÆÎÓÐÍÉÅÇÁ¿ÄÉÊü³¦|½ÒÐÔÓÓÓÒÏÊÉÌÌ q“ÃÌÍÏÎÐÓÒØ¿€v…ÒÛÐÎÏÊÍÐ×ÕÓ××ÐÐ××ÐÖÕÊËËÏÕÚØÈ±šˆ†ŒŽ‚mdr’»ÕÞÝ×רÚÛÜÜÛÛÚÙÙÛÜÛÝÜÛÜÜáçéêêêëêëëëëëëëëìëëëëëëëìììëììëìììììììëëëêêêêééèéèééééééÞ¨on„}q‘ÁÍÌÐÐÍËÊÄ¿ÂÄÊȺ§¶®z…ÁÖÒÓÔÓÓÑÊÊËÌË¢sžÈÉÎÐÏÒÓÒÕ³z†ÖÛÐÍÊÁÌÓØÖÔÒÔÑÒÙÕÏÔÑËÍÐÕÓÀ¦“ŠˆŠˆ|j^ršÃÜà×ÑÓÚÝÜÚÙÚÚÙÙÚÙÚÜÛÝÔÔÝÛßæèéêêêêêëëëëëëëëëëêìëëëëìíìëììììììëëëìëëëêêêêéééééèèèèéçâÙ³vl‚~q�ÄÎËÏÏÏËÆÁ¿¾Ç˽¨¶Æ«w†ÃÕÑÒÓÔÓÌÌÐÌÌÌ™w¦ÈËÎÏÐÒÑÐÏ©‡ÖÕÐÑËÈÑÕÔÕÕÑÒÑÕ×ÓÔÓÐÐÐ̼¢�‰ŒŒ†wkiyœÉßßÙÖÕÔÛÕÒÛÛÛÛÚÙÚÚÛÚÙÜÝÔÔÜÝäèèéêêêëëêëëëëëëëìëëëëëëëìíìììììëëëëìëëëëëëêêéêééèéèèèèèèåØ×ºwh~~o�ÃÎÌÌÍÊÈÃÀÀÄÉÆ±¸ÈÆŸqˆÅÓÏÓÓÒÏÍÎÌÉËË’z±ÍÍÐÐÐÒÐμ‰ÔÓÑÐÍÏÕÙÔÓ×ÖÒÒÖÔÓÖÕÓDzœŽ‹‘“†uik�¤ÇÞßÙÕÖÙÚÛÜÕÔÛÜÙ×ÛÚÚÚÚÚÚÛÛÜÛÝäççèéêêêëëêêëêëëëëëëëëëëëëììëììëìììììëëëëëëëêêêéééééèèèèèèçÜÏÕ¹|h{|n‰¿ÐÊËÊÉÅÀÂÃÃɼÀÏǸ™rŽÉÕÒÕÔÓÏÏÏÍËÏÈ’¸ÑÍÏÑÒÒ˳ˆÒÕÑÍÌÎÖÖÓÕ×ÓÑÒÕÖÛׯ¬’ŠŠ��‚tkmƒ­ÎÜÝØÕÖÖÙÚÚÚÙÜÜÕÕÙ×ÚÛÚÛÚÛÜÛÛÛÜâæçèèéêêêêëêêêëëëêêêëëëëììëëëëëìììììììëëììëêêêêêéééééèèèèèèçãÕÌÔÂj~}o†¾ÒÉÇÈÇÆÄÁÃÊÄÈÓʹ¶šr’ÍÔÑÒÓÕÔÒÍÎÊÐÈ�„½ÏËÐÐÑ͵„ÎÑÍÌÍÓØÑÑÖÒÐÓØÚÔÄ©’††’•†ofr�¸ÈÕÞÖÓØÛÚ×ÚÛÛÚÚÚÚÖÖרÚÛÛÛÚÜÛÚÛÛàåæççèééêêêêêêëëëêêêëëëììììëëëìëìììììëìëëëëëëêêêëêééééééèèèèçäÛÎËÓ¿vf€~nƒ¿ÏÇÈÇÈÇÅÆÆÁÊÑÐĬ³�m•ËÐÍÒÖ×ÔÎÏÏÊÏËŒ‡¿ÌÍÎÎй„ÎÐÍÌÏ×ÕÑÒÒÏØÜÓ¸žŠ‚‡““‚ts€£ÀÑà×Ò××ÙÛÜÛÚÚÚÚÙÙÙÚÛÛרÚÚÚØØÜÜÛÛÝãæçèçèééééêêêêêêëêêëìëëëëëëëëëëëëììììììëëëëëëëëêêêééééééèèèèèåàÓÌÉͬzn{xg¸ÌÅÉÉÈÊÉ¿¸ÇÐÎÈ´±¬‘r˜ÏÒÐÔÖÕÒÓÔÏÊÔÆ‚ŠÁÎÍÍÏ·†ÑÒÎÍÐÔÐÑ×ÙØÏ·™…‡’‰{nn…«ÎßàÜÖ×ÙØÚÚÛÚÚÚÚÙØØÙÙÚÚÚÚÙÛÚÚØ×ÛÜÛÛÞâåæççèèééééêêêêêêêëëëêëëëëëëëëëìëììëëëëëëëëëêëëêéêêêééèèéèèèèæâØÍËÉÒÃixyl{®ÉÍÍÆËÎǺÂÒÐÆ¼²®¸’p ÍÑÒÒÒÔÕÕÒÐÎÔ³z�ÅÏÎиˆÏËÊÎÐÑÕÚÙÍ´•��ŠŒ~qlr�³ÒàÞÖÕ×ÚÛÙÙÚÙÛÖ×ÙÙØØÚÚÚÚÙÙÙÙÚÙÙÚÙ×ÖÙÜàâåææççèéééééêêêêêêêëêëëëëëëëëìëëëëìëëëëëëìëêêêêêêéêêéééèéèèèèæâÜÏÉËÌÕÅ�u}zix°ÈËÊÌÎÎÄÆÓÑÊÀº²¹´ŒsŸÎÓÐÒÔÔÖÓÔÓÍͯ}–ÆÎз…ÄÃÇÐØÚÕÀ¦‘�ƒ‹ˆxhf{�¿×àÞÙÕ×ÚÚÚÜÛÜÛÚÚØÙÙÙÙØÙÙÙØØÙÚÚÙØØ×ÖÖØÙßääææåçççèéééêêêêêêêëëëëëëëëìëëëëëëëììëëìëëëëëëêêêêééêééééèèèèçæãàÕÊÌÌÊÖÑ–mvwly¨ÈÌÌËÍÈËÓÏÊÅ¿·²·µ�x¨ÓÓÓÓÓÖÕÔÔÐÊЬz�ÊÒ¶x­¯ÌÜÖº—…‚†ˆ„ygg‚ªÏÞáÜ×ÖØÚÚÚÚÛÜÜÜÛÚÙÜÚÙÙÙÙØ×ÕרÙÚÚÙØÙÝßßÕÖßãäåååæççèééééêêêêêëëëëëëëëëììëëëëëëëëëëìììëëëëêêêéêêêééééééèèçæäáÚÎËÌÊÊÓÈ‹ovzt}¨ÅÊÍÐÎÍÔÑËü¸³®¸¶�{¯ÕÒÓÖÖ×ÖÖÖÏÊʤ~¥Ð¶s•–Áºœ‡€‰Ž…tjx’µÔßÞÚÕÔÙÛÙÙÛÚÙÚÛÛÚÚÚÙÙÖըרÚÙרØ×רÛßßÚȱ¶ÓÛáâäååææèèééééêêéêêêêëëëëìììëëìëëëììëëëëììììëëëëëëêêêééééééééèèçåâÝÑÊËÉËÌÔÊ‘oz‚v�«ÌÐÐÍÊÒÓÎŽ»½¶¶·°Š{²ÔÔÔÖרØÖÔÌÉË�z­º}²Ÿ‘Œˆ�Œ~to}¨ÊÜâÜÖÕ×ÙÙÚÚÙÚÜÚÚÚÜÝÚØÚÙ×ÖרÖ×ÚÙØÖÕÖÛÞÜϺ¡Š†¹×ÚââääåææççèèééêêêéêêëêëìëìììëëëìëìíìëììëëëëëëëëëëëêêêééééééèéèèèæãßÕÌËÊËÌÎÖÊ’o}‚y€¬ÍÐÊËÑÓÏËú¿¿¾µ³®‹�µÓÑÓÖÖ×ÕÓÏËÌÈ•�¥yÊ®�Œwgo�°ËãâÜÕÏØÙØÚÚÙØÚÜÜØÛÝÞÞÛÙÚØ×ØÙרØ×ÖÖÚÜÛÓÁª–Œ‰�©ÖÚÞâããäåææçççèèéêêêêëêëëëëëëëëììëëìëëììììëëëëëëëëëëêëêëêêêéééèèèèèæäàÙÎÌÉÊÇÇËÏÊ“kv{v~­ÓÎÌÒÓÏÊÆ¿¼½Á¼±¸¿‘ƒ¶ÖÔÒÕØÖÓÏÎËÎÆ�{qº²‚mlw“·ÕâßÙר×ÕÙÙÙÙÙØØÙÕ×ÙÛÜÜÙØÚÙÙ×ÖÖÖÕÔÖÜÞÚÆ®šŽŠ“�¢ŸÁßÝàáããäåååçèèèééééêêêêêëìëëëëìììëìììëëììëëëëëëëìëëëëëêëêéêéééééèèèçäáÜÒÍÊÉÇÇÌÉÎÈŽhy‚v~¯ÐÍÐÕÑÊÉÆÂÂÄÀ³ºÍ¸ƒ‰ºÓÒÔØÖÓÏÎÌÊÎÀŒw£�w~�ÃÚÜÙ×ÖÙÜÚÚÚØÙÚÚÙ×ÙÙÔÖÙ×ÙÙ×ÖØÚÙ×ÔÓÖÙÛÚп¦ˆ„Œ™Ÿœ•‰�ËâßßáâããääåæçèèèéééêêêêêêëëëëììììëëëëìëììëìëëëëëëëëëëêêêêéêêééééèèèçäâÞÕÍËÊÉÊÈÌÍÓОru{nu¬ÐÏÑÓÍÊÉÄÀÀÁ¸¼È¿¡�„ºÔÑÕÖÔÐÐÏÍËдg‹Œ¥ÎÜÝÚÕÖÚÜÜÛÚÛÙØØÙÚØÕÙÚÚÙØÖØÙØØ××ÕÕÙÜÛÓï˜�‹‹–›–‰~vžÛßßàáâãâãååææçèèèéééééêêêëëììëììëëëëëìëììëìëëëëëëëëëêêêêééêéééééèèèçåãàÙÎÊËËÅÀËÆÈÖÓ pwuiz«ÎÑÑÒÏËÆÀ½¾»ÀÊÀ¬š~‹½ÔÑÓÓÑÒÐÍËË·nµÓÛÜØÖ×ÚÙÙÛÛÚÚÚÖØÙÙÙ××ÙÚÙÙÙÚÙÙØ×ÕÖÛÝ×ȯš�Œ“šš“ˆ€zwxx~½àÝßàááâããäååææçèèééééêêêëëëëëëëëììëëëììëëëëìëëêêëêëëêêêéééêéééééééèçæäàÛÏÊËÃÇÊË´±ÍÏÔ¢qswqt£ÏÐÊÈÍÌÅÿ¼ÂÌȯ –zŠÇÖÐÑÐÏÑÎÌ̶‡×ߨÓÖØÚÚÛÚÛÜÛÛØ×ÙÙÙÙרØÙÚÙÙÙ×Õ×ÜÞØË¹ �Š’��•Šwuurtyƒ¡ÓÞÞßàááâããäååææçèèèèééêêêêëëëëëëëìëëëëëêêêêëëëëêêêëëëëêéééééèéêéééééèæäâÝÔÎÌÅÉÍËľËÊÒÓ¥xsxpp¢Í¿®ÉÐÇÄÅÇÈÌι£¢›s‰ÈÔÐÑÏÐÐÎζ†Ñ×ÖÖרÙÛÝÝÜÚØÙÙÚÙØÚÙ×Ø×ØÚØÔÖÙÜÚÓ¾£‘‰Œ—�Ÿ—„wttrqt€”«ÈØÛÞÞßàáááãääääåææççèèéêéêëëëëëìëëêëêëëëëëìììììííìëëëêëëëëìëëêéééèéèèèèæåâàÔÉÍÍËÊËÏÎÊËÌÒÖ²{s}mr Â¿ÈÏÈÃÈÍÍÍÏÁ¯¦®˜o‰ÆÓÎÑÒÒÏй…ÓÙÕØØØÚÜÛÛÜØÐÖÚÙÕÖ×ÖרØÖÕÔÙÞÜÎ²š†…“œŸ—Š�xvuuvyŠ¥ÃÖßßÙÚÞÞßàáââãääääææçççèéêêêêëëëëëëëëëëìííííìêéèåäáßÝÜÜÛÛÛÛÝßáåçéëìëêëêéééçåãâÖÊÈÈÍËËËËÊÊÍËÍ×¶yuzpršÂÊÎÌÆÆÉÏÏÎÆ´¨ª­–p‰ÉÕÐÓÕÑѼ…ÔÚØÙÙÙÚÛØÚÛÚØØÙ×ÖÖÕÕÖÕÕØÛÛÓ¿§•Œ�™¡�‘†}yqsxŠ£ºÏÜßÜÚÐÒÝÞÞßááâãããäååæççèèèêéêêêêêêëëëííìëéæâÞÚÕÐÌÇÃÀ½¼»º»¼¼½¿ÁÃÄÆÊÎÓÙÝáæéêëêéèäáÛÐÇÆÌÎËÉÌËÉÎÍÊÎ×´|txrr�¾ÌÉÇÄÁÌÑÏȽ·´¨¤˜o�ÉÐÐÓÒÒ½…ÔÛØ×ØÚÚÚØÙÙÚÚÚÙ×ÙÖÒÔÙÚÛÙË·Ÿˆ‡–  ˜Œ�}|zwx‚—³ÅÙãÙÖ×ÖØ×ÙÞßÞàááâãäääåææççèéééééééêëìíìêæáÚÔÏÉÄÀ½º·´²°®­¬«¬®®¯°±±±±²²²²µ·¼ÃÊÒÙßäæçæáØÐÍËËÊÉÉÆÄÌÍÍÍÎ׸~oyww›ÃžÄÅÊÒÐÈÂǽ¯ª±›nˆÄÑÐÓÔ»†ÔÚØØ×ØÙÙÚÙÙØ×ØØÖÕÓÕÛÜÑ¿¬›”—š¡ž‘…}{yx|ˆ“ªÇÚàÒÔÖÎÔÚÙØØÛÞßÞàâââãäåååæçççèèèèêêìíìêæàÙÒËÆÁ¿½¹¹¹·´²¯«§£Ÿœ™˜˜—˜š™––𡦍©©¥¡¢£§¯¸ÀÈÐÕÙÛÛÚØÔÒÐËÿÅÊÍÐÍÎ׺�r{yw™¿¹ÃËÉÍÐÈÁÀ»·³²· v•ÌÔÐÔ»†ÔÚרÙÚÙÙÙØÙ×ÕÕÖØÚ×ÒdzŸ’”ž¤¡—‹�zxxwzЧÇÖÝßÛÖÔÕÔØÚÚÚÙØÜßßßàáâãäååæåææçèèêêëíìéåÝÕÎÈÂÀ½»¹¶²¬¦¡œ—‘Œ‡�|ywvtsrqrrstw|‚Š“˜™™›žžŸ ¡¥§®´»ÂÉÎÓ×ÙÙÔÍÊÊËÌÍÎÏ×½zixsn”­½ÉÊÌÎÌÁ¼À¿¶º¾Æ¦yœÏÓÓ½…Ó×ÕÖÚÜÛÚØ×ÖÕÖÛÞÛγœ�“˜Ÿ¥ž�ƒ~|{ws|—´ÍÛÞÚØØ××ÙÙÙÚÛÚÚÚØÝàßßàáâãääåæåæçééêëéæáÜÕÍÇÁ»·³®¨¡›–‘Œ†�|vpljigffddddbadedfit{}~}�Š“œ¢£¥¤££§ª®´¹½ÂÉÏÒÕÖÕÒÐÏÊÌÖ¶|ozoj‡·ÉÍÑÎÎÅÀÁÀ½ÄÂÄ¿—rœÎÔ¼†Ñ×רØÙÙÖÕ×ÚÛÚÒ®—Љ‘ž¡™�€{yxvz}“¾ØàÞÚÖÒ×ÛÚÚÙÙÙÚÛØÚÙÙÞààààâããååææèééèäáÜØÓÎÆ¾´ª¡›˜’Œˆ…‚�}{yvsld_]\\\[Z[\^]YZ\[\bospjcdjs~Š”œ¥«¬¬®±³´³°°³·¿ÇÎÓÖÕÓÐÍÔ¾�kwpl—ÈÎÏÒÏÆ¿Ã½¾ÄÁÄŶŒnœÒ½†ÒØÙÙÕÕÖØÚÜÕŰŸ•�‹”š˜�ˆƒzrsy†—®·ÊáÜØÖÓÙÚÚÚÙÚÚØÙÛØØ×ØÚßáááâäææçççåãßÚ×ÔÒËû°£—އƒƒ‚��ƒƒ€}xtpmjgbYOLJNTSMLLJLMMOMLXeihaVV_hlqy€‡’£®³¶¶¶¶³°­«­°´ºÃÊÒ×Ôǽ´wh|nl›ÊÍÏÎÇÃÆ¿¼ÈÅÉÊÁ´�t©½…Ò×ÒÕÚÜÜÕÆµ¥˜—š�˜‘�‰„|wvv|›¶ÆÚÜÚ×ÖÖØ×ÑØÜÚØÛÜÚÚÔÊÒÚÕÖÛßáããääãâàÞÚÕÑÏÏÎȼ® ’‡ƒ‚‚„……ƒƒ�~zuqmiedbcdaZXXZ]YSSSNMNNNKIPVVXXRRV\djpwzwƒž¯±²±±²°¯®®­­®²¶ºÁÐ͹ͼvduqm›ÉÐÌÆÇÊÄÀÇÇÌÍÅÁº”z˜…ÔÚÕÙÙÌ·¡•’—šž—Œ…�~wsy‹�£ÅÙáßÛØÕÒ×ÚØÙÚÚÛÙÙÚÙÛÛÔÌÖÜØ×ÝáââßÜÚØÕÐÌÌÎÑÏŲŸ‘‰†‚‚…‡‡†ƒ€}zuqnkhfffhkmoqrqqrpliikjjfb_]ZYXRPOJGJNVaipy{|Š ­¯±³´³²²°¯°°°²´´ºÊÍË׺td{vo”ÄÏÄÃÉÆÄÃÀÅÌÈÁº¸�p†ÐÐÅ»ª›•”–š—Ž†|wvw}ˆ—´ÏÔÙâÚÕÖÔ×××ÚÚÚÛÜÛÚÚÜÕÒÛÙÚÛÚÛØÙßàÛ×ÔÑÏÍÌÎÑÓ̽¥Ž~~…ˆˆ‡††„�~zuqmkihkllmoqtttuutvxxvspmmoonmkgc`\XSH>?HOU^eny~„�¥¯°³µµ¶µµ¶¶´³²¶·¶ÃÍÎÍÖ¿vc~ul‘ÄÉÁÅÁÃÊ¿½ÉÌô·®€�³š‘•˜š›–Œ„zwux…˜¯ÉÛâáßÙÔÔ×ÖØÚÙÙÚÚÚÚÚÚÚÚÚÙØÚÛÛÙÙÙØÚÛÕÒÐÎÍËÏÔÔǰ—„xwz„ŒŒˆ„‚€|xtpmkjjjlqsrrrrsttustvvuuusqnmnpppokhgd`[TPRXVW^epx€ˆ•¦¬¯´···¹ºº¹····¾ÇÍÐÐÎ׿wfzuj’Äļ»ÀÎÊÆÌÌÈ»¹²—n˜ŠŽ™˜Ž€{yxuu~‘«ÃÓÝßÚÙØ×ÚÖÖÙØÛÜÙÕרÚ×ÕÙÙÚÚÜÛÙÙÙÚÙÚÛÙÓÏÍÌÍÓÖϽ¥�|wz}€ƒˆ‡…�{vronmkjlmqssstttuutsqpomiggikmmnopnnoonlkgdcbbfeWYcju€†Ž ®´¸»¼½¼»»º»º¹ÁÊËÌÏÒÐÍÙÃ}h|yo–Ä¿·¾ÊÍÍÏÌÊÀÀ»œoŸš‹‚zxywtz�©¾ÎÝÞÛÚÖËÖÛÙÙÚÛÙÛÜÛÚÚ××ÛÚרØÕØÚØÙÒÓÚÛÚ×ÑÍÌÌÑÔÑ»™�xx}�‚}}ƒƒ‚{qooonnooqrrqqqstsplifdd`YTTWZ_cfjnqommonkjjhfgjkodPVeq{€ŠŸ®·º¼¿ÁÀ¾½½¼»ÀÊÍÌÎÐÑÑÐÎÓ¾€o†}rœÀº¾ÈÆËÐÎÍÄÀ£u�ˆzvtrw•²ÐààÝÖÔÖÙÛØÚÛÙÒØÜÛÚÛÚÚÜÛÖÔÛØ×ÙÕ×ÚØØØ×ÚÛÔÌÊÊÐÖÒ¿¢~pw~�‚}~~}{}~~zplnppqssspnpqoljga^ZVTQOLMNRVZ\`djmomlllkjlljknpsuZK[jw‰œ«´¹½ÁÂÁÁÀ¾ÀÇÉËÍËËÐÑÐÑÏÈË»…s�|s�Ÿ³ÈÈÉÏÑÒËÄÅ«h„usx�‰¡½ÖàÕÑ×××ÙÙÙÛÝÜÚÛÚÚÚÛÙØÙÚÚÛ×Õ×ÕØÚÛÚÕÑÙÛÚÙÑÊÈÌÓÖŧ‘}oy€~||}}yssxzwpkpstuttpkmolfa`\WSPMGDGJMOSXZZ\_eglnmlklllmllnoqto\[eu��ž«³¸½¿¾¾¿¾ÂÉÎÍÌÍËÈÍÑÐÏÐÎÈÍĆl~vp}¦ÅÉÍÎÑÑÍÊÈ«_x|—­ÀÐÛÞÚÖÍÒÙÙÚÙØÚÚÙÛÙÛÜÜÚÛÛØÙÚÙÚÚÚ×רÙÚÛÖÎÒØÖÏÈÉÍÓ̲”…Œ„u{}~~}|{wrmkkmommptuvvusomlfa]\[YXZ[ZXTTVWTUZ[[\`dfjmnnlnpoookhfdgnlgjvƒ‘¢¬²µ¶º¿½¼ÃÊÊÊÇÉÍÍÌËÎÏÍÎÏÏÌÕÇŒo{~v’¿ÇËÍÐÑÎË̱o©ÀØààÞÚÕÕ×ÛÜÙØØØÙÜÚÚÛÚÛÚÚÚÚÛÙÚÙÙÛ×ÓØ×ØÚØØÚÕÑÖÌÇÌÏÒÕw‚‘”ƒx|}}}|xqkhfdcfilosuuvusqpmfcccdghkmnornhgec`^]__`eiiknnnprrqnha^ZY_lqr}‰—¦®°¯´·¯ºÉÈÉÊÉÅÄÌÌÍÌÌÏÍÍÍÐÏÍ×ËŒmzxu”ÁËÍÐÑÍÉηˆÚâÍÏ×ÕÖÙÙÚÚÙØ×ØÙÚÚÛÛÙÚÚÛÚÚÙÙØÙÙÙÙÖÓ×רØ×֨רÒÇËÒÓÁ�jq���xz{}{ytkeca[V_jmpstvvusqpniimpstuxxtqrtspommlheedbdgiknmnorsrnfc_XOO\oxƒ’¡­®®³±�~Œ¾ÍÇÈÉËÉÉÈËÍËÍÍÍÍÏÎÍËÓȉgyzo’ÃÐÏÑÍÇ͹ˆÕÖÁÌÚØØÙÙÙØÙØØ×ÙÚÙÛÚרÚÕÖÚØØ×ØØÖÓרÕÖÕÓÖ×Ö×ÖÎÊÎÏÄ–qhy‹uyzyzvmd`^UKLVemprtvuttqpomqtuy{yxxvsrqrpnoooonmkjighiknnnnpssmfc_XPIJ_}� ®²¯­�ŒqkƒµËÇÆËÊÈÇÊÌÌÊÊÊÍÍÌÎÍÊÔÊ‹k€xk–ÈÎÐÐÅÊ»†ÒÖÑÖÚØØÙÙÙØÙÚÓÓ×ÖØÛÚÙÚÚÓÔØÖÖ××ÖÔÒÖ×ÖÕÔÕØÒÒÕÑÍÏÏÈ¢}wgguyy{yupg_[WM@AQ^hmrtuuutsqqruxwy{{{vsrqpopnllmmnnnnnmkkknppoonqpkgcb]UKHSt™­²´»»ˆh{‚xk|®ÈÆÇÈÇÈÉÊËÊÊÊÎÍÌÍÍËÌÓÉŽm|yt™ÇÏÍÈʺ†ÒØØÙÙ××ÙÙ×ØÙØÑÓÖÓØÙØÙÚÔÖÖÔÒÕÙ×Ö××ÖÖÓÒÖÙÙÒÔ×ÐÍÑÎ¹Ž‚zgdq{zyumbZXQC9:LZbkqstuttusstw{{{|}}zsqpolllkgefikmnppmklmnpomnnmmjhhhbYNHJe™²¶ÂÌ͹“w|‚{mv¥ÃÆÆÈÊÎÍÊËÊÊÎÏÌÌÍÊÍÍÐÈ�m~�v�ÈÊÇϺ…ÓÙÕ×ØØØØ×ÖØØ×ØÙØÙÙØØØ×ÒÔ××ÔÕØØ×Ø×××ÒÒØØÖÕÔÕÑÌÏÆª�‰}mjs{yskc\WK;89CR_gnstuvvuuttx{}~~|ytrpmjgeda^\]`eilnonnonnnlllmlmkijjhd\SL`œÀËÎÐÑ×Μzu||nsžÄÊÈËÃÂËÊÊÊÌÍÌÌÍËÍÏÈÎÆ‹l�‚xŸÇÉͽ…ÕÚ×××ÙÙ×ר×ÕÖÙÙÙÙØ×Ø×Ö××רÙÖÖ×××רØ×ÕÔÒÓÖרÓÍÍ¿¨–�‡untyukb]\Q<9>AJUajostuvwwvvwz}~~~}ytqle^ZWTQQRUVW\bgjmnooooomlkmlllijmnmjieg¦¾´ÌÎÍÐÐ̯zp€st˜ÂÉÆµ¶ÉÉÊËÌÍÍÍËÈÍÐÌÈÍÆ”p|~w™Â˹‡ÕÙØ×Ö×ר××ØØØÖØØÙÙØ×Õ××ÕÕר×ÖÕÕÔÖÖÕÔÒÖØÛÛÑÄ®µÎ¿¬œ—�ypvuoe`cXD@AADKUblpstuwxxzz|}€|xtnf]XUSQMHEEJOQT[`eilmopoqpnmnnmmlnonlnpsr¢¾¬ÎÐÌÏÐÓØ¹‚o|‚rl�¿Ç¼ÂÇÇÉËËÍÍÌÌËÌÌÉÊÊÍÌŸt}~t‘¾¸…ÓÙØÖ××רØÙÙÙÙÚÙÕÖÖÕÙ×××ÖÖØ×Ö××ÕÒÓÖ×ÙÛ×ÍÀ± “†“¼Åµ§ž‘xvrqi`aM=?A?BKXckqtvvy{{{}€~|wrk`ZZ\YVURNH@>DKOTY]chlnpqqrqppqomnmiefkosyŸÐÐÌÍÎÑÐÎÓÖ¹‚m}�rk�¾ÆÄÇÄÇËÊËÍÍÍÎÌÇÆÈÌÈÌÓ©v|„v“±…ÑÖÔÔÔÕרØ×ÔÓÙÙØ×ÖÓÕØØ×ÖØ××ÖÔÔÔ×ÚÚ×ÑÆ¸¢•Ї‹Ž‘’¢¾Å¸¢Ž…�yplhZL=9@CADP[ckqvxz|~~€€~|xsj^[]]\ZZ[[VQH>D@=DKTY`lvy}€‚ƒ‚��€~zuoc^_`a`\VQNLC60126?JQV[afjntwz{|}p[OF?<=ETajvŸÊÎÍÍÏÐÏÏÐÐÎÍÕÔ¥v{„xh|¬ÃÅÈÈÉÍÎËÍÍÊÊËÍÎÌÍÏÎÒ«vy‡„ÐÙ×ØÚØ×ØÙÚÕÖÚÙ×ÖÔÓÒÔØÚ×ËÉ´¡”Šˆ‹‹•’ˆŠƒ{urnhgfdeadz›±¡‰ƒpQ<:??;?DKOU`nz�…‡ˆ‡ˆ‡†�|wtrppolljie`\XWVPICDO\a_^cknptwy~‚…€bHDA@FUZT`ˆÀÏÎÍÎÌÎÎÏÏÏÎÑÑÏÌÐÔµ€jx}psšÁÊÉËÌËÊÉÊÉÍÌÇÌÎÊÌÎÍÔ±†ÒÚØÖÖÔÓÔÔÖ×ÚÚÒȹ¦•Šˆ‰Œ�Ž‘��‰skfehjjjkklmnmnponnonpl_nƒ„€t`K>?ELOPW`p~ƒ†ˆ‰‰ˆ‰ˆ‡‚}~|zxtpnljhge`ZURSWXXY_hnpruy|€„……pJBE:-3CNeœÉÏÏÏÌÆÊËÏÏÏÐÐÐÍÏÑÑÜÇ‹kv~ro‘¾ÌËËÊÉËÌÉËÍÊÍÌÉÇÇÍϾ…Ï×ÕÓÔררÕÍñ£•�Œƒˆ™—––”Œ~smhfeiiillllmmmoppoopponnim~wrwztdNKSSPRXbt~…ˆˆˆ‰ˆ‰‹‹‰ˆ‡†…‚|yuqonkgb\WUUWWVY`gnpqvy|}…††^LLE879Di«ËÎÎÍÎËÅÈËÍÏÏÍÎÏÌÏÓÓÚÏœss{qlˆ¹ÍÉÊÉÉÌÍËÌÌÎÎÍËÊÍϺ„ÎÑÖÙÚÛÓõ§™’Ž’˜œ˜Šƒ�Œ…~xmgfhikllmnnlkmonmonoqqqpponp}rfkotwsleaWNQXhz�ˆŠŠŠ‰ŠŒŽŒŒ‹‹Š‡†ƒ�~yuokheb`_]^_``elrstwz}€�…‡ŠˆpYXWVSLQ{¶ÅÁÊÌÍÏËÍÍÎÎÎÎÎÒÍÌÒÓÎÔÓ«wr|wn…¶ÊËÉÉÌÎÌÊÌÎÎÎÍÐÎн†Ó×ÓÌ¿­œ�‰�”—�¢Ÿ›„ty{skjheflmppnmnnnnnprpopopsrqoopnuxiknquvwvpi`TRau‚‡Š‹��Œ�����Œ��Šˆ‡„|zuqonljjhhikotxzyz~~�‚�‚…ˆŒ‹|a^dhkad•ÂÆÀËÎÍÎÍÎÏÐÎÎÎÍÏÏÐÒÒÐÌÏÔ´|n|xm€«ÇÇÇÍÍÊÊÌÎÍÎÎÐÎ̼„ô ‘ŠŠ�—œ ¡›’Œ|qhfmmhhiillmmnmllljmnmnpppqrqpqpooooxsimku|vqwtqkggu‚‡ŒŒ‹ŒŒ�Ž�’’‘���ŽŠ‰‡‚€~{ywuusrstv{}|}}~�ƒƒ‚��…Š��‡lY\cmlt¬ÆÇÎÏÏÏÐÐÍÏÏÌÏÍÌÈËÑÒÒÐÒÐÐØ¹~lwxmx¢ÂÈÉËÉËÌÎÏÎÐÑÌÊ»o•‹Œ’š£¥œ“†{tols‚Œƒm\[abdfcdijjikkjmnmmnopqpoopnnoonzskno}ƒwlvwuutx�†Š��‹‰Š��’““”’‘‘�ŽŽ�‹ˆ†„ƒ�~~{z{|~~~~�ƒƒ�€€ƒ‹�’�|e^`ip‚µÈÇÏÎÎËÈËÍÍÊËÐÎÏÌÍÎÑÓÑÑÒÑÒÙÊkuxou�¾ÆÇÊËÊÌÎÎÐÐÎϺnœ ¥£��rlkq�œ¹ÌȾ°‡\PW[[Z\`cfhijjlllmnooppnopomlmm|vmqt‚ƒzv}|xzz|‚ˆŒŒŽ�‰ŠŽ�“””““•”’“”““��Ї†„‚‚€~€‚�€�€€�‚‚�€�…Œ“•“ˆtmkls…´ËÌÊÌÌ̾¾ÏÏÌÎÏÏÌÏÐÎÏÓÓÒÒÒÎÐÙÊ“puxor–½ÃÅÊËËÌÐÐÎÎÑ»w¥•„xqor}� ±ÀÈÍÙÑÁËÜÒ bJJLPTWZ]`cfffghijlmlllmnopnlk{znsx…‡…ˆ€y|}~~„ŠŒ�ŽŽŒŒŽ�“••”•˜˜˜˜˜—•“�ŽŒŠ‡†…„ƒ��‚ƒ�€€��„ƒ��‚ƒ‡‹�–•Ž~urrv‚«ÉÊÉËÌÌÊÌËÊÏÎÎÍÉÎÏÍÐÒÓÒÒ̾ÇÐ×Óœmsxps—½ÅÅÊÍÌÏÐÎÍѾbzopz‹Ÿ³ÄÑ××ÔÊÉÐÊ¿ÅÎÒÑ«nG>BIMPSVY]`abdfiklihkkjlopomx{pszˆ‹Ž‰eg|‚„‰Š‹���Œ��“””–˜š››š™—–•’‘�ŒŠˆ…„…ƒ�€�€€�‚ƒƒƒƒƒ†‰‹Ž•™“†{xy{�¢ÆÇÉËÍÌÏÒÈÆÏÏÐÍËÏÍËÎÑÏÐÏËÇÌÓÒØÒ›oqwpt•¸ÆÇÊÍÎÐÐÏѽb�œ´ÆÔÚÝÝÛ×ÔÒÏÏÕɾ¾ÄʪuR>9?FJMPTW[]_behjijkjjjlmons|rt|‰‹ŠqOcz„€‚†ˆŠŒ�ŒŒŽ‘•™›žž��œ›š˜˜—––”‘�Œ‡„†…„‚�€�€€~~€�„‰�‘™¥«¥’�}}„˜ÀÊÅÊÌÊÊÍÍÊÌÏÒÍÎÑÏÌËÎÎÏÎÏÐÏÐÓÑ×Ö¢omxupН¿ÄÉÌÎÐÏÏ»uÂÛàÞÜÛØÖÖÕÖÕÔØÑÁÀÂÿº½½¯‰`C58?EIMPQVX[_cffhhhiijjkkjxwv~‰‰z]Veuƒ‡‚€„†ˆ‰‹Š‹�—¡§©««¬¨¤£žš——™˜–•’ŽŠ‡………ƒ€~€~~}}€ƒˆ�š®»º³¤‰~~�‡�—¹ÊÉÊÊÊÌÍÉÉÎÏÎÅËÑÎÍÎÏÏÏÑÎÍÏÎÐÑÖÙ¬uo~vn‚§½ÄÇÊÏÏϺ|É×ÕÕÖÖØÙ×Ö×ÔÕÕÅÀÀ¿¾¾»½¹»­ŠkM938@EHJMPV]_aabcdfefhiiclxx~ˆ„kZaezŽ‹…€€‚„†‡ˆ‹”£¬­­®³µ³±ª£Ÿ›™š˜”‘ŽŒŠˆ…ƒ�}~~~|}€€„Š”§¸»µ°«•}�‡‹s~°ÌÉÇÉÉÉËËËÍÎÃÇÐÎÏÑÌÌÏÏÐÐÏÎÑÒÍÕÚµzlvsr†¦ÀÅÅËÏÑ»†ÔÒÑØÙÖÔÓÐÖÔÐÔʺ»¼¹¹Ã´³»´µ£ƒoXB327>CEJQUWZ\]_bdcdefgb_v{‡d]fm‡’Œ†€€�‚„†ˆŒš¦¨©«­°²²³¯¬ª¥Ÿ™—•‘Ž‹ˆ…ƒ�|}}{yy|‚‚ƒˆ“ ©¯²°¬¨™ƒ}€†ŒzeqžÃÉÅÈÊÊËÌÎÌÌÍÍÍÏÐÌÌÐÏÏÐÏÐÒÒÒÏÑØº‚ksxv�žÀÆÄÌÒ»ƒËÙרÕÑÒÐÍÔÑÑÔɽ»¼½»»²²½º¹´–|naN:018>CGJMRWY[^abbbcdcYm~}‡~ffr{Š�‹†���‚„…†�™¡¤¦¨«­¯­¯°²°­¦ž˜”‘�‹‡ƒ€€|}|xw{‚†…†ˆ�™Ÿ¡£©ª¦£™„}„‰ƒwddŒºËÉÈÇÊÎÍÉËÎÍÍÍÍÏÏÎÏÐÑÐÏÑÓÓÒÐÏ×È™ppwpuœÀÃÅκ‚ÌÜÙÙÔÏÖÖÒÏÒÕÓÁ»ÁÀ»°º½½½º´¥‹{siXD5/16=BGJNTVX[^^]`cd^ezyƒ�mn|{��‹‡ƒ€€‚„…†�–�£¦¦©««¨ª­¯¯®ª£š”�Œ‰†„€~€|xx~…Љ††Œ”™� ¢£ Ÿ™ƒy~�ˆwwja|®ÉÇÅÈËËËËËÍÏÏÎÍÌÌÍÎÐÎÍÐÒÐÐÑÏÏ×Ò¢olupl‹­¼Çµ†ÖÚÖ×ÖÕÖÖÔÐÔØÐ¼·¿ÀÂú°¸½»»³®Ÿ†}tj^N?3/29?CGKPSVYYZ]adb`s|‡|wvq†Ž‰„�‚ƒ…†‹“˜ ¤¥§¨§¤¦©ªª©§¢œ–�Ї†ƒ~�ƒ€ytvyzzz{~�ƒ‡�–››šœ—�v{€†{fmwp_n�ÂÊÅÈÌÍËÊÎÎÑÑÊÇÍÏÎÌÊÎÐÑÐÐÐÎÏÎÒÓ®whvneƒ²Ç²…ÕÛØ×ÕÕÔÔ××ÙÕÈÃÁÀÁÀ¿½²¸»¹¹¹¶±‘~zsmdWH90-3:ACHKOTVWZ^bb]e||„‰‹�…mu‹‹„‚‚�„†…‰�”™ž¢£¢¡¡¡¤¥¤£¢¡�–�‹‰†‚€�„„€ulmmgO?I[ltuz„�‘���{sy~…}a]hvsdh�ºÊÉÊËÊÈÉËÆÊÌÇÉÎÐÎÌÏÐÐÑÑÏÎÐÑÎÏÔ´|kysp‡°¶…ÔØÕÖÕÕÖÕÔØ×¿»ÇÅÄ¿¹½»¶·º¸¹º·£‡~zvogYLB6..4:>DIMPSUY\^_\q|u~Š”‘~o�‹„‚�‚†‡‡‹Ž�’•˜™™™™›�žžž�›˜“�‹‰…€~‚„ƒ‚xh`b[?.2;I^lqv}€€}qpx}…y`^\drvkd{ªÈÉÇÉÅÀÊÇÊÈÇÊËÍÎÏÎÏÏÏÑÐÏÐÐÎÌÍÔÁ‚hvsj~Ÿ†ÒÔÔ×רÙ××Ú͸ÀÇÄÅÄÄÀ¾¾¹µ¹¼¼½µ±™ƒ}xsnh_UK>2-.4;@CHMOSUV\\bxvr}Ž•‘‰ˆ‡„��ƒ…‡Š�Ž��Ž�‘“’’’“•••”‘�ŽŒ‡„�}}�ƒ…„€tcYTLEEE=?Ujoqsrtqjnv}„v^^[Y`qvobnžÄÇÄÇÆÊÐÍÈÍÌÊÉÌÌÎÏÏÍÏÐÎÎÍÍÏÐÐÖ‡jstmq†ÓÙÖØÙÙÚÙÚÚÎÈËÇÃÃÅÂÁ¿ÁÀ»¹½¿½·¶«�‚|wqnic\QE91,/7<8;d€„‡…�€zvx|zx{…”žŸš–—™™œ£¤ •†}‚�™ž�š•�Š…ƒ„‚€„…ƒ€}wqr{�vlq}uYRQNOONONKU^`][\]_`aa`^]]\Z[]Y_nxobx«ËÊÂÄÆÈÈÇÇÉËϼ†×ßÛØÍÉÎÑÐÐÒÎÌÉËÎÊÊËÌÍÉÈÉÈÈÈÉÉÈÉÈÅÅÀ»½½»°”‡…„€|zrsurnkhfc^WPF@>:;Z{‚†„€€{srxywv|Š˜Ÿž˜••—–˜š—‘��™  žžžš•”“‘�ˆ…„ˆˆ…ƒƒƒ~|‚ƒzss|mVVUSTROMPSQTSLHKU^___`b`_]ZZ\ZWYfsocl™ÂÉÅÃÅÅÅÈÅÅλ…×ÞØÕÌÎÐÑÅÇÒÑÑÌÊÍÌÎÍÊÊÉÉÈÈÈÇÉÉÉÉÉÆÅÅÀ½½¼½«�‹ˆ‚~{wvvuqolid]^XFAED2Eq~ƒ„�}toruusu€�šœ—��”•’“’Ž‘˜›Ÿ¡žšœ�™––“މ‡‡†„ƒƒ�~z|‚„{wvxgZ[XVVSTTVZSLJFDIV^_`_`cbba^\ZZ[YU_otgdˆ¶ÆÂÀÁÂÇÅÇ̹‡×ÝØÒËÏÐÐÈÈÒÓÎÎÑÎÎÐÍÊÉÊÈÅÊËÇÉÌÇÇÊÆ¿»½½½½¼¸œ‰‡„‚~{wurplieehZG@Vy]8]z�†…�}xqpstsqv‚‘™—‘����‘‘�”˜›��œ™˜™—’‘ŽŠ‡ƒ~zxvtsqqv~‚~xzu`ZYZ[WTVUUVUOJKPX_][ZWWZ\[]\\]\Z[YW]gunbw¦ÄÅÂÃÅÈÌ͹‡ÙÞØÍÌÐÑÒÓÎÎÏÌÍÏÐÎÍÎÍÎÍÆÇÈÁÄÇËÅÄÈȽ¶»¿½»º·¦‰†‡…„�~wturookkgZRB`�–XIq†‡„€{topttqpxˆ”–‘‹†ˆŽ‘•™šš�Ÿž›–�Ž�Œˆ„~|vrommmlou}�€}}n\ZXZ]YUVTSVVSQU[]YQOMNNOPLNX\]]]\\\YXbrqcl™ÄÊÃÃÇÉι†ØÞÓËÌÎÑÓÒÍÌÏÒÎÊÑÍËÎÌÌÌÊÌÈÂÆÈÉÅÇÉÊÄÃý»¼»µ­“ŠŒˆ†„vuz{uoljd^XDd€�H`y…Šˆƒ€zsopqqpuŠ�އ‚�…‰‘œžžœž¢ž—�‡‰Šƒ|xsqpmjjjiiow~�€�{e\[[[ZXVUTSWVU[]YTNIJMNOOKHJRQQY^[Z[]^Y_ntfdŒºÇÂÂÆÌ¸†ÖØÎÊÌÍÑÓÐÎÍËÐÎËÎËÍÍÍÌÌÍËÊÍËËÊÉÉÊÈÄÁÃÀ¾¾¼¹´©–�‹‡†�||{{vnjjga[Ps†~�]Qo‚Љ„‚|uopqpqx‚‹�„~|„Œ—£¨¢ žœš“‹ŠŠ†€yspnjgedfkry~€ƒ…wc]\]]\[YYXXWW[a]UPQQNOLNNJJKJINX^]]]]]\Z[fsnez©ÄÅÄ˺‡ÖÔÉÊËÏÒÔÒÏÍÉÌÏËÃÉÎÏÎÍÍËËËËÌÍÎËÊÉÈùÁ¿¾¿¿º¹¤ŽŒ‰‡ƒ€�~ytpmomdcd€Šw‘�Tg}ˆŠ„�€€|uqqpoqy„‰„{y~†Œ“ž¥¨¥ œ˜˜—’�Œ‡€zqjfc`bgms{}�Ž‹sa]]]]_^\\[[[[^\VTRQSROPQONONLJNXadb_]YY[YYewzfk–¼ÆÉ¹†ÖÕÈÉÉÎÒËÈÎËÍÎÍËÉÌÍÎÍÍÌÉÊÈÉËʾÃÊÉËËÆÁ¾ÀÀ¿¼º»´™‹‰…€€‚€~ysqsphfkƒ�x—jg{„Š…ƒ…ƒ�}tqrqmrz‚‚|wx�‹’•�¥¥¦¡š˜˜•‘�ŽŠ„�}{zwy|€‚~‚�Œn^]__]^^]]^^^]YUUTTSRSRTTPRSRPKKRZaa_^]ZY[\]csyfbƒ°Æµ†ÔÒÊËËËÒÇ¿ÊÇËÐËÌÍÊÍÍÌËÊËÉÆÈÊȹÀÉÉËËÉÁÁøµ·ºª�ˆƒ�‚„‚�€zuvslfg‚�}m•†k|�‡‰‡‰Š…‚|vvsoory~xvz‡�‘–œ£§¥Ÿ™–••––˜š���›——™›šŠ�ˆ„i\_``^^__^__[YWWXWWWUTSSRPQRSRMKO[bca_^[YXX_\Yjxncx¢°†ÓÎÊÐÑÎÏÑÎÏÍÂÃÅÈÌÎÊËÎËÈÊÊÇÈÉÊËÊÊËÊÉÆÄÄÃú³´¸¸ �‰‚‚…‚€~~}zwpkg}Ž‚h†�xxƒ†ŠŠŠ��‡€ywvsnow|}}yw}‰�‘—žŸ ¡žž�œœž¢§¨¦ œš›šš›•…€„|d[]_````_]]^^\[ZZ[[YWVUTUSOQSRMIP]a^_`_^ZWWXYYXarrioˆ„ÏÌËÑÔÓÒÓÒÏÎÉÀÂÈÌÈÇÍÐÎÊÊËÊÈÈÊÊËÊËÊÉÇÅÅÃÄÁ¿¼¾»½²—�ˆƒ„‚€}|~~{tomzŠƒii—“w�……†‡�‘Žƒ{xwupntz||xvw�ŠŽ‘“–—� ¢¢¢¡¢¢Ÿ ž™••–““•™Ž�†zb_^``__`_^^^_]\Z[][ZYWWWXYWWUSPNPQNLPW[]]]ZWUWWR[ktlcƒËÌËÍÒÒÒÑѽ»ÑÎÊËÊÅÉÏÏÎËÂÈËÊÊËÊÊËËËÊÇÅÅÆÄÀÀÂÀ¾¾»¥�ŽŠ‡ƒ€~||~|yspy†‚l[uœ‡}‡†�‚†Ž‘‰}wvtrmouxusssxƒˆ�“—œ¢¡¡£¢¢¡›˜—˜”�“–””–�†‰t_``_^^_^^_`_]]]]][ZZ[XUZZYYYUQTVQJFKRWZ\_c`ZXVVWWWaok†ÊËÎÎÐÑÎÐѾ¹ÊÏÐÌÈÍÍÎÍËËÄÉÊÌÍËÊÊËËÊÊÈÇÆÆÁ¼¼¼»ÀÀ½´™�ŽŠ„‚€~}}z{wrw……p`\…œƒ‡Œ…€‚ˆ‘Ž�ywtqmlnqsqnmnsz„ŒŽ“˜œžžžžŸžš˜”“��Ž�•’�‹‹‡jY[]^_^^^_`a`__^^^[]\]ZZ\\YTUVSRQNKIMUYZ\Z\a^[[Z[^ZU^lƒÉÌÌÔÓÐÐÌËÍÍËÌÏÍÌÐÏÎÍÌÌÍÍËÌÌÊËÌÊÉÉËÊÈÇÆÄ¾»¹»ÁÁ¾¿®”��Šˆƒ‚ƒ�~}zww‚†tc[i˜–‡�‹ƒ�ƒ‹�Š~xurmhhkqnihiou}†‰ŒŽŽ•˜™�š——™“ŽŒŠŠ‹ŽŒ‰ˆ‰€bWY\\\\]___^_a_]^^\]]]]_][ZWWXVRPNLJHHHIRXX[]]]\[]^\Z^€ÈÏÍÐÐÌÎÇÉÍÌËÌËÌÑÑÐÏÎÎÌÊËËÌËÌÎÌÊÉÉËËÉÉÇǽ»Á¿¾¾¼¸¡‘��ˆ…„„„‚�€{{ƒve_Y{ ’ˆ‰…‚€‚ŠŠƒzrpnhgfikifhmos|„ˆŠˆŒ�“˜”’“‘‘�Œ‡‰Œ‡‡‡††t]YZ[\ZZ\\\[[]]_```^\^][\\[ZZXUSSRQPOONLFLW[\]^^[Z\\]\W�ÉÏÒÉÈÎÎÍÌÍÊÊÎÍËÏÒÐÏÍËÎËÈËËËÌÍËËÌËÌËÉÈÈÆ¿ÀÄþ»¿»º±˜�Žˆ†‡†„„„ƒ€~ƒzf\Xb‰ –Œ„€��„†}okljgdchiggklouz�…†…‡‰ŠŒŽŠˆ‹�‹‰Š‰†…‚ƒ�iZ[YXYY[[YYXXXX[^_^]^][XYZXXYXVUSRRTVUSPMOY^^^^]]^_`][Y‚ÎÒÏÎÐÓÎÎÎÎÐÏÍÎÐÑÒÏÌÍÍÊÈËËÊËËËËËËÌÍÊÈÉÉÇÄÅþ¼¾¿¾¼¼¨’�ŠˆŒŠ†……„ƒ€�„|g\XWg†—š•ˆ�}{‚|ofeggedecacgjkpu{ƒ††ƒƒ‡‡�€†ˆŠŒˆ„€{‚}_WXVVUVYYYWVSRTUXXXYYYZZZZVUVVVUVVVTUVRMJP[`_^__`aaa_\ZƒÎÒÑÓÓÑÎÎÍÌÏÏÎÎÐÏÏÎÍÏÎÅÉÏÍÍÎÍÌËÊÉËÈÁÅÉÊÇÅÄÅþ¿½¿¿·›ŽŒŠ‹‹„…‡†„€}xk_XV]dp�‹‘ˆ}uxzyl]Z`ccefb^_`cgjptx}ƒ†ƒ~~yvx|€…ˆ‚yxx~pVVVVUUTUXXVWVQPQQQPRSXZXUUTQQSXXXXWSRXWRLR]^\]a`[Z]`_]]ƒÌÎÍÒÑÏÏÐÎÍÎÌÊËÍÏÌÊÍÍÏËÉÌÎÎËÌÌÌËÌÌÆÃÆÉÉÆÄÃÄÆÃÁ¿¿Á¿¿«’ŽŒŠ‹‡ˆ‰‡ƒ†|pxn`XWZ_`cb{‰€vquwr^SW]`aedb_\]befjotz‚~xuutsruyyuppsv`QSSSTVUTSPPRRNLLNSTSTWURQUWURTYXUVVTTVTQQY`^[[WVWTX__^X…ÑÑÍÒÒÐÑÑÐÐÎËÈÈÉÍÍÍÍÎÎÍÆÈÎÎÌÌËÌËÌÎËÊÅÆÈÄÃÅÃÅÄÀ¾ÀÁ¿º¡��‹‹‹ŒŠ‡‰“ŒrsqcWTV]^ba`}‡}rosuiSMV]^^adb]YY]`ejlsy|}xsqqljjmmmkjniOKPNMONOLJJHGHIJJNUVWXXWUXZ[\ZZYXXWUTVTQRY`][\YPOX\ZZ\[W„ÏÔÓÔÓÑÒÒÎÌÌËÍÎÉÉÍÏÎÍÌÎÊÉÌÎÏÎÌÌËÌÌËÊÈÉÇÆÆÆÅÄÄÁÁÂÁ¾¾²–‘�Œ‹ŒŠˆ——•ŽxodYTTYZ[fai…†xjjpn]NMU[Z[]`^ZWX[]achmpppplhddeddefihcXHFJKJFDBCFHGIKLJLPPPQQUYZZYYYXVXZYVTUTU\a_VW[YVXY^^[]WS‚ÍÔÕÕÑÐÐÊËÌÍÍÎÏÍÎÏÏÎÌËÍÌËËÊÉÍÎÊÉÌËÉÉËËÇÇÄÄÈÆÆÀ¿ÃÂÿ½º¦–’ŽŒŒ‰‹™˜‹›™}bYVVWZVZhaq‰ƒqahphZOMTYXWZ[ZXWWWY\`bdfeffbabaaaafaVYe^JBHGDBACDGHJKMNOPQQPQQVXWVSTVUTUVUUVWY`bZTUYYVXYYZYXQK„ÏÒÏÐÏÏÏÇÊÍÎÐÏÎÎÐÑÐÍÎÎËËÌÌÉÉËËÊÇÇËÉÇÉÊÇÃ»ÄÆÁÃÃÁÃÃÂÁÀ¼¶Ÿ’’��Љ‹™‹‰ž�tWRWVVWT_ebzˆ�k\dg_XOKRXYWVUUTSVWXZ[\]ab`_aa`]\]UIEKVffNAEHIJKGEGHHLPRRSVWUPOSTRSUZZY[[XWXZ\ab_[[YVUSWWXWTPO…ÏÑÌÍÍÐÑÎÌÏÏÏÑÑÎÏÎÌÍÏÏÍÌÌÊÌÈ¿ÈÌÉÈÌËÈÊÇÁÅÄÄÁ¾¿ÆÅÅÃÁÁ¾»«”’‘Œ’’‚…‘†‰›‹gROTTVST_bf}†�dT^]YVMIOUTTQOOPRTVUVVVY\ZYZXTSUJ;:@GMWghN>EKMMLLONNKMOOOOMJJKORSTWYZ[[[[^``bddfdc\XVVYXWVYZRƒÏÔÍÊËÎÐÎÍËÊÍÑÒÍÌÌÌÍÍËÌÌËÉÍÈÁÉÉÉËÉÇÆÉÆÃÆÇÆÆÃÃÂÀÆÅÃÂÁ¼º²œ‘�—¦¥Žs…�…‡��iQJOSQQU_`k�…|^PVUVUMHJOUTPPPNPUSPQRQRSPNNSdeA5:=BKS[jmO:?CEGIMPSPOMIGHIIIKOQRSSSSVXX\bccfggefd]YWYZWUSW\W„ÐÑÌËÉÈÇÇËÉÇÊÎÏÌÊÎÏÏÎÍÎÍËÈÍËÉÆÆËËÇÆÆÉÇÈÆÆÈÈÄÄÂÂÈÆÄÃÀ¼·²¨––¤­©ŸŒ‚‹�ƒƒ‚ymTEGOOPV]ar�€y[KKMRSNIHKPRSQOOPPMMMOOMNR]n~sC68>CIRZ`npP9?DHJKKJNSVYZ[TLLNPOOQSTUY\WVUTWTRSRTVX[`fc„ÎÏÌÊÇÊÊÌÉÅÍÎËËÌÌÌËÍÍÍÏÍÍÊËÊÊËËÉÉÊ̽¼ÊÈÈÇÇÄÀÁÅÈÇÆÈ¾­·½º¯¨¥£•—¦ª­£‘‡‹—Œpkfpym^LDGNUXn|ka]YNDCLQOKJKMLKMPUYZ]elpsw|pB039CJRY_fmptw‚¡”ubJ=AGKLJKOQUXXSIGJLMMKPQNPSRQOUXSPW^^`d_ZX\‚ÎÐÌÊÈÌËÌÌÌÐÏÍÎÊÈÌÎËÉÎÍÌÏÑÎÈÊËÌÉÊÉÉÂÂÈÆÉÇÅÄÄÆÊÉÆÅžª©©¦¥¦¥¤™’›œ££�†…“�}vifhmofVLEHO\~‚k[YYULILPPQOOOMPSVY]bhlotwzqC.28CLUY^jv|}b@]~ЇtQA>CJLKMORSSUSKLRPQQOOOQPU\[^]YXXY^^YZ`hZƒÍÌÉËÉÉÊÌÌÍËÊÊÍÌÉÍÍËÌÎÍËÌÏÌËËËËÊÇÄÇÍÉÅÅÈÉÇÇÇÈɽ±°¯®¬£�—𢡡›Š�‰„„‚ƒ‡��…vspddllmh[RJIbyfYXWUPMOSVSRPQSWX\aehlptxyrE-18DNUZj}‰Œ‡a:0EJJHIJKIJNUWT[n Ã­‹¡°¢€vªßÔËÚØÂ�ÇÉÃÃÄÈÊÉÈÄËÍËËÊÉÇÆÉÍÍÉËÌÊÉÌÌÆÄÄÀÀ¾¼½¸°­¬©©­´°£™•˜�¥§¡‘�‡‘¢˜�–˜¡¦“„wuy}zsrx~qg^ahnpw}‰’™Ÿ�zdMHKKOSVXZ]^adfhknqqmjN.,5CXw„ˆ‹ˆ†wSAADHLH<6Hh}�žŠ\DA=:CJP`et‡“|Pa|ÀéÀ¡§—wv±ÓË»¸»·¡‚ÈÇÃÃÆÊÌÍÌÅÉËÅÂÈÈÉËÌÌÍÉÇÈÉÆÈËÈÆÄÀ»¶³¯®°«®¯«­³°¤•�‘— §§¡’ŠŠ‚�—�ŒŒ˜ž£¬†{Œ•�…‚‹‘yu‚‹……„|ww‚�š£ª‘h\[\^abbdfhkosvz{xusY:17Sz����‘‹•{PLNQRSTL>?Nd�¤œreŽ’‰�’�·ÉÆ©“�ŠÄÙÁ»»²­½Æºµ·µ²³§‚ÇÆÆÄÁÇÉÊÉÉÉÉÄÃÉÉÊÊÊÉÈÉÈÈÈÈÊÇÁ¼·³¯¬©«¯®«­¯±¶µª›ŽŠ�›£¦§¤—xƒ‡zŒ�Šˆ�—~la\gg`ZU[^RNMX`ahplbZPIT[p{ZEDCCDDDFHHJNQSUURQP?,()C_c[MS_\ib?8:;;<=@=2+/=Usv_e’|ggdi{„�|ˆsm�€|}|ƒ~vy{{|}~vƒˆˆ‰‰ˆ‰‰‰‡ˆ‚yzzzyvptzxuvuvwxxyyzxvuppuvuy€~yyxvwxxw{xvsrvxxwvwuuysswxxutywqsttuxssustuqvƒˆˆ‰‰ˆ‰‰‰‡ˆ‚yzzzyvptzxuvuvwxxyyzxvuppuvuy€~yyxvwxxw{xvsrvxxwvwuuysswxxutywqsttuxssustuqv†’““’”“““‘‘‡xzxusuwwuuvwvwwxyxxwtsstuvz}}{yyzxxxzzyxzyvrrwxwwvuuuxttxxwuvzvpsutvxstttvtu†’““’”“““‘‘‡xzxusuwwuuvwvwwxyxxwtsstuvz}}{yyzxxxzzyxzyvrrwxwwvuuuxttxxwuvzvpsutvxstttvtu€‚„ƒƒ‚€��€�xurswxvuvvvwxvvxxutsstux||{yxyz{|}~~~~{vstwxxuuvtuxstwwvuuytqusswxrtutuv€‚„ƒƒ‚€��€�xurswxvuvvvwxvvxxutsstux||{yxyz{|}~~~~{vstwxxuuvtuxstwwvuuytqusswxrtutuv||||zxyzxvtstvwwwwvvwwvwwvurrsuvx|}{yxyz{}€€€€�ƒ�ztswxvuvutuxstwwvuvxtsutsxxqttsv||||zxyzxvtstvwwwwvvwwvwwvurrsuvx|}{yxyz{}€€€€�ƒ�ztswxvuvutuxstwwvuvxtsutsxxqttsv}||{xxyvrsvwttvxxvuvwvvvsrrsuw{}|zyyzz|~€€€€€‚„~tsxwvvuutvxsuwvvuvysrtttzvrusu}||{xxyvrsvwttvxxvuvwvvvsrrsuw{}|zyyzz|~€€€€€‚„~tsxwvvuutvxsuwvvuvysrtttzvrusu}|{wstsruwvtruwxxutuvutrrtuw{|{zyxyz|~€€€€€„€tsvwwuutsuwruwwuuwxrqstwztrtv}|{wstsruwvtruwxxutuvutrrtuw{|{zyxyz|~€€€€€„€tsvwwuutsuwruwwuuwxrqstwztrtv€|wurrvwwvuvtswxxwutsrrstuy||{xxyyy{~€€€€€€€€€€€ƒ~sswxvuutsuvruvvvuxxrqtvxztrv€|wurrvwwvuvtswxxwutsrrstuy||{xxyyy{~€€€€€€€€€€€ƒ~sswxvuutsuvruvvvuxxrqtvxztrv~wutvxyxuuvvrtwxxurqqrtvy||zyxxxyz|€€€€€€€�‚zsswwvutssuvsuvwwuxxrruvyyru~wutvxyxuuvvrtwxxurqqrtvy||zyxxxyz|€€€€€€€�‚zsswwvutssuvsuvwwuxxrruvyyru~zyvxxvuuvvtsvwvsqrstv{}|zxyxxyyy|€€€€€€€€€€€€€‚wtsvwvusstvvruwwwvyyquvvxwt~zyvxxvuuvvtsvwvsqrstv{}|zxyxxyyy|€€€€€€€€€€€€€‚wtsvwvusstvvruwwwvyyquvvxwtzutvvvuvvustusqprty||{yyzyyyyyz|€€€€€€€€€�{vtrvwvtsttvwsvwwwvzwruuuwxzutvvvuvvustusqprty||{yyzyyyyyz|€€€€€€€€€�{vtrvwvtsttvwsvwwwvzwruuuwx€zuuxwvvvvtqqqqrsx}}zxxyyyyyzyy|€€€€€€€€€€~{xtrvwussttxvrvxwvvyvruuux€zuuxwvvvvtqqqqrsx}}zxxyyyyyzyy|€€€€€€€€€€~{xtrvwussttxvrvxwvvyvruuux~ytvwwvvvsppqrtw{|zxyyyyxxyzyyz€€€€€€€€}z{wtsvutstuvxuswxxwvzurtuv~ytvwwvvvsppqrtw{|zxyyyyxxyzyyz€€€€€€€€}z{wtsvutstuvxuswxxwvzurtuv~xtwwwusqqrruy{{yxyyyxxyyyyyzz}€€€€xxzwtrtuuttvuvvsvxxxwzsqtw~xtwwwusqqrruy{{yxyyyxxyyyyyzz}€€€€xxzwtrtuuttvuvvsvxxxwzsqtw~vuxvsqpqsvz|zyyyzyxxxyxyyyyy{€€€€{vy{xtruvuuvutwurwxyxxxrrw~vuxvsqpqsvz|zyyyzyxxxyxyyyyy{€€€€{vy{xtruvuuvutwurwxyxxxrrw|uvtrqstw{{zxyzzzyyxxxxxyzzxx}€€€€€€wuy|xtruwvwuttwusxzzyxwrv|uvtrqstw{{zxyzzzyyxxxxxyzzxx}€€€€€€wuy|xtruwvwuttwusxzzyxwrv}urrsvz|{yxyxyy{zxxxxxyyxwuuz€€€€€€zvvy{wsquwwvtttwttyzzwwwt}urrsvz|{yxyxyy{zxxxxxyyxwuuz€€€€€€zvvy{wsquwwvtttwttyzzwwwt~rsw{}}zxxxyyyzzyxyxxxwuttuy€€€€€€€€€}wvvy{wtruxwvuttxttyzwuwy~rsw{}}zxxxyyyzzyxyxxxwuttuy€€€€€€€€€}wvvy{wtruxwvuttxttyzwuwy|v|}{zzzyxyxyyyyyxywvtttvvu}�€€€€€€€€xuvvy{xtrvxvvttvwruyxwux|v|}{zzzyxyxyyyyyxywvtttvvu}�€€€€€€€€xuvvy{xtrvxvvttvwruyxwux|{zzzzyxyyxyyyyxvttutuuux{€�€€€zvvvwy|xtruvwuvwvusuxwvw|{zzzzyxyyxyyyyxvttutuuux{€�€€€zvvvwy|xtruvwuvwvusuxwvw€{zz{{yyxxxxyxwutttuutvx{}}€~~}|zzyyyyz{|}~€|uvvwwy{yuruxuvxvtvstwwy€{zz{{yyxxxxyxwutttuutvx{}}€~~}|zzyyyyz{|}~€|uvvwwy{yuruxuvxvtvstwwy|z{{zyyxwwxvsstuuuuw{|||{{~}|zxvutsrqqqrqrrstuvy{}}xwvvvvx|zuruuuxvtuvstwy|z{{zyyxwwxvsstuuuuw{|||{{~}|zxvutsrqqqrqrrstuvy{}}xwvvvvx|zuruuuxvtuvstwy{z{zyyyxusssstttwz{||{z{{}€€€~}zwtrqpnkkkiiiijijknpqqqrstuvwwwwwy|yvrsvwuttuvsty{z{zyyyxusssstttwz{||{z{{}€€€~}zwtrqpnkkkiiiijijknpqqqrstuvwwwwwy|yvrsvwuttuvsty{z{yxwvsqrtsstwy}}{z{{{{{~€~}|yuqljjiihfegjklnooomknmihilopqrrstvwwy{yusuyvtttvwrw{z{yxwvsqrtsstwy}}{z{{{{{~€~}|yuqljjiihfegjklnooomknmihilopqrrstvwwy{yusuyvtttvwrw{zyvtssssttuy{||{z{{{{zz{~€~~}|zxurmfcabceghknprtsstutttrrohddfmrrsssrrsvx|yusvwuuuuvts{zyvtssssttuy{||{z{{{{zz{~€~~}|zxurmfcabceghknprtsstutttrrohddfmrrsssrrsvx|yusvwuuuuvts~wussststvy{|}{zz{{{{{{zz{~}{zywsmgjib`bcgkprrqqrrqqqqqrssstqkeemprrstssrsvz~zutuuuvuusv~wussststvy{|}{zz{{{{{{zz{~}{zywsmgjib`bcgkprrqqrrqqqqqrssstqkeemprrstssrsvz~zutuuuvuusv|ttsttuxz{{{zzzzzzzz{zzzz{{yyvpjdabhkeejnrsqppqrrqpqopopqqqqrpjemqqsssttsuwyz}yvsstvvvsu|ttsttuxz{{{zzzzzzzz{zzzz{{yyvpjdabhkeejnrsqppqrrqpqopopqqqqrpjemqqsssttsuwyz}yvsstvvvsu|tsuw{|{{zz{z{{zzzzz{zzz{zywskdca``hpnpttsrqrrsuuuutsrqqqpppoppjlqrrssttuvwyxy{yussvwxtv|tsuw{|{{zz{z{{zzzzz{zzz{zywskdca``hpnpttsrqrrsuuuutsrqqqpppoppjlqrrssttuvwyxy{yussvwxtv|wz{|{zzz{{zz{{zzyyz{yzzywtqqicbabdmtssssqqstuwxyyywuusrrrrqqppmnqrrrstvvvvxxwy|yvstwwuv|wz{|{zzz{{zz{{zzyyz{yzzywtqqicbabdmtssssqqstuwxyyywuusrrrrqqppmnqrrrstvvvvxxwy|yvstwwuv€|{{z{zzz{z{zzzzzyzzzyyywrosoecccipttsssrstvvvvwxyyxxvttsrssssspprrrssuwvwvxxxxy|yvstxvw€|{{z{zzz{z{zzzzzyzzzyyywrosoecccipttsssrstvvvvwxyyxxvttsrssssspprrrssuwvwvxxxxy|yvstxvw€{z{z{zyy{{{zyzzzzyyzyxxsnomfddgmuvutssrstvvutttuvwxxwvutttttvvtrrsvwwttvwvwwxxxy|zurtuw€{z{z{zyy{{{zyzzzzyyzyxxsnomfddgmuvutssrstvvutttuvwxxwvutttttvvtrrsvwwttvwvwwxxxy|zurtuw€|zzzzzyzzzyyyyzzzyyzyxupppkefjqwyvttssstvvwutttuuwxxwvututtvvwwssvz{ywuuwvvwwxwwxzytrsw€|zzzzzyzzzyyyyzzzyyzyxupppkefjqwyvttssstvvwutttuuwxxwvututtvvwwssvz{ywuuwvvwwxwwxzytrsw|zzzzzzzyzyyyyyyzyxxwutprrmglrwzxttttstuvwvuuuuwvuwxvvututtuuvwuvxxz|zwutvvvvxwwwwzyuqu|zzzzzzzyzyyyyyyzyxxwutprrmglrwzxttttstuvwvuuuuwvuwxvvututtuuvwuvxxz|zwutvvvvxwwwwzyuqu{yzzzzzyxyyzzyyxwvuuvvvrrtpkpvyywtuttuuuuutuvwvwxwxywuuvvuttttuuwvwxz{ywutuvwwwwwwwzytt{yzzzzzyxyyzzyyxwvuuvvvrrtpkpvyywtuttuuuuutuvwvwxwxywuuvvuttttuuwvwxz{ywutuvwwwwwwwzytt{zzzxyzyyyyyxwuuuvwwwvvusttqrxzzwtutuuuuttuuvwxy{zyy{yvutvvvusstwwvxxx{zwusvwwwwwwwwyxv{zzzxyzyyyyyxwuuuvwwwvvusttqrxzzwtutuuuuttuuvwxy{zyy{yvutvvvusstwwvxxx{zwusvwwwwwwwwyxv{zzzyyyyxvuuuuvwwwvvvvvvvsssvyyzwuuuuuttstuuxxz{|{wxzxvttwxxxvrsvwwwwwxzzwusuwvvvwwvvxy{zzzyyyyxvuuuuvwwwvvvvvvvsssvyyzwuuuuuttstuuxxz{|{wxzxvttwxxxvrsvwwwwwxzzwusuwvvvwwvvxy{yyyxxvutuuwwwvvvwwvwwvvvttuuwyxvutututssttuvvvuvxwxxutttvyyzyttxwvwxwwwzzwvsvwwwwxwvvy{yyyxxvutuuwwwvvvwwvwwvvvttuuwyxvutututssttuvvvuvxwxxutttvyyzyttxwvwxwwwzzwvsvwwwwxwvvyzxxvuuuuuwvuuvvvwwwvwwwwvvrrstuuuvuuttssrrstssstuwxwvsstttxwzzuuwwwwxwwwxzzxvttvwxxwwvxzxxvuuuuuwvuuvvvwwwvwwwwvvrrstuuuvuuttssrrstssstuwxwvsstttxwzzuuwwwwxwwwxzzxvttvwxxwwvx~vuvuvuvvuvvvvwvvvwwwwwwvwuqsssttvwvttsrrqrrrrsstttuuttutttxvuxuuwwwwwwwwxwxzywttwwwwwvx~vuvuvuvvuvvvvwvvvwwwwwwvwuqsssttvwvttsrrqrrrrsstttuuttutttxvuxuuwwwwwwwwxwxzywttwwwwwvx}vvvuwwyzxvvwvwvvwvwwwwvvxuqsrsssvwutttsrrqqrrsssstttttuttuwzwwuuwwwwwwwvwxww{zvttvwwwvx}vvvuwwyzxvvwvwvvwvwwwwvvxuqsrsssvwutttsrrqqrrsssstttttuttuwzwwuuwwwwwwwvwxww{zvttvwwwvx}vwyz{zzyyxuxyyywvvvvvvvvwupsspqsuvusstsrqqrrrsssttttttutttuxxxvvwwwwwwwvwwvvy|ywttuvwwy}vwyz{zzyyxuxyyywvvvvvvvvwupsspqsuvusstsrqqrrrsssttttttutttuxxxvvwwwwwwwvwwvvy|ywttuvwwy~|}}|{zyxxwvvy{{yxwwvvvvvvvqsqostuvuttsrqppqrrssstttstvvttrruxwxuuwvvwwwvwwwvwy{zwtstvvy~|}}|{zyxxwvvy{{yxwwvvvvvvvqsqostuvuttsrqppqrrssstttstvvttrruxwxuuwvvwwwvwwwvwy{zwtstvvy}|{{{zxwxwwvux{|{yyvvwvuvvsrppustvwuurponnoqrstttsstuvutrposwvyxtuvvwwvvwwwwwyyzzwtrtux}|{{{zxwxwwvux{|{yyvvwvuvvsrppustvwuurponnoqrstttsstuvutrposwvyxtuvvwwvvwwwwwyyzzwtrtux}|zzzzwxwvvvtuyy{|{xwwwuuussrrtrsvwvurppoonoqrtttssuvttsqporvuxywttvwvvvwwvwwyxwzzwtrsw}|zzzzwxwvvvtuyy{|{xwwwuuussrrtrsvwvurppoonoqrtttssuvttsqporvuxywttvwvvvwwvwwyxwzzwtrsw}{zz{ywywuuttuxyxy||ywwvvuttrssrsuwvvtrqqpppprsssssvuuussrqrutwwwwutuvvvwwvwxxxwxyyvtqu}{zz{ywywuuttuxyxy||ywwvvuttrssrsuwvvtrqqpppprsssssvuuussrqrutwwwwutuvvvwwvwxxxwxyyvtqu|z{{zwxxwwuuvvvyyyy{}|zxwwuustsrsuwvvvttsrrrrrsssrtvuvyxvutuuswwtvxvtuuvwwvwwxwwwxwywtt|z{{zwxxwwuuvvvyyyy{}|zxwwuustsrsuwvvvttsrrrrrsssrtvuvyxvutuuswwtvxvtuuvwwvwwxwwwxwywtt|{||zxxwwwwwvvtxzyyyy{|{zxvuuusqruwwvvvutsssssssssuvvwwwutvxurvwutuxwttvvvvvwwvwwwwwxwv|{||zxxwwwwwvvtxzyyyy{|{zxvuuusqruwwvvvutsssssssssuvvwwwutvxurvwutuxwttvvvvvwwvwwwwwxwv€}|}|yxyyxwwwwvuvyzyxxxy|{yvuvvtrqswwvuuvtsttssssttuvvvwwtuy{wtvvuutuvxutuvvvvvvwwwwwvxy€}|}|yxyyxwwwwvuvyzyxxxy|{yvuvvtrqswwvuuvtsttssssttuvvvwwtuy{wtvvuutuvxutuvvvvvvwwwwwvxy€~}}|yyyyywwvvvvuwzzyyxwxvvuutvusprvvvttutstssrqrtuuuuuvvuvyzyvvvuutttwxvttuuuvvwwwvvvux€~}}|yyyyywwvvvvuwzzyyxwxvvuutvusprvvvttutstssrqrtuuuuuvvuvyzyvvvuutttwxvttuuuvvwwwvvvux}||{yzzyxwwwvuvvvyzzyxxxusstuxxsqsvvvutttssrqppqstuutttuwwxyxxxvututttuwwuuvvvuvwvvvvuw}||{yzzyxwwwvuvvvyzzyxxxusstuxxsqsvvvutttssrqppqstuutttuwwxyxxxvututttuwwuuvvvuvwvvvvuw}|{zyzzyxwwwvvvwuwyzzzxxutrrux{urstuvusttsspoqrstuutsstuwwwwwxwuuuutttutvwutuvuvvvuuutx}|{zyzzyxwwwvvvwuwyzzzxxutrrux{urstuvusttsspoqrstuutsstuwwwwwxwuuuutttutvwutuvuvvvuuutx€}|zy{{zzyxwwwwvvvvxzzzywtssruz}vssuvuusrrsronqstuvvvvvvwxyyvvxwuuuuuuutttuwvuuuvvvutttx€}|zy{{zzyxwwwwvvvvxzzzywtssruz}vssuvuusrrsronqstuvvvvvvwxyyvvxwuuuuuuutttuwvuuuvvvutttx€}|zz{{zzzxxxwvvwvvwz{zywvsssuz|xsstvuvtrqrqnnpstuxxwwxwwxz}wsxwuuuuututttttwwttuvvutttw€}|zz{{zzzxxxwvvwvvwz{zywvsssuz|xsstvuvtrqrqnnpstuxxwwxwwxz}wsxwuuuuututttttwwttuvvutttw€|{y{{{zyzxxxxwwwvvux{yyxwuttvxzzussuuvvsqrrompssrsuvvwwvw{}wswwttuuuuuuuttssvwusuvuuttw€|{y{{{zyzxxxxwwwvvux{yyxwuttvxzzussuuvvsqrrompssrsuvvwwvw{}wswwttuuuuuuuttssvwusuvuuttw€}{z{{{zzyyxxxwwvvvvvxyyxwvttvvxzwrstuvwuqrrqopqppprsuvvvvxzwsvusttuuuuutttsstuvutuutssw€}{z{{{zzyyxxxwwvvvvvxyyxwvttvvxzwrstuvwuqrrqopqppprsuvvvvxzwsvusttuuuuutttsstuvutuutssw}zz{{{zzyyxxxxxwvwvvwzyxwwvvvtz}xtsstuvvtqrqponnpqrsututtuwwuutsssttttuuuttttttvvutsssv}zz{{{zzyyxxxxxwvwvvwzyxwwvvvtz}xtsstuvvtqrqponnpqrsututtuwwuutsssttttuuuttttttvvutsssv€|z||z{{zyyyyxxxxvwwvvyzyxwvuus~„ztrssuuvurrrpmllnqstuuuuuuvvvusssssstttututttusruvusssv€|z||z{{zyyyyxxxxvwwvvyzyxwvuus~„ztrssuuvurrrpmllnqstuuuuuuvvvusssssstttututttusruvusssv{z}|{{{zyyyxxxxxwwwvuwzzzywvvu~†~tqqrstuusrsroklmnpsstsuuuuuvussttssttttsttutttsstvusrv{z}|{{{zyyyxxxxxwwwvuwzzzywvvu~†~tqqrstuusrsroklmnpsstsuuuuuvussttssttttsttutttsstvusrv€{z||{zzyxyyxxxxxxwwwvvyzzzyyyv~‡„vppqrsttsrrrpnmllmnooprssuuvuttttstsssssssttttssstuurt€{z||{zzyxyyxxxxxxwwwvvyzzzyyyv~‡„vppqrsttsrrrpnmllmnooprssuuvuttttstsssssssttttssstuurt{{}|{z{zxyyxxxxxxxxwvwwz{{zzzx~…ˆ}ppqpqstsrqrrqonmlllmpqrruvvuutttstssrsrsrrtttsttsrsut{{}|{z{zxyyxxxxxxxxwvwwz{{zzzx~…ˆ}ppqpqstsrqrrqonmlllmpqrruvvuutttstssrsrsrrtttsttsrsut||}{zzyzzyxyxxxxxxxxwwvx{{{{{y}„ˆ‡voqporsssqrsrqpnmmmmpqqrtvvttttttssrssrsssssttttrqrrs||}{zzyzzyxyxxxxxxxxwwvx{{{{{y}„ˆ‡voqporsssqrsrqpnmmmmpqqrtvvttttttssrssrsssssttttrqrrs|||zzzzzzyyyxxxxyxxwwwwwz||||z{ƒ‡Š‚rnppqrrsrrtssrqpoooprrruwuttttuutsstssssssssuttsrqqp|||zzzzzzyyyxxxxyxxwwwwwz||||z{ƒ‡Š‚rnppqrrsrrtssrqpoooprrruwuttttuutsstssssssssuttsrqqp€}|{z{zzzzyyyxxxxyxwxxxwvx{|||{{‚ˆ‰Š€tppqqrrrrsssrrqqppqrstvwustsstsstsstssssssrssssrrqq€}|{z{zzzzyyyxxxxyxwxxxwvx{|||{{‚ˆ‰Š€tppqqrrrrsssrrqqppqrstvwustsstsstsstssssssrssssrrqq€}}{{{zzzyyyyyyxyxxxxxxwvwz|||||�‡ˆŠŠ‡zpqqrssrsssssrrrrsstuvvtsttttsssssssssssssssstsrqr€}}{{{zzzyyyyyyxyxxxxxxwvwz|||||�‡ˆŠŠ‡zpqqrssrsssssrrrrsstuvvtsttttsssssssssssssssstsrqr€}|{{{zyzzyyyyyyyxxwxxxwvwx{}|}�…‡‰ŠŠ…soqrttsrsssssrssstuuzyutuuuttttssrsssssrrrsssrrqr€}|{{{zyzzyyyyyyyxxwxxxwvwx{}|}�…‡‰ŠŠ…soqrttsrsssssrssstuuzyutuuuttttssrsssssrrrsssrrqr€}{{{zzzzzyyxxyyyxxwxxxxwwwy||}‚‚€…ˆ‰ŠŠ~oprsutsssssssssstuyƒ„{vvvuttststssrsssrrsrrrrqqr€}{{{zzzzzyyxxyyyxxwxxxxwwwy||}‚‚€…ˆ‰ŠŠ~oprsutsssssssssstuyƒ„{vvvuttststssrsssrrsrrrrqqr€}z{{{zzzzzzyyyyyxxxxxxxxwvwz|„„ƒ�„‰ŠŠ‰znqsttttstsststutx‚‡‡wvvuuttttssrrrssssssrrqqr€}z{{{zzzzzzyyyyyxxxxxxxxwvwz|„„ƒ�„‰ŠŠ‰znqsttttstsststutx‚‡‡wvvuuttttssrrrssssssrrqqr€}zz{{zzyzyyyxxxxyxxxxwwwwvvz€‚‚„ƒƒ‚ƒ‡Š‹†umstrststttttutw{~€…‰ˆwuuutttsrssrrssrsrrqqqpr€}zz{{zzyzyyyxxxxyxxxxwwwwvvz€‚‚„ƒƒ‚ƒ‡Š‹†umstrststttttutw{~€…‰ˆwuuutttsrssrrssrsrrqqqpr|zz{zzzzzyyyxxxxyyxxwwxwwvv}ƒ„ƒƒƒƒ„„‚…‰‹‚rnssssssuuuttuwz}€…‰‹‡wruvtttsstsrsrrqrqqrqrqq|zz{zzzzzyyyxxxxyyxxwwxwwvv}ƒ„ƒƒƒƒ„„‚…‰‹‚rnssssssuuuttuwz}€…‰‹‡wruvtttsstsrsrrqrqqrqrqq€}{|{zzzzzyyzyyyxyyyywxyxx{}�„„…„„„„†„‚ƒ‡Š~nqstrrstttttuw{}†ˆˆ‰}sstuuussstttsrrrrrrpquu€}{|{zzzzzyyzyyyxyyyywxyxx{}�„„…„„„„†„‚ƒ‡Š~nqstrrstttttuw{}†ˆˆ‰}sstuuussstttsrrrrrrpquu€}{{{zzyyyyyyyzzxxxxzz|~~‚‚ƒ„„„„…„„†……ƒ‚ƒ€roqsssttssstuw{~€…††ˆ~vuqtuutsttsssrstsnfjzƒ�€}{{{zzyyyyyyyzzxxxxzz|~~‚‚ƒ„„„„…„„†……ƒ‚ƒ€roqsssttssstuw{~€…††ˆ~vuqtuutsttsssrstsnfjzƒ�€|{|{zzyxyyyxyyxwxy{�‚‚‚ƒƒ�‚ƒ„„„ƒ„………„……‚�}xtrrtsssssuvvz}~ƒ…ˆ†zuuuvtuwuussnejr~p[\owrp€|{|{zzyxyyyxyyxwxy{�‚‚‚ƒƒ�‚ƒ„„„ƒ„………„……‚�}xtrrtsssssuvvz}~ƒ…ˆ†zuuuvtuwuussnejr~p[\owrp€|||{zzyxxyxxyyy{}�‚ƒ‚‚‚‚„ƒ�€ƒ„…†„ƒ„ƒ„„„…ƒ‚�ƒ�ztstuuuuvwxy}ƒ‰‰ƒyvvvwxw{{ytujZhrpbZ]_][^€|||{zzyxxyxxyyy{}�‚ƒ‚‚‚‚„ƒ�€ƒ„…†„ƒ„ƒ„„„…ƒ‚�ƒ�ztstuuuuvwxy}ƒ‰‰ƒyvvvwxw{{ytujZhrpbZ]_][^xjmhikjhgmkv„‚‚‚ƒƒ…†…………„„„„„ƒƒ„„„„††……„…„ƒƒƒƒ„„„ƒƒ„„„„…„ƒƒ„„„…†…„„„ƒ„…………………†…†„„††ˆ‡ƒ„xjmhikjhgmkv„‚‚‚ƒƒ…†…………„„„„„ƒƒ„„„„††……„…„ƒƒƒƒ„„„ƒƒ„„„„…„ƒƒ„„„…†…„„„ƒ„…………………†…†„„††ˆ‡ƒ„sPQNQKMNOSUg†‚ƒƒ„……………………„„„„„„„………†………„ƒƒƒƒƒƒƒƒƒƒƒ„„ƒ„……„„ƒ„………†…„„ƒƒ„……†……†††††……††ˆ†ƒsPQNQKMNOSUg†‚ƒƒ„……………………„„„„„„„………†………„ƒƒƒƒƒƒƒƒƒƒƒ„„ƒ„……„„ƒ„………†…„„ƒƒ„……†……†††††……††ˆ†ƒ}ststtustvuy„ƒ„……„„„……„„„„„ƒƒ„…………………„ƒƒƒ‚‚‚‚‚�€�€€‚‚ƒƒ„…„„ƒƒ„………†…„„ƒ„„……†…†…††…†„……‡ˆ…}ststtustvuy„ƒ„……„„„……„„„„„ƒƒ„…………………„ƒƒƒ‚‚‚‚‚�€�€€‚‚ƒƒ„…„„ƒƒ„………†…„„ƒ„„……†…†…††…†„……‡ˆ…�ƒƒ‚‚‚‚ƒƒ‚ƒ„…………„ƒ„„„„ƒƒ„„„„…†…………„„ƒƒƒƒƒ‚‚���€€�€€€€���ƒ„„„ƒ„„„„…………„„„……†………††…†…„…†ˆˆ�ƒƒ‚‚‚‚ƒƒ‚ƒ„…………„ƒ„„„„ƒƒ„„„„…†…………„„ƒƒƒƒƒ‚‚���€€�€€€€���ƒ„„„ƒ„„„„…………„„„……†………††…†…„…†ˆˆ�‚‚‚‚ƒƒ„ƒ„………††„ƒƒƒ„„„„„„……†……………„„„ƒƒƒ‚���������€€�€�€�€‚„…ƒ„„„…„…†…„…„„………†…†††…†…„†‡†�‚‚‚‚ƒƒ„ƒ„………††„ƒƒƒ„„„„„„……†……………„„„ƒƒƒ‚���������€€�€�€�€‚„…ƒ„„„…„…†…„…„„………†…†††…†…„†‡†€��‚ƒ„………………„†…ƒƒƒ„…„„…………………„„„„ƒƒƒ‚‚�€�€€���������€���€€‚„„„„„„……††……„„„……†††††……†……††€��‚ƒ„………………„†…ƒƒƒ„…„„…………………„„„„ƒƒƒ‚‚�€�€€���������€���€€‚„„„„„„……††……„„„……†††††……†……††€�ƒƒ…†……„……„……„ƒƒƒ„………†…………„„ƒƒ„ƒƒƒ‚��€€���€��€������€�€�€�‚„„ƒƒ„„…†††……„„………††…†………†………€�ƒƒ…†……„……„……„ƒƒƒ„………†…………„„ƒƒ„ƒƒƒ‚��€€���€��€������€�€�€�‚„„ƒƒ„„…†††……„„………††…†………†………�ƒ„„……………„„„……„ƒƒ„……†……„„„„„„ƒ„„ƒ‚‚�€�€�€€���€€�€�€��€€�€€€€ƒ„„„„„„…†††………………†††………„…†……�ƒ„„……………„„„……„ƒƒ„……†……„„„„„„ƒ„„ƒ‚‚�€�€�€€���€€�€�€��€€�€€€€ƒ„„„„„„…†††………………†††………„…†……�ƒƒ„……„„„„„„…„ƒƒ„…†………„ƒƒƒƒƒƒ„„ƒƒ‚����€��€€����€€€���€€�€€€€‚„„„„„„…††††………„„…†††…†…„…†…�ƒƒ„……„„„„„„…„ƒƒ„…†………„ƒƒƒƒƒƒ„„ƒƒ‚����€��€€����€€€���€€�€€€€‚„„„„„„…††††………„„…†††…†…„…†…€�„……„„„„ƒ„„„„„…………„„ƒƒƒƒƒƒƒƒƒƒ‚‚����€€€€€€����€€€���€€€€€€€�ƒƒ„…„„……†…††……„„„…………†……„††€�„……„„„„ƒ„„„„„…………„„ƒƒƒƒƒƒƒƒƒƒ‚‚����€€€€€€����€€€���€€€€€€€�ƒƒ„…„„……†…††……„„„…………†……„††€‚„…„ƒ„„„„„…†…………„ƒƒƒƒƒƒƒƒƒƒ‚ƒƒ‚���€€��€�€€€��€€€�€€€�€€€€€€€ƒ„„„„„„…††…††…„„„………†……………†€‚„…„ƒ„„„„„…†…………„ƒƒƒƒƒƒƒƒƒƒ‚ƒƒ‚���€€��€�€€€��€€€�€€€�€€€€€€€ƒ„„„„„„…††…††…„„„………†……………†€‚„„ƒƒƒ„ƒ„……†…„„ƒƒƒƒƒ‚ƒƒ„ƒƒ‚‚ƒ‚�€�€€�€€€€€€���€€��€���€€€€€€€�ƒƒƒ„„„…††…†…†…„„„„……†……………€‚„„ƒƒƒ„ƒ„……†…„„ƒƒƒƒƒ‚ƒƒ„ƒƒ‚‚ƒ‚�€�€€�€€€€€€���€€��€���€€€€€€€�ƒƒƒ„„„…††…†…†…„„„„……†……………€ƒ…„ƒƒ„……………„ƒ‚ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚�€€€€€�€�€€€€�€�€€€�€���€€€€€€€€‚„„„„„……††……††…„„ƒ„„…………†„€ƒ…„ƒƒ„……………„ƒ‚ƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚�€€€€€�€�€€€€�€�€€€�€���€€€€€€€€‚„„„„„……††……††…„„ƒ„„…………†„€„„ƒƒ„……………„‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ‚ƒƒ‚€€€€€€€€€€�€€���€��€€���€€�€€€€€�„ƒ„„„…………†…†‡†…„„ƒ„„……………€„„ƒƒ„……………„‚‚‚‚‚‚‚ƒƒƒƒƒƒƒ‚ƒƒ‚€€€€€€€€€€�€€���€��€€���€€�€€€€€�„ƒ„„„…………†…†‡†…„„ƒ„„……………�…„„……†…„ƒƒƒ‚ƒƒ‚‚‚‚ƒ‚ƒƒƒ‚ƒ‚ƒƒ‚€€€€�€€€€€�€���€€��€����€€�€€€€€ƒ„„ƒ„………„…„†‡‡†…„„ƒƒ„…††…�…„„……†…„ƒƒƒ‚ƒƒ‚‚‚‚ƒ‚ƒƒƒ‚ƒ‚ƒƒ‚€€€€�€€€€€�€���€€��€����€€�€€€€€ƒ„„ƒ„………„…„†‡‡†…„„ƒƒ„…††…‚…………„„ƒ‚‚‚‚‚‚‚‚‚ƒ‚ƒƒƒƒƒ‚‚ƒ„ƒ�€€€€�€€€€€�€�€€€€€��€€€€€�€€€€€€€‚„„„„„……„„„…‡‡‡‡…„ƒ‚ƒ„††„‚…………„„ƒ‚‚‚‚‚‚‚‚‚ƒ‚ƒƒƒƒƒ‚‚ƒ„ƒ�€€€€�€€€€€�€�€€€€€��€€€€€�€€€€€€€‚„„„„„……„„„…‡‡‡‡…„ƒ‚ƒ„††„‚……„ƒ‚‚ƒƒƒ‚‚‚ƒ‚‚‚ƒ‚ƒƒƒƒ„„„„„�€€€€€€€�€€€�€€�€�������€€€�€€€€€€�„„„„„„„„„ƒ„††‡‡……„ƒ‚ƒ…††‚……„ƒ‚‚ƒƒƒ‚‚‚ƒ‚‚‚ƒ‚ƒƒƒƒ„„„„„�€€€€€€€�€€€�€€�€�������€€€�€€€€€€�„„„„„„„„„ƒ„††‡‡……„ƒ‚ƒ…††‚„ƒ‚‚‚‚‚ƒƒ‚ƒ‚‚‚‚‚ƒƒƒƒ„…„„„„‚€€€€€€�€€€€��������€��€�€€€��€€€€ƒ„…„ƒ„„„„„„…†††††„ƒƒ„„……‚„ƒ‚‚‚‚‚ƒƒ‚ƒ‚‚‚‚‚ƒƒƒƒ„…„„„„‚€€€€€€�€€€€��������€��€�€€€��€€€€ƒ„…„ƒ„„„„„„…†††††„ƒƒ„„……��‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ‚ƒƒ„„„„„„ƒƒ�€€€€€€€�€€€€€�€€���€€€�€�€€€��€€€€‚„„„„ƒ„„„„………………††„ƒƒ„…„��‚‚‚‚‚‚‚‚‚‚‚‚‚ƒ‚ƒƒ„„„„„„ƒƒ�€€€€€€€�€€€€€�€€���€€€�€�€€€��€€€€‚„„„„ƒ„„„„………………††„ƒƒ„…„��‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„ƒ‚‚€€€€€€€�€€€€€€������‚‚ƒ‚ƒ‚‚��€€�€€�„ƒ„„„ƒ„ƒ„…„„…„„†‡†„„„„„��‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„ƒ‚‚€€€€€€€�€€€€€€������‚‚ƒ‚ƒ‚‚��€€�€€�„ƒ„„„ƒ„ƒ„…„„…„„†‡†„„„„„€���‚‚‚‚‚‚‚‚‚„„„„„„„„ƒƒ‚‚‚�€€€€€€€€€€€€€€��‚ƒ……†‡‡‡ˆˆˆˆ‡‡††…ƒƒ�€�„„„„„„„ƒƒ„„„†…ƒ…†††„„„ƒ€���‚‚‚‚‚‚‚‚‚„„„„„„„„ƒƒ‚‚‚�€€€€€€€€€€€€€€��‚ƒ……†‡‡‡ˆˆˆˆ‡‡††…ƒƒ�€�„„„„„„„ƒƒ„„„†…ƒ…†††„„„ƒ€�‚‚‚‚‚‚‚ƒƒ„„…„„„„„ƒ‚‚‚‚‚‚�€€€€€€€€€€��‚ƒ…‡ˆ‰‹Œ����ŽŽ����‹Š‰ˆˆ‡‡†……„„„„„ƒƒ„„„†…„…†††……„ƒ€�‚‚‚‚‚‚‚ƒƒ„„…„„„„„ƒ‚‚‚‚‚‚�€€€€€€€€€€��‚ƒ…‡ˆ‰‹Œ����ŽŽ����‹Š‰ˆˆ‡‡†……„„„„„ƒƒ„„„†…„…†††……„ƒ€�‚�‚‚ƒƒ„……„„†…„„ƒ‚�‚��‚‚��€€€€€�€�‚‚„†ŠŒŒ�Ž��‘���ŽŽ���ŽŽŒŒŽŽ�ŒŒŠ‰‰ˆ††…ƒƒƒ„„„…„ƒ„…†…†…„„€�‚�‚‚ƒƒ„……„„†…„„ƒ‚�‚��‚‚��€€€€€�€�‚‚„†ŠŒŒ�Ž��‘���ŽŽ���ŽŽŒŒŽŽ�ŒŒŠ‰‰ˆ††…ƒƒƒ„„„…„ƒ„…†…†…„„€�‚‚ƒ„„……„„„„„‚ƒƒ‚‚‚‚‚‚‚‚‚€€€€��‚ƒ„‡ŠŽ‘“’’‘‘�����Ž���ŽŽŽŽ�ŒŽ�’‘�‹Š‰‰‰‰ˆ‡†…„„„„„ƒ„…………††…€�‚‚ƒ„„……„„„„„‚ƒƒ‚‚‚‚‚‚‚‚‚€€€€��‚ƒ„‡ŠŽ‘“’’‘‘�����Ž���ŽŽŽŽ�ŒŽ�’‘�‹Š‰‰‰‰ˆ‡†…„„„„„ƒ„…………††…€‚ƒ„„…„„„„ƒ‚‚‚‚‚‚‚�‚�‚‚‚‚�€�‚‚ƒ„†‰�Ž�’““’�����‘‘‘‘’’’““’““‘ŽŽ�’�ŒŠŠ‰‰‰ˆˆˆˆ„ƒƒ„„„„……………‡†€‚ƒ„„…„„„„ƒ‚‚‚‚‚‚‚�‚�‚‚‚‚�€�‚‚ƒ„†‰�Ž�’““’�����‘‘‘‘’’’““’““‘ŽŽ�’�ŒŠŠ‰‰‰ˆˆˆˆ„ƒƒ„„„„……………‡†�ƒƒƒ„„„ƒ‚‚‚�‚‚‚‚‚‚‚‚‚‚‚�‚�‚ƒƒ„‡‹Ž‘’�Ž‘‘��ŽŽ�������‘‘‘’““””“’‘‘’‘‹‰Š‰‰ˆˆˆˆ†ƒ‚‚ƒ„ƒ„……„„…‡†�ƒƒƒ„„„ƒ‚‚‚�‚‚‚‚‚‚‚‚‚‚‚�‚�‚ƒƒ„‡‹Ž‘’�Ž‘‘��ŽŽ�������‘‘‘’““””“’‘‘’‘‹‰Š‰‰ˆˆˆˆ†ƒ‚‚ƒ„ƒ„……„„…‡†�„ƒƒƒ‚‚���‚���‚‚‚‚‚‚‚‚‚��‚ƒ„†‰Ž‘’’’�Œ�Ž�Ž���Ž�����Ž���‘’““’’’’��ŒŠŠ‰ˆˆˆ‡†„„ƒƒƒƒƒ„„…„ƒ„†…�„ƒƒƒ‚‚���‚���‚‚‚‚‚‚‚‚‚��‚ƒ„†‰Ž‘’’’�Œ�Ž�Ž���Ž�����Ž���‘’““’’’’��ŒŠŠ‰ˆˆˆ‡†„„ƒƒƒƒƒ„„…„ƒ„†…�ƒ‚����‚‚����‚�‚‚‚‚‚‚‚‚‚ƒ„…‡ˆ�‘’’‘�Ž‹ŒŽŽŽ�Ž��Œ‹Š‹‹Œ����‘’’‘‘’���ŒŠŠˆ‰ˆ†…„„ƒƒƒ„ƒƒƒ„„„ƒƒ„…�ƒ‚����‚‚����‚�‚‚‚‚‚‚‚‚‚ƒ„…‡ˆ�‘’’‘�Ž‹ŒŽŽŽ�Ž��Œ‹Š‹‹Œ����‘’’‘‘’���ŒŠŠˆ‰ˆ†…„„ƒƒƒ„ƒƒƒ„„„ƒƒ„…����‚��‚‚‚�‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†ˆˆŠ��‘�ŽŒŒ�Ž�ŽŽŽ����ŒŒŒ‹‹Œ�����‘‘‘��Ž�‹ŠŠŠˆ†…„„„„„„ƒƒƒƒ„„„„ƒ„„����‚��‚‚‚�‚‚‚‚‚‚‚‚‚‚‚‚ƒ„†ˆˆŠ��‘�ŽŒŒ�Ž�ŽŽŽ����ŒŒŒ‹‹Œ�����‘‘‘��Ž�‹ŠŠŠˆ†…„„„„„„ƒƒƒƒ„„„„ƒ„„€�‚�‚��‚‚‚�‚‚‚ƒ‚‚‚‚‚‚‚ƒ„†ˆˆŠŽ���Œ‰‹�ŽŽ�ŽŽ���ŽŽŽŽŽ�ŒŒŒŒŽ���‘��ŽŒ‹ŠŠˆ‡„„„ƒ„„„„„ƒƒƒƒ„„„„„„„€�‚�‚��‚‚‚�‚‚‚ƒ‚‚‚‚‚‚‚ƒ„†ˆˆŠŽ���Œ‰‹�ŽŽ�ŽŽ���ŽŽŽŽŽ�ŒŒŒŒŽ���‘��ŽŒ‹ŠŠˆ‡„„„ƒ„„„„„ƒƒƒƒ„„„„„„„€�‚�‚��‚‚�‚‚‚‚‚‚��‚‚�‚‚„‡ˆˆŒŽŽŒŠ‡ˆŒ�ŽŽŽ���Œ�����ŽŽ�Œ�ŒŒ�����ŽŒ‹Š‰‡„ƒƒƒ„ƒ„„„ƒ„ƒƒ„ƒƒ„„„„„ƒ€�‚�‚��‚‚�‚‚‚‚‚‚��‚‚�‚‚„‡ˆˆŒŽŽŒŠ‡ˆŒ�ŽŽŽ���Œ�����ŽŽ�Œ�ŒŒ�����ŽŒ‹Š‰‡„ƒƒƒ„ƒ„„„ƒ„ƒƒ„ƒƒ„„„„„ƒ€�‚����‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ…‡‡‡‹Œ‹ˆˆ‡‰ŒŒ�ŽŽ�Œ��Ž�������Ž��Ž����ŽŒ‹‹‹ˆ„ƒƒƒƒƒƒ„„……„ƒƒ„ƒƒ„„„„„„€�‚����‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ…‡‡‡‹Œ‹ˆˆ‡‰ŒŒ�ŽŽ�Œ��Ž�������Ž��Ž����ŽŒ‹‹‹ˆ„ƒƒƒƒƒƒ„„……„ƒƒ„ƒƒ„„„„„„€��‚‚‚�‚‚‚��‚‚‚‚ƒƒ„ƒƒ„ƒ…‡‡†‰‹Šˆ‡ˆ‰‹���ŒŒ��Ž������ŽŽ���ŽŽ����ŒŽ��ˆ„„ƒƒƒƒƒƒ„…„„ƒƒƒƒ„„„„„„„€��‚‚‚�‚‚‚��‚‚‚‚ƒƒ„ƒƒ„ƒ…‡‡†‰‹Šˆ‡ˆ‰‹���ŒŒ��Ž������ŽŽ���ŽŽ����ŒŽ��ˆ„„ƒƒƒƒƒƒ„…„„ƒƒƒƒ„„„„„„„€���‚‚‚‚‚‚‚‚‚ƒƒ„„„„ƒƒ„ƒ„…‡††ˆ‰‡‡ˆŠ‹�Ž��Œ�Ž�����Œ‰‰‹ŽŽŒŒŽ��Ž�����‰ƒ„„„„ƒƒ„ƒ„„„„ƒƒƒ„„„„„„„€���‚‚‚‚‚‚‚‚‚ƒƒ„„„„ƒƒ„ƒ„…‡††ˆ‰‡‡ˆŠ‹�Ž��Œ�Ž�����Œ‰‰‹ŽŽŒŒŽ��Ž�����‰ƒ„„„„ƒƒ„ƒ„„„„ƒƒƒ„„„„„„„€���‚‚‚‚‚‚‚ƒƒ„„ƒƒƒ„„ƒ„„„„„…†ˆˆ‡‡ˆ‰‹ŒŽ����Ž���Ž�Œ‰ˆŠ��‹Œ��‘���ŽŽ�Š„ƒƒ„„ƒ‚ƒ„ƒ„„„ƒƒƒ„„ƒƒƒ„„€���‚‚‚‚‚‚‚ƒƒ„„ƒƒƒ„„ƒ„„„„„…†ˆˆ‡‡ˆ‰‹ŒŽ����Ž���Ž�Œ‰ˆŠ��‹Œ��‘���ŽŽ�Š„ƒƒ„„ƒ‚ƒ„ƒ„„„ƒƒƒ„„ƒƒƒ„„€�‚‚‚‚‚ƒƒƒƒƒƒƒ„„ƒ„„ƒ„„„„„„…‰��Œ‰‰Š‹Œ����Ž��ŽŽŽ���ŽŽ����‘‘’��‹‰‹Žˆƒƒ„ƒƒƒƒƒƒƒ„ƒ„„„„ƒƒƒƒƒƒƒ€�‚‚‚‚‚ƒƒƒƒƒƒƒ„„ƒ„„ƒ„„„„„„…‰��Œ‰‰Š‹Œ����Ž��ŽŽŽ���ŽŽ����‘‘’��‹‰‹Žˆƒƒ„ƒƒƒƒƒƒƒ„ƒ„„„„ƒƒƒƒƒƒƒ€�‚‚ƒ„„„ƒƒ„ƒ„„„„……„„…„„„„„†‘–’��‹ŒŒ�ŽŽŽ�������������Ž�‘‘‘‘‘Ž�Š‹‹†„„„„„ƒ„ƒƒƒ„„„„„„ƒƒƒƒƒƒƒ€�‚‚ƒ„„„ƒƒ„ƒ„„„„……„„…„„„„„†‘–’��‹ŒŒ�ŽŽŽ�������������Ž�‘‘‘‘‘Ž�Š‹‹†„„„„„ƒ„ƒƒƒ„„„„„„ƒƒƒƒƒƒƒ�‚ƒƒƒƒƒ„ƒƒ„„„„„„……„„„…„„„ƒˆ–•��ŽŒ‹Œ������’‘‘‘‘��������‘�‘‘’���Љ„„„„„ƒƒƒ„ƒƒ„„„„„„„ƒƒƒƒƒ„�‚ƒƒƒƒƒ„ƒƒ„„„„„„……„„„…„„„ƒˆ–•��ŽŒ‹Œ������’‘‘‘‘��������‘�‘‘’���Љ„„„„„ƒƒƒ„ƒƒ„„„„„„„ƒƒƒƒƒ„�‚‚ƒƒƒƒ‚‚‚ƒ„ƒ„„ƒ„„„„„„„…„ƒ‰–”����‹‹Ž����‘’’““’’‘‘‘��‘‘‘‘’““‘��‹‡ƒƒƒ„ƒƒƒƒ„ƒ‚ƒƒƒƒ„„„ƒƒƒƒƒƒ�‚‚ƒƒƒƒ‚‚‚ƒ„ƒ„„ƒ„„„„„„„…„ƒ‰–”����‹‹Ž����‘’’““’’‘‘‘��‘‘‘‘’““‘��‹‡ƒƒƒ„ƒƒƒƒ„ƒ‚ƒƒƒƒ„„„ƒƒƒƒƒƒ€‚‚‚����‚�‚ƒƒƒƒƒƒ„„„„„„„„ƒ‰•”‘��Ž‹‹�����‘’““”“““’’‘‘’’‘‘’”•”���ˆƒƒ„ƒ„ƒƒƒ„ƒ‚ƒƒ‚‚ƒƒ„ƒƒƒƒƒ‚€‚‚‚����‚�‚ƒƒƒƒƒƒ„„„„„„„„ƒ‰•”‘��Ž‹‹�����‘’““”“““’’‘‘’’‘‘’”•”���ˆƒƒ„ƒ„ƒƒƒ„ƒ‚ƒƒ‚‚ƒƒ„ƒƒƒƒƒ‚€€€€€���‚‚ƒƒƒƒ‚ƒƒƒƒ„„„„„„ƒˆ“”““’Ž‹ŠŒŽ��‘“••••”“““’’’“’‘’“•—˜”Ž�‰„„ƒ„„ƒƒƒ„ƒƒƒƒƒ‚ƒ„ƒƒ„„ƒƒƒ€€€€€���‚‚ƒƒƒƒ‚ƒƒƒƒ„„„„„„ƒˆ“”““’Ž‹ŠŒŽ��‘“••••”“““’’’“’‘’“•—˜”Ž�‰„„ƒ„„ƒƒƒ„ƒƒƒƒƒ‚ƒ„ƒƒ„„ƒƒƒ€€€��‚‚‚‚ƒƒƒ„„‚‚‚‚ƒ„„„„„„„†�””•‘��Š‹�Ž�“•–——–•”“““’’‘’““”—™š—�ŽŠ„ƒƒ„„ƒƒƒƒƒƒƒ‚ƒ‚‚ƒ„ƒƒ„ƒƒƒ€€€��‚‚‚‚ƒƒƒ„„‚‚‚‚ƒ„„„„„„„†�””•‘��Š‹�Ž�“•–——–•”“““’’‘’““”—™š—�ŽŠ„ƒƒ„„ƒƒƒƒƒƒƒ‚ƒ‚‚ƒ„ƒƒ„ƒƒƒ€€€��‚‚‚‚ƒƒ„ƒ„ƒ�‚��‚ƒ„…„„……Œ“•“�‘Ž‹‹Œ��“”––——–””““’’’”••–˜š›—�ŽŒ…ƒ„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„ƒƒƒ€€€��‚‚‚‚ƒƒ„ƒ„ƒ�‚��‚ƒ„…„„……Œ“•“�‘Ž‹‹Œ��“”––——–””““’’’”••–˜š›—�ŽŒ…ƒ„„„ƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„ƒƒƒ€€���‚�‚�‚ƒ„„…„��‚���ƒ„„„„…‰�•’’’ދЋŒŽ‘“””•–—”“’’’’“–“‘’’•—”��Œ†ƒƒ„„„ƒƒƒ„ƒƒƒƒƒƒƒ‚ƒ„„„„ƒ€€���‚�‚�‚ƒ„„…„��‚���ƒ„„„„…‰�•’’’ދЋŒŽ‘“””•–—”“’’’’“–“‘’’•—”��Œ†ƒƒ„„„ƒƒƒ„ƒƒƒƒƒƒƒ‚ƒ„„„„ƒ€����‚ƒ‚‚‚ƒ„„„„ƒ��‚ƒ‚‚‚ƒ„„…†Œ”’““�ŒŠ‹ŒŒ�‘’’“””“‘‘’“’”–”���‘‘���Œ‡…„ƒ„„„„„„„ƒƒƒƒƒƒƒƒƒ„……„€����‚ƒ‚‚‚ƒ„„„„ƒ��‚ƒ‚‚‚ƒ„„…†Œ”’““�ŒŠ‹ŒŒ�‘’’“””“‘‘’“’”–”���‘‘���Œ‡…„ƒ„„„„„„„ƒƒƒƒƒƒƒƒƒ„……„€€����‚‚ƒ‚ƒƒ„„„„‚€�‚‚ƒ‚�ƒ„……ˆ�’””’�Š‹ŒŒŽ���’’‘‘‘‘‘’‘’’“’���ŽŒ��‹†…†…ƒ„„„„„„„ƒƒƒƒ‚ƒƒƒƒƒ„„€€����‚‚ƒ‚ƒƒ„„„„‚€�‚‚ƒ‚�ƒ„……ˆ�’””’�Š‹ŒŒŽ���’’‘‘‘‘‘’‘’’“’���ŽŒ��‹†…†…ƒ„„„„„„„ƒƒƒƒ‚ƒƒƒƒƒ„„€€€€€�‚‚‚‚ƒƒƒ„ƒ„ƒ��‚�ƒ„ƒ‚ƒ…†‡Š‘”•”�Š‹Œ���Ž�����‘‘‘‘‘‘�ŽŽŽ�ŽŠ‰�ŽŠ†…………„„„„„„„„ƒƒƒƒ„ƒ‚ƒ‚‚ƒ€€€€€�‚‚‚‚ƒƒƒ„ƒ„ƒ��‚�ƒ„ƒ‚ƒ…†‡Š‘”•”�Š‹Œ���Ž�����‘‘‘‘‘‘�ŽŽŽ�ŽŠ‰�ŽŠ†…………„„„„„„„„ƒƒƒƒ„ƒ‚ƒ‚‚ƒ€€���‚‚‚ƒƒƒƒƒƒ„„„‚�‚�‚ƒƒ„…†‡‡‡Œ“––’‹‹Œ��������’“’‘�������ŒŒ‰ˆ‰‹‰††……†…„„„„„„…„„ƒƒ‚ƒƒ‚ƒƒƒ€€���‚‚‚ƒƒƒƒƒƒ„„„‚�‚�‚ƒƒ„…†‡‡‡Œ“––’‹‹Œ��������’“’‘�������ŒŒ‰ˆ‰‹‰††……†…„„„„„„…„„ƒƒ‚ƒƒ‚ƒƒƒ€€���‚�‚ƒƒƒƒƒƒ„„„„����‚ƒ„†ˆ‰‰‰‰�““�‹Š‹�ŽŽŽ��‘’“”“�Ž�����Ž�Œ‰ˆ‰‰‡…††…††……ƒ„„„„„„„„‚ƒƒƒƒƒƒ€€���‚�‚ƒƒƒƒƒƒ„„„„����‚ƒ„†ˆ‰‰‰‰�““�‹Š‹�ŽŽŽ��‘’“”“�Ž�����Ž�Œ‰ˆ‰‰‡…††…††……ƒ„„„„„„„„‚ƒƒƒƒƒƒ€€���‚�‚‚‚‚ƒƒƒƒƒƒ„ƒ����‚„†ˆ‰‹Šˆˆ�ŽŽ‹‹‹���Ž�‘’““’‘Ž�ŽŽ�’’’�ŽŒ‰Šˆ†……†………†………ƒ„„„„„ƒƒƒƒƒƒƒƒ€€���‚�‚‚‚‚ƒƒƒƒƒƒ„ƒ����‚„†ˆ‰‹Šˆˆ�ŽŽ‹‹‹���Ž�‘’““’‘Ž�ŽŽ�’’’�ŽŒ‰Šˆ†……†………†………ƒ„„„„„ƒƒƒƒƒƒƒƒ�€��‚�‚‚‚‚‚ƒ„ƒƒƒƒƒƒ�€��‚„‡ˆŠŠŠ†…‹Ž�Œ‹‹�����‘””“‘�ŽŽ�“””•”’�ŽŒ‹‰†……………†††††…„„ƒ„„ƒƒƒƒƒ„„ƒ�€��‚�‚‚‚‚‚ƒ„ƒƒƒƒƒƒ�€��‚„‡ˆŠŠŠ†…‹Ž�Œ‹‹�����‘””“‘�ŽŽ�“””•”’�ŽŒ‹‰†……………†††††…„„ƒ„„ƒƒƒƒƒ„„ƒ€€��‚�‚‚‚‚‚ƒƒƒ„ƒƒƒ„‚���‚„†ˆŠŠˆ†…‰Ž��ŒŒ��‘��‘”•“��‘“–———™˜•‘��Œˆ………†……††††††…„„„„„ƒƒƒ„„„ƒ€€��‚�‚‚‚‚‚ƒƒƒ„ƒƒƒ„‚���‚„†ˆŠŠˆ†…‰Ž��ŒŒ��‘��‘”•“��‘“–———™˜•‘��Œˆ………†……††††††…„„„„„ƒƒƒ„„„ƒ€�‚‚‚‚�‚‚‚‚ƒƒƒ„ƒ„„„ƒ‚�‚‚„…‡ˆ‰ˆ‡‡ˆ��Ž����‘‘��“”“��“–™šššœ›˜“�ŒŽˆ…………………†††††††…„„„ƒƒƒ„„„ƒ€�‚‚‚‚�‚‚‚‚ƒƒƒ„ƒ„„„ƒ‚�‚‚„…‡ˆ‰ˆ‡‡ˆ��Ž����‘‘��“”“��“–™šššœ›˜“�ŒŽˆ…………………†††††††…„„„ƒƒƒ„„„ƒ€��‚�‚�‚‚‚‚ƒƒƒƒƒƒƒ„ƒ„‚�‚„…†‡ˆˆˆˆˆ�‘����Ž�‘��’“’�’•—˜˜˜™šš™”�‹�‰…††††………††…††††…„„ƒƒƒ„„„ƒ€��‚�‚�‚‚‚‚ƒƒƒƒƒƒƒ„ƒ„‚�‚„…†‡ˆˆˆˆˆ�‘����Ž�‘��’“’�’•—˜˜˜™šš™”�‹�‰…††††………††…††††…„„ƒƒƒ„„„ƒ€€���‚‚‚‚�‚ƒƒƒƒƒ„„ƒƒ„‚��‚„……†‡‰�“��‘‘‘����‘‘’’“”•–•”’‘’’’’�‹‹‹ˆ†††††…†…††……†††††„„ƒƒ„„„ƒ€€���‚‚‚‚�‚ƒƒƒƒƒ„„ƒƒ„‚��‚„……†‡‰�“��‘‘‘����‘‘’’“”•–•”’‘’’’’�‹‹‹ˆ†††††…†…††……†††††„„ƒƒ„„„ƒ€€���‚‚‚‚ƒ‚‚ƒƒƒƒ„„ƒƒƒƒ‚�‚ƒ„…‡ˆˆ’¥›‘”“’’�����‘‘“–˜˜•’�ŽŽŽŽŽ�‹ŒŠ†††††††††††††…†††††…ƒ„„„„ƒ€€���‚‚‚‚ƒ‚‚ƒƒƒƒ„„ƒƒƒƒ‚�‚ƒ„…‡ˆˆ’¥›‘”“’’�����‘‘“–˜˜•’�ŽŽŽŽŽ�‹ŒŠ†††††††††††††…†††††…ƒ„„„„ƒ€�����‚‚‚ƒ‚‚ƒƒƒƒƒƒƒƒƒƒ‚��‚ƒ……†…•¬¥–––”““’‘‘���’–˜˜—”’�����ŽŒŒ‰†††††††…‡††‡†††‡††††…„„…„„€�����‚‚‚ƒ‚‚ƒƒƒƒƒƒƒƒƒƒ‚��‚ƒ……†…•¬¥–––”““’‘‘���’–˜˜—”’�����ŽŒŒ‰†††††††…‡††‡†††‡††††…„„…„„€�‚‚�‚‚‚ƒƒƒ‚ƒƒƒƒƒƒƒƒƒ„ƒ‚���‚‚ƒ„–±¬œ–™–”“’’’���’”—˜˜—––––””’�Œ‰……††††††‡†‡‡†‡‡‡†††††…„„„„€�‚‚�‚‚‚ƒƒƒ‚ƒƒƒƒƒƒƒƒƒ„ƒ‚���‚‚ƒ„–±¬œ–™–”“’’’���’”—˜˜—––––””’�Œ‰……††††††‡†‡‡†‡‡‡†††††…„„„„€�‚��‚ƒƒ‚ƒƒƒƒƒ„ƒƒ„ƒƒƒƒ„ƒ�����‚‚’³°£™™˜—”“““‘��‘‘“•—˜˜™™š™˜–�Šˆ………†††††††‡‡‡‡‡††††††††…„„€�‚��‚ƒƒ‚ƒƒƒƒƒ„ƒƒ„ƒƒƒƒ„ƒ�����‚‚’³°£™™˜—”“““‘��‘‘“•—˜˜™™š™˜–�Šˆ………†††††††‡‡‡‡‡††††††††…„„���‚‚‚ƒ„ƒƒƒƒƒƒ„ƒƒ„ƒƒ„„„„‚����‚�Œ¯³©¡™š™–”””“‘����‘”–—˜˜™——–�‰‡††…†††††††‡†‡‡‡‡†‡††††‡‡†…���‚‚‚ƒ„ƒƒƒƒƒƒ„ƒƒ„ƒƒ„„„„‚����‚�Œ¯³©¡™š™–”””“‘����‘”–—˜˜™——–�‰‡††…†††††††‡†‡‡‡‡†‡††††‡‡†…���‚‚‚ƒƒƒ‚ƒƒƒƒ„ƒƒ„ƒ„„„ƒ„ƒ������…¦´ª© š™˜••–•“‘�����’“•––••”�ˆ††††††………††††‡‡ˆ‡†‡††‡‡‡‡‡‡���‚‚‚ƒƒƒ‚ƒƒƒƒ„ƒƒ„ƒ„„„ƒ„ƒ������…¦´ª© š™˜••–•“‘�����’“•––••”�ˆ††††††………††††‡‡ˆ‡†‡††‡‡‡‡‡‡���‚ƒ‚‚‚‚‚ƒƒƒƒ„ƒƒƒ„„„ƒƒ„„ƒ�€��€�›²«¨¨¢›˜—•——”’‘�ŽŽŽ��’““’“�‹‡…†‡††††††††…†‡‡‡†‡‡‡‡‡‡‡†‡‡���‚ƒ‚‚‚‚‚ƒƒƒƒ„ƒƒƒ„„„ƒƒ„„ƒ�€��€�›²«¨¨¢›˜—•——”’‘�ŽŽŽ��’““’“�‹‡…†‡††††††††…†‡‡‡†‡‡‡‡‡‡‡†‡‡€��‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒ„„„‚����€�ª®©£§¤™˜–˜˜•“’��Ž�ŽŽ������Ї†††‡†††‡‡‡††‡‡‡‡‡ˆ‡‡‡‡‡‡‡‡‡€��‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒ„„„‚����€�ª®©£§¤™˜–˜˜•“’��Ž�ŽŽ������Ї†††‡†††‡‡‡††‡‡‡‡‡ˆ‡‡‡‡‡‡‡‡‡€��‚ƒƒƒƒƒƒƒƒƒƒƒ„ƒ„„„„ƒƒ„„„ƒ�€��~„�­ª¤ £�˜——˜–”“’��Ž�Œ��Ž�ŒŒ‘އ†††††‡‡‡‡‡‡†††‡‡‡‡‡†‡‡‡‡‡‡€��‚ƒƒƒƒƒƒƒƒƒƒƒ„ƒ„„„„ƒƒ„„„ƒ�€��~„�­ª¤ £�˜——˜–”“’��Ž�Œ��Ž�ŒŒ‘އ†††††‡‡‡‡‡‡†††‡‡‡‡‡†‡‡‡‡‡‡€�‚ƒƒƒ‚ƒƒ‚‚ƒƒƒ„„ƒ„„„„„ƒƒ„„„‚�€€||‰ ©¦¢Ÿ ›™—––•“’‘���Ž�����“¢¢‘‡†††‡††‡‡‡‡‡‡†‡‡‡‡‡‡ˆˆ‡ˆ‡‡€�‚ƒƒƒ‚ƒƒ‚‚ƒƒƒ„„ƒ„„„„„ƒƒ„„„‚�€€||‰ ©¦¢Ÿ ›™—––•“’‘���Ž�����“¢¢‘‡†††‡††‡‡‡‡‡‡†‡‡‡‡‡‡ˆˆ‡ˆ‡‡€‚ƒƒƒƒƒƒƒƒƒƒƒ„„„ƒ„„ƒ„„„„„„„„‚€}|{|…™¥£ ŸŸ™™˜”•”’‘‘�������’Ÿ¦ª¦”‡†††‡‡‡‡‡‡‡ˆ‡‡‡‡‡‡‡ˆˆˆˆˆ‡€‚ƒƒƒƒƒƒƒƒƒƒƒ„„„ƒ„„ƒ„„„„„„„„‚€}|{|…™¥£ ŸŸ™™˜”•”’‘‘�������’Ÿ¦ª¦”‡†††‡‡‡‡‡‡‡ˆ‡‡‡‡‡‡‡ˆˆˆˆˆ‡€‚ƒƒƒƒƒƒƒ‚ƒƒƒ„„„„…„„„„„„„„„…‚}{{{{|��œ¡Ÿ œ–™–•”’‘‘‘��‘�ŽŒ“ ¤©¬§”‡†††‡‡†‡‡‡ˆˆ‡‡‡‡‡‡ˆˆˆˆˆ‡€‚ƒƒƒƒƒƒƒ‚ƒƒƒ„„„„…„„„„„„„„„…‚}{{{{|��œ¡Ÿ œ–™–•”’‘‘‘��‘�ŽŒ“ ¤©¬§”‡†††‡‡†‡‡‡ˆˆ‡‡‡‡‡‡ˆˆˆˆˆ‡€‚ƒƒƒƒƒƒƒƒƒƒ„ƒ„„„„„„„„…„„„…„€{{{{{{{}‡–ŸžŸ˜•––”’‘‘‘‘����‹‘ž¤ª«¬£‹„††‡†††‡‡‡ˆˆˆ‡‡ˆˆˆ‡ˆˆˆ‡€‚ƒƒƒƒƒƒƒƒƒƒ„ƒ„„„„„„„„…„„„…„€{{{{{{{}‡–ŸžŸ˜•––”’‘‘‘‘����‹‘ž¤ª«¬£‹„††‡†††‡‡‡ˆˆˆ‡‡ˆˆˆ‡ˆˆˆ‡€‚ƒƒƒ„ƒ„„ƒƒ„„ƒ„„„„„„„……ƒƒƒ‚€}z{{{{{{{|‚�˜Ÿ�•””•”“’‘‘����Œ�œ¥ªª±¬�‚ƒ…‡‡†‡††‡‡‡ˆˆˆˆ‰ˆ‰‰ˆ††€‚ƒƒƒ„ƒ„„ƒƒ„„ƒ„„„„„„„……ƒƒƒ‚€}z{{{{{{{|‚�˜Ÿ�•””•”“’‘‘����Œ�œ¥ªª±¬�‚ƒ…‡‡†‡††‡‡‡ˆˆˆˆ‰ˆ‰‰ˆ††€‚ƒƒƒƒ„„„„„ƒƒ„„„…„„…ƒ‚‚€~|}|zz{{{z{z{{}ƒŒ•“’“”““’‘���ŽŽ��™¥©°¾°�…„„„…†‡‡‡‡‡ˆˆˆˆ†‡Œ“�„|~€‚ƒƒƒƒ„„„„„ƒƒ„„„…„„…ƒ‚‚€~|}|zz{{{z{z{{}ƒŒ•“’“”““’‘���ŽŽ��™¥©°¾°�…„„„…†‡‡‡‡‡ˆˆˆˆ†‡Œ“�„|~€‚ƒƒƒ„„„„„„„„„„……„ƒ‚}||||{||{{z{{{{{z{{z}‚†Š�’“’���Ž����™£®½Á¥ˆ†††„ƒƒƒ††‡†Œ”�‡€�œœ�†Š‹€‚ƒƒƒ„„„„„„„„„„……„ƒ‚}||||{||{{z{{{{{z{{z}‚†Š�’“’���Ž����™£®½Á¥ˆ†††„ƒƒƒ††‡†Œ”�‡€�œœ�†Š‹�ƒƒƒ„……„„„…„„„„ƒ‚€~}}|||||{|}|{{{{|{{{||{|}}}~ƒŠ��ŽŽŽ�‹‹ŒŽ—¡®³±–‚………†„‚€�‚†„Ž�’‰Œ˜�›˜šœ™�ƒƒƒ„……„„„…„„„„ƒ‚€~}}|||||{|}|{{{{|{{{||{|}}}~ƒŠ��ŽŽŽ�‹‹ŒŽ—¡®³±–‚………†„‚€�‚†„Ž�’‰Œ˜�›˜šœ™ \ No newline at end of file diff --git a/bin/foreman_part_qcif_444.yuv b/bin/foreman_part_qcif_444.yuv new file mode 100644 index 0000000..0e43f4a --- /dev/null +++ b/bin/foreman_part_qcif_444.yuv @@ -0,0 +1 @@ ++Øþùûþþýûüþþþþþýûþþþþþùîàââáßáâáßàãåß¿›œ¨¾ÖÛÖ×ÛÛÛØ×ÛÝÜÙÝÝÜÞÜÜßßßÛÖÕØÝáÔħ‘“””Œ�…tu†µßÞÝßÞÝÞÔÌÙÙÑÑÑÒÓ×Ô˜o�†}y§ÏÏÏÔÔØÖÔ××ÑÐÔÒËÀ¾Éº�€¢ÖÓÐÖ×ÙÙÕÐÎÏÉÌ®ww§ÈÍÒÐÏÏÈÃÏÉ“r¦ÑÏÊÁººÈÀ�i—ÀÆÖ¾1ÆÁÓäÍÕ¹ÓϺøÆËзØÄÆîкÕíâááâáààâæçÞÁ�’£¸ÉÑÔÕÒÔÙÛÙ×ÚÙÛÝÛÜÜÝÝÝÞßßÜØÔÝàÕÀ¤—““—šŒuv{Œ©ÐÞÝÝÜÜÛÚÛÇ¿ØÒÎÑÐÑÑÈÑΘu…ˆvvªÎÏÒÓ××ÒÓÓÑÎÏÏËÆÌν¬Ž~ªÖÕÔÖØÙÕÑÎÏÉÉÁœvyªÊÑÑÏÎÎÎÌѼ‚}´ÑÍÅÃÀÈÆ¦xn¦ÍÒ¾0±«Å­¹ˆ¿Ãгް±‡Ê°Š»Ë¦´çãááàßáäåÚÁ¢‘—¬ÉØÜÙÕÔÕ×ÙÓÎØÙÔÙÜÛÜÜÝÛÝÙØÙÙÝÛÓºŸ‘�‘——Š{qx”·ÖáãßÜÜÜÜÝÜÛÙÙÙÔÑÒÐÏÐÍÐͼ’t…„ms¤ÊÏÓ×ÖÓÓÔÒÑÐÌÌÏÎÏÂÀ¯„|­×ÓÔÙÙØÔÍÎÎÎÌÌ«z‚·ÎÌÍÍÏÊËÎÓ²w€ÀÓÊÆÄË˵˜os´Ô¼.Öᩱ½Æ Ëб¥­Ä¿œÑË®¡åΡÐçàÝáæàÖ¾¢™¡·ÐÙÙØËÉÖÖØÜÙÍÏÛØÖÛÚÛÛÛÝÖÓ×ÙÝÝͰ–‰‰—�’†{xƒ�ÁÙâáÞÛÜÝÝÜÝÝÛÚÜÚÖÔÓÒÏÑÑÒѸ°Â�o�†stŸÅÌÒÕÕÕÖÒÒÔÍÊÎÌÑȼé~z²ØÔÖØØ×ÐÍÐÐÈÌÒ±}‹¹ÂÉÍÎÆËÐÐÓ¬sŠÇÏÆÇÎп¶£o~ý)¹Ð´ËäâÈÖâáãäáàÒÝâçÚåÝÕßàáæãÔº¥›£½ÕÖÖÕÖÖÃÈÖÖØÚØ×ÙÙØÛÚÖÛÝÚÙÔØáÜˬ�…Š—™‘�tu‰«ÉÜâáÞÛÞÝÝÝÞßàßÞàßÛØÓÍÌÎÑÐÐÑǼÌË”p}…wv ÈÐÓÓÔ×ÖÒÓÏËÉÌÓÉ¿ÃÂ¥~·×ÒÕÕ×ÖÓÑÐÍËÌȨv�´ÅÌÍÍËÏÐÒÕ£k’ÉÏÌÏÒÇ¿À›n�²‚­²×æÝÔÜåãäåãââßâãèáàææååÕ´›™”²ÒÚ×ÔÔÓ×ÙרÖÙ×Ó×ÚÚØÖØØÙÚÙÛÛÜ×ç’……“œ’sw“¶ÑÚÙÝÛÙÍÖ×ÙâäæèéëêëêéèãÝÚØÔÏÐÏÑÉÄÓÏšmzŠ€|£ÌÒÑÖÔÕÕÎÐÐÊÐÖËÃÂÊ˨{·ÖÔÔÖÕÖÒÐÐÍËÆÆœqŽ¿ÌÍÍÊËÎÌÕÑ‘i›ÍÍÎÐǽ¼¶ŒlˆwÂØÓÕÛÞáßÜÛÚÚÚÚÝÜÚÔÜäãàÔ¶Ÿ˜�¨·ÒÛÚ×ÙÙÙÙÙÜ××ÙÙØØÙÚÛÙÙÖ×ÛßßѸ �‹�˜�~{v›¿Øáߨ×ÛÝÕÇÔÔáêëììëìììììíííìêäÜÖÍÏÓÏÍÐÏžq{Œ�{ ÌÒÕÓÒÖÏËÎÐÓÔÍÇÉÉÈÁ x~¸ØÔÕÓÒÔÑÐÍÏÊÈÈ™tŸÌÑÍËÍÍÌÍÔăl£ËÎÏʽº·°Šq~ÛàÙàãããâáàÜÜÝÞÝÝÞâæÝɶž˜¤¸ÈËÖØÕÛÝÛÙÛÙØÙÖØÛÞÛ××ר××ÖÙÜͱ“†ˆ‘–Ž}qp„£ÆÚÝÝÙØÜÝÛÜÜâåèëêëëëëëëëëëêêêëíìëçßÔÒÓÐÊÐÓ§wzŠ�x�ÊÓÒÕ×ÕÅÆÒÎÌËÈÌǼ¹·šu�¾ØÔÔÓÕÒÏÐÍÎÌÍË�s¯ÒÍÌÐÎÌÍÎÓÀ|p²ÑÎËÀû¾³ƒƒ×ßâááááâßÛÝÝÛÜÞâãÛä‘—©ÀÉÌÒ×רÛÝÝÛÙÖÖÓÓ×ÙÛÙÔÕÖÕÖÛÛÓĬ“ƒˆ�–‰uoqŒ±ÅÕáØÐÙÝÞÝØÛâçêìíëêëëìëëëëëìëëëëêëìíìå×ÐÐ˾ÉÓ¶|vˆu—ÆÑÑØÕÍÎÓÑÍÊÊÎÎÇ¿¿¼™x‡ÂÙÓÓÕÓÏÏÍÏÍÉÍÀ‡€¶ËËÏÎÍÎÎÎÖ¶u~½ÒÎÈÈÁ¼¿¡ˆØâßàááàÝÙÝÞÛÜâäÕ»¤•™£µÏÔÎÎÍÓÙÜÝÜÛ×Ô×ÙÓÔÙÛÕÓÕÕÙÛÚÕÀ£�‰‹“›Šzmw’³ÍÞÕÑØØÛÞÞÝÜßåêëëëêëëëììëìììììììëëëììëëíèÚÐμ½È¿¨qr‡~q•ÊÓÕÓÏÔÕÔÓÍÍÎÌÍÉÀÀ¹–r…ÂÖÐÔÖÖÔÒÏÍÌÉ´ÊÍÏÌÌÎÎÐ×­r„ÁÓÎÊ¿½½®ˆØãààáßÝÚÝØÓààÓ¸�‘–¦ÁÎÒÕÏËÎÑ×ÚÜÝÙØØÖÔÔØÖÙÚÕÐÙÝÛζŸ�ŠŽ–“‰yny›¿ÒÔÕÙØØÝßÞÞÝÝâéìëëëëëìëëëëììììììììëëììììììíçØÏÌÉǭ®sr…u–ÉÓÑÈÏÕÓÔÐÍËÊËÉý³�rˆÈ×ÒÖØÙÔÎËÍÎÊͱzƒ·ÊÏÊÈÏÎÒÖÔ£g‹ÊÑÐÈÂÀ«‡ÙáÞÝÞÞÝѵ›ºÒº¤�” ¶ÍÒÑ×ÖÊÍÎÑÕÛÝÞÝÚÙÙÃÅÖÒÓÕØÙÜδœŽŒ’•Œup€ ÂÚßÚÕ×ÜÝÝÕÖÞÞáæêëëëìëëëììëëëëëìëëìëëìëìëìììëëìå×ÐÍÍÅÂÓ«kqˆ~o�¿ÎÉÎÔÔÒÏÍÌÌËÊȽ·±—t�É×ÑÒÖÔÏÍÎÎÎÌɪx‡¶ËÅÄÎÍÒÒÔЖk˜ÌÐÌÇÅ«†Øàâææãα’q•¢“–£µ¼ÇÔÑÐÙÓÌÐÏÑÖÚÛÛÜÚÚÖÍÏÑÑÖÛÔȲ˜�”˜•‡xmtŒ¬ÌÞàÛ×ÙÝÜÜÝÛÑÕàäéëêêëëëëììììëëëëììëëëëëëìììëëëììëëå×ÎÍýÊÑ¥ns†}nнÑÓÕÖÔÏÎÍÎÌÈÈdz¬¶¶švŽÊÖÌÑÓÏÑÎÎÎÎÉÇ©wнÁ¾ËÏÏÒÑÖÏŽj¤ÐÉÈ̱‡Ûçáɾ¹£�™Œ�¥¸ÈÑÏÄÎÒÔÙÐÐÐÓÚÜÚÛÛØÖØÖØÕÔÚ×ħ“�“�šˆto{˜»ÓßáÛ×ÓÙÜÜÛÜÝÙÛãçêëêëëëëëëììëëëììììììëëììììììëëëëëëêéäØÏÈÊÌÏÓ¨qq…‚t‹ÂØÔÖ×ÑÐÐÏÍÉÅÇ¿³µ½ºžv‘ÎÔÏÖÓÑÐÑÎÌÌÈÇ¢s‘º½ÈÎÏÑÒÑØÈƒs´ÏÃdz‹ÒÀ¥Ž†…���Š–²ÉÏÓÖÑÐ×ÊÒÖÏÐÎÖÜÛÛÜÛÙÖÒÖÓÑͺ£’‘”——ˆurƒ¡ÃÚàÝ××ÙÚÙÜÖÒÜÝÝÞäéëëëëìëëëëëìëëëëëììëëëììììììììëëëëëëëèèä×ÎÎÎËÌѬonˆ„o…ÃÖÑÔÓÑÑÏÌËÅÂÉÀ½¾¸¸–u•ÎÖÒÐÑÕÔÑÍÍÌÇÈ�r‡¥ÃÌÎÐÒÓÓÙ¿€½¼¼²}¦‘�š„ov¡¯´ÌÖÕÑÐÑÕÙÔÏÖÒÍÉÏÙÙÚÜÜÖÔר֯®—Š‹”š�~tv�°ÍÜÞÚØ×ÙÞÝÛÚÛÕÓßÞÞåêëêëëìììëëëëëëëëììëëëìëëìëëìëëëëëëëëëëêèèäÕÌÏÍÊÌЯzp„€j‚¾ÓÐÑÑÑÑÌËÉÃÄÁ¿Àº®¨šs”ÎϽËÕÔÔÒÎÎÈÉÊ—i�ºÊÌÏÏÒÒÒÙ¹{ˆ·Ã°m¢¹ÉË¢ju²ØÚÚÖÔÓÔÕ×ÔÑÚÔÍÏÊÓØØÚÚ××ÛÖ锈ˆ’š�uoz�®ÕáßÛØØÜÜÜÕÔÛ×ÖÜÞרåéêêëëëììëìëëëëëëëìììëëììììêëëëëëëëëëëëêêéèéâÔÎÎÏÍËѹ|nƒ€kƒ¼ÔÍÏÑÑÎËÊÉÅÃÁÃÁ¶¯¸�o™ÏÈÊÓÓÕÖÒÎËÆÌÊ’oŸÅÊÍÎÑÑÒÕØ°vŽÅµÌÛßÜÊ­½ÐÏÑÓÖÔÒ×××ÔרÏÍÏÒ×ÖÕÙÜÛÖĨ�†‹’’†vju ÃÔÝàÚÛÓÐÜØÙÛÏÒÜÛÜÜÜ×ÞéêëëëëëëëëëëìëëììëëìììëìëìëëëëëëëëëëëëëëêéççèáÓÎÏÏÌÊм„o„„p�¸ÉÆÐÔÐÌÉÈÅÁÂÄÆÇ¾»®�qŸÐÎÐÔÔÖÕÒÏÊÆÑĆsªÉÌÏÐÑÒÓÕÖ¥r›´ŠÖØØÓÍ×ÙÔÕÖÕÖÑÐÖ×ÖÖØÑËÍÎÓÔ×ÛÜÓÀ§�ˆ�–�yhn„ŸÅÝáßÛÛÝßÕÑÜØ×ÚÙÛÜÝÞÜÝåêêëëëëëëìììëìììëìììëìììììëëëìììëìëëëëëëëëêéèèèèàÑÍÏÏÍÊо{fƒp~­ÆÍÒÒÏËÆÈÿÂÈËŽ°°’q¡ÏÓÔÓÕÕÔÐËÊËμƒ{´ÌÌÐÐÐÔÔÖЙu�†ÔÕÑÐËÎÏÔÖÔרÑÐÖØÓ××ÌËÎÏÕÛÜл¡Œ†Š�‡rej†¯ÑßàÚØÙÛÝÝÝÜÛÛÛÛÜÜÝÞÞÜÞäêëëëëëëëëììììëìëìììììëìììììììëìììììëëëëêëëëêééèéçÝÑÎÎÌÌËÏ»€d{‚p~²ÌËÐÑÏÎÌÆÂÁÁÉʼ¦²½�v¦ÒÔÔÖÕÕÒËËÎÌÏ¿€…¾ÊÍÏÐÒÔÓÔÉ’q‡ÕÔÎÌÃÌÓØÖÔÓÔÒÒØ×ÐÔÔÍÍÐÖØÌ´š�ˆ‰Šƒp]gŒ·ØâÛÔÕÛÞÝÜÛÜÜÚÚÚÚÛÝÜßÖÓÞãèêëëëëëìëëëìëëëëëììììììììììììììììëìëëëëëêëëëêééééèæÛÐÎÍÏÐËÓÉ‹ex‚t{¯ÏËÍÐÐÌÇÂÁ¾ÄÌì³Ç¿‹t¨ÑÒÒÓÓÔÏÍÑÎËи|‹ÂÍÌÐÐÑÒÑÐÇ�‰ÐÒÐËÆÏÖÖÖ×ÓÒÒÕÙÔÔÔÏÏÐÎÆ®•Š‹Œ‰~nhp�»ÚàÜØÖÔÛ×ÒÚÝÜÝÜÛÛÛÛÜÛÛÝÕÒáèéêëêëëëìëëëëëëëëëììëììììëëëìëëìììëëìëëëêëëëëêéèèèèçãÖÏÏÏÐÍÉÔÍ�dv€qy®ÌÌÌÎËÉÄÁÂÄÇË·¸É˱t¬ÓÓÔÔÔÓÍÎÎÍËÒ±|–ÈÎÏÑÑÒÒËͱˆÎÓÐÍÏÔÚÖÔØ×ÓÒØ×ÔÖÖÕÏ»¤’ŠŽ’‹{mfv—½ÙáÜ×ÕÙÛÜÝÖÑÜÝÚÙÛÜÚÚÜÜÛÜÛÝßåèéêëêêêëëëëëëëëëëëëëëëìëìëëëëëëìììëëëëëëëëëëëêéèèéèçæÝÐËÎÏÎÍËÓË–hr€rv§ÍÌÉÊÊÇÃÃÅÃÊÂÂÑË»«‚x³×ÔÕÕÖÓÑÑÏÍÌÒ³|›ÌÎÌÑÓÓÌǵ†ÐÔÎÍÎÖÙÔÖÙÕÒÔÕÖÛÛϹžŽ‰‹�Š{liwœÅÚßÛÖÖ×ÛÛÛÛÜÜÝØÕÚØÚÜÚÛÛÛÜÝÜÝãèèééêêêêêëëëëêëëëëëëëëëììììììëëëììëììëëëëëëëëêêêéééèçåâÕÊÌÍÎÎÎËÐÑ�hs€vw¨ÐÌÇÉÇÈÅÂÄÊÇÈÔÏ¿³¬w³ÓÐÒÔ××ÔÎÍÍÌÒ±{žËÊÎÑÑÎк†ÏÐÌÌÒØÔÒÔÕÑÒÖÛÙзž‰‚Ž–ŒuekªÁÔáÙÔ×ÚÚØÜÜÛÛÛÜÛÖÕÙÙÚÛÛÛÛÜÝÛÜàæèééêêêêêêëëëëëëëìëëëëëììëëëìëììëëëëììëëëëëëëêêêéééèèææåßÑÌÎÎÎÎÌÊÎÍ‹ax�rq¤ÏËÆÇÈÆÇÇÄ¿ÇÐÐË®²¦wxµÓÏÑÕØÖÐÏÒÎÌׯz£ÊÍÍÍÌм…ÍÏËÍ××ÒÓÓÏÔÜÚǬ”„„�•‹{st�²ÉßÚÔ×רÜÜÜÝÜÛÛÚÚÚÚÜÛØ×ÚÛÛØ×ÝÝÜÝãæèééêêêêêêêëëëëêëëëëëëëëëëëëëëëëëëììììëëêëëëëêêêêéèèèèçæäÙÎÏÏÍÌÌÍÉÌÁ•oqylmžÆÆÊÍÈÊËÄ·ÀÐÏÈ»²®§}{½ÓÐÓÖÕÕÖÖÒÎÏמv¨ÍÎÏÍÏ»…ÎÒÍÏÖÒÑÕÙØÖÆªŒ~ƒ�Ž„tlx™ÁÛáߨÖÙÙÚÛÜÜÜÛÚÚÚÛÚÙÚÛÛÛÚÛÛÛÙØÜÝÜßäæçèêêêêêêéêêêëêêêëëëëëëëëëëëëëìëëëìëëëëëëëëëëêêéééèèèèçæäßÑÌÎÌËÌËËÊÑÔ ms}ql“ÃÎÎÈÊÏÎÀÁÓÔʾ¶­º©w�¹ÒÓÒÓÖ×ÖÔÔÐÐÉ”|¯ÎÎÎи…ËÍÎÑÑÒÙÜ×Ĥˆ~†�‡{pl} ÃÛáÛÖØÛÜÛÙÛÜÝ××ÚÙÚÙÛÜÛÛÚÛÛÛÛÙÚÚÚÙØÜâåçèèééééêêêêêêëëêëêêëëëëëëëììëëìëëëëëëëëëëëëëëêêêééèèèèçæåãÖÍÎÍÍÌËÊËÊÏÕ®}v|qj–ÂÌËÍÎÏÇÇÓÑÌľµ´º¦yƒ¾ÖÒÔÕÕ×ÖÔÔÏÍÉ•~²ÍÍÑ·ƒÇÉÍÕÛÛ϶ ‰‡‹ƒrdm‰­ÍßáÝÖÖÚÛÚÜÝÜÜÛÛרÛÚÚÚÚÚÚÚÙÚÚÚÚÙÙØÖרÝäæççèééééééëëêêêëëëêëëêëëëëëììììììììëëëëëëëëëìëëëêêééèèççææäÞÔÏÍÍÌÌËËÌÉÐÙ°qpyqo’½ËËÌÎÊËÓÏÉÆÀ¸±³¹§|ŠÅØÒÕÖ××ÕÕÕÍÎË„¹ÏѶ|·ÉÙÞË«‘ƒ‚…Š‚nbp’¾ÖááÛØÙÜÜÛÛÜÜÝÞÜÚÚÛÜÛÛÛÛÙÙØØÙÚÙÛÚØÚÝàÞÛàäæçèéèéééêêëëëëëëëëëëëëëëëëììììíëìíìììëëëëëëëëëëëêêêééèççæåäâÛÓÎËËËÊÊËËÊÎÒ©uq{zt‘ºËÎÒÐÍÔÔÍżº·¯³º¥{ŽÈÕÔÖ×ÙØØØÔËÊÁŒˆ¼Ò¸k˜Å̰‘„�‹~ml|ŸÆÛáÞØÕÙÜÜÛÜÜÛÜÜÝÜÛÛÛÚØ×ÙØØÛÚÙÙÙØØØÛÞáÞËÃÙâäææççèéééêêëëëëìëëëêëëëëëëëëëëììëììììëëëììëëëëëëêêêêêèéççææåãÝÕÏÊËÊÊËÊÉËÍÒׯys‚{x•ÂÒÑÎÊÒÔÐÊ»¿¼¹¶´¡z‘É×ÓÕÙØÙÖÔÐÊÏ»ƒ�Ƽsžž•†‹�‡{oq�µÐááÚÕ×ÙØÛÛÚÛÜÛÚÚÜÞÛÙÛÛÙØÙÚ×ÖÙÚÙ×ÖÖÛßßÔÁ¨Ž©ÝâäåæççèéééêêêêêêêêëëêêëëëìëëêëìììëëëëëëëìëëëëëëëêêêêêéèéèççæåãßÕÍÍÌÊÉËÌÊËËÍÑÔ±yr�{u“ÂÓÌËÒÓÐÍȼ½¾À¹°µ§�–ÇÔÓÖרÖÓÐÍÊη—¶…¯€Š’ƒni~˜·ÝåáÙÑÖÚÚÛÛÛÚÚÜÝÙÚÝßÞÜÚÛÚÙÚÙØØØ××ÖÙÞÝ×DZ›Žˆ”ÆááäåæçèèéééêêêêêêéêëëëëëëëëìëëëëìëëëëëëìëëììëëëëëëêêêêééèèçææåäâÙÏÍÍÌÅÈÍÉÊÇÅÉËÒ±sl{|u“ÈÒËÑÔÑÊǽ¾ÄÀ²¶É­}˜ÌÖÑÔØ×ÔÐÎËËЭ‹�µˆwql|ŸÈÞãßÙØ×ÔÙÚÚÚÛÚÚÛרÛÜÝÞÜÚÛÚÙÙØ×ÖÕÔÕÜàÞζŸ�Š�œŸ±ØàáäåæçèèéééêêêêêëêêëêëëëëëëëëëììëëëììëììëëìëëëìëëëêêêêéèèççææåäãÞÔÍÍÍÇÈÎÊÉÉÈÌËÌѱwq�zs‘ÃÐÏÔÔÌÊÉÄÃÄô¸ÊÄ—~šÈÕÓרÕÐÐÎÌËЬwv¡zm…¬ÎÛÛÜØÙÜÜÚÚÙÙÛÛÚÙÚÚÕÖÛ×ÙÜØ×ÙÚÚÙÖÔÖÙÜÜÕÈ±Žƒ‰•Ÿ�˜Š®Ýßâäåæçèèéêéêêêêëëëëëêëëëëëëêëììììëëëììììëëëëëëëëëëêêêêêèèèçææåãâà×ÏÎÌËËÍÌËËÊÅÌÏÐÙ¿‚m{si�ÃÒÑÔÑÌËÇÁ½Á»¼Èì’zŸÍÔÓÖÕÒÒÑÎËËΤiˆ�¹ÔÝßÚ×ÙÜÝÝÜÝÜÙÙÛÛÚØÙÛÛÚÛÖØÛÙÙÙÙÖÖÙÜßÙ˸Ÿ’�‰’œ™Ž�zƒÀàßâäæççèèéêêêêêêëëëêëêëëëëëëëëìììëëìììììëëëëëëëëëëëêëêêééèèèçææäããÚÌÍÍÊËÌÊËÈÆÂÌÂ½ÏØÁƒqxqpŒ¾ÓÑÒÑÍÊÅÀ¾¼ÀËÆ°¢Œ|ŸÒÔÓÓÑÑÑÏÍÉ;u¾ÓÞÞØÖÚÜÛÝÝÛÜÜØÚÚÚÛØØÚÛÚÚÛÛÚÚÚÙ××ÛßÜÑ»¢‘Œ‘™›–Œ„}xw|®ÚÜàâäåæççéêêêêêêéêëëëêêëëëëëììëëììëëìììììììëëëëììëëëëëêêêéèèèçççåäãÞÐÅÈÉÊÌËÌÁÅÍË»¬ÈÌׄpyuk„¼ÒɽÉÐÉÅ¿ÄÊÍ· ž‹u¥ÔÔÑÐÏÑÑÎÍ͸†ÜßÔÕÙÙÙÛÚÜÝÜÛÚØÚÛÛÚØÚÚÚÚÚÚÚÙרÛàÝÒë•‹Ž™ž™�„yuvtsuˆÂÜÜàâäååæçèééêêëëêêëëëëêëëëëëëëëëììëìììëëëìëëëëëìëëëëëëëêéééèèèèçæåãáØÈÇÊÌÌÌÎÊÊÌÊÊÆÊËÍׯ�pvxi‚»Ç®ÂÒÉÄÇËËÌÑÁ­¥©ˆn¦ÒÒÐÒÐÑÏÍÍ·†ÓÙÖØÙÙÚÝÝÜÜÙÙÚÛÛÚÛÛØÙÙÙÙÙÖÖ×ÛÝÙÊ²šŠŠ’œ¡�Šzuusps{Œ¢ÀÑØÞàâäääæçèéêêëëëêêêêêêëëëìëëëëëëëììììììëëëëëìëëëëëëëëëëêééééèèçççåäãÜÐÊËÏÊÃÊÍÍÌÌÍÏËÊÌÏÖÌ—qzuk‚³ÈÊÎÌÄÆÌÏÏÐȶ¦««…q£ÑÐÐÓÕÒÏи…ÔÙ×ÙÚÛÜÜÝÝÛÓÖÛÚØØÙØØÙØØ×Ô×ßßÖ¿¥�„Ž™Ÿœ�…{vuuuvƒœºÑÞÞÖÚÞáããååæçéêëëêêëëêëêëëëëëëëììëìììììëëììëëëìëëëëëëëëëëëëëêêêéèèèççæåäßÑÈËÎÍÈÇÆÍÍËËËËÊÍÍÈÒÑ•pzvmªÆÍÍÈÆÄÌÑÏʺ¬­«¤…o¨ÕÑÒÕÒÐÔ»†ÕÚÚÚÚÜÜÚÛÝÜØØÚØÖ××Õ××Õ×ÛÜÛ̵žŽ‹“œŸ˜‹ƒ~zssu‚™°ÉÚßßÝÒÐÜßáãäåæçèêêêëëêëëëëëëêêëëëëëëëìììëëìëëëëëëëëêêêêêëëëêêëêêêêéèèèèçææåâÖËÌÎÏÎÌÊÍÎÌÈÊËÈÍÏÌÌÔÏšsuxszªËÉÅÅÀÈÑÑËÁÀ½­¤ª‰r§ÌÏÑÓÑÖ¿‡ÖÝÙÙÛÜÜÙÚÛÛÜÙÙØØØÓÓ×ÙÜÝÔĬ�…�œ¡œ’„~~|xv{Œ©¾ÔãÜÙØ×Ù×ÕÜßàâääæçèéêêëëêëêêêêêêêëêêëëëëëëëëëìëêêêêëëëêêêéêëëëëêëëëëêééèéèçææäâÙËÈËËËÎÎÎÌÌÌËÆÁÉÍÎÐÍÔÑžqu}vƒ¯Ç¼ÁÈÉÐÒÌÃÇÀ³°²°‡o¥ÐÒÒÒÕ¼†ÕÛרÙÙÚÛÛÛÚÙÙÙØ×ÕÓÙÞÙ̹¥•’”�¢™‹{zyz�Šž¼ÔáÕÒÙÐÔÛÚÙÖØÜÞàâäååçèêêêêëêééêêêëëëëììííììëìììíììíííííííîíííìììëìëëëêëëëêêêêêêéèæàÒËÍÌÊËËÌÌÍÏÍÆÂÈÌÍÐÎÍÓÒ¡qszs|¬¹½ÌÊÌÑËþ½»µ´¸º‘|±ÖÒÑÖ»†ÔÚØÙÚÙÚÚÚÚÙ×ÖÕÖÙØ×Ò«—’˜¡£œ’†}yxvx‚š¼ÐÚàßÙÔÕÕ×ÛÛÛÚÔ×ÝßàâäæææéêêééêëììëëéèæäáßÝÜÜÜÜÜÜÛÚÚÙÙØØÙÙÙÙØÖÕÓÒÐÎÍËÌÌËÊÉÉÉÉÊÌÏÑÔÕ×ÚÚÛÚØÚÙÖÖÓÏÎÎÍÎÌÅÄÈËÎÐÑÎÒÔšiszkxš·ÈËÎÎÎÆ¿Âº¾Áƽ‰|´ÕÑÔ»†ÓÙ×ÚÝÝÛÙÙÙÕÔÙÝÞØÃ¬š””›¤£™‰~|wswŠ¥ÁÖàÞÛÙ××ÚÛÚÛÛÚÛÛÕØÝßáãäåæçééêëììëèãÝØÑËÆÁ¿½¼¼¼º¸´¯¬«ª¥Ÿ™—˜—™››™—“���’”•˜›œžŸ £¥¥§¨ª®±³¶¸½ÀÃÈÌÑÕ×ÖÑÍÌÌÉÅÆÊËÎÐÏÍÓÏ¢utwir¥ÈÍÑÑÐÈÀÂÀ¿ÄÂÂÄ®w±ÓÓº…ÓÙÙÙÛÛÙÖØÙÚÝÛп§‘ˆ‹š£ •‡{ywyy…®ÏÞàÜØÒÖÜÚÚÛÚÛÛÜÚÚÚÖÚÞßáâäåæçéììéäÝÓÊÁºµ²¯¬©§¥£ž™“އ„|{vrppoopvxxtmkkmqux{…‰�’—œ¡¥§§¨§¦¨ª«ªª­±µºÀËÒÐÌÊËÊÈÌÍÌÍÍÏÍÏÌ¡lo{ky°ÐÍÑÐȿÿ»ÅÂÄÈ¿¨}xºØ¼„ÔÝÚØÕÖ×ÙÞÜÒÁ«œ�‰�˜›”�†~vsw~‹ ¯¿ÞßÚ×ÔØÙÚÛÙÛÛÙÙÜÛÙØÙÖÛÞàáãäæèééäÛÑÆ½·´²³³°¬¥�”Œ…zwsppojhihhhjkntvuoe_]adfjmruy}�„…‰’�©¯±±¯±±°°¯®¯¯°´ÂÍÎÌÊÉÈÌÍÌÌÍÎÎʶágrui{²ÐÏÍÈÆÇüÈÈÊËÄ¿¯‚�¾¿…Ó×Õ×ÛÝÜÓÅ´¡––š—’�މ�ywuvŠ¥·ÑÛÙÙÙרÙÑ×ÜÚÙÚÜÛÚØÌÐÛ×Ö×ÜÞßáãåèèâ×Ê¿¹¸¸¹¹µ¯¦œ’ˆ€ytrpmlkjkigc_\[[[\bhijd[Z[[Z[[`ehnqux{zxz…•¢®²±±³µ¶µ´´·´·ÆÍÍÍËÉËÍÌÍËÊÎÐÃÉÖ dlzmz°ÍÍÆÅÉÇÃÆÅÊÍÈþ°€…©†ÔרÞÙɲ ••˜žž”‹†�{uu€…’´ÐßààÛØÔ×ÚÙÚÚÛÛÙØÛÚÚÛ×ÌÓÜÚÖÙÜßàáäçâÖÇ¿½½½»¶¬¢˜�‡ƒ~wqlkhfdcb^[WTQOPSSOMSXWVSOONLMRUWUX^diouy{vx�„�£±µµ·¹¸¸¸º¸¸ÆÎÍÍÌÊËÎÍÍËËÏÏÏÌÑÕ empv¨ÎÈÀÇÆÃÇÁ¿ÈË÷¹«yy†ÔÓÉ»§™‘“™œ•�„|yxz~‡Ÿ¿ËÓâßÙÙÕ×Ù×ÙÛÛÜÝÜÛÛÜØÓÙÚÛÜÛÛÜ×ÙÞßáåäÙÊ¿½¿¾¸®¡•Œ†ƒ�}ypg^WRSX]ZTSWWVWZ^`^^a`][ZWND@BMX[WSPT\bhmsv~‰†�‚•®µ¸º¹º»¼¸¹ÇÌËÊËËÌÍÎÍÌÍÏÌÌÏÏÒÖ¤eq~ms¦ÉÃÁ¿ÀÍÈ¿ÇÌȹµ¶—s­ž™–—››•Œ†zwv|‰�¸ÎßãâÞ×Õ×רÚÚÙÚÜÛÛÚÛÜÛÜÚØÚÜÜÛÚÛÛØÚßáäßÎÁÀÀ¹«œ”Žˆ„ƒ‚€|xsoid]WVZaffglorsqpnmljihfedb]WTU^gigbUKKR\chms{„ˆ‚{�«µ¹»º»½¹»ÇËËËÌËÌÍÍÎÎÍÍËÍÑÓÏÑÙ©ko|ns©Ç½¹½ËÐÉÍÍËÁ½º¦•rŽˆ—œ˜Š�}zxvwƒ˜±ÆÕßáÝÚØÙ×ÕÚØÛÜÜÖ×ÙÛÙ×ÛÛÚÛÜÜÛÚÚÚÚÚØØÞâà×Ǿ¿¸¥�„�ƒ„„…‚~yrmjjjmpqtwywtuutvxyxwtrolmnljgeccfjjmlmhYHEKU`fkns}†|t’®³¹ºº»·ÁÌÈÊËÊËÌÍÌÍÍÌÍÍÎÐÒÒÏÒÙªorƒux­Å¼½ÈËÌÑÎÌÆÀÁ«žsž�‰‚{yyus~•ª¾ÖÞÝÝÙÍÓÝÛÚÛÛÛÛÜÜÜÛØ×ÜÛ×ÙÚÖÙÛÙÛÕÓÚÙÚÛÜÞÙÎÄ¿¶£�€„‡‡…‚zunjikosvy{}~}|zvuwxxxwwxwsqrpnmkijnnmnnool^QJMV_goqsvwr}¡¯³¸¹¸²£·ÌÇÈËËÎÌÌÍÆÉÎÌÍÑÑÑÑÏÎШsz‡v}©´¸ÉÇÈÑÑÑÌÃöŸs–�xutwy„š»×ßàÜ×רÛÖØÜÜÖÙÞÜÛÛÛÛÜÛØÕÛÚ×ÚרÜÚÙÙ×ÚÜÞÜØÑÉŽ¥‡{~‚†ˆ‡ƒ€zuqlimpruwyz{}||||{ywwxyyvuwxvsppqrompssttttqojcZSSYajqsstvx“¬¯²¶¸ª|²ÊÉÉÉÎÍÌÎËËÎÍÉÎÒÒÐÑÌÇ̬xtƒsvФÄÊÊÎÒÓÐÉÈ»§i�uvyzЦÄÜÜ×ÚÙ×ÙÛÚÛÞÜÛÛÚÚÜÜÚÙÛÚÛÜÙÕØÖØÛÜÛ×ÑÙÜÛÜÛÕÐÌË̹”wq~‡†„„�|wrnllptttvxzzyxuqpopqprtwyvstuurqqrpnnpqqqpnpqpmid\Z\aflsuvxx�§®°µµ™|o{¯ËÇÇËËËÍÍÌÎÍÉËÐÑÎÏÏÌËÕ²us|uu”ÀÇÌÏÑÑÏÌ̽ª^x�•©»ÏÜÞÜÏÍÚÚÚÚÙÙÚÚÜÛÛÜÛÛÛÛØÙÛÛÚÛܨרÙÛÛ×ÐÒ×ÖÒÍËÌÏϳƒot|„‡„�}xtqommruuvwxwusmd_^`begjmpsuvttsrrrrqqsqnmjgdcdhlmmjfa^aeiqsvz{�¥±¶µ˜‚{qz«ÌÉÆÉËÊÆÄÍÍÎÌÍÏÍÍÍÏÏÐØ¸}q�y|¦ÅÊÎÐÐÏËÌÆ°j¦ÈÛÞáßÙÕÖÙÚÛÚÙÙÙÛÛÙÜÛÛÚÚÚÛÜÛÚÚÚÚÙÔØÙØÚÙÙÙØÐÕÐÉÌÑÒήyiv||‚‡�|vrqppqstsuxvqjdc\VTV\_`bejmmqsrsrrstuuuuqkgc^YVTX_eikkhaaejmsy~ƒ‘¤²µ¼šn{ƒrx§ÊÊÉÊÊÈÅÉËÌÍÌÎÎÎÍÏÐÍÏØ¹zlyuu¤ÈÎÑÑÎÉÌ̵ˆÜÚÖÛØÖÙÚÚÛÛÙØÙÙÛÜÜÛÚÚÛÛÜÛÚÚÙÙÙØÚØÓ×ÙÙÙÙ×רØÖÎÐÒÒÌ­�ks}}|€ƒ�xnopprvuqqqng_XTPNPSUY^aachlknpprsstvxwusmhfb\WOJIKS]eijgcbfpy�„�—¤¯·ÈÄ—s{�znrŸÇËÈÈÌÌÉÉÊÍÌÌÎÍÎÐÎÍÍÍ×¹xk�tr¤ÎÐÐÐÇÊÏ´ŠÙÆÄÙØÚÚÚÚÙÚÙÙÙÙÛÜÜÛ×ÙÛ××ÚÙÙØÙÙØÕ×ÙÖרÔÖÙרØÔÏÒÓͳ�€xx}~~}€…}qllquvsqngbZSQOKOTWXZ^bcehlmnoqrrssuwxvrkhfb[VRLFCFNW^che`iyˆ‹’ ¬³ÃÎËÌ¥ro}|po”ÁËÆÊÊÈÉÉÊÌÊÌÊÍÏÌÍÎÌÎØ»|r�px«ÌÏÒÉÇε…ÓÒÒÙØÙÚÚÚÙÚÚ×ÕØØÙÛÚÚÛÜÖÔÙØ×ØØ×ÖÒÖØÖ××Ö×ÔÒ×ÖÑÎÒнž�‰{y~xy��sjpvxwqkd_][]bddcefdcddffhkmnprrqrrsvxvqkgdc^ZWNGFEEHQ]eigty|Œ’�«´¿ÌÎÎÓÓ¡su�€tm�»ÈÆÇÈÊËËËËËËÎÐÍÌÍÌÍÏÕ½€q€{{«ÍËÉËϹ…ÓÛÙÙÙØÚÚÙÙÙÚÓÒ×ÓÖÛÙÚÜØÖØ×ÓÓØØÖ××רÖÔ×ÚÚÓÓ×ÖÏÎÓÈ­˜Ž‡yw€}xqntsjnuwyumdabhmsuvyvtrppmkklmmmopssqqrrttsojgffb]ZVSRPNORW^hillz”£¯µÀÊËÑÑÏÐϸ‡u€vl„²ÈÇÈËÍÌËÌÌÊÍÏÎÌÎÌÌÏËÑ»~o†}~­ËÉÌѺ‡ÔÚ×ÙÙÙÙÙÖØÙØØØÙÙÙÙÙÙÙÕÔÙØÔÕÙÙ×ØÙØØÕÒØÚ×ÖÖÕÕÎÎϽ¤‘Œ‰xwxqlihcltvwxqkkpuz}|xx{ywutttrqrsrqrsutrrqrrqqnkiiheeggddfggfa_ceck‰¨±¹ÄÍÎÉËÌÏÒÓØ»�st€ym€±ËÊÊÀ·ÉÊËÊÌÍÎÌÍÊÌÑÌÈϸqƒ{€¬ÉÊι‡ÕØ×ÙØÚÙØÙÙ×ÖÙÚÙÚÙÖØØØØ×ØÙÚÙ×רÙÙØØØ××ÔÒÔרØÏÌ˸Ÿ‰ŒŠxz|rkfe]druwxuqrw~}{xxxvsrsrrsttssrstutqooqqppoljiiiklkjloooqspiii|¦¶»ÅÎÎÏŪÄÑÎÎÐÒÍ›sx‚}oy¨ÇȺ¶ÅÈÊËÌÍÍÌÌÉÌÏÎËËϾ‰o{y¡Äʶ†ÕÚ××ØØØÙÙÙÖØ××ÙØÙÙÙרØÖÓØÙØ×ÕÖÔÖØÖÕÓÕØÛÝ×˺©ÀÍ»£��ˆz{xnebZTiswyxuxz~€|zyvuutpmmnoqrssttttttqoooppnomjikkjhhiklmnquxwrwš¹ÂÌÐÎÎÐ̺ÊÔÍÏÑÒØÓ¤rqƒ|ls¡ÈÃÃÇÅÆËÊÌÍÌÍÎÍÊÇÇËÉÎÉ”s}w�È·†ÕÛ××ØØØØØÚÚØØÙ×Ö××ÙØØØÖÔØ××××ÖÒÒÕÖÙÜÚÔÊ»ª™Œ…¨È½¬šŽ…�}sh`]OXnvxyxx|}�~wuusrpnjebcfkmqsttttvvtqooppponkjkjfbaeiklorsw|z�¸ÉÎÐÐÌÌÐÓÕËÈÎÒÑÐÐÒͨwp‚}lr ÃÄÆÄÅÊÊÊÌÍÍÍÌÊÈÉËËÆÔÑ•oƒ�z¡´†ÔØÖÔÕØØØÙ×ÖØÙÙ×ÖÓÒØØØÖØÙØØÖÔÔÕÙÚÚÕÎŰŸ‘‰ŠŒ�‘›½Æµ¡�‡ˆ�pd]ULarxyzz{}~~yuspkgdb_\[YY^cilpqtuuvtrppqqqolige`YV[bhjloqqty}”ÂÏÌÎÑÍÍÎÐÎÄÂÊÑÑÏÐÐÑÖ¸|k|}no”¾ÇÁÇÊÉÉËÌÌÌÌÌÏÍËËÇÊÕÊ’o�ƒyއÏÒÕÑÑØÙÖÌÒÖÙÕÖÚØ××ÖÖ×ÕÖÖÔÖØØÚÚÖÍ»§™�…‡‹�”™™”‘˜·Â¯š�Œƒnc\PQdsy{zz~€}xtqkfcbcb^[XVUUX^cinqtvvvusrrqqkeb^WOLQVXYZ`ejlpw}’½ÊÉËÏÑÐÏÏÐÎÈÈÏÐÎÏÒÐÏØÂ†n€rj�»ÃÃÉÈÉÌÌËÌÍÊÊËÌÍÊËÏÒË–q�…u…ÑÖÖÖÖ×ÙÕÍÕØÙØÙÚרØÖÖÕ×ÚØØÛÚÓÆµ¢“‰‡Š�”™˜•�‡�ytn{£¹´¥•…pc[OTcsz||}€~zuogadhiijd^YUSSQTZ_diouxxwwwusnb\XOHHMSTURLJS^flu|•¾ÌÎÂÆÐÐÏÎÑÒÍÍÐÑÏÑÑÎÎÏÙÌ“t�qj‡µÅÇÉÈÌÍÌÍÍÊÉÊÊÏÎÍÑÍÐÎ�q~„…ÔÙרØ×ÙÙÚÕÖÚÛÙØ×ÕÓÓÖÚÝÔÏÌÁ¯ž�ˆ‰‰�•‹ŒŠ€yvrkggeeak�¬¸±�ŠvYKTcr{~�€€|uoe`cgiiigc^YQMOOOSX]bipwzzzzzwhXSKCDHNSW[]XOMT`hpz—ÁÉÉÇÉÎÊÍÏÏÐÑÐÐÐÐÏÏÌÏÐÎ×Кqu}ui~°ÆÆÉÊÌÌÌËÉËÊÈÌÌÍÏÎËÏΟov‡Ó×רÙÙÚÚÙÖÖÙ×ÓÓÕØÖ×ÖϽ¦¤Ÿ“‹‹�”™’Žƒwtnhigffghijljiv�£¤”uTLVcq}€�‚€~yrh`bedbcb`^ZTMFGLORW[aflu{||{|yeSJB@?CJQX]bc^SNXemx�ÄžÍÍÉËËÏÏÎÐÑÏÎÏÎÎÍÐÒÐÎÔÑ›nq|vi|ªÄÉÈÌÌËËÈÉÉËÌÈËÏÌÌÏÐÑ¥o‡ÕÙÖÕÖØÙÙØÔÑÕ×ÙÛÛØÉ¸®ŸŒ�ˆŒ“˜™—�‚wsmmjjlomjjllnnmqojlrzp[QNYao~‚ƒ‚|wodbdabcbcc`[UMHEHRXZ^agmtz}}~{iSGA>=ACBBCDEGNY][^iorw{ƒƒƒƒ|jYQHA??@@>>CDDLZcn…³ÇÈËÊÈÈËʾÆÎÍÐÎÎÏÐÐÎÎÎÑÐÍÑÕÑÎÔÍ�su}vo�ºÉÉÈËÌÍÊËÍÎÎÍÐÑÎѽ‡ÒÙÙÑIJŸ�‹�’˜Ÿ¡£’|x{{qkkgeimnonnnnnmmnqpopoorssqoopomkbUIKQVmƒ††„}vqmkie]TQTUVYYVRRRUVW[empty~�ƒ…†…‚ubSNLHFIOQUZ`e^]gq†±ÅÆÉÊÊÈÉËÅËÏÏÏÎÎÏÑÐÏÏÍÌÍÑÒÔÒÐÎÓÔ§qp{un†²ÇÇÊÍËÊÍÏÏÎÏÐÐÉν…ƹ¥•Œ‰�“› ¢›—Š{pfoqkgihkmnnonlllklmnopppqrqpqqooponq|hSJQWn†‰ˆ…€xvvvtqoljhhgd`[VVWY[`hmpty}€�ƒ‡‰‰†}obXTPLKOW^bgoqlpw„œ¹ÇÆÈËÊÉÈÎÏÑÏÏÑÎÎÐËÏÐÎÌÈÏÑÔÑÑÓÑÔÖ¬xlyun€«ÅÇÊÉËÌÍÏÐÏÑÏËλp”‰‰Ž˜¡¡ž•Šuonp{zk_]cedffdhlkjjjjknnmnnopqooponnonnwzxubSTXp‡‰‰ˆ…€~~}zyusolifb^[[[]bgnsuwz}€�ƒ†Š�‹ˆ�xqlb]ZUQRW\dkpuy~‡�‰·ËÈÆÉÊÊÍÎÎÍÇÄÌÏÌÊÑÐÐÎÏÎÐÓÓÒÑÓÓÕÚ»�mxwmz¤ÂÄÇÌËÊÎÐÐÐÐÐлnš�£¦ “�umkp|ˆž¼¿´¦„\RX]][\`cfhijikklmmonpqpppnnklmpwihsrhZXu‰‰ˆŠˆ…„‚�}}yrokfedbcdfimsxyz|€�€„ˆŒ��‹…~utpieb`\[\clqw~‚Šƒi|¯ËÊÆÈÌÌÌËÌŽÌÐÍÎÑÐÌÌÐÎÏÒÓÒÒÓÉÊÒØÃ‹nvwnx¢¿ÄÆÊÌÌÏÐÎÎÎѺx¦˜ˆ}uopx‡—­½ÄÔÚÇÆØÐ¡dKKORUY[^adffggijjkmnmmmmopnlkqshgmwte^z‹‹‹‹ˆ††…‚€~zvtqnnnoonqsvy{{{~���€‚ˆ�“”�‰�yuurnkkkkklpvz„ŠŠqcn—ÄÍÅÈÉÊÍÍÍÏÍÇÎÎÎÏÊÍÏÌÏÓÒÑÑÏ¿ÃÐÑÚɉlvxoy¢ÀÄÇËÌÍÏÏÎÏÓºezmnt†—¬ÀÍÔÔÏÈÐÍÀÂÐÖÓ­qK?CJORSVZ^`bcdehjllijkjlnpomsriioxwpn‚Œ‹ŒŒ‹‰ˆ‡…ƒ�}|zxwvvwwwxyz|}}~‚ƒ‚�‚…Š�’”�Š„yvvutrqqqrvy}€„‰Œ|p^]‡ºËÈÆËÌÍÍÐÌÇÍÎÐÎÌÏÎÌÌÑÐÐÎÌÍÏÐÔÒÙÊ�krvpw—»ÅÅÊÍÎÏÏÏѽ`„”«¿Ï×ÜÝÚØÔÍÌÓÐÁÁÄÀÆÍ±yQ?;AGJLQTV[]_behjijkjjkjlonssihs{tsyˆŠŠ�Ž�ŒŠˆˆ‡†…ƒ€|{|||{|~~€‚„„ƒ‚ƒ‡‰�›¡™Ž†€{wwvvxwvwwz}‚„…‹Švrrhc{«ÆÆÇÍÌÊÍÎËÉÎÑÏÌÏÐÏËÍÑÐÎÐÏÎÏÒÑÑÚÏ–mq|sq�¯ÀÃÉÌÏÐÍλyÈÚÝßßÜÙÕÖÖÖÔÖ×Ƚ¿ÂÀ¼½¿®ŒbE47@DHLOSUZ]`befghhhihilkpsiiv|x{~‰Š‰��Ž�Œ‹‹‹‹Š‡„„‚�‚�€~~€€€€‚ƒƒ„ƒ„‡‰�žµ»°Ÿ�‚|ywwuwz{}}}�…†‡�ŒmbpwpanšÁÌÉÊÊÊËËÉÌÍÏÇÄÏÐÎÎÏÎÏÐÎÍÏÏÏÓÏØÕ£rr|qp‹«ÀÆÇËÐÏй‚×Ý×Õ×ÖØÙ××ÖÓØÏÃÂÂÀ¾»½º»±ŽnO947>DIKMQUZ^acbceeefgihmthjx‚ƒ}}Š‹‰Ž���‘‘��Ž‹‰‰ˆ†…ƒƒ‚‚���€�ƒ�€€‚…‹’¢µÂû­š‡}ywwuvz{}�‚„‡ˆ‰Ž�oWYgvugiŒºÉÆÇÈÈËÌÌÌÎÉÆÎÏÎÑÎËÏÐÏÐÐÐÒÔÑÏÖØ¬tjuuv‰ªÂÅÃËÐÑ»…ÎÒ×ÚØÖÖÔÕ×ÓÓÒÀ»¼½ºÂ¼µºµ´©‰r[D427>CEINUXZ]__accdfffjtjiz†ƒin‰‹‹Ž��‘““’���ŒŒŒŠŠ‡…„……„ƒƒƒ�~~€‚ƒŒž®»ÁÀº°¤Ž~wttvyzz}�„…ˆ‹‹ŽŽpXQTetwmbx©ÆÈÆÉÉÊÍÎÌÌÏÎÎÎÐÐÍÎÑÐÑÏÏÒÓÔÓÐÓ×µ„ntxt|¦ÆÄÈÍÑ»…ÓÙרÔÒÓÍÔÓÏÕÏ¿º»»ºÀ·­ºº¸·Ÿ€paP<106=AGLOQVZ[]`abcbcdsni|‚uYb…‹‹Ž‘‘‘’““‘�������‹‡††…„„‚�~€�‚ˆ—¥¬´»½¸¯¥“€vqptz{|�…‡‰Š‹�ŽrZVRT\n{p^kšÂËÇÆÉÌÍËÊÍÍÎÍÍÐÐÍÍÏÑÐÏÐÓÔÓÓÏÑ×È“kqunw�»ÀÅͺ�ÕÞÙ×ÎÒÖÔÓÒÔ×ɼÁÁÀ¾²·¾¼¾º·«�}tk[F5/27=BFJOSVX[]^^^a`mpl}|jWg…ŠŠŽ’“”””•“‘‘’‘�ދЉ†…„‚‚€}}��…“¡¤©±¶·±ª¢•…xomptw|€�…ˆ‰Š‹�ŽpXYZYX]kvufd†¶ÉÆÄÉËÌÌËÌÏÐÑÏËËÍÍÎÍÎÐÒÒÑÑÑÐÏÔÍ›nlujiаÄǹ…ÕÚØØÔרÖÑÒÖÔó½ÁÂýµ¸¼¼»·®£‹vl`Q@4/18>BFKOSVXYYZ\_clo{xcZv‰ˆ‹�““•–”’““““‘��Šˆ‡„ƒ‚€€~z}„…„Œ™žž¤¬°¯ª¦¡˜�‚tlkmqw|€ƒ†‰Œ‹�Œr`cea\\\bqxi^v§ÇÈÆËÌÌÈÌÏÍÏÏÉÊÎÎÎÉÍÑÑÑÐÏÎÐÐÎÒѦokxol‘·Çµ†ÕÜ××ÖÖÕÖÖÖÙО¾Á¿²²»º¹¹¶³š�|smeXJ:0/28>CFKORTVWY^[dqzvba~‰ˆ��‘“““’‘“”‘‘‘�ŽŠ‡…‚‚€}zz€†††Œ“–𠦧§¦¤ š“Œ|mihmsy€ƒ„†Š‰‹Šviifd_\[[^kwpcm–¿ËÊÊËÉÅËÆÅÌÈÈËÎÏÎÏÐÑÑÒÑÏÐÑÐÌÏѰxkyrm…¶·…ÔÚ×ÖÔÖÖÖ×ÛͽÄÇÅù»º¶·º¸¸º¹ªŒzvqi\NC8/-39>AFJNQUXZYaqyvcd~†‡Œ�‘’“’’””“‘��Ž‹ˆ‡…�€}}zux}€‚„†‡ˆ�™¢¢ ¡ ›”އ|mgehpx}‚ƒ‚†‡Š‹tfgd`]ZZ^[]gtvic�±ËÈÇÈÁÇÌÍÈÇÍËÌÍÎÐÏÐÏÐÒÏÏÏÎÏÍÎ׸{juolƒŸ…ÏÔÖÖרØÖÙÕ¼·ÅÄÅÃÄÿ¿ºµ¸»»½¸±Ÿ…~yvph`VL?4-.3:>CFJQWWX_nyxji{…‡‹��‘“‘‘’’‘Ž�ŽŒ‰†…‚}}zvqorrhenx{~ˆ•˜”“’ކxoqmgdfnv{~�ƒ…†‹Špbdd`^]\][XYerulau¦ÄÆÆÈÉÎÏÊÏÌÉÊËËÌÎÏÎÎÏÏÍÍÍÏÑÑÏÕ¾ƒmsuju…Ó×ÕØÚÙÚÙÜÐÃÈÈÅÄÅÄÄÀÀÁ»·¼¾¿¹´°”‚}xsojc^SG:0,/5;?DJQXXZhx}}~w‡‰Ž‘‘’�����‹ŒŒŠˆ‡„€|{zyvngfcVJLXju{�„ƒ‚‚l[anqlgekt{~€�ƒ†‹†j`ddcb_]\[Y[]`gtufi’»ËÈÇÊÌÌÎÊÇÉÊÊÌÍÎÎÐÏÏÎÎÌËÐÑÐÎÖÆ•pqsj†ÓÚØÚÜÛÛÜÛÓÍÌÉÆÄÅÃÁÁ¿µ²»¿º¶µ¦‰�}xtokgbYJ@:1,06=BFOUWaty…‹zvƒ‡��‘�ŽŽŽŒ‹‹Š‰‰‰‡ƒ~ywxxxtlb]ZWPLRapuvuuvnXWfqwvojkry|~�„Š„h`cca^^``_]\ZX[guvid¯ÊÈÆÌÌËÌÊÄËÏÍÌÌÎÑÐÏÎÎÍÊËÍÏÐÏØÒ¡rot†ÓÛÛÛÜÜÝÝÙÍÊÊÊÊÈÆÇÇÆÆÅú­µ¿»´²°•‚�|yuoedcZRJA6-,184.-3:?DM^u|‹‹‡€ƒ�‘��‹‰ˆˆ‡„ƒ„ƒƒ�~|||~~~{vpkhhllkmmllicfmquz}€|wtwyz|~ƒŠyecb`fg_]][^`_[XXWYjytce�ºÈÈÇËÉð¼ÍËÉÊÍÎÐÏÌÍÎÍÍÐÐÏÑÏÕÕ°{‡×ÞÜÝÝÝÛÛÔÊËÍÏÍÍÎÌÈȼÀÃÁ½º¸´¸´´¡‡‚zutsnhddd^UME<30/4@PVs‡ˆ…~|�‹��‹Š‰ˆ‡†ƒ‚‚€�€€‚‚�€}|zxtpnmmkhfffdgmtx}€��‚€}{wvvx{�‡raaaacc_^ZY_`ba^ZWVYdprg_{«ÆÇÆÄÄÄÆÈÉÇÈÍÐÒÏÍÎËÌÍÏÐÍÏÑÏÒØ´‡ØßÝÝÜÜÝÛÏÉÊÊÍÍÉÈÌÊÈÇÅÄÅ¿»¹¹¶º·³®•…�|vsokihe`XWSKB:21>LPb‡‰ƒ€ƒ‚ˆ�Œ‹ŠŠ‰‡†„‚�€‚ƒ‚„…„‚‚�€€~}zxsnkhebbcgnuz~�ƒƒƒ„ƒ��|vtuz�…l^_bcb`]\\^_^ab`\YX[[^jvnbošÀÇÅÇÍËÄÃÄÇÍÏÑÏÎÏÎÌÍÏÏÏÑÒÑÑÓÁ‡×àÝÜÜÝÞÖÊËÍÌÊËÆÅÇÊÅÂÈÇÅÄþ»¸¶¶µ¶¨Šƒ€yvqkljd\SZ[VPIDAGGJP{އ‰Š���ŠŒ�‹ˆ‡„„„……‡ˆˆ‡„ƒ„„ƒƒ‚€~|vrlgeccfkqx}€�ƒ…†‡„„„zqs|ƒ…k_`aa_^]]_`__]]]]\Z\\W\lzyda‰·ÇÅÅÄÇÆÃÇÌÆËÐÎÏÌËÌÍÍÏÒÑÒÓÔº‡ÖÜÝÝÝÞÜÓÊÍÏÎÌÍËËÇÇÄÀÅÇÈÈÅÿº³´¸¸µ›„ƒ~|xqpof[]\XWZYROUONHb‰††…tt�ŽŠŠŒ‹‰ˆ…„†‡ˆ‹Œ‹‡„……„ƒƒ‚�€~ysld``chnsx|�„„„……�ƒƒ�~su~…�h``_\[\^__`^]_``__\YXZZ\euvf`|ªÅÈÅÈÇÄÇÊÇËÏÌÍËÊËËÎÏÑÒÐÑÕ½ˆÕÖÛÞÙÚÙÏÌÊËÌÍËÅËÉÆÆÆÇÈÈÅÀÁ¼º¹»»¸°ª’†ƒ�|xsokdeb[V[caZZXWNQuƒ�|gfˆ�‹‰‹Œ‹‰‡†ˆŠ‹Œ‹Š†ƒ„ƒƒ„„‚�€€}xrkdbfksy|€ˆ�‡‚���‚………}{‚‡}d_`_\Z]^^`_]]acb`_][Z\ZWV\hsocn›ÄÊÆÆÅÅÊÎÏÍÍÎÌÊÈÌÏÏÍÎÌËÔ¾ˆ×ÝÜÜØÖØÑÎÊÊÎÌÌÊËÉÉÉÈÉÉÇÄÁ½¸¹¼»»º²²¢‰†€|}xpnmifc_]`cb_\\YQWnvqee„�‹‹�Ž�‹‰‰‹Ž��‹‡…ƒ�‚ƒƒƒƒ†‰…~{xsqsux{~ƒ��ˆ}|„……‡ƒ€…ˆ{c`^]_\^`__``^```_]^\\ZYWWST`qtdf�¸ËÈÃÅËÍÎÍÍÍÊÉÊÆÃÌÊÆÍÏÓ½‡ØßÛÛÙ×ÎËÑÑÏÑÐÐÑÍÌÆÆÊÊÉÆÅÇĿ¾µ¶¹º·³˜‰�||ywrnljgdb__eec_\VJHMRdn�ŠŠ‹��ŒŠŠ��ŽŽŠ„�€}||~���…ƒxooprttrnmos|�~yurx‚…ˆ†ƒ‡ˆxb]X]baa`^_c`^b`]_^\Z[ZZZWUUT[mtjcy©ÇÄÃÊÌÌÎÇÅÊÉÊÆÀÉËÌÏÑÔ½†ÖÝÛÚÙÙÀ¶ÏÒÐÐÑÏÐÍËÈÀÇÇÇÈÇÈÉÆÄľ¹¸¹·¹ªŒƒ�{zvqomlihebcdd`ZSM@8>_r}ŒŠ‰Š‹‹�‹‹���Œ‡�{wvwwvtroliea]\__^\\\[]bikllmrz‚‡Š‰‡‰‰wda^ca^_^`bb^]__\^][\\]]\YWXYSVhuoal˜»ÄÆËËÌÊÈÈÆÈÊÉÉËÎÐÐÒ½‡ÖÞÚÙÚÖÉÅÎÑÓÒÑÐÐÏÏÎÄÆÇÆÇÇÅÅÄÃÅÅÂÀ¹µ·°’‚…ƒ{zurpolihfc`a`[RMH??\s|ЋЋ‹‹ŒŒ�ŽŒŽŠƒ}uqonle^Z[]a^[ZXSQRRTXVPOKHM[gpy�‡ˆŠ‰‰ˆuc`\[[[^`b^UZ^[[]^^^aa_^\ZWW[YUVcsugd…²ËËÉÉÌÍÉÆÇÉÆÇËÌÎÏÒ¼‰ÙÜÛÞØÐÎÒÑÒÔÒÑÐÎÎÏÎÍÉ¿ÂÄÆÆÃÃÃÂÃÅÆ¾µ¶´§�†…�|zywsjighjie``^YRLF@Yw}ˆ‹‹ŠŠŒŒ�Ž��Œˆ‚zqbPFCFJS]acbtxmffih`_aVG11;>Ibt}‚…‰Š‰‡pXRNJS^`ab^X]^]]`ca__^^^][Y[^_]XW`rykbx©ÉËÈÊËËÈÄÆÆÅÊÌÍÎÒ¼‡ÖÚÖ×ÎÇËÍÑÑÏÑÑÍÍÍÍÍÏŵ¿ÇÅÅÅÄÅÆÅÅź¹¹¹¤Œ‡…‚ywxummjiligb][YTMH?Ry�…‹‹ŠŠ‹ŒŽŽŽŽ‰†‚xcH:8:?ANZMI[{€tijmgWIEEGJY\UMUky…Š‹‹†kVQNLUaba_bed`]]`ba`^]__]^_^_^^^[Y_nyscl™ÂÍÉÉÈÇÇÄÇÆÅÊÍÏÑ»†ÔßÎÎÐÈÎÏÑÑÑÕÒÎÍÎÎÎÍÄ¿ÅÇÄÆÇÅÇÉÉÅÿ¾¾¼´›‰„}usttutoljhgd\YUPJDDFIKOMHIJIJNPRRTUSPLNRSRTX\[[\ZZZ]_bdda`^WUTVYXWWWRM…ÐÎÍÎÐÑÏËÍÏÐÐÑÐÏÐÎÍÐÏÎÎÍÌÊËÆÄËËÇÊÍÉÇÊÃÄÃÃÅ¿¾ÃÇÅÅÂÂÀ¿½¸Ÿ‘“��Œ†{‰‚iWRRQUUZbfjI10/16AIPUWZ^_ab```aabbba]YX]enu}…ŠƒVAEHMR]lfG:AEHJLKNQQMJNMLLLIHIMQRTUWXYYXY^cbcggfggb\XXYXVTU\YP…ÐÑÌËÎÑÑÍÎÍÍÑÒÐÏÍÌÍÏÎÎÎÌÉÉÌÃÄÊÊËÌÊÇÉÊÂÃÉÇÆÅÂÃ¿ÂÆÃÄÁ¿¼º©•‘��Œ„{||…�€cNMQSTR[biiD30//2:ELOPQSVYXXYYZ[YWQPW`fjpx†‹‚T?CCIOU`olM:>@@DGILQPOPKHHHKLLMQRSTTRSVWZ_bbdeddbc_[WVYZVTTXZV…ÏÐÊËÊÉÈÊËÈÊÎÑÏËÌÎÏÐÎÍÎÎÊÊÍÊÈÆÈÍÉÇÆÈÉÈÇÅÆÈÇÃÄ¿ÃÇÅÅþº¶¯ ”��Œ‚yrƒ„„ƒv]IINSQQ\akb@3///06;DIJKLNPRQQPOMLLV`dgntz‚‡Š‚SDLMQ[bnU972./125;BFGGHIILPSY^aekpu|�…†ˆ‚R:@AEJRZ_fkyyhtyM8;@FGILMLRVWZZYWRPOQSSTRRTW[\XXWYYXWTRTTPS^ca…ÎÏËÉÊÌÌÊËÍÎÎÍÐÏÍÍÏÑÐÏÌËÍÉÈÈÇÈÊÊÊÉÊÊÊËÈÈÇÄ¿½ÅÈÈÇÇÆÆÃ¾À½¼²§š’šœœ�ƒŒŠtnsvjS@?IMSZcjM9930024;BJOQRQSVY[]`elosy~ƒ†‡ˆ�R8=ACISX^ekq~�—¤Š^K@>EIKJHIORVYYXNGJLNNMOTTRWYSQPUSPQUY[]aa`aa…ÎÏÍÉÈÉËÌÆÊÏÌËÍÎÎËÌÐÎÏÎÍËÉËÉÊËËÉÊÌÉ»ÅÊÈÇÈÆÁÀÄÇÈÆÅÆ´°ÀÁ¾·«¦š�•œ�™�†‰nkloo\E>FNTXagG7753126=FMRTTVY[^afjnrx}�„‡‡ˆ�R6:=AHRX^gmq|�…›�|iK>@GLKLNPSUVWSIGMONMLONNOPSSU]ZXY\]_a[TUUY„ÏÏÍÉÊÌÌÎÊÍÐÏÎÌÈÊÎÎÊÊÎÌÎÏÐËÈÊËËÉÊÉÆ½ÅÈÈÈÆÆÄÃÅÈÈÇÇȶ±Àºµª¥¢ž“•¡¡£–‡ƒˆznegnvdNAAKSWcaB7645448@IOTWZ[^aejmpw|�ƒ†‡‡€Q49<@IRX_ekv‡”ƒMRs�†sQD?@GKKMPQSUWSNTWRSTSSUUSZ][ZUTTV^ZRg‡œ“[ƒÎÎÌÊÉÌÌÍÍÏÍÌÍÏÈÉÍÍËÎÎÌËÎÏÌËÊÌÌÉÆÅÉËÈÇÈÉÆÅÇÇÌÌþ½»º¹°£ž¡¢  —’ž¤§œŠ‚ˆ„tngcongYG@ENUh_?967788;CLTY[[^afkoty|~�„†††O28;?ISZadn„�‘„O3;J`ryv[I<><:99:?HPTVY]chlqtw|€ƒ†‡‡†P/5:?GS\al€Ž��xRG=77Dt™”Š^D>@HKJNQQTSQQNONPUTf�Ž}{›§£ƒožÒÎÚÝâȃÉÊÉÆÈËÊÉÉÅÇÍÍÊÇÇÉÈÊËÉÊÍÊÊÍÍÃÂÇÄÄÄÆÄÄÄÅÆÄ»´±¬©©§¥£�˜™›–Ž•™›™ˆˆ†xqy�‰‡ysntl`behkd\SP^[?:9;<=>?DJOV[_ehlpty~‚ƒ„†…ƒ~V/3;?HU_iŽ�ŽŠfCFJKC9Ce…–‹†zX<>DEAEEJQQZhr]Rh‘Öஞ¬Ÿyw²ÞÛÄÉÌÆ­‚ÉÈÅÃÃÊÈÇÆÆÍÍÍËÈÇÃÅÊÎËÈÍËÊÌÍÈÄÆÂÀÂÁÀÁº¯©¦¥¦ª®®¨ž–”—œ›�Š�™�ŽŒ˜†|Š‹†yglvpfa[]^ekt…ІoYK?98:?AFMUZ_eilpuxz|~‚€|wZ726=HR`yˆ‹‹‹VBCFILI=4AZt‹š‰iWG?P\`lx€œ¬§{^k�ÒÒ®§¤�…©Ä·®­ª§¥”‚ÉÅÁÅÈÊÍÎÇÅÌÊÆÈÊÉÉÊËÎÌÈÈÉÈÈËÉÇÅÃÃÀ½½»·´¬©ª¨¥¨®°¦˜‘‘•œ£ “‡…Žž”Œ—™›¢–‚„|q}€zy‚xjefjy�”œ¢¢˜ŠvaTMKOU[agntx|€�„ˆ‹��‹„‚fC=9?Md�“–˜˜•�jPOOQQSVPA>E[q•² t�½ ™–•§ÁǺ°¬‹¤ÇÁ¹º¹¸¿¼²±³´´´¶©�ÆÆÄÂÅÊÌÍÊÈÉÆÂÆÉÉËËËÊÉÈÇÈÈÈÉÆÅľ¸³¯«¨ª©©«ªª¯²©™ŒŠŽ— ¤ “‰…�•Š‹�š�u`WRSUQQRVSMHCGMNRSYgmzzmZA89@NW[iw|€ƒƒ�€}yumfcaadfda]XQG;5434@O]bachmqvy{|€mPEDDFKPW`g^OVeƒ¸ÈÉÉÌÏÎÍÐÐÎÎÎÎÎÎÑÑÎÎÖ»jw|nm’»ÉÈÉËÊÌÉÈÊÉÌÉÉÍÎÊÍÎÒ¿…‡ÔÙÕÕÔÖÙÙÖÕÒÔÙÛÚ×Óê�–‹��‹‘šš’‰qmkjjjkmmkjjlmnlmpqpkgeYECB:ALRXhyƒƒ„„�|ysmhda`YOHC?>:620002AVdc`cinrvy|€‚‚vVA>=?BFNYfiVTf”ÄÆÊÍÎÎÎÐÍËÏÎÏÏÐÎÑÐÎÎÐÖÇ�js~tnŒ¹ËÊÊËËÊËÊÈÍÌÈÍËÈÊËÌÔ·…ÑÚ××ÖÔÔÕÕØØÛÖË¿¬š‹‡‰‰�“‘�‹‰‚wlgddiljlkkllllopomoonqshSG?AB:AJOWiy�„………�|wrmjgfaVKEDCDFHIGEDIT\\[_glosw{‚„„~dC987987:I^YWo¨ËÊÉÌÏÑÏÏËÄÆÊÍÎÏÏÎÎÎÐÒÒÜÒŸrs}sj‚²ËÊÊÊÉËÌÊËÎÌÎÍÊÈÈÎμ…ÏÖÓÓÖÙÙÙ×ÑÅ·¦š�ŽŒ„�š–•”�„wmiffhjiimlllmmloonooooonmkkpkYMF@CLPWhz�„†ˆ†ƒ~wtsssqmid_\\\][WSPPRTUV\elprvz}€ƒ…†„tYHD@>=716BO\€ºÊÈÉËÊËÎÍÏËÆËÍÏÏÎÍÏÏÊÎÔÒÖÖ¯}oytl}­ÊÊÊÈÉÍÍËÌÍÎÐÎÍÍÎк…ÎÓ×ÚÛØÌºª�”��•œŸ•„�Œ‡~yrhefjjklnnmnllnqnnonoqppooomly�ucNCJQRWi}…†‡‰ˆ†„}~~|ywtqmkigc_ZVUUVVY_florvz}�ƒ†ˆˆ~fTMKLLIJOKK^ŽÅÉÇÉÌÿÌÍÎÏÎÏÎÐÎÎÍÏÐÎÏÓÓÎÐÔºƒoz|oy§ÆËÈÉÌÍËÊÌÍÍÍÍÑÏÑ»‡Ô×ÏÄ´¢”‹Š‘—› ¢›“ypyxnhhheimnpnmnmmmnnprpopoqrrpnoqoxxlqvqcUVTQYn€‡ˆ‡ˆ‰‰ˆ†…„‚}{wsokheb`]\[\^aekqsux{~€�‚„‡ŠŠ…r_UQQUY_gi^e”ÅÊÉÈËÈÇÎÏÏÎÍÍÎÐÎÎËËËÎÑÓÑÑÏÏÖĈjwzou�ÁÈÈÌÌÊËÍÎÍÍÎÑËÊ»ƒ»©—‹ˆŒ”›Ÿ¡�”ŠƒslgfkiehhhkklnnkklkklmmoopppqppqoonoqxkeksuslcXO]v„ˆ‰‰‰‹‹‰‰ˆ‡…‚�~{vqmjihgefggjmrvwy|}€€�ƒ†‰‹Œ‰pd\USY`iqqr—ÂÈÉÊÇÊÐÏÐÍÐÐÌÏÍÌÐÍÌÉÌÐÒÑÐÒÑÑÙÈŽmszor•½ÇÈÈÉËÌÏÏÍÐÐË̺o‘Š�–ž¥¡—‹~vpmn|�•†n[Z_abcabhiijkjjlnnnnopppnoonmmlrtjjkrvvsmd\k�‰ŠŠŠ‹�Œ‹‹‰‰‡„ƒ�}zxvtssrrqqsvxz{{|}€‚�€�‚†Œ�‘ކ{qid^X[dnu{šÄÆÆÉÊÌÎÎÌÉÁÇÏÎÊÏÑÐÏÎÏÏÑÓÒÑÒÓÓÙÑœorypp޶ÄÄÊËÊËÎÐÐÐÏкo ¤¥ –†xnkmx‹šªÇÒÇÄ·‰\OTXXY[^beghijkklmnnoponooollkttiijx{wtrpp|ˆ‹Š‰Š�Ž��ŽŒ‹‰‡†…‚€~}|{{{yyz|}}~~~‚ƒ‚�€‚‡Ž“•’‹�ytpmigipx‘¹ÎÈÆËÍËÌÊË¿ÅÐÎÍÐÐÎËÎÐÎÑÒÓÒÔÍÆÎÖÔ©vqyrnŒµÃÅÈËËÍÐÏÍÍмwž‹|snqxˆ›­»ÉÉÏÚÌÀÏÝÓŸ`IGKPSVZ\^adfffghjmnkkmmnppnkutijo~|stvux‚‰‹ŠˆŠ��‘��Ž�‹‹‹Š‰ˆ†„‚��€}~~€€€€‚„„‚�‚…‰�‘”“Ž…}zxttssuz‚ˆŠ«ÍÊÇÉÊÌÍÍÏÐÈÊÏÎÏÍÊÏÎÍÑÒÑÑÑȾËÐÕÛ«spyrpŒµÄÆÊÍÌÎÐÏÏÒ½avnu„—­¾ÏÖØ×ÓÉËÐÈÀÇËÑЩnG>AHLOQUY\_abceilmiikkklnonvwjlt€}z}|y{ƒ‹Œ‹ˆŠŽ�’‘�‘‘�‘���Œ‰ˆ†…„„„ƒ€€��€�‚„…„ƒƒ…‡‰Œ” ¢˜Š{{{zyyz}ƒŒwjžÇÌÆÈÌÍÌÎÐÈËÎÏÐÌÎÐÌËÏÐÏÐÍÍÏÏÓÓÔØ®umvsq…­ÃÅÈÌÍÐÐÐÑ»e–©ÀÏÚÝÞÝÚÔÔÓÐÒÔļ¿ÆÉ¨vT>8>EHLORVY\_behjijijjikmntxlmvƒ…ˆzp{}„‹ŒŒŠŠ��‘‘’”•••“‘�ŽŒŒŠˆ‡…„„ƒ‚‚‚��ƒ„„‚�ƒ„‡ŠŽš®»¹¬™„{{|~~~�…ŽˆihŽ»ÊÆÉÌÊËÎÍÉËÐÐÌÌÐÏÌÍÏÐÏÏÐÎÍÐÑÑÖÛµ{kyyn~¡ºÃÆÊÍÏÎϺvÊßáÝÛÙØ××Ö×ÔÔØÎÁÀÂý¹½¼¯ŠbD67>DHKNQUY\`cfefgghhijjoxmlx…‡„b^y~„ˆŠ‹Š‹Ž‘’“••——–•“‘‘��Œ‹Š‡……†……„ƒƒ‚�~�ƒ†‹š¯ÀĽ´¥�}yx{~€‚ƒ‡Œ�|ib}­ÊËÈÊÊÊÌÉËÍÍËÂËÑÏÎÏÎÎÐÐÎÍÏÍÒÑÒÛ¾ƒmyxm}žºÄÆÊÎÎк{Ì×Õ××רØ×רÓ×ÒÃÀÁ¿¾½º¼¹¹«‰lP:26?DGILPV\_a`aceedfhhkxqm{…‚qT\u€ƒˆŠ‹‰‹Ž�“•••———–”“”•“‘��‹ˆ‡†…„„„ƒ�~}€€€‚‡“¤³»½¹´ª•xy{}ƒ„ˆ��|wqer ÅÉÇÈÉÊÌÌÍÎÍÆËÐÎÐÑËÌÐÏÐÒÐÑÓÒÏÑÚÆ‰jqvt~›ºÄÄÉÎѹ‡ÓÔÔÚÙÖÕÒÐ×ÓÑÖǺº»¹½Â±´º´´ ƒpYD416BFJOSVYXZ]_]bsx€rcixˆ‰„�‚…ˆŠ�‘’“””“”••””’‘�ŽŒ‰†…ƒ�€}zxz~‚……†ˆ‹�“œ¡¡¢¡ ž•onsx}€„ŠŒv`^]]hvtbd‰¸ËÆÉÌÌÉÊÎÍÍÏËÈÍÏÏËËÏÐÐÑÐÏÎÑÐÏÕÀ†huwi~ªÃ´‡ÕÝÙ×ÕÖÕÕרÚÑÅÅÃÂÃÀ¿»²¹»¸¸¹·¯�ztndYI;2/19@AFKORUX[\]`ox€{kov~‰†€�…‡Š��’’““’’“’“��ŽŽ�‰‡…ƒ€~~~|wssttmiov{|�‹•˜—––”Šxljouz€ˆ‰ta]\\[cqtic|ªÇÌÉËËÆÅÊÄÊÉÇÊÎÐÎÎÐÐÏÑÒÏÎÑÑÎÌÓÅ‘ktxov¡´†Ô×Õ×ÕÖØÖÔÚÒ¸¼ÇÅÄÂÀ¼¿ºµ·¹¸º»·¡‡~yvpfYND8/-4:=BFINSX^]\hx~ƒ€„{p�ˆ‚‚„†‰��‘’’‘‘‘‘‘�ŽŒŒŒŠˆ‡…�}~~|ztlhibO?CRcpv{‚†‡††‚xojhlsx|†‡o_]Z^^[_mwqck—ÁÌÇÈÅÃËÍÌÆÊËËËÎÐÏÐÏÏÒÑÏÏÎÎÏÍÔΕjpslv�†ÓÕÔ××ÙØØÙÙÇºÄÆÄÅÃÄÁ¾¾¹¶»½¼¼´°–‚}ytniaVLA5//39>BFKPVZ[_rx{‡�‡ss…ƒ�…†ˆ���‘��ŽŽ�ŽŒŒŒ‹‰ˆˆ‡ƒ€|||{yvmc_\SHBBHUepvxwwwtsqkgipv{~„†n`_\]\YX_lsrffЏÆÅÈÉÊÐËËÎÉÉÊÍËÍÏÏÎÎÐÎÎÎÎÐÑÎÓОopwpj…ÔÚרÙÚÚÚÜØÌËËÆÅÅÄÂÀ¿ÂÀº¹¼¿¼¶¸ª�‚|vqnid^TF:2,.5<@DGJQUWfuoxŠ�†„‚€„†‰���Ž�ŒŒ‹Š‰ˆ‡†††††…‚}{{{}}|vla][YVSLKYippoonouwrihouz}„‚la`]]\ZZ\]`lxocy¦ÆËÆÈÌËÍÌÈÉÊËËÌÍÏÏÏÐÎÎÎÌÍÐÑÎÓÓ¬znul‡ÓÙØÚÛÛÜÜÛÕÌËÉÉÇÅÅÃÃÄÂÁ½¯±¾½¸µ´›ƒzwsoiebVID:/,.7?CEILSZr{x‰‘Ž‹ƒ€�„‡‰�Œ‹‹Œ‹‰‡‡‡†„‚ƒ„ƒƒ‚|||~��€~yqidbbdbcgkmlmmnsx|zqlovy|‚|g_^_`_`][ZY`nwqdj•ÁËÇÉÌÌÌÌÅÇÎÎÍËÍÐÑÐÏÎÎËÊÍÏÑÏÓÚº�ls‡ÔÚÙÚÛÛÝÝÜÑÈÊÉËÊÈÈÈÇÇÅÄ·²¼½¸³´©�‚|yukee`ZSJA6.-2:?EOVSf„‡‹Š†€~€€ƒ†ˆ‹‹‹ŠŠ‰ˆ‡‡‡‡„€�‚�‚�€‚‚‚ƒƒ‚€~zuplkkjihhijjmsx|€yrrvy{�xfea_aa`_[ZZ[_fuwgb…´ÈÈÈËÌÍǾÄÍÌÊÊÍÏÎÏÎÍÎÍÍÏÐÒÑÒÚ¿†n†ÖÝÛÛÜÜÜÚÚÑËÍÍÌËÌÌÉÈÆ¿¿Ãþ»»·¶¶´£ˆ‚|wurmfab_XPH@4//5ELTQTv�‹‡…ƒ†„€‚„ˆ‹‹Š‰ˆ‰‹Šˆ†„ƒ�€�‚�€ƒ††…„„ƒ‚€~|xtqlid`adgkrw{��~yvvvy€tdgb]^[[_`]XWYX`sxk_t¥ÃÈÇÉËȸ³ÉÍÊÈÌÎÏÐÎÍÎÎÍÎÐÏÐÏÑ×Ä�†ØßÜÜÜÝÝÜØÌÊÌÍÎÍÍÍËÈÇÀ¾Ã½¹¸¶¸¹´±•„~xwtqlheea[TLD?85CEJRNc†�‹ŠŒŽ„|�ƒ‰��Šˆ‰‹Œ�‹ˆ…„ƒƒƒ„„„…‡ˆ‡………„„ƒ‚�}{vqkfcbbhpv{~�‚ƒ‚~zvsxpbca^\Y]_bca[WWV]krm`h“½ÉÅÅÅÅÅÉÉÇÇËÏÑÐÍÎÌËÌÍÑÎÎÑÐÐ׿‡ÚàÝÝÜÜÝÜÑÈËËËÌÉÄÈËÉÆÈÇÅ¿¼º¸¸¹µµ¨�„�zusmjjfcZWXSQIBIJDMPUq‰‰ˆ‹‹{lzƒˆŒŒ‹‰ˆŠ��ŒŠ‰†……†‡ˆ‰‹‹Š‡†‡‡†„„ƒ�€~ytnhedfkqw|‚„…ƒ‚xqx~oca^[]]___`a]YYZ\[brufd‚±ÈÅÅËÍÇÄÄÅÊÎÐÑÍÎÎËËÍÏÏÐÒÑÑÓ½‡ÙàÞÝÝÝÝÚÌÊÎÍËËËÇÆÇÇÀÃÉÈÆÆÂ¾º´³´¶¶Ÿ„„}xwplng^VX[[`[QRSNLNO\v„†„€lYqƒ†Š�Œ‹ˆ‰Ž�ŽŒŠˆ††ˆŠ‹�ŽŒ‰‡†‡†……ƒ‚��~zuniddhlrw{�„„���yqz~k___]_a_^]\\]]\[\ZXdt{n]r¤ÃÅÅÄÅÈÅÆËÈÇÏÍÎÎËËÍÍÎÑÑÑÓÕ¹‡ØÙ×ßÜÛÝØÎÌÎÍÌÍÌËËÆÄÂÃÆÉÈÅÃÁ¾·µ¸¸µ­‘…‚~{urqm_^aZW]e^XXYUOKMVm|{r`Xo�…Š�Œ‹‰Œ�’’�Œ‰ˆ‰‹�Ž��Ї…„ƒ‚ƒ„ƒ‚€€ƒ‚{tnihkpuy|€€€ƒ~w€|e\]___`_\^``__^ZWZZ[_lwnaj”¼ÉÆÇÈÄÅÊÉÉÎÍÌËÊÊËÌÎÎÒÒÐÔ½ˆØÙ×ÝÛ×ÚÔÍËÈËËÌÆÆÊÈÈÇÆÆÈǾ¼·º¼½»³¯¤‹†„zxpljifa]\ceba^[ULD>@Pflegq}ƒˆŠ‹ŠŠ�‘””’�‹‰‹Ž�‘�Œ‡„ƒ~�‚‚�‚‰‘�†}xutuvx{||}{{}�…ƒ~„zb[[^^`__]^bb`_^][Z[XVYamrhd‚³ÊÈÆÆÄÈÌÏÎÍÍÌËÉÊÍÎÎÍÍÊÑ¿‡ÖßÝÛÚÖÕÑÏÎÊÍÏÎÎËËÉÉÉÈÈÇÅÄÁ¼¹½¹¸¹ºµ°™‡ƒ}~{tnmkihhedcdea\VOE<44Qmpos}ƒ‡‰Œ‹‹Ž‘••”“Ž‹Ž����ˆƒ€}zyz|€…‰ˆ€wrrstqmkmqtuvux€…†‚…tb^\__^_`_^^``]]^][YWVVSYhuk`w£ÄÊÅÂÈÌÍÎÍÌËÉÊÊÃÇÎÆÉÎÒ¾‡×ÞÛÛÙØÑ¾ÈÒÐÏÑÏÑÏÌÉÂÇÉÈÆÄÇÊĹ´¶¹º¸¬�„~~zxuomjjlifaab_]VNG@72Hjrrv{�…‰‹�Ž�’––—•’���ŽŽŠ„~yuuvvutrrqokea``bb`]\]cjmlls|„ˆ‡‡qcdaa^]ba_aa^^^\[[[\[XTUTUdspdh�¼ÆÁÆÌÌÎÌÅÈÈÉÊÂÅËÌÎÐÔ½†ÖÛÚÛØØÑ·ÂÒÑÐÐÏÏÏÌÌÄÁÈÆÇÇÇÈÇÃÄÄ¿º¸·¶¶œ…„ƒzytpnmolhdba`_ZQHA90?etuz|ƒ‡Š�“’’•™š˜–“��ŽŽ‡€yspomkh_[^^`a][ZXVVWWVSRRWahp{ƒˆ‰†sc_``_ab`\^_\\]\[\]^]ZXWXVR]pteb€¬ÃÄÉËÊËÊÉÈÈÊÊÊÉÍÐÏÒ¾‡ØÝÚÛÛÙÑÌÍÐÓÔÑÐÐÏÏÐÊÇÈÅÆÇÇÄÃÂÃÄÄÃÀ´µµ¥Šƒ…‚|{yusonnkhd`^_]VNC;39`xz~‚…‰’”“’“˜›››™•’‘Œ‡€xkYIGGEKTQIIXba]XUSLBFJ;28I_oy‚‡Š…iZ]]^``WW]][[]^^_a`]\[YWZ[VT[kvoap ÃÌÉÉËÎÊÇÆÈÇÅÈËÍÏÒ½ˆÙÜ×ÝÙÐÊÎÑÑÐÑÑÏÎÎÎÎÍο¼ÅÅÆÅÂÄÄÁÂÄĺ¶¶³¡Š…ƒ�|yywojlmle_[YXSKB966Wz‚€|ƒ‡Ž“”’“—œŸ£¢œ˜–�ˆ€oT?68951/57AJENdt}…Œ…\N[_`aa[\`^\^ba_``_]]\Z[]^_\WZjxsci’¿ÎÉÉÌËÉÄÄÆÅÈÌÌÍÑ»ˆÕÜÖÍÏÅÉÍÐÒÏÐÒÎÌÍÎÍÌÊ»»ÇÅÃÆÅÅÈÇÅÂÂÀ¹º»µ›‰†ƒ}vvwrnmklga]VSMD=<<8Mw‚„€{}�ƒˆ‘•”–™�¡§©¢�œ•ˆxaT[_`_`^ZQC601468;=<5&'In{jU[nzƒ‹€[R]ba^`dea^\^aa`_^__^]^_^^^_]Z\euyic‚´ËÉÉÉÇÆÄÆÉÅÈÌÍл‡ÓÝÚÏÓÊÍÐÎÐÑÕÖÒÏÌÌÍÍÈÃÆÈÆÆÈÇÇÈÉÈÄÃÁ¾¾¾»­‘…}vttsutoligda^TLFBDD>Fq„…‚{y}ƒŒ�‘”˜›ž£ª©¤ —†tgo{{x{„Ž–—ŒwbMBCEHIJD=Kn‹’„nemx‚‰|`\_[WSQUVUVRQZabb`a``____\[\\Z\\`oxqdt£ÇÌÅÃÅÆÉÉÆÇËÍй†ÓÜÝÝÒËÌÏÒÓÒÑÒÐÐÎÈÊÌÊÉÉÉÉÈÈÈÉÈÇÈÇŽ¼¿¼¹Ÿ†y{|zytqqiddc_VPNMKKBBjƒ…ƒ{wy{~‡��‘“—™�¥¬¨¡•…zz€ƒƒˆŽ�‘𢧩¥œ‘†€ylijmyˆ––‹€tqw†ya^YSRROQMJKMMV\ZUTW[_````a^\\Z[\XYfusch”ÀÊÅÃÅÈÇÇÈÇÉк‡ØßÜÖËÊÎÑÏÏÓÎÍÊËÏËËËÌÍÈÈÉÈÈÇÉÉÈÉÈÆÅÁ¼¾½»±•ˆ‡…�{uvuoife_\ZYSTPACf��{vvy{‚‹�Ž�’”–œ¥¥ž”‹†‡‰‡‹—œ˜’��”ž©³µ°­£•‘�‹†Š��Š„{vw|ƒr][XXXVUVSPPTWPNLFDHV^^__ada`_][Z[YW^mria€³ÉÆÁÂÃÄÈÅÇͺ†×ÝÙÕËÎÑÏÀÅÒÓÑÍÌÎÍÎÌÊÉÊÉÉÉÉÉÉÉÊÊÉÅÃÃÀ½½¼½«�І‚|yxutrpkeca][YNBDaz€€zsquwzƒ‹�Œ���‘–š˜––•—™˜˜˜˜–•“���”𠤍¦¡›”‹„ƒƒ†ˆ„}zx{~jZYYZYYWUTUVWYSLIGGP[^^]]_a`aa^\[[[ZV[hsnbs¡ÃÅÀÂÃÇÈËË·‡×ÜØÑÌÐÑÐÊËÒÓÍÎÑÎÎÎÌÌÊËÇÅÊÉÈÊÊÇÇÉż¸¼¾¼¼¼¶š‡†„‚€|ywtrqlfbbb`WOUTGk}zrnpsv|…ŠŠ‰Š�ŒŒ�’”˜ž¢¥§¤�—“����І†‰Œ�ŒŠ…‚€}}~‚ŒŒ{z~wd\[ZYX[\WUVTTTUQLOW__ZWRPQTVTW[]_\Y[[ZY_qteg�»ÊÅÃÇÈÊθˆÙÞÖÍÍÏÑÓÔÏÏÏÍÍÏÐÎÍÎÌÎÌÅÇÇÀÄÈÉÄÅÇȼ·¼¿¼»º·¤‡‡‡…ƒ€|urrplidhh`[Vnw@Rt|{tnkoru{ƒ†„‚‡Š‰‰Œ�–ž¡£¥¥¡š“Œ†‚~}{zzzzyzxvvwxŽ•‰€}~n^^\\[YY[XUUQRVUQUX]ZSLLLMNMLGKVXZ\]\Z[[Y\kvja€µÊÅÃÆÉ͹‡ØÝÒËÍÎÒÓÒÎÎÏÓÎÉÑÍËÍËËÌËÌÈÅÉÊÉÆÈÊÊÄÄý¼¼º·­”Œ�ˆ…ƒ}stxvoighdbc_s‰cFeuxtniknos|‚‚��„‰�“™� ¢¥¦¢š“�†~xtsqomnqrromnqw�Ž˜˜‘…xe]^]\\]][XWTSUWUW_\UQOKKNNPNJGKMKOY^[[\^^Y[gsnbt¥ÃÅÂÇÌ·‰ÕÖÌÊÌÏÓÔÐÏÍËÐÎÊÌËÍÍÎÌÍÎÌÍÍÌÌÌËÊÊÈþÁÀ¾¾½»¶­—�‹‡†‚}|{yslggfhicr……RUjttojiknqv{}}zy}ƒŠ•›ž¡¢¥¦¡š”�Š€ytpmihiiiiggkry„‘˜œ›Œr_^_^\\^^^\[Z[YWY^_XRQSTQPMONLLMJINZ`b`_][Z[X_qxkl‘ºÅÅÌ·ˆÖÓÉÊËÐÓÖÒÏÍÊÌÏÊÂËÏÏÎÎÍËÊËÊÌÎÎÌÊÈÉýÀ¿¾¾À¿»º¤ŽŒ‰†‚�‚~xsnmnpnjfuy�mO`krnkigjmpuxwutuy€Œš£¤¡  žš”‘�…}vqmkjiihggjpv|ˆ“—œœŒm^^__\]\]_^\^]\]]]XTTRQRRQSROPQPNJLX`eb^][YZZ[bq~n`|ªÄÊ·†ÖÔÉÊËÐÓÇÅÎÉÍÏÍËÉÌÍÏÍÍÍÉÉÇÈÌɺÄÊÉÌÌÇÀ½ÀÁÀ»º¼³™Š‡„€ƒ�{rqusqkjws‹ŠZZemnlkhfhkotvspry€Š˜ ¢¢ Ÿ�›˜–’�ƒzuqomjhggkpuy��™œ œ„f__^^]`_]^^]^^]\[XVVUUTSSRSRPRRRPKLQZab`]][YY\_]gvqaoœ¼¶‡ÔÑÊÍÌÌÓÅÀËÆÊÏÊÌÍËÍÍÍËËÌÊÆÈËÇ»ÃÉÊËÊÇÂÃÃÃÁ·´·¼ª�‡„�‚…ƒ‚€{wwusmjyr|•rZcimnlkhiijorpoqv€‹“™žŸŸŸ�œ›˜”‘‹„}vqmifgimqu{Œšž¡¡™{`]_]\^_`_^__^^^[YYYYYYXWUTSSQPORRLJO^dca_^^ZVW\[W`rtgj‹¥ˆÒÍËÐÑÏÐÓÏÐÎÂÂÅÉÌÎÊÌÏËÉËÊÈÈÉËÍËÊËÊÉÈÇÆÃÃÁ¹´·º¹¡�‹ƒƒ…‚€}~~zxunj{yo‘Šb^fjnonkhiijlnoor{†Œ’—›ž�ššœœ™—”�†~vpljknpu~Œšž¡Ÿ›�t]\^]]]_`___^]^__^\[\]\YYXWVWUSSRRMJQZXTX]__[YWWYYVWhtpir‡ÎËÍÑÔÓÒÒÑÌÍÌÄÄÊÌÇÈÐÑÎÊÊÌËÉÉÊÉËËÌËÊÈÅÆÄÅÁÀ¿À»¾³˜�ˆ…„�€}}~~|xqm}‚l‡›s\cglnomggihknnqtw‡Œ“™›œ›šž¢¢Ÿ�›™•�‰…��„‰‘›¡¢¡Ÿœ”‡l\[[_`__^^__^__^^]\\]\[ZYWVYYYZZTQSSPLGIPVZ[^`ZXVVWUWbqpc†ÊËËÎÒÑÐÑѸ»ÓÏËÊÊÆÌÑÎÎÉÁÊËËËËÊÊËÌËÉÇÅÆÇÿÀÂÀ¿¾»¥�Ž‹‡ƒ�||}|{tq~„ll˜�gbfggjmidffilnqrsyƒŠ��“–šœŸ¡¤¤¥§§§¦¤¡žž ¢¥§¤¤£Ÿ˜�‚dYYX]^_^^__^_``_^]]^][Z[[XX[[WVWTQTTMIHPX[\\]a`ZXYYZZUZjq…ÈËÏÏÑÐÍÐϾ¼ÊÏÐÌÉÎÍÍÌËËÅÊÊÌÌËÉÉÊËÉÊÈÇÆÆÁ¼¼»¼ÁÀ½µ›��‹…ƒ€~~}zzxv~„o\zœ~cfedejjcddeijklosz„Š�”™� ¢¤¤£¡£¦§¦¦§¦¥¤¤¢¡¥¤œ’�z]VWWXZ\]^^^__````^]_][\\\\]][WTUWUQNLKIJMPRXYY^^\\[[^]X[gƒÈÌÌÕÓÐÏÉÊÏÎËÌÏÎÏÐÏÍÌÌÎÎÌËÌÌÊËËÊÉÉÌÊÈÇÇÆ¾¼»¼ÁÁ¿¿®•��Іƒ�‚‚~|x}„ta_‹–ldhfddgebbcceghijmu‡�“™œž¡¢¡ žŸ¡¥¥¥¤¥§¦¥¢¤¦ •�‰mVTUVWY[[Z[\^^\]^_`_`_]]]]\]\[YXWVTSPONLJIGDPYZ\_^^[Z[]][XƒÈÎÌÏÏÍÍÆÊÍËËÌËËÐÑÑÏÎÍÌÊËËÌËËÎÍÊÊÉËÊÉÈÇÆ½¼Ã¿½¾»¸¢‘��‡„ƒ„„ƒ‚€{}ƒudZoœˆgfgeabda_`_adeeeiox…ŠŽ’˜™› ¢¡ ¢¥¤¢ £¥¦¥¢ Ÿ—Ž‹�cVWWXZZZ[Z[[[\Z[[[_`a`^^_]Z[\YYZXTTTQQSTSSPINY[^^]]\Z\^][WƒÊÏÑÈÊÎÎÎÎÎÊËÎÍÌÎÑÐÏÍËÎËÇÊËÊËÌÌÌÍÌÌÊÉÈÇÅ¿Àþ¼¿»»²˜��‰†‰ˆ…„ƒ‚€�ve]Z… |cehd^^a][^^_cdfhhmv~‚„ˆ�”˜�ž £¤¢Ÿ››š™��›—”‹„ƒt\WWWXZXWWWZZXWVUVWY[]]\]\\Z[YVWXWWVTSTUVTROMP[^]\\\``bb]ZX„ÎÑÏÏÒÓÎÎÎÏÒÏÎÏÐÑÑÎÌÎÌÉÉËÌÊËÌËËÌËÍÍÈÇÊÉÇÄÄþ¼À¿½¼½§‘މ‰Œ‰………„ƒ�‚zh]Ue•›zbac\Z[ZUZ]]`acefhlsz~€„Š‘•–›žž�›™—–—•‘��Šƒ{eTRSUUVVTSTWXXVURQSTUUSUUX[ZYVTTUVXWXYWTTXTOKR]`\\`__`aa^\[…ÎÑÑÓÔÓÏÍÍÍÏÏÍÏÏÎÏÍÍÏÎÆËÐÎÎÎÎÍÌÊÊÊÇÂÆËÊÆÅÄÆÄ¿ÃÀ¿À¾¸›��ŠŠŠ„…‡†„‚ƒ{j`XSp•™~ic]XWVPOV\^]\`cdfjpvxy{€…�“’”––——˜—�Œ‹ˆƒ}wjPLPQQTVVUUUUWVSUUQOOPQQQSWWURTSQQTZYXXVSSWUROW`]Y[]\YU\aa_Z„ÎÍÌÒÑÐÏÐÏÎÎËÉËÌÏÌËÍÎÏÍÈÌÏÎËÌÌËËÍÌÈÆÆÈÉÆÃÃÃÇÄÁ¾¿Â¿¿­“�Œ‹‹ˆ‰‰‡„„ujbZTXkƒŽ‹|cYUUQJJSZ]\\]_cfgkruusw„…‡Š�’““�‹‹‡€{vqbQJILOSRQSTSQPMKLLLKKOUWVWXVSUXZXUWXVVVUUVURQV^_[\YOQXWZ]^]U„ÐÑÏÔÓÑÑÐÐÐÎËÊÈÈÌÍÎÎÎÏÎÇËÎÍÌÌËÌËÌÎÌÉÅÇÈÄÄÆÃÄÿ¾¿ÀÁ¾¼¤‘��Œ‹ŒŠ†„…{podZUTYclv†q\SRQJBDOY^][Z^`acinpnlosuy~‚„†‡†ƒ€zurqj`a\PHINLLMKJHFIGFFHJJMTSUUVWW[ZZ\[[XYYYUSUUSV^_YY\XRSX_][\XV„ÏÕÔÔÔÒÒÐÍÌÍËÍÎÉÈÍÏÎÍÍÎÊÊËÌÎÏÍÍËÌÍËÊËËÇÆÇÅÆÅÄÀÁÂÁÁ¼¾²˜’�Œ‹Œ‰‡ŒŒˆxphZQQX]][lxfXNOMF?BMWZYXX[]`beiigefgkopsvxyvqnkkeUSU^cZIBFIIEBABFHHKKKKLNPOMORXZYXVVVTVVXUSUVW_a\UVYYXYY\\[ZQKƒÏÕÔÓÑÑÐÉÊÍÏÎÎÐÎÏÏÎÎÎÌÌËËÌÊÉÎÎÉÈÌÌÉÈÊÊÇÆÁÅÉÆÇÀ¿Â¾½·§–’ŽŽ�ˆŠ””‘’ye[SQTZZ`_prcTLMJC<@LSUVVVWZ\^bdedbcddefhjjjgebmdDIIMZfbLAEFECDFDDGIJNPQPSSSSQSVUTRSWVUWWUUUX[aa\WWXWUUYWXWRMK„ÐÒÎÐÐÑÏÈÊÎÎÐÏÏÏÐÏÏÏÐÏÍÍÍÌÉÈÈÉÊÇÈËÉÆÉÉÆÁ»ÆÅ¿ÂÅÂÃÃÂÁÀ¼¸ ’’‘�ЅДЖ�oZRRRWWYcerk_QFHGA:>JRSSRRTVY\]_aaba_^`abba^_j€mA@CGMWejTACIKMNJHIIJLORRRUTPMMQRSUX[[Z\[ZZZ^`dec`_YUUTXWXVVTP„ÐÑËÌÍÑÒÏÍÏÎÐÒÐÎÏÍÍÎÏÎÎÎËÈËÆ¿ÈËÉÊÌÊÈËÇÀÇÆÅ¿ÁÆÃÄÄÂÁÀ½¼­”‘‘��‰�ŠŠ‡“…gOLRSVTZbhsh]KBED>9=HNONNPSUUTUW[\[Z[]]\ZZ`n~‰oA<>CIOWhnV@CHIKLMOPQLLMLKLJHHNQRRUVVXXXX\abbeggghc\YXYXWVTY\S‚ÏÔÌËÌÍÏÍÌÌÊÎÒÑÍÍÍÍÎÎÌÍÍËÈÌÉÆÉÇÊËÊÇÆÉÇÅÇÇÇÈÃÄÁ¾ÅÅÄÃÀ¼º²œ’‘•¢ �w‡‡…„ybJIPRPP[akrcZJ??@>9;CJLLNOSSQPRSRSTSRQPVbn{‚†oB<>@DMU\jrZ=BEJS[blu[<79AECFHILNPSQLQQNOSTQPRSSTTVWY__ZZ[\[ZVTUWVTVSTW†ÐÓÎÌÉËÉÈÎÌËÐÏÎÎÏÐÐÏÎÎÌÎÇÇÈÄÄÆÈÌÌÉÉÉÊÇÇÊËÇÅÃÃÇÈÇÄÅÿ¿·´¶¥Ÿ Ÿ¤Ÿœ‰‡�}ttvhN?FNMQ[bqkZWJ<7:=>AEIHHIJIHHIKKLPV\bhow~�†p@9=DGJSY_eqy]BA=?CEEFIMPRWUUXWUUTPORUVUQOPSY\YVX[[\WUVUTQORW[…ÏÑÌÉÊËÍËÍÍÌÏÐÏÏÏÏÏÐÏÎËËËÌÅÅÇÆÇÊÌÇÇËÌÉÇÈÈÆÃ¿ÃÈÈÆÅÆÆÅÀ¿½¹±©›“�ž¡”‚ŒŒxntvkTA@JMRZbobUTK>68GMTXan]OOKA969BGKMNMNMNOQTX\aekpv{~�…p?59;BLRY`fnt{‰¢šmRD=AHJIIIMPSWYXRIKMMMLMRTRVZURORTNNSYZ[_bbb`„ÎÏÍÌÈÊËÎÉÇÎÏÍÌËÌÍÍÍËÎÏÍÍËËÉÊËËÉÊÉÊ»½ÊÇÉÉÈÄÀÁÅÈÈÇɼ¨¹¾º¯§¢Ÿ”•¢£¦›‰„‰{ofhnueLABKTYcjYOKHB<9DLLKMNQSUVUMHMONMLNNMPOQST[[WV\^^a^VTSWƒÍÐÌËÉÌËÌÌÍÐÏÏÏËÇÌÍËÊÏÌÌÎÐÎÊÊÊËÊÊÈÈÄÅÈÇÉÇÅÇÆÇËÇÂÁÁº¯±©¤¤¤¡¢™”Ÿ¥ª Œƒ‰‡vnhdpogXF@GOUhoXMGDCA=>EMPRRSRSV[_chlrux|~€‚o>06:BMU\_grwxuKDdz†~\JA>DJLLNQRTVUNQXTRUSRSTRW^]\VSTT[^TZz�•h…ÍÌÉËÈÉÊÍÌËÊÊËÎÌÊÎÌÊÍÎÌËÌÍÌÌËÌËÉÆÄÇÎÊÇÇÈÉÉÇůĹ­©§ª¬£›–˜žŸŸ›Ž�‘˜˜‰„‡uxoebdkm`THCHQhdVPIDBA?AIORUTSUW]bfknruz~€��p=/6:BLW\dtƒ‰‡vM65BVlv|fOA;BJMLMPRRTX^\\`]VVXSNPSS[bixu_i—Íáâ©„ËÉÉÊÈÉÊÏÌÇÄÉËËÉÉÌÌÊËÌÌÌËÉËÍÈÅÈÆÅÃÆÇÅÆÆÆÆÂ¹´±®¬¨¦¥žšœ�—�—›œšŠŠˆzsz€ˆ‰|torkacgikcZOJXdVRNIECABHLOQQTX[^cgjntx|}€rA-49BMVayˆŽ�ŒmKIB;6;_�—’oKB=EJILQQSTPPONNNTT^xŒƒs‘¦¦’m„ÄÏÔââÉ‚ÈÊÈÇÄÉËÆÈÇÈÌÎÌÉÆÅÃÇËËÇËÌÊÌÎÈ¿ÃÄÂÂÄÂÃý´­ª¨§«®°¬£™–™�ž‘‹‘›ž�Œ—†z‡�†‰knytid`bdins‚ˆˆwdYNFBCEFHKOSW\`bcglquxz|~~{rG-29BP]vˆŒŒ‹„_CDIMH<;Uy’�‹†hC?ACEHKMOQUY[]\WVU<+0):]gbUO\adkG8<<<=<>?8/.3JswZwœtcagsz~~xpnwwxyz}|x{~~}}~~tƒƒˆˆˆˆ‰‰‰‰ˆˆ‰‰‰‰‰‰‡‡ˆˆ‚‚yy{{zzyyxxttppwwyyvvttvvvvvvxxxxxxxxyyyyxxvvssppssvvuuvv||€€||yyyywwvvvvwwwwvvzzyywwrrqqvvwwxxvvvvvvuuvvyysssswwxxwwuuttyywwppssttuuuuyyttrruurruuuuqqvvƒƒˆˆˆˆ‰‰‰‰ˆˆ‰‰‰‰‰‰‡‡ˆˆ‚‚yy{{zzyyxxttppwwyyvvttvvvvvvxxxxxxxxyyyyxxvvssppssvvuuvv||€€||yyyywwvvvvwwwwvvzzyywwrrqqvvwwxxvvvvvvuuvvyysssswwxxwwuuttyywwppssttuuuuyyttrruurruuuuqqvv††’’’’““’’””““““““‘‘‘‘‡‡yyzzwwssssvvxxvvttuuvvvvvvwwxxxxyyxxxxvvrrrrssttvvxx||~~||zzyyzz{{{{{{{{||{{yywwzzyyvvrrsswwxxwwwwuuuuuuuuxxttttwwxxwwvvuuyyvvppssuuttwwyyssttttuuvvttuu††’’’’““’’””““““““‘‘‘‘‡‡yyzzwwssssvvxxvvttuuvvvvvvwwxxxxyyxxxxvvrrrrssttvvxx||~~||zzyyzz{{{{{{{{||{{yywwzzyyvvrrsswwxxwwwwuuuuuuuuxxttttwwxxwwvvuuyyvvppssuuttwwyyssttttuuvvttuu€€ƒƒ„„ƒƒƒƒ‚‚€€��€€€€��wwttssuuxxwwvvvvvvvvwwwwwwwwwwxxwwttssrrssuuvvzz}}||{{yyxx{{}}~~€€€€€€€€}}{{{{xxvvttttwwxxwwuuuuvvttvvxxssttwwvvwwuuuuxxuuqquuttsswwxxrrssuuttuuuu€€ƒƒ„„ƒƒƒƒ‚‚€€��€€€€��wwttssuuxxwwvvvvvvvvwwwwwwwwwwxxwwttssrrssuuvvzz}}||{{yyxx{{}}~~€€€€€€€€}}{{{{xxvvttttwwxxwwuuuuvvttvvxxssttwwvvwwuuuuxxuuqquuttsswwxxrrssuuttuuuu~~||||||||zzxxxxyyxxvvssssttvvwwxxxxvvvvvvwwwwwwwwvvuuttrrssttuuwwzz}}||zzyyyyzz}}€€€€€€€€€€€€€€~~||yywwsssswwxxwwvvuuuuttvvxxssttwwwwvvuuvvzzuurruuttttyyxxrrttttssvv~~||||||||zzxxxxyyxxvvssssttvvwwxxxxvvvvvvwwwwwwwwvvuuttrrssttuuwwzz}}||zzyyyyzz}}€€€€€€€€€€€€€€~~||yywwsssswwxxwwvvuuuuttvvxxssttwwwwvvuuvvzzuurruuttttyyxxrrttttssvv€€}}||||zzxxxxxxttrrssvvwwssttvvxxwwuuuuvvwwvvvvuurrrrssttuuxx||}}{{yyyyzz{{}}€€€€€€€€€€€€€€€€€€€€~~yyvvsssswwwwvvvvuuuuttuuwwrruuxxwwvvttwwzzssqqttttttzzwwrruusstt€€}}||||zzxxxxxxttrrssvvwwssttvvxxwwuuuuvvwwvvvvuurrrrssttuuxx||}}{{yyyyzz{{}}€€€€€€€€€€€€€€€€€€€€~~yyvvsssswwwwvvvvuuuuttuuwwrruuxxwwvvttwwzzssqqttttttzzwwrruusstt}}||zzvvssttsssswwvvuussrruuwwxxwwuuttuuvvttrrqqrrttvvyy||||zzyyyyxxzz}}€€€€€€€€€€€€€€€€€€€€}}yyvvssrrvvwwwwuuuuttrrttwwrruuwwvvuuuuxxxxssrrssuuwwzzuurrttuu}}||zzvvssttsssswwvvuussrruuwwxxwwuuttuuvvttrrqqrrttvvyy||||zzyyyyxxzz}}€€€€€€€€€€€€€€€€€€€€}}yyvvssrrvvwwwwuuuuttrrttwwrruuwwvvuuuuxxxxssrrssuuwwzzuurrttuu{{vvttrrsswwwwxxvvuuuusssswwxxwwwwuussssqqrrttttvvzz||||zzxxxxyyyy{{~~€€€€€€€€€€€€||yywwsssswwxxvvuuttttssttvvssuuvvvvvvvvxxyyrrppttvvxxzzttqquu{{vvttrrsswwwwxxvvuuuusssswwxxwwwwuussssqqrrttttvvzz||||zzxxxxyyyy{{~~€€€€€€€€€€€€||yywwsssswwxxvvuuttttssttvvssuuvvvvvvvvxxyyrrppttvvxxzzttqquu~~vvvvttwwxxyyvvttuuvvuurrttwwxxwwttqqpprrssuuxxzz}}{{yyxxxxxxxxyy{{€€€€€€€€€€€€€€€€€€||zzyyvvttssvvwwwwuuttssrruuwwrrttvvwwwwvvxxyyrrssuuvvxxxxrrtt~~vvvvttwwxxyyvvttuuvvuurrttwwxxwwttqqpprrssuuxxzz}}{{yyxxxxxxxxyy{{€€€€€€€€€€€€€€€€€€||zzyyvvttssvvwwwwuuttssrruuwwrrttvvwwwwvvxxyyrrssuuvvxxxxrrtt~~{{xxvvyywwvvuuvvvvvvssssuuwwuurrqqqqttuuxx||~~||yyyyyyxxyyyyxx{{€€€€€€€€€€€€€€€€€€€€zzyyzzwwttrruuwwvvuussssttvvvvrruuwwwwwwuuyyyyrrttvvvvxxxxtt~~{{xxvvyywwvvuuvvvvvvssssuuwwuurrqqqqttuuxx||~~||yyyyyyxxyyyyxx{{€€€€€€€€€€€€€€€€€€€€zzyyzzwwttrruuwwvvuussssttvvvvrruuwwwwwwuuyyyyrrttvvvvxxxxtt€€zzuuttwwwwvvuuvvuuttssttttqqqqqqrruu{{}}||{{yyyyyyyyxxyyyyyy{{€€€€€€€€€€€€€€€€€€€€€€€€€€~~xxyyzzwwttqquuvvvvuussssssvvvvssvvwwwwvvuuyywwrruuuuvvxxxx€€zzuuttwwwwvvuuvvuuttssttttqqqqqqrruu{{}}||{{yyyyyyyyxxyyyyyy{{€€€€€€€€€€€€€€€€€€€€€€€€€€~~xxyyzzwwttqquuvvvvuussssssvvvvssvvwwwwvvuuyywwrruuuuvvxxxx€€yyttuuwwwwvvvvvvuussqqppqqqqrruuzz}}||yyxxyyyyyyyyyyyyzzyyzz€€€€€€€€€€€€€€€€€€€€||vvyy{{xxssrruuvvuussrrttttxxvvrrvvxxwwvvvvyyvvrrttuuttxx€€yyttuuwwwwvvvvvvuussqqppqqqqrruuzz}}||yyxxyyyyyyyyyyyyzzyyzz€€€€€€€€€€€€€€€€€€€€||vvyy{{xxssrruuvvuussrrttttxxvvrrvvxxwwvvvvyyvvrrttuuttxxxxttvvwwwwvvvvuurrooppqqssuuyy||{{yyxxyyyyyyxxxxyyyyyyzzzz}}€€€€€€€€€€€€€€€€€€€€xxvvyy{{wwttrruuuuttssssuuvvwwuussvvxxxxwwvvzzvvrruuttwwxxttvvwwwwvvvvuurrooppqqssuuyy||{{yyxxyyyyyyxxxxyyyyyyzzzz}}€€€€€€€€€€€€€€€€€€€€xxvvyy{{wwttrruuuuttssssuuvvwwuussvvxxxxwwvvzzvvrruuttwwwwuuwwwwvvttrrppqqrrssvv{{||zzxxyyyyxxyyxxxxxxyyyyyyzzzz||€€€€€€€€€€€€€€€€€€€€||vvuuyy{{wwttrrttuuttttttvvuuvvvvrrvvxxxxxxwwzzttrrttwwwwuuwwwwvvttrrppqqrrssvv{{||zzxxyyyyxxyyxxxxxxyyyyyyzzzz||€€€€€€€€€€€€€€€€€€€€||vvuuyy{{wwttrrttuuttttttvvuuvvvvrrvvxxxxxxwwzzttrrttww~~wwvvxxuurrppqqrrttwwzz||zzyyyyzzzzxxwwxxyyxxyyyyyyyyzzzz~~€€€€€€€€€€€€€€€€€€€€~~€€xxuuvvyy{{xxuurrttvvvvuuvvuusswwuusswwyyyyxxxxyyttrrww~~wwvvxxuurrppqqrrttwwzz||zzyyyyzzzzxxwwxxyyxxyyyyyyyyzzzz~~€€€€€€€€€€€€€€€€€€€€~~€€xxuuvvyy{{xxuurrttvvvvuuvvuusswwuusswwyyyyxxxxyyttrrww}}vvvvssrrqqssuuxx{{{{yyxxyyyyzzzzyyxxwwxxxxyyyyyyyyyyxx{{€€€€€€€€€€€€€€€€€€€€€€{{uuvvuuxx||xxttppttwwvvwwuuttttwwuussxxyyzzyywwxxrruu}}vvvvssrrqqssuuxx{{{{yyxxyyyyzzzzyyxxwwxxxxyyyyyyyyyyxx{{€€€€€€€€€€€€€€€€€€€€€€{{uuvvuuxx||xxttppttwwvvwwuuttttwwuussxxyyzzyywwxxrruu}}ttrrqqttww{{}}zzxxxxxxyyyyyy{{yyxxxxxxxxxxyyyyxxuuttxx€€��€€€€€€€€~~€€~~vvuuvvvvyy{{wwssqquuvvwwvvuuuuttwwuussxxzzzzwwwwwwss}}ttrrqqttww{{}}zzxxxxxxyyyyyy{{yyxxxxxxxxxxyyyyxxuuttxx€€��€€€€€€€€~~€€~~vvuuvvvvyy{{wwssqquuvvwwvvuuuuttwwuussxxzzzzwwwwwwss||rrttxx||}}||yywwxxxxxxxxyyyyzzyyyyxxxxwwxxvvttttuuvv}}��€€€€€€xxuuvvvvvvxx{{xxttrruuxxwwvvttttttxxttttyyzzxxuuvvyy||rrttxx||}}||yywwxxxxxxxxyyyyzzyyyyxxxxwwxxvvttttuuvv}}��€€€€€€xxuuvvvvvvxx{{xxttrruuxxwwvvttttttxxttttyyzzxxuuvvyy||xx||}}{{zzzzyyxxxxxxwwyyyyyyyyyyyyxxvvuuttttuuvvvvww~~��€€€€€€€€€€{{uuuuvvvvuuxx||xxttrruuwwvvuussttwwwwrruuyyxxwwuuww||xx||}}{{zzzzyyxxxxxxwwyyyyyyyyyyyyxxvvuuttttuuvvvvww~~��€€€€€€€€€€{{uuuuvvvvuuxx||xxttrruuwwvvuussttwwwwrruuyyxxwwuuww}}zzzzzzzzyyyyxxxxxxxxyyyyyyxxxxuussttuuuuuuuuuuxx}}€€€€€€€€€€€€}}vvuuuuuuvvvvxx{{yyuurrttwwwwuuvvxxwwuussttwwwwvvww}}zzzzzzzzyyyyxxxxxxxxyyyyyyxxxxuussttuuuuuuuuuuxx}}€€€€€€€€€€€€}}vvuuuuuuvvvvxx{{yyuurrttwwwwuuvvxxwwuussttwwwwvvww{{zzzz{{{{yyxxxxxxxxxxxxxxvvttssttttuuuuuuwwzz||}}||€€~~~~~~~~}}~~~~~~€€yyuuvvvvvvvvvvxx||zzuurruuwwuuvvxxvvttvvrrsswwvvxx{{zzzz{{{{yyxxxxxxxxxxxxxxvvttssttttuuuuuuwwzz||}}||€€~~~~~~~~}}~~~~~~€€yyuuvvvvvvvvvvxx||zzuurruuwwuuvvxxvvttvvrrsswwvvxx||zz{{{{zzyyxxwwwwwwwwuussssttuuuuttuuxx{{||}}{{zz{{€€~~}}||zzyywwvvvvuuuuuuuuuuvvwwwwxxyyzzzz{{{{||||~~{{wwwwwwvvvvvvwwxx{{yyuussssttvvxxvvttttvvrrssvvyy||zz{{{{zzyyxxwwwwwwwwuussssttuuuuttuuxx{{||}}{{zz{{€€~~}}||zzyywwvvvvuuuuuuuuuuvvwwwwxxyyzzzz{{{{||||~~{{wwwwwwvvvvvvwwxx{{yyuussssttvvxxvvttttvvrrssvvyy{{zz||zzyyyyxxwwttssssssssttttttwwzz||||||zzzz{{zz||~~||zzwwuurrppoonnmmlljjkkkkkkkkkkmmoooommmmooppppqqrrssttuuvvvvvvwwwwwwwwxx||zzuurrsswwwwvvttttuuwwrrsszz{{zz||zzyyyyxxwwttssssssssttttttwwzz||||||zzzz{{zz||~~||zzwwuurrppoonnmmlljjkkkkkkkkkkmmoooommmmooppppqqrrssttuuvvvvvvwwwwwwwwxx||zzuurrsswwwwvvttttuuwwrrsszz{{zz{{zzxxvvuurrqqssttssssuuww{{}}||{{{{{{{{{{{{zz}}€€€€}}{{vvssqqooookkgggghhhhiikkmmoooooooopprrppmmiigggghhjjllqqqqrrrrrrrrssttvvwwvvxx||yyuurruuxxvvuuuuuuvvvvqqvv{{zz{{zzxxvvuurrqqssttssssuuww{{}}||{{{{{{{{{{{{zz}}€€€€}}{{vvssqqooookkgggghhhhiikkmmoooooooopprrppmmiigggghhjjllqqqqrrrrrrrrssttvvwwvvxx||yyuurruuxxvvuuuuuuvvvvqqvv{{yyxxuussrrssssssttttww{{||{{||{{zz{{{{{{{{zzzz{{~~€€€€||yyssnnjjkkiiggggeeffkkooqqrrssttuuuuuuvvttssttttqqllggddcchhooqqrrssttttssssssvvvvwwxx||zzuussvvwwuuuuttuuuutttt{{yyxxuussrrssssssttttww{{||{{||{{zz{{{{{{{{zzzz{{~~€€€€||yyssnnjjkkiiggggeeffkkooqqrrssttuuuuuuvvttssttttqqllggddcchhooqqrrssttttssssssvvvvwwxx||zzuussvvwwuuuuttuuuutttt~~wwuussssttssssuuwwzz||||||zzyyzz{{{{{{{{zzzz{{zz{{~~}}{{xxrrnnggccbbcccceehhmmpprrssttrrqqqqqqqqqqssssssssttuuqqoojjddffnnppqqrrssttttttttvvwwwwxxzz}}zzvvttttttttvvuuttssvv~~wwuussssttssssuuwwzz||||||zzyyzz{{{{{{{{zzzz{{zz{{~~}}{{xxrrnnggccbbcccceehhmmpprrssttrrqqqqqqqqqqssssssssttuuqqoojjddffnnppqqrrssttttttttvvwwwwxxzz}}zzvvttttttttvvuuttssvv||uuttssttuuvvyyzz||||{{{{zzzzzzzzzzzzzz{{zzzzzzzzzz{{zzwwrrjjggkkddaabbddiinnqqrrppppqqrrppppppooppppqqqqppppqqqqppqqqqllggkkqqppqqrrssssttvvwwwwwwxxyyzz||zzvvssssttvvwwuussuu||uuttssttuuvvyyzz||||{{{{zzzzzzzzzzzzzz{{zzzzzzzzzz{{zzwwrrjjggkkddaabbddiinnqqrrppppqqrrppppppooppppqqqqppppqqqqppqqqqllggkkqqppqqrrssssttvvwwwwwwxxyyzz||zzvvssssttvvwwuussuu||ttttvvxx{{{{||zzzzzz{{zzzzzzzzzzzz{{zz{{zzzzzzzzyyxxuunnffbbddkkhhddiinnrrrrqqrrqqrrrrssrrssssrrqqqqrrqqpppppppppppprrqqjjkkppppqqrrrrssvvwwwwwwvvwwyyyyxx{{zzvvssssuuvvwwttuu||ttttvvxx{{{{||zzzzzz{{zzzzzzzzzzzz{{zz{{zzzzzzzzyyxxuunnffbbddkkhhddiinnrrrrqqrrqqrrrrssrrssssrrqqqqrrqqpppppppppppprrqqjjkkppppqqrrrrssvvwwwwwwvvwwyyyyxx{{zzvvssssuuvvwwttuu||xxzz{{||zzyyzzzzzzzzzzzz{{zzzzzzzzzz{{{{zzyy{{zzxxssmmggddbbbbkknnnnssttrrqqrrssttuuwwwwwwwwwwuussssssssrrrrrrqqrrqqrrrrkkjjqqrrrrqqssttuuwwwwvvvvwwxxwwwwyy||zzvvssttwwwwuuvv||xxzz{{||zzyyzzzzzzzzzzzz{{zzzzzzzzzz{{{{zzyy{{zzxxssmmggddbbbbkknnnnssttrrqqrrssttuuwwwwwwwwwwuussssssssrrrrrrqqrrqqrrrrkkjjqqrrrrqqssttuuwwwwvvvvwwxxwwwwyy||zzvvssttwwwwuuvv€€||zzzzzzzzzzyyyyzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyxxrrppmmffccbbccmmttssssssrrssttvvwwxxzzzzyyyyxxvvuuttssssssssssssttuuttssnnllrrrrrruuwwvvssttwwvvvvvvxxwwxxxxxx||zzvvssttxxuuvv€€||zzzzzzzzzzyyyyzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyxxrrppmmffccbbccmmttssssssrrssttvvwwxxzzzzyyyyxxvvuuttssssssssssssttuuttssnnllrrrrrruuwwvvssttwwvvvvvvxxwwxxxxxx||zzvvssttxxuuvv{{zzzzzzzzzzyyyyzzzzzzyyyyzzzzyyzzzzzzzzyyxxwwrroosskkeeeeeekkssttttssrrrrttvvvvvvvvvvwwxxxxxxwwvvuuttttttttssttuuwwwwwwssqqrrssuuzz{{xxwwttttwwvvvvwwwwwwwwwwxx{{zzvvrrttuuww{{zzzzzzzzzzyyyyzzzzzzyyyyzzzzyyzzzzzzzzyyxxwwrroosskkeeeeeekkssttttssrrrrttvvvvvvvvvvwwxxxxxxwwvvuuttttttttssttuuwwwwwwssqqrrssuuzz{{xxwwttttwwvvvvwwwwwwwwwwxx{{zzvvrrttuuww||zz{{zzzzzzyyzzzzzzzzyyzzyyyyzzzzyyzzzzyyxxuuooqqssjjeeffmmttuuuussssssuuuuvvuuuuvvuuvvvvwwxxwwwwvvuuuuuuuuttttuuvvvvxxvvssttwwwwxxzz||zzwwuuuuwwvvwwwwwwwwvvwwxxzzyyuuqqssxx||zz{{zzzzzzyyzzzzzzzzyyzzyyyyzzzzyyzzzzyyxxuuooqqssjjeeffmmttuuuussssssuuuuvvuuuuvvuuvvvvwwxxwwwwvvuuuuuuuuttttuuvvvvxxvvssttwwwwxxzz||zzwwuuuuwwvvwwwwwwwwvvwwxxzzyyuuqqssxx||zz{{zzzzyyyyzzyyyyyyzzzzzzyyyyyyyyxxxxuuuuttppqqssnnggllttxxuuttssttuuwwvvuuuuttttuuvvuuvvxxwwwwvvuuuuuuuuttuuuuttttuuvvuuvvxxwwvvxxzz||yywwvvttuuvvvvvvwwwwwwvvwwyyzzuuqqtt||zz{{zzzzyyyyzzyyyyyyzzzzzzyyyyyyyyxxxxuuuuttppqqssnnggllttxxuuttssttuuwwvvuuuuttttuuvvuuvvxxwwwwvvuuuuuuuuttuuuuttttuuvvuuvvxxwwvvxxzz||yywwvvttuuvvvvvvwwwwwwvvwwyyzzuuqqtt{{yyzzzzyyyyzzyyxxyyyyyyyyzzyyxxvvvvuuvvvvwwvvrrrrttqqkkppvvxxuuttttuuvvwwvvuuuuuuuuuuvvvvvvxxxxwwvvvvvvuuttttuuvvuuttttuuuuvvxxxxvvvvxxyyzzyywwuussvvwwwwwwwwvvvvwwvvzzxxtttt{{yyzzzzyyyyzzyyxxyyyyyyyyzzyyxxvvvvuuvvvvwwvvrrrrttqqkkppvvxxuuttttuuvvwwvvuuuuuuuuuuvvvvvvxxxxwwvvvvvvuuttttuuvvuuttttuuuuvvxxxxvvvvxxyyzzyywwuussvvwwwwwwwwvvvvwwvvzzxxtttt{{yyzzyyyyyyyyyyxxyyyyxxwwvvuuuuuuvvvvwwvvuuuuuussrrrroossxxxxuuuuuuuuvvvvttttvvvvuuvvwwvvwwwwyyzzwwvvttttvvvvvvvvvvuussssttvvwwxxwwvvxxxxxxzzzzwwuussvvwwwwwwvvwwwwwwwwyywwvv{{yyzzyyyyyyyyyyxxyyyyxxwwvvuuuuuuvvvvwwvvuuuuuussrrrroossxxxxuuuuuuuuvvvvttttvvvvuuvvwwvvwwwwyyzzwwvvttttvvvvvvvvvvuussssttvvwwxxwwvvxxxxxxzzzzwwuussvvwwwwwwvvwwwwwwwwyywwvv{{zzzzzzxxyyxxxxwwvvuuttuuuuvvwwwwvvvvvvuuvvvvvvuuttssssvvxxxxuuuuvvuuuuttttuuttuuvvwwyyzzyywwxxzzxxuuttttvvxxxxwwwwxxvvrrttvvwwwwwwwwwwwwwwxxzzzzwwvvssuuwwwwvvvvwwwwvvvvxxzz{{zzzzzzxxyyxxxxwwvvuuttuuuuvvwwwwvvvvvvuuvvvvvvuuttssssvvxxxxuuuuvvuuuuttttuuttuuvvwwyyzzyywwxxzzxxuuttttvvxxxxwwwwxxvvrrttvvwwwwwwwwwwwwwwxxzzzzwwvvssuuwwwwvvvvwwwwvvvvxxzzzzyyyyyywwwwvvttttuuvvvvvvvvvvvvvvwwwwwwvvwwwwvvuuuussvvxxyyxxvvvvvvuuttttttttttvvxxyyzzyyyywwwwwwuuttssrrvvyyyyyyxxxxvvssuuwwwwwwwwvvvvwwwwwwwwzz{{xxvvssuuwwvvvvwwwwvvvvvvyyzzyyyyyywwwwvvttttuuvvvvvvvvvvvvvvwwwwwwvvwwwwvvuuuussvvxxyyxxvvvvvvuuttttttttttvvxxyyzzyyyywwwwwwuuttssrrvvyyyyyyxxxxvvssuuwwwwwwwwvvvvwwwwwwwwzz{{xxvvssuuwwvvvvwwwwvvvvvvyyzzxxwwuuttttuuuuuuvvvvuuuuvvvvvvwwwwxxwwvvwwwwwwvvuuuuuuvvxxwwvvuuuuuuttssssttuuuuvvvvuuvvwwwwwwuussttttssuuyyyyxxxxzzwwssuuwwwwvvwwwwwwwwwwwwwwxxxxzzyyvvttttvvwwwwvvwwwwvvxxzzxxwwuuttttuuuuuuvvvvuuuuvvvvvvwwwwxxwwvvwwwwwwvvuuuuuuvvxxwwvvuuuuuuttssssttuuuuvvvvuuvvwwwwwwuussttttssuuyyyyxxxxzzwwssuuwwwwvvwwwwwwwwwwwwwwxxxxzzyyvvttttvvwwwwvvwwwwvvxx~~vvuuuuuuuuuuvvuuuuuuuuvvwwwwvvvvvvwwwwwwwwwwwwwwvvttrrssttvvvvwwwwuuuuttssrrssttssssttttuuvvvvttssssssttttuuxxyywwuuwwyyuuuuwwvvwwwwwwwwwwwwvvwwwwwwwwzzyywwttttvvvvvvwwwwwwxx~~vvuuuuuuuuuuvvuuuuuuuuvvwwwwvvvvvvwwwwwwwwwwwwwwvvttrrssttvvvvwwwwuuuuttssrrssttssssttttuuvvvvttssssssttttuuxxyywwuuwwyyuuuuwwvvwwwwwwwwwwwwvvwwwwwwwwzzyywwttttvvvvvvwwwwwwxx}}vvuuvvuuvvwwzzzzxxuuvvwwvvwwvvwwvvvvvvvvwwvvvvvvwwrrqqttssttvvxxvvuuttssrrrrrrrrssssttttssttttssssttttttttttwwyyxxwwwwxxwwuuvvvvwwwwvvwwwwwwvvvvwwxxwwwwzz{{wwuuttuuvvvvwwvvxx}}vvuuvvuuvvwwzzzzxxuuvvwwvvwwvvwwvvvvvvvvwwvvvvvvwwrrqqttssttvvxxvvuuttssrrrrrrrrssssttttssttttssssttttttttttwwyyxxwwwwxxwwuuvvvvwwwwvvwwwwwwvvvvwwxxwwwwzz{{wwuuttuuvvvvwwvvxx}}wwxxzz{{{{zzzzxxyyxxuuxxzzzzxxxxwwvvwwvvwwwwvvvvwwqqqqttssttvvxxuuuuuussrrssrrrrttssttssssttssssttttttttttssuuyyxxwwxxxxyyvvuuvvwwwwwwwwwwwwvvvvwwxxwwvvxx||{{vvuussuuvvwwvvyy}}wwxxzz{{{{zzzzxxyyxxuuxxzzzzxxxxwwvvwwvvwwwwvvvvwwqqqqttssttvvxxuuuuuussrrssrrrrttssttssssttssssttttttttttssuuyyxxwwxxxxyyvvuuvvwwwwwwwwwwwwvvvvwwxxwwvvxx||{{vvuussuuvvwwvvyy}}}}}}{{{{zzyywwwwxxvvvvyy{{{{yyxxwwwwvvvvvvwwvvwwssqqttqqqqvvwwuuttttttssssrrssttttssssssttssssuuvvuuttrrqqrrwwwwvvxxxxyyzzvvttuuwwvvvvwwvvvvwwwwwwwwwwxxyyzzzzwwttssuuvvvvxx}}}}}}{{{{zzyywwwwxxvvvvyy{{{{yyxxwwwwvvvvvvwwvvwwssqqttqqqqvvwwuuttttttssssrrssttttssssssttssssuuvvuuttrrqqrrwwwwvvxxxxyyzzvvttuuwwvvvvwwvvvvwwwwwwwwwwxxyyzzzzwwttssuuvvvvxx}}||{{{{{{zzxxwwxxwwwwvvuuwwzz||{{xxxxvvvvwwvvvvwwttrrssoossvvvvvvuuttttssrrssssttssssttssssssuuvvvvuurrooooppttvvuuwwxxyyyyxxwwttttvvvvwwvvvvvvvvwwwwwwwwyyyyzzzzwwuussssttxx}}||{{{{{{zzxxwwxxwwwwvvuuwwzz||{{xxxxvvvvwwvvvvwwttrrssoossvvvvvvuuttttssrrssssttssssttssssssuuvvvvuurrooooppttvvuuwwxxyyyyxxwwttttvvvvwwvvvvvvvvwwwwwwwwyyyyzzzzwwuussssttxx}}{{zz{{zzyywwwwwwvvwwvvttvvyyyy{{||{{yywwwwvvvvvvvvssrroottuuvvwwvvuuttttssssssssttttssssrrttvvuuttssqqppnnoouuwwssuuwwxxyyvvwwxxuuttuuvvvvvvwwwwwwvvvvwwxxxxwwxxyyxxttrrssww}}{{zz{{zzyywwwwwwvvwwvvttvvyyyy{{||{{yywwwwvvvvvvvvssrroottuuvvwwvvuuttttssssssssttttssssrrttvvuuttssqqppnnoouuwwssuuwwxxyyvvwwxxuuttuuvvvvvvwwwwwwvvvvwwxxxxwwxxyyxxttrrssww€€}}{{{{{{{{yywwxxwwuuuuttttuuyyyyxxyy{{||zzxxwwwwwwvvuussqqssssuuxxwwvvuuttttttssssttttttssssuuvvttttssssrrppppuuwwssssuuwwyyvvttwwxxvvttuuvvvvvvwwvvvvwwwwxxwwwwxxxxyywwttrrtt€€}}{{{{{{{{yywwxxwwuuuuttttuuyyyyxxyy{{||zzxxwwwwwwvvuussqqssssuuxxwwvvuuttttttssssttttttssssuuvvttttssssrrppppuuwwssssuuwwyyvvttwwxxvvttuuvvvvvvwwvvvvwwwwxxwwwwxxxxyywwttrrtt€€||{{{{||yywwxxyyxxvvvvvvvvuuvvzzzzyyxxzz||{{zzyyxxvvuuttttssssuuwwwwwwuuuuttuuuuttttttttssssttvvuuvvwwuuttssssvvwwssrrttwwyyvvttuuvvwwvvttttuuvvwwwwwwwwwwwwwwwwwwxxwwyyxxtttt€€||{{{{||yywwxxyyxxvvvvvvvvuuvvzzzzyyxxzz||{{zzyyxxvvuuttttssssuuwwwwwwuuuuttuuuuttttttttssssttvvuuvvwwuuttssssvvwwssrrttwwyyvvttuuvvwwvvttttuuvvwwwwwwwwwwwwwwwwwwxxwwyyxxtttt€€}}||||||zzxxxxxxxxwwwwwwvvuuttwwzzzzxxxxyy{{{{{{zzxxvvuuuuttrrttwwxxwwuuuuttttuuttttttssrrttuuvvwwwwwwvvuuuuwwyyxxttrrssvvxxvvuuttttuuwwwwuuttvvvvvvuuvvvvwwvvwwwwwwwwwwyyxxvv€€}}||||||zzxxxxxxxxwwwwwwvvuuttwwzzzzxxxxyy{{{{{{zzxxvvuuuuttrrttwwxxwwuuuuttttuuttttttssrrttuuvvwwwwwwvvuuuuwwyyxxttrrssvvxxvvuuttttuuwwwwuuttvvvvvvuuvvvvwwvvwwwwwwwwwwyyxxvv}}||||||yyxxyyxxxxwwwwvvvvvvuuvvyyzzyyyyxxxxxx{{||zzwwwwwwuurrrrvvxxwwvvttttttttttttssttssttuuvvwwwwvvuuttuuxxzzyyvvssssvvxxuuuuuuuuuuuuuuxxwwttttvvvvvvuuwwvvwwwwvvvvvvvvwwxx}}||||||yyxxyyxxxxwwwwvvvvvvuuvvyyzzyyyyxxxxxx{{||zzwwwwwwuurrrrvvxxwwvvttttttttttttssttssttuuvvwwwwvvuuttuuxxzzyyvvssssvvxxuuuuuuuuuuuuuuxxwwttttvvvvvvuuwwvvwwwwvvvvvvvvwwxx€€~~||||{{xxyyyyxxxxwwvvuuuuvvvvuuwwzzyyyyxxxxxxxxxxyywwwwwwvvssqquuyywwvvttttttttttssssttttuuvvvvvvvvvvvvttuuwwyyxxxxuuttvvwwuuvvuuuuuuttssvvxxvvttttuuuuuuuuuuwwwwwwvvvvvvuuxx€€~~||||{{xxyyyyxxxxwwvvuuuuvvvvuuwwzzyyyyxxxxxxxxxxyywwwwwwvvssqquuyywwvvttttttttttssssttttuuvvvvvvvvvvvvttuuwwyyxxxxuuttvvwwuuvvuuuuuuttssvvxxvvttttuuuuuuuuuuwwwwwwvvvvvvuuxx€€~~}}||zzxxzzzzyyxxwwwwwwvvvvvvuuvvyyzzyyyyyyyyxxvvvvuuttvvwwttqquuxxxxvvuuttssssttssttttttuuvvvvvvuuuuvvvvvvwwxxxxwwwwvvvvvvuuuuttuuuuttttttuuwwwwttttuuvvvvuuvvwwwwvvvvvvuuxx€€~~}}||zzxxzzzzyyxxwwwwwwvvvvvvuuvvyyzzyyyyyyyyxxvvvvuuttvvwwttqquuxxxxvvuuttssssttssttttttuuvvvvvvuuuuvvvvvvwwxxxxwwwwvvvvvvuuuuttuuuuttttttuuwwwwttttuuvvvvuuvvwwwwvvvvvvuuxx€€}}||{{yyzzzzzzyyxxxxwwxxvvvvvvvvvvwwzzzzzzyyxxxxvvttttsssswwwwssttwwxxvvuuttrrrrssttvvuuuuvvvvuuuuttuuvvvvvvvvvvwwvvvvwwwwvvttuuuuuuuuttttttttssuuwwvvttuuvvuuvvvvvvuuuuuuttww€€}}||{{yyzzzzzzyyxxxxwwxxvvvvvvvvvvwwzzzzzzyyxxxxvvttttsssswwwwssttwwxxvvuuttrrrrssttvvuuuuvvvvuuuuttuuvvvvvvvvvvwwvvvvwwwwvvttuuuuuuuuttttttttssuuwwvvttuuvvuuvvvvvvuuuuuuttww€€}}||zzxx{{zzzzyyyyxxwwwwwwwwwwwwuuvvyy{{zzzzzzxxuuttttssttxxyyuuttwwxxvvuuttqqqqrruuvvuuuuuuvvwwwwxxxxxxxxxxxxwwuuttvvwwxxuuttuuvvuuuuttttuuttssttuuvvwwuuttuuvvvvuuuuttttttww€€}}||zzxx{{zzzzyyyyxxwwwwwwwwwwwwuuvvyy{{zzzzzzxxuuttttssttxxyyuuttwwxxvvuuttqqqqrruuvvuuuuuuvvwwwwxxxxxxxxxxxxwwuuttvvwwxxuuttuuvvuuuuttttuuttssttuuvvwwuuttuuvvvvuuuuttttttww€€}}||zzzz{{{{zzyyyyxxwwxxvvwwwwvvuuuuvvzzzzzzyyxxvvttssssttxxzzvvssuuxxvvttttqqppqqssttttuuxxzzzzzz{{zzyyxxzz{{zzwwttttwwxxttttuuuuuuuuuuuuttuuttttssttvvxxttssuuvvvvuuttssttvv€€}}||zzzz{{{{zzyyyyxxwwxxvvwwwwvvuuuuvvzzzzzzyyxxvvttssssttxxzzvvssuuxxvvttttqqppqqssttttuuxxzzzzzz{{zzyyxxzz{{zzwwttttwwxxttttuuuuuuuuuuuuttuuttttssttvvxxttssuuvvvvuuttssttvv€€||{{yy{{{{{{zzyyyyxxwwxxwwwwwwvvvvvvvvxxyyzzzzyywwvvttssuuxxyywwttuuwwwwuuttssppooqqrrssttvvwwwwwwxxyyyyyy{{zzyyyyttrrvvxxttttuuuuttuuuuuuuuttttttttttssuuvvuuttuuvvuuttssssww€€||{{yy{{{{{{zzyyyyxxwwxxwwwwwwvvvvvvvvxxyyzzzzyywwvvttssuuxxyywwttuuwwwwuuttssppooqqrrssttvvwwwwwwxxyyyyyy{{zzyyyyttrrvvxxttttuuuuttuuuuuuuuttttttttttssuuvvuuttuuvvuuttssssww€€}}{{zz{{{{{{zzzzyyxxwwxxxxxxxxvvvvvvuuvvxxzzzzxxwwuuuuuuuuvvwwxxttttwwxxvvttttrrppooqqrrrrssssttuuttvvuuvvxxyyyyxxuurrvvwwttttttttttttuuuuuuttttuuttssssssttvvuuttuuuuttssssvv€€}}{{zz{{{{{{zzzzyyxxwwxxxxxxxxvvvvvvuuvvxxzzzzxxwwuuuuuuuuvvwwxxttttwwxxvvttttrrppooqqrrrrssssttuuttvvuuvvxxyyyyxxuurrvvwwttttttttttttuuuuuuttttuuttssssssttvvuuttuuuuttssssvv€€}}zz{{{{{{{{zzzzyyxxxxxxxxxxxxwwvvwwwwuuwwzzzzyyxxwwwwvvvvvvwwzzvvttuuwwwwuuttssqqppoonnooqqrrssuuuuvvvvuuvvwwxxwwttssvvuurrssssttttssssttttuuuuttuuttuuuuttssttuuuussssssssvv€€}}zz{{{{{{{{zzzzyyxxxxxxxxxxxxwwvvwwwwuuwwzzzzyyxxwwwwvvvvvvwwzzvvttuuwwwwuuttssqqppoonnooqqrrssuuuuvvvvuuvvwwxxwwttssvvuurrssssttttssssttttuuuuttuuttuuuuttssttuuuussssssssvv€€{{yy{{{{{{zzzzzzyyyyxxxxwwxxxxxxwwwwvvuuuuyyzzzzyywwvvvvwwvv||wwttttvvwwvvttrrrrppnnllmmoorrttuuuuuuuuttttttuuttqqssvvttssttttttssssssttttttssttttuuttttttttrrttwwttrrssssvv€€{{yy{{{{{{zzzzzzyyyyxxxxwwxxxxxxwwwwvvuuuuyyzzzzyywwvvvvwwvv||wwttttvvwwvvttrrrrppnnllmmoorrttuuuuuuuuttttttuuttqqssvvttssttttttssssssttttttssttttuuttttttttrrttwwttrrssssvv€€{{zz||||{{zzzzzzyyyyyyxxwwxxxxwwwwwwwwvvvvwwzzzzzzyyvvvvxxwwƒƒxxttssuuvvwwuussrrppnnkkllmmppssttttuuttttttttttrroottvvssssttttttssssttttssssssuuttssttttttttrrssttuuuussqquu€€{{zz||||{{zzzzzzyyyyyyxxwwxxxxwwwwwwwwvvvvwwzzzzzzyyvvvvxxwwƒƒxxttssuuvvwwuussrrppnnkkllmmppssttttuuttttttttttrroottvvssssttttttssssttttssssssuuttssttttttttrrssttuuuussqquu€€{{zz||||{{zzzzyyxxyyyyxxwwxxwwxxxxwwwwvvvvvvxxzz{{{{yyyyzzww††{{ttssssuuuuuuttssqqoommmmmmllnnqqrrssttuuttssqqnnnnttuuttttttttttssssssssssssssssssssssssttttssssssttttttssss€€{{zz||||{{zzzzyyxxyyyyxxwwxxwwxxxxwwwwvvvvvvxxzz{{{{yyyyzzww††{{ttssssuuuuuuttssqqoommmmmmllnnqqrrssttuuttssqqnnnnttuuttttttttttssssssssssssssssssssssssttttssssssttttttssss{{{{}}||{{yy{{zzyyyyyyxxxxwwwwyyxxxxwwwwwwwwwwzz{{{{{{{{{{yyˆˆ‚‚vvttttttttttttssssrrppnnnnllkklloopprrssrrppoommqqvvuuttttttttttttttssssssssssrrssssttttttttssttssssssssttuu{{{{}}||{{yy{{zzyyyyyyxxxxwwwwyyxxxxwwwwwwwwwwzz{{{{{{{{{{yyˆˆ‚‚vvttttttttttttssssrrppnnnnllkklloopprrssrrppoommqqvvuuttttttttttttttssssssssssrrssssttttttttssttssssssssttuu||||||{{zzzzyyzzyyyyyyyyxxxxxxyyyyxxwwwwwwwwvvxx{{{{{{{{{{zz~~††ˆˆ}}ttttttssuuttssttssqqqqoommllkkmmmmnnooppppoooottvvttttttttttttttssttttssrrssssssssttttttttttttttrrrrrrqqss||||||{{zzzzyyzzyyyyyyyyxxxxxxyyyyxxwwwwwwwwvvxx{{{{{{{{{{zz~~††ˆˆ}}ttttttssuuttssttssqqqqoommllkkmmmmnnooppppoooottvvttttttttttttttssttttssrrssssssssttttttttttttttrrrrrrqqss||{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxyyxxwwwwwwwwwwvvzz{{{{{{{{{{}}„„ŠŠ……wwrrssttttttssttuuttssqqoonnllmmmmmmnnnnoopprrvvuurrttttttuussttttssttssssssrrssssssrrssssssssttssrrrrqqrr||{{{{zzzzzzzzzzyyyyyyyyxxxxxxxxyyxxwwwwwwwwwwvvzz{{{{{{{{{{}}„„ŠŠ……wwrrssttttttssttuuttssqqoonnllmmmmmmnnnnoopprrvvuurrttttttuussttttssttssssssrrssssssrrssssssssttssrrrrqqrr€€}}||||{{{{zzzzzzyyyyyyyyyyxxxxxxyyxxxxxxxxxxwwvvxx{{||{{{{{{||ƒƒ‰‰ŠŠ��uussssuuttssssuuuuttssrrppoommnnoooooopprruuwwuuttttttttttttssttssttssssssrrssssssssssrrrrrrttssrrrrqqrr€€}}||||{{{{zzzzzzyyyyyyyyyyxxxxxxyyxxxxxxxxxxwwvvxx{{||{{{{{{||ƒƒ‰‰ŠŠ��uussssuuttssssuuuuttssrrppoommnnoooooopprruuwwuuttttttttttttssttssttssssssrrssssssssssrrrrrrttssrrrrqqrr€€}}||{{{{{{zzzzzzzzzzyyyyyyyyyyyyyyxxxxxxxxxxwwwwwwyy||||||||||‚‚ˆˆ‰‰ŠŠ‚‚xxttuuvvuuttttttuuttssssrrqqqqrrqqqqssttwwyywwuuttttttttttttssssssssssssssssssssssssssssssuussrrrrqqrr€€}}||{{{{{{zzzzzzzzzzyyyyyyyyyyyyyyxxxxxxxxxxwwwwwwyy||||||||||‚‚ˆˆ‰‰ŠŠ‚‚xxttuuvvuuttttttuuttssssrrqqqqrrqqqqssttwwyywwuuttttttttttttssssssssssssssssssssssssssssssuussrrrrqqrr€€}}||{{{{{{zzzzzzzzyyyyzzyyyyzzyyyyxxxxxxyyxxwwwwvvww{{||||}}‚‚‡‡ˆˆ‰‰‹‹††wwttuuvvvvttttuuuuttttssssssttssssttuu{{ƒƒ��yyuuuuttuuttttttttttttssssssrrssssssssrrrrssssssrrrrqqrr€€}}||{{{{{{zzzzzzzzyyyyzzyyyyzzyyyyxxxxxxyyxxwwwwvvww{{||||}}‚‚‡‡ˆˆ‰‰‹‹††wwttuuvvvvttttuuuuttttssssssttssssttuu{{ƒƒ��yyuuuuttuuttttttttttttssssssrrssssssssrrrrssssssrrrrqqrr}}||{{{{{{zzzzzzyyyyzzyyyyyyyyyyyyxxxxxxxxxxwwwwvvwwyy{{||~~ƒƒ‚‚ƒƒ††ˆˆŠŠŠŠssssuuvvwwuuttuuuuttttssttttuuttttuu}}ƒƒ††……}}wwvvvvuuttttttttttttssssrrssrrssssssssssssrrrrrrqqrr}}||{{{{{{zzzzzzyyyyzzyyyyyyyyyyyyxxxxxxxxxxwwwwvvwwyy{{||~~ƒƒ‚‚ƒƒ††ˆˆŠŠŠŠssssuuvvwwuuttuuuuttttssttttuuttttuu}}ƒƒ††……}}wwvvvvuuttttttttttttssssrrssrrssssssssssssrrrrrrqqrr||zz{{{{zz{{zzyyzzyyyyyyyyxxxxxxxxwwwwxxwwwwxxwwwwwwwwzz||€€ƒƒ„„‚‚‚‚††‰‰ŠŠˆˆ{{qqttuuwwvvuuttssssssttttuuuuttuuww}}€€‚‚‡‡ˆˆwwvvuuttttssssttssrrrrrrssrrssssssrrssrrqqrrqqppqq||zz{{{{zz{{zzyyzzyyyyyyyyxxxxxxxxwwwwxxwwwwxxwwwwwwwwzz||€€ƒƒ„„‚‚‚‚††‰‰ŠŠˆˆ{{qqttuuwwvvuuttssssssttttuuuuttuuww}}€€‚‚‡‡ˆˆwwvvuuttttssssttssrrrrrrssrrssssssrrssrrqqrrqqppqq}}zzzz{{{{{{yyyyzzyyxxxxxxxxwwxxxxxxwwxxwwwwxxwwwwvvvvxx‚‚‚‚ƒƒƒƒƒƒ‚‚††ˆˆŠŠˆˆyyqqttwwvvuuttssttttttttttttttvvww||……‰‰‰‰€€vvttttuuttssssssrrttssrrrrssrrrrqqqqrrqqqqqqqqrr}}zzzz{{{{{{yyyyzzyyxxxxxxxxwwxxxxxxwwxxwwwwxxwwwwvvvvxx‚‚‚‚ƒƒƒƒƒƒ‚‚††ˆˆŠŠˆˆyyqqttwwvvuuttssttttttttttttttvvww||……‰‰‰‰€€vvttttuuttssssssrrttssrrrrssrrrrqqqqrrqqqqqqqqrr€€||{{{{{{zzzzyyyyzzzzxxxxxxxxxxxxyyyyxxxxvvwwxxwwwwwwww||ƒƒƒƒ‚‚‚‚ƒƒ„„„„‚‚ƒƒˆˆ‹‹††wwrruuwwvvssrrrrrrssssssssttvvwwzz}}€€……‡‡ŠŠˆˆzzqqssuuttssssssssttssrrssrrqqrrrrpprrrrqqqqqqqq€€||{{{{{{zzzzyyyyzzzzxxxxxxxxxxxxyyyyxxxxvvwwxxwwwwwwww||ƒƒƒƒ‚‚‚‚ƒƒ„„„„‚‚ƒƒˆˆ‹‹††wwrruuwwvvssrrrrrrssssssssttvvwwzz}}€€……‡‡ŠŠˆˆzzqqssuuttssssssssttssrrssrrqqrrrrpprrrrqqqqqqqq€€||{{{{{{zzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyywwxxyyxxxxzz}}��„„ƒƒ„„ƒƒ„„„„…………‚‚‚‚‡‡‹‹ƒƒuurruuvvuuttrrrrssrrssssttuuww{{}}€€……ˆˆˆˆŠŠ‚‚ttrrttttttssssssssssssttssrrrrrrrrrrqqnnqqxxww€€||{{{{{{zzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyywwxxyyxxxxzz}}��„„ƒƒ„„ƒƒ„„„„…………‚‚‚‚‡‡‹‹ƒƒuurruuvvuuttrrrrssrrssssttuuww{{}}€€……ˆˆˆˆŠŠ‚‚ttrrttttttssssssssssssttssrrrrrrrrrrqqnnqqxxww€€||{{{{zzzzzzyyxxyyyyyyyyyyyyyyxxyyxxxxyyzz||~~€€‚‚‚‚‚‚„„„„„„„„„„„„„„††……„„‚‚„„††||qqttuuuuttssssssrrssssssuuwwzz}}……††……ˆˆ‚‚vvuuqqttttttttssttssrrrrqqqqsswwttkkbbll}}ƒƒ��€€||{{{{zzzzzzyyxxyyyyyyyyyyyyyyxxyyxxxxyyzz||~~€€‚‚‚‚‚‚„„„„„„„„„„„„„„††……„„‚‚„„††||qqttuuuuttssssssrrssssssuuwwzz}}……††……ˆˆ‚‚vvuuqqttttttttssttssrrrrqqqqsswwttkkbbll}}ƒƒ��||{{{{zzzzyyyyxxxxxxxxxxyyxxwwwwwwyy{{~~����‚‚‚‚ƒƒƒƒ����ƒƒƒƒ„„ƒƒƒƒ„„……††…………„„ƒƒ��~~vvrrrrssssssssssssssssssuuvvyy||~~ƒƒ……‡‡ˆˆ}}ttttuuuuttvvwwuuuussssjj__hhtt}}kkXX]]mmoohhff||{{{{zzzzyyyyxxxxxxxxxxyyxxwwwwwwyy{{~~����‚‚‚‚ƒƒƒƒ����ƒƒƒƒ„„ƒƒƒƒ„„……††…………„„ƒƒ��~~vvrrrrssssssssssssssssssuuvvyy||~~ƒƒ……‡‡ˆˆ}}ttttuuuuttvvwwuuuussssjj__hhtt}}kkXX]]mmoohhff||||||{{zzyyxxyyxxxxyyyyxxxxxx{{~~��‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ����‚‚„„„„……ƒƒ‚‚…………„„ƒƒ„„ƒƒ‚‚‚‚ƒƒ€€zzttttttttuuuuuuuuvvvvwwyy}}~~‚‚ˆˆŠŠ„„||vvvvvvvvxxww{{||{{vvuuhhZZhhoohh^^ZZ[[[[ZZYY\\||||||{{zzyyxxyyxxxxyyyyxxxxxx{{~~��‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ����‚‚„„„„……ƒƒ‚‚…………„„ƒƒ„„ƒƒ‚‚‚‚ƒƒ€€zzttttttttuuuuuuuuvvvvwwyy}}~~‚‚ˆˆŠŠ„„||vvvvvvvvxxww{{||{{vvuuhhZZhhoohh^^ZZ[[[[ZZYY\\xxjjmmhhiikkjjhhggmmkkvv„„‚‚‚‚‚‚‚‚„„……††……„„„„„„„„„„„„„„„„ƒƒƒƒ„„„„„„……††††………………„„„„‚‚‚‚‚‚ƒƒ„„„„ƒƒƒƒ„„„„……„„……„„„„ƒƒƒƒ„„„„„„…………„„„„„„„„„„„„„„………………………………††††††……„„††††ˆˆ††ƒƒ„„xxjjmmhhiikkjjhhggmmkkvv„„‚‚‚‚‚‚‚‚„„……††……„„„„„„„„„„„„„„„„ƒƒƒƒ„„„„„„……††††………………„„„„‚‚‚‚‚‚ƒƒ„„„„ƒƒƒƒ„„„„……„„……„„„„ƒƒƒƒ„„„„„„…………„„„„„„„„„„„„„„………………………………††††††……„„††††ˆˆ††ƒƒ„„ssPPQQNNQQKKMMNNOOSSUUgg††‚‚ƒƒ„„…………††………………„„„„……„„„„„„„„„„„„……………………………………„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒƒƒ‚‚ƒƒ„„……„„„„„„„„„„ƒƒƒƒ„„………………††……„„„„ƒƒ„„…………††††…………††††††††††„„††††††ˆˆ††ƒƒssPPQQNNQQKKMMNNOOSSUUgg††‚‚ƒƒ„„…………††………………„„„„……„„„„„„„„„„„„……………………………………„„„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒƒƒ‚‚ƒƒ„„……„„„„„„„„„„ƒƒƒƒ„„………………††……„„„„ƒƒ„„…………††††…………††††††††††„„††††††ˆˆ††ƒƒ}}ssttssttttuussuuvvuuyy„„ƒƒ………………„„……„„…………„„„„„„……„„„„„„………………††††……………………ƒƒƒƒ„„‚‚‚‚����€€€€��€€����ƒƒ„„„„„„„„……„„ƒƒƒƒ„„„„……„„††††„„„„„„„„„„…………††††……††††††††……………………††‡‡ˆˆ††}}ssttssttttuussuuvvuuyy„„ƒƒ………………„„……„„…………„„„„„„……„„„„„„………………††††……………………ƒƒƒƒ„„‚‚‚‚����€€€€��€€����ƒƒ„„„„„„„„……„„ƒƒƒƒ„„„„……„„††††„„„„„„„„„„…………††††……††††††††……………………††‡‡ˆˆ††��ƒƒƒƒ‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„……††……„„ƒƒ„„„„„„„„ƒƒ„„„„„„„„„„„„…………………………„„„„„„ƒƒƒƒƒƒƒƒ��€€����€€€€������€€����‚‚ƒƒƒƒ„„„„„„ƒƒƒƒƒƒ„„„„…………………………„„„„„„„„……††††………………††……††††„„……‡‡ˆˆˆˆ��ƒƒƒƒ‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„……††……„„ƒƒ„„„„„„„„ƒƒ„„„„„„„„„„„„…………………………„„„„„„ƒƒƒƒƒƒƒƒ��€€����€€€€������€€����‚‚ƒƒƒƒ„„„„„„ƒƒƒƒƒƒ„„„„…………………………„„„„„„„„……††††………………††……††††„„……‡‡ˆˆˆˆ€€��‚‚‚‚‚‚ƒƒƒƒƒƒ„„……………………††††„„ƒƒ„„„„„„„„„„„„………………††††…………………………„„„„„„ƒƒƒƒ‚‚��€€€€€€����€€€€������€€€€������‚‚„„ƒƒ„„„„ƒƒ„„„„„„…………††††……„„„„„„„„……††……††………………††……††……„„††ˆˆ‡‡€€��‚‚‚‚‚‚ƒƒƒƒƒƒ„„……………………††††„„ƒƒ„„„„„„„„„„„„………………††††…………………………„„„„„„ƒƒƒƒ‚‚��€€€€€€����€€€€������€€€€������‚‚„„ƒƒ„„„„ƒƒ„„„„„„…………††††……„„„„„„„„……††……††………………††……††……„„††ˆˆ‡‡€€��‚‚‚‚ƒƒ„„„„……††††††…………††……ƒƒƒƒ„„…………„„„„„„……††………………„„„„„„„„„„ƒƒ„„‚‚‚‚��€€����€€€€������€€€€��€€��€€��€€����‚‚„„„„„„„„„„„„„„………………††††††„„„„„„„„††……††††……††††…………‡‡…………††††€€��‚‚‚‚ƒƒ„„„„……††††††…………††……ƒƒƒƒ„„…………„„„„„„……††………………„„„„„„„„„„ƒƒ„„‚‚‚‚��€€����€€€€������€€€€��€€��€€��€€����‚‚„„„„„„„„„„„„„„………………††††††„„„„„„„„††……††††……††††…………‡‡…………††††����ƒƒ„„……††…………………………„„…………ƒƒƒƒƒƒ„„„„………………††…………„„……„„„„ƒƒ„„„„ƒƒƒƒ‚‚����€€€€€€€€€€€€€€€€��€€€€€€€€������€€€€€€��ƒƒƒƒƒƒ„„„„ƒƒƒƒ„„………………††‡‡…………„„„„………………††††……††††…………††…………††����ƒƒ„„……††…………………………„„…………ƒƒƒƒƒƒ„„„„………………††…………„„……„„„„ƒƒ„„„„ƒƒƒƒ‚‚����€€€€€€€€€€€€€€€€��€€€€€€€€������€€€€€€��ƒƒƒƒƒƒ„„„„ƒƒƒƒ„„………………††‡‡…………„„„„………………††††……††††…………††…………††��ƒƒ„„……„„…………„„……„„„„„„…………ƒƒƒƒƒƒ„„……††……………………„„„„„„ƒƒƒƒƒƒ„„„„ƒƒ‚‚��€€��€€€€€€€€€€��€€��€€€€€€������€€€€€€€€€€€€‚‚ƒƒ„„„„„„„„ƒƒ„„„„„„……††‡‡††……„„„„………………††††…………††……„„……‡‡……††��ƒƒ„„……„„…………„„……„„„„„„…………ƒƒƒƒƒƒ„„……††……………………„„„„„„ƒƒƒƒƒƒ„„„„ƒƒ‚‚��€€��€€€€€€€€€€��€€��€€€€€€������€€€€€€€€€€€€‚‚ƒƒ„„„„„„„„ƒƒ„„„„„„……††‡‡††……„„„„………………††††…………††……„„……‡‡……††��ƒƒƒƒ„„…………„„„„„„„„„„…………„„ƒƒƒƒ„„……††…………„„ƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚����€€��€€€€€€€€€€����€€€€������€€��€€€€€€��€€€€€€‚‚„„„„„„„„„„„„„„……††††††††††………………„„„„………………††††††……„„……‡‡„„��ƒƒƒƒ„„…………„„„„„„„„„„…………„„ƒƒƒƒ„„……††…………„„ƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚����€€��€€€€€€€€€€����€€€€������€€��€€€€€€��€€€€€€‚‚„„„„„„„„„„„„„„……††††††††††………………„„„„………………††††††……„„……‡‡„„€€‚‚„„…………„„„„„„„„„„„„…………„„„„……………………„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚������€€����€€��€€��€€��€€€€����������€€€€€€��€€€€€€��ƒƒ„„„„„„„„……„„„„……††††††††††……„„„„„„„„……………………………………„„††††€€‚‚„„…………„„„„„„„„„„„„…………„„„„……………………„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚������€€����€€��€€��€€��€€€€����������€€€€€€��€€€€€€��ƒƒ„„„„„„„„……„„„„……††††††††††……„„„„„„„„……………………………………„„††††€€‚‚„„……„„ƒƒ„„„„„„„„„„††……††…………„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ‚‚��€€��€€����������������€€€€������€€€€€€������€€€€€€€€‚‚„„ƒƒ„„ƒƒ„„„„„„„„……††††††††………………„„„„……„„……††††††………………††€€‚‚„„……„„ƒƒ„„„„„„„„„„††……††…………„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ‚‚��€€��€€����������������€€€€������€€€€€€������€€€€€€€€‚‚„„ƒƒ„„ƒƒ„„„„„„„„……††††††††………………„„„„……„„……††††††………………††��ƒƒ…………„„„„„„„„ƒƒ„„……††……††„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ��€€€€€€������������������€€������€€����€€������€€€€��€€€€€€ƒƒ„„„„„„„„„„„„………………††††…………††……„„„„„„„„…………††††……………………��ƒƒ…………„„„„„„„„ƒƒ„„……††……††„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ��€€€€€€������������������€€������€€����€€������€€€€��€€€€€€ƒƒ„„„„„„„„„„„„………………††††…………††……„„„„„„„„…………††††……………………��ƒƒ……„„ƒƒ„„„„„„…………………………ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚€€€€€€€€��������€€€€����€€��������������€€€€€€��€€����€€€€‚‚„„„„„„„„ƒƒ„„„„……………………††……††…………„„„„„„„„„„…………………………„„��ƒƒ……„„ƒƒ„„„„„„…………………………ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚€€€€€€€€��������€€€€����€€��������������€€€€€€��€€����€€€€‚‚„„„„„„„„ƒƒ„„„„……………………††……††…………„„„„„„„„„„…………………………„„��„„„„ƒƒƒƒ………………………………„„‚‚‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚��€€€€€€������€€€€€€��€€€€��€€����������€€€€��€€€€€€€€€€€€€€€€ƒƒ„„„„„„ƒƒ„„„„…………„„………………††††††……„„„„ƒƒƒƒ„„……††………………��„„„„ƒƒƒƒ………………………………„„‚‚‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚��€€€€€€������€€€€€€��€€€€��€€����������€€€€��€€€€€€€€€€€€€€€€ƒƒ„„„„„„ƒƒ„„„„…………„„………………††††††……„„„„ƒƒƒƒ„„……††………………‚‚……„„„„………………„„„„ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚€€€€€€€€€€��������€€��€€€€��€€€€€€€€��€€€€€€€€€€€€€€€€€€€€€€‚‚„„„„„„ƒƒƒƒ„„„„………………„„„„††‡‡‡‡††……„„ƒƒ‚‚ƒƒƒƒ……††……„„‚‚……„„„„………………„„„„ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚€€€€€€€€€€��������€€��€€€€��€€€€€€€€��€€€€€€€€€€€€€€€€€€€€€€‚‚„„„„„„ƒƒƒƒ„„„„………………„„„„††‡‡‡‡††……„„ƒƒ‚‚ƒƒƒƒ……††……„„‚‚……………………„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒ€€€€€€€€€€€€��€€€€��€€€€€€��€€€€€€€€€€��€€€€€€€€��€€€€€€€€€€€€€€��„„„„„„„„„„„„„„„„……„„„„„„……††‡‡‡‡‡‡……„„ƒƒƒƒ‚‚„„††††……‚‚……………………„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒ€€€€€€€€€€€€��€€€€��€€€€€€��€€€€€€€€€€��€€€€€€€€��€€€€€€€€€€€€€€��„„„„„„„„„„„„„„„„……„„„„„„……††‡‡‡‡‡‡……„„ƒƒƒƒ‚‚„„††††……‚‚……„„„„ƒƒ‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚„„„„„„„„‚‚€€€€€€€€€€€€€€€€����€€€€€€€€€€€€€€€€��€€€€€€��€€��€€��€€€€€€€€ƒƒ„„„„„„„„……„„„„„„„„„„„„…………††††‡‡††……„„ƒƒ‚‚ƒƒ……††††‚‚……„„„„ƒƒ‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚„„„„„„„„‚‚€€€€€€€€€€€€€€€€����€€€€€€€€€€€€€€€€��€€€€€€��€€��€€��€€€€€€€€ƒƒ„„„„„„„„……„„„„„„„„„„„„…………††††‡‡††……„„ƒƒ‚‚ƒƒ……††††‚‚„„ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„‚‚€€€€€€€€€€€€€€€€��€€€€€€€€€€€€��€€€€€€��€€€€€€€€€€€€€€€€€€€€€€€€‚‚„„„„„„„„„„ƒƒ„„„„„„„„„„„„……††††††††††……„„‚‚ƒƒ„„…………‚‚„„ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„‚‚€€€€€€€€€€€€€€€€��€€€€€€€€€€€€��€€€€€€��€€€€€€€€€€€€€€€€€€€€€€€€‚‚„„„„„„„„„„ƒƒ„„„„„„„„„„„„……††††††††††……„„‚‚ƒƒ„„…………��‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„……„„„„„„„„„„ƒƒƒƒ��€€€€€€€€€€€€€€€€��€€€€€€��€€€€€€€€€€����€€€€��������€€€€€€€€€€€€��„„„„„„„„„„„„ƒƒ„„„„„„„„……„„……††……„„††††……ƒƒ„„„„……„„��‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„……„„„„„„„„„„ƒƒƒƒ��€€€€€€€€€€€€€€€€��€€€€€€��€€€€€€€€€€����€€€€��������€€€€€€€€€€€€��„„„„„„„„„„„„ƒƒ„„„„„„„„……„„……††……„„††††……ƒƒ„„„„……„„€€��‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„……„„„„„„„„ƒƒƒƒ‚‚‚‚€€€€€€€€€€€€€€����€€€€����€€��€€€€€€��€€€€����������€€��€€€€€€€€€€ƒƒ„„„„„„ƒƒ„„„„ƒƒ„„„„„„…………„„……„„ƒƒ††††††„„„„„„„„ƒƒ€€��‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„……„„„„„„„„ƒƒƒƒ‚‚‚‚€€€€€€€€€€€€€€����€€€€����€€��€€€€€€��€€€€����������€€��€€€€€€€€€€ƒƒ„„„„„„ƒƒ„„„„ƒƒ„„„„„„…………„„……„„ƒƒ††††††„„„„„„„„ƒƒ������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„……„„„„…………„„„„ƒƒ‚‚‚‚‚‚‚‚��€€€€€€€€€€€€€€€€��€€€€����‚‚ƒƒƒƒ„„………………„„…………„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚��€€€€‚‚ƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒ„„„„„„…………„„ƒƒ……††‡‡……„„„„„„ƒƒ������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„……„„„„…………„„„„ƒƒ‚‚‚‚‚‚‚‚��€€€€€€€€€€€€€€€€��€€€€����‚‚ƒƒƒƒ„„………………„„…………„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚��€€€€‚‚ƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒ„„„„„„…………„„ƒƒ……††‡‡……„„„„„„ƒƒ��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„„………………„„„„„„ƒƒƒƒ‚‚��‚‚‚‚‚‚‚‚��€€€€€€€€€€����€€��‚‚„„……‡‡‰‰‰‰ŠŠ‹‹‹‹ŒŒŒŒ‹‹ŒŒŒŒŒŒ‹‹ŠŠŠŠ‰‰ŠŠ‰‰ˆˆˆˆˆˆ‡‡††††…………„„„„„„„„„„ƒƒƒƒƒƒ„„ƒƒ……††„„„„……††††††……„„„„ƒƒ��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„„………………„„„„„„ƒƒƒƒ‚‚��‚‚‚‚‚‚‚‚��€€€€€€€€€€����€€��‚‚„„……‡‡‰‰‰‰ŠŠ‹‹‹‹ŒŒŒŒ‹‹ŒŒŒŒŒŒ‹‹ŠŠŠŠ‰‰ŠŠ‰‰ˆˆˆˆˆˆ‡‡††††…………„„„„„„„„„„ƒƒƒƒƒƒ„„ƒƒ……††„„„„……††††††……„„„„ƒƒ€€‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„…………„„…………„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��€€€€€€€€����‚‚……‡‡ˆˆŠŠ‹‹ŒŒ����������ŽŽ��ŒŒŒŒŒŒŒŒŒŒŠŠ‹‹��������ŽŽ��ŒŒŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡††……ƒƒƒƒƒƒ„„ƒƒ„„……„„ƒƒ……††††††……††……„„€€‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„…………„„…………„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��€€€€€€€€����‚‚……‡‡ˆˆŠŠ‹‹ŒŒ����������ŽŽ��ŒŒŒŒŒŒŒŒŒŒŠŠ‹‹��������ŽŽ��ŒŒŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡††……ƒƒƒƒƒƒ„„ƒƒ„„……„„ƒƒ……††††††……††……„„€€��‚‚‚‚ƒƒ„„„„„„„„„„„„„„„„„„‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��€€€€€€€€��ƒƒ……ŠŠŒŒ��ŽŽ����‘‘��������ŽŽ������ŽŽŽŽŽŽ����ŒŒŒŒŒŒ��‘‘’’‘‘��‹‹‰‰‰‰‰‰‰‰ˆˆˆˆ‰‰‡‡……„„„„„„„„„„„„„„„„„„……………………††††„„€€��‚‚‚‚ƒƒ„„„„„„„„„„„„„„„„„„‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��€€€€€€€€��ƒƒ……ŠŠŒŒ��ŽŽ����‘‘��������ŽŽ������ŽŽŽŽŽŽ����ŒŒŒŒŒŒ��‘‘’’‘‘��‹‹‰‰‰‰‰‰‰‰ˆˆˆˆ‰‰‡‡……„„„„„„„„„„„„„„„„„„……………………††††„„€€‚‚ƒƒ„„„„„„„„„„„„ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��€€€€����ƒƒ‡‡ŠŠ��‘‘““’’’’‘‘��������������’’’’’’““““““““““’’����‘‘��‘‘’’��ŒŒŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡„„„„„„„„ƒƒ„„„„„„„„„„††……………………‡‡……€€‚‚ƒƒ„„„„„„„„„„„„ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��€€€€����ƒƒ‡‡ŠŠ��‘‘““’’’’‘‘��������������’’’’’’““““““““““’’����‘‘��‘‘’’��ŒŒŠŠŠŠ‰‰‰‰ˆˆˆˆˆˆ‡‡„„„„„„„„ƒƒ„„„„„„„„„„††……………………‡‡……��ƒƒ„„„„„„„„ƒƒƒƒ‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††‹‹��ŽŽ‘‘““’’‘‘��ŽŽŽŽ����������‘‘‘‘’’’’““““““””””””““““““’’��‘‘‘‘��ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡……„„„„„„ƒƒ‚‚ƒƒ„„„„„„„„††……ƒƒ„„……‡‡††��ƒƒ„„„„„„„„ƒƒƒƒ‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††‹‹��ŽŽ‘‘““’’‘‘��ŽŽŽŽ����������‘‘‘‘’’’’““““““””””””““““““’’��‘‘‘‘��ŠŠŠŠ‰‰‰‰ˆˆˆˆ‡‡……„„„„„„ƒƒ‚‚ƒƒ„„„„„„„„††……ƒƒ„„……‡‡††‚‚„„„„„„ƒƒ‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„……‰‰��‘‘’’����‘‘��ŽŽŽŽŽŽ������ŽŽŽŽ��������‘‘’’’’““““““““’’’’’’‘‘����‘‘ŽŽŠŠŠŠŠŠ‰‰ˆˆ‡‡……ƒƒƒƒ„„„„„„ƒƒƒƒ„„„„„„„„…………„„„„„„††††‚‚„„„„„„ƒƒ‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„……‰‰��‘‘’’����‘‘��ŽŽŽŽŽŽ������ŽŽŽŽ��������‘‘’’’’““““““““’’’’’’‘‘����‘‘ŽŽŠŠŠŠŠŠ‰‰ˆˆ‡‡……ƒƒƒƒ„„„„„„ƒƒƒƒ„„„„„„„„…………„„„„„„††††‚‚‚‚‚‚����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��‚‚‚‚‚‚ƒƒ„„††‰‰ŽŽ‘‘’’’’��ŒŒ����������ŽŽ����ŒŒ‹‹ŒŒ��ŽŽ����‘‘‘‘’’’’’’’’‘‘‘‘‘‘����ŽŽ��ŽŽŠŠŠŠŠŠŠŠ‡‡…………„„„„„„„„„„ƒƒƒƒ„„„„ƒƒ„„„„…………„„„„„„……‚‚‚‚‚‚����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��‚‚‚‚‚‚ƒƒ„„††‰‰ŽŽ‘‘’’’’��ŒŒ����������ŽŽ����ŒŒ‹‹ŒŒ��ŽŽ����‘‘‘‘’’’’’’’’‘‘‘‘‘‘����ŽŽ��ŽŽŠŠŠŠŠŠŠŠ‡‡…………„„„„„„„„„„ƒƒƒƒ„„„„ƒƒ„„„„…………„„„„„„……��������‚‚����‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††‡‡ŠŠ����‘‘‘‘��ŠŠ��ŽŽŽŽŽŽŽŽŒŒ‹‹‹‹‹‹‹‹‹‹ŒŒ����ŽŽ����‘‘‘‘’’‘‘‘‘��������ŒŒŽŽ��ŠŠŠŠ‰‰‡‡„„ƒƒ„„„„„„„„„„„„„„„„„„„„ƒƒƒƒ„„„„„„„„„„„„„„��������‚‚����‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††‡‡ŠŠ����‘‘‘‘��ŠŠ��ŽŽŽŽŽŽŽŽŒŒ‹‹‹‹‹‹‹‹‹‹ŒŒ����ŽŽ����‘‘‘‘’’‘‘‘‘��������ŒŒŽŽ��ŠŠŠŠ‰‰‡‡„„ƒƒ„„„„„„„„„„„„„„„„„„„„ƒƒƒƒ„„„„„„„„„„„„„„€€��‚‚��‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒ††ˆˆ‡‡ŒŒ��������‹‹ŒŒŽŽŽŽŽŽ����ŒŒ��������ŒŒ‹‹ŒŒŒŒ��ŽŽ������‘‘������ŽŽ��ŒŒŒŒ‹‹ŠŠŠŠŠŠ††„„ƒƒ„„„„„„„„„„„„„„ƒƒ„„„„„„ƒƒƒƒ„„„„„„„„„„„„„„€€��‚‚��‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒ††ˆˆ‡‡ŒŒ��������‹‹ŒŒŽŽŽŽŽŽ����ŒŒ��������ŒŒ‹‹ŒŒŒŒ��ŽŽ������‘‘������ŽŽ��ŒŒŒŒ‹‹ŠŠŠŠŠŠ††„„ƒƒ„„„„„„„„„„„„„„ƒƒ„„„„„„ƒƒƒƒ„„„„„„„„„„„„„„€€����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒƒ„„ˆˆˆˆ‡‡ŒŒŽŽŽŽ��ŠŠŒŒ��ŽŽŽŽ��ŒŒ��������ŽŽŽŽŽŽŒŒŒŒŒŒ����ŽŽ������������ŽŽ��ŒŒŒŒ‹‹ŠŠˆˆ……„„„„ƒƒ„„ƒƒƒƒ„„„„„„„„„„„„„„„„„„„„ƒƒ„„……„„…………„„€€����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒƒ„„ˆˆˆˆ‡‡ŒŒŽŽŽŽ��ŠŠŒŒ��ŽŽŽŽ��ŒŒ��������ŽŽŽŽŽŽŒŒŒŒŒŒ����ŽŽ������������ŽŽ��ŒŒŒŒ‹‹ŠŠˆˆ……„„„„ƒƒ„„ƒƒƒƒ„„„„„„„„„„„„„„„„„„„„ƒƒ„„……„„…………„„€€����‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„……ˆˆ‰‰‡‡ŠŠ��ŒŒ‰‰‰‰ŒŒ������������ŽŽ������������ŽŽŒŒŒŒ��ŽŽ����������ŽŽŒŒ��ŽŽŽŽ‹‹ˆˆ……ƒƒ„„„„„„ƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„ƒƒƒƒ„„„„……„„„„„„„„€€����‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„……ˆˆ‰‰‡‡ŠŠ��ŒŒ‰‰‰‰ŒŒ������������ŽŽ������������ŽŽŒŒŒŒ��ŽŽ����������ŽŽŒŒ��ŽŽŽŽ‹‹ˆˆ……ƒƒ„„„„„„ƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„ƒƒƒƒ„„„„……„„„„„„„„€€��‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„„„„„ƒƒ……‡‡ˆˆ‡‡ˆˆŒŒŠŠ‰‰ŠŠ‹‹ŒŒ��ŒŒŒŒ����ŽŽ��ŽŽ����������ŽŽ������ŽŽ������ŽŽ��ŽŽ��������‰‰……ƒƒ„„„„„„ƒƒƒƒ„„„„ƒƒ„„„„„„„„„„„„„„ƒƒ„„„„„„„„„„……„„€€��‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„„„„„ƒƒ……‡‡ˆˆ‡‡ˆˆŒŒŠŠ‰‰ŠŠ‹‹ŒŒ��ŒŒŒŒ����ŽŽ��ŽŽ����������ŽŽ������ŽŽ������ŽŽ��ŽŽ��������‰‰……ƒƒ„„„„„„ƒƒƒƒ„„„„ƒƒ„„„„„„„„„„„„„„ƒƒ„„„„„„„„„„……„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒ„„„„„„ƒƒƒƒƒƒ„„„„„„……‡‡‡‡††‰‰ŠŠˆˆ‰‰‹‹ŒŒŒŒ‹‹‹‹��ŽŽ��ŽŽŽŽ��‘‘����������‹‹ŒŒŽŽ����ŽŽ��ŽŽ����������‰‰„„ƒƒƒƒ„„„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒ„„ƒƒ„„ƒƒ„„……„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒ„„„„„„ƒƒƒƒƒƒ„„„„„„……‡‡‡‡††‰‰ŠŠˆˆ‰‰‹‹ŒŒŒŒ‹‹‹‹��ŽŽ��ŽŽŽŽ��‘‘����������‹‹ŒŒŽŽ����ŽŽ��ŽŽ����������‰‰„„ƒƒƒƒ„„„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒ„„ƒƒ„„ƒƒ„„……„„€€��‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒ„„„„„„ƒƒ„„„„ƒƒƒƒ„„„„„„„„„„††††ˆˆ‡‡‡‡‰‰‹‹ŒŒ‹‹‹‹ŒŒ��������ŽŽŽŽ��ŒŒŒŒŒŒŽŽŽŽ‹‹ŒŒ��‘‘‘‘ŽŽ��ŽŽŽŽŽŽ������ˆˆƒƒ„„ƒƒ„„ƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„„„ƒƒ„„……€€��‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒ„„„„„„ƒƒ„„„„ƒƒƒƒ„„„„„„„„„„††††ˆˆ‡‡‡‡‰‰‹‹ŒŒ‹‹‹‹ŒŒ��������ŽŽŽŽ��ŒŒŒŒŒŒŽŽŽŽ‹‹ŒŒ��‘‘‘‘ŽŽ��ŽŽŽŽŽŽ������ˆˆƒƒ„„ƒƒ„„ƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„„„ƒƒ„„……€€��������‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„„„„„……ˆˆˆˆ‡‡‡‡‰‰‹‹‹‹‹‹‹‹ŒŒ��ŽŽ��ŽŽ����‹‹‹‹‹‹ŒŒŽŽ��������‘‘’’������ŒŒ‹‹ŠŠ��ŽŽ††ƒƒ„„ƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„ƒƒ€€��������‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„„„„„……ˆˆˆˆ‡‡‡‡‰‰‹‹‹‹‹‹‹‹ŒŒ��ŽŽ��ŽŽ����‹‹‹‹‹‹ŒŒŽŽ��������‘‘’’������ŒŒ‹‹ŠŠ��ŽŽ††ƒƒ„„ƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„ƒƒ€€��‚‚‚‚ƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„„„„„„„„„……„„„„„„„„††����ŒŒ‰‰ŠŠŠŠ‹‹ŒŒŒŒ��ŽŽŽŽŽŽŽŽŽŽŽŽ������ŽŽ��ŽŽ��‘‘‘‘‘‘’’��������‹‹ŠŠŒŒŒŒ……ƒƒ„„„„ƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„ƒƒƒƒƒƒƒƒ„„„„ƒƒ€€��‚‚‚‚ƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„„„„„„„„„……„„„„„„„„††����ŒŒ‰‰ŠŠŠŠ‹‹ŒŒŒŒ��ŽŽŽŽŽŽŽŽŽŽŽŽ������ŽŽ��ŽŽ��‘‘‘‘‘‘’’��������‹‹ŠŠŒŒŒŒ……ƒƒ„„„„ƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„ƒƒƒƒƒƒƒƒ„„„„ƒƒ��‚‚ƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„„„„„……„„„„ƒƒƒƒ‹‹””’’��‹‹ŠŠŠŠ‹‹ŒŒ������ŽŽŽŽŽŽ����������������‘‘’’‘‘’’““‘‘����ŽŽŽŽ‹‹ŠŠ‰‰„„ƒƒ„„„„ƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ��‚‚ƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„„„„„……„„„„ƒƒƒƒ‹‹””’’��‹‹ŠŠŠŠ‹‹ŒŒ������ŽŽŽŽŽŽ����������������‘‘’’‘‘’’““‘‘����ŽŽŽŽ‹‹ŠŠ‰‰„„ƒƒ„„„„ƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ��ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„„„ƒƒƒƒŽŽ——‘‘ŽŽ��ŠŠŠŠŒŒ��������������‘‘������‘‘‘‘��‘‘’’‘‘‘‘’’““““��ŒŒ‹‹ŒŒŒŒ‹‹‰‰„„ƒƒ„„„„ƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ��ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„„„ƒƒƒƒŽŽ——‘‘ŽŽ��ŠŠŠŠŒŒ��������������‘‘������‘‘‘‘��‘‘’’‘‘‘‘’’““““��ŒŒ‹‹ŒŒŒŒ‹‹‰‰„„ƒƒ„„„„ƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ��ƒƒ‚‚‚‚������‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„……„„……„„„„„„„„ƒƒƒƒŽŽ˜˜’’��ŽŽ‹‹ŠŠ��ŽŽŽŽ��‘‘‘‘’’’’’’’’’’’’’’‘‘’’’’’’‘‘’’““••––““��ŒŒŒŒ����‰‰……„„„„„„„„„„„„ƒƒ„„„„„„ƒƒ‚‚ƒƒ„„‚‚ƒƒ„„„„„„ƒƒ„„ƒƒƒƒƒƒƒƒ��ƒƒ‚‚‚‚������‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„……„„……„„„„„„„„ƒƒƒƒŽŽ˜˜’’��ŽŽ‹‹ŠŠ��ŽŽŽŽ��‘‘‘‘’’’’’’’’’’’’’’‘‘’’’’’’‘‘’’““••––““��ŒŒŒŒ����‰‰……„„„„„„„„„„„„ƒƒ„„„„„„ƒƒ‚‚ƒƒ„„‚‚ƒƒ„„„„„„ƒƒ„„ƒƒƒƒƒƒƒƒ��€€€€������‚‚‚‚‚‚ƒƒƒƒ„„„„‚‚��‚‚„„„„„„„„„„„„„„ƒƒ„„ƒƒ��——’’����ŒŒŠŠŒŒŽŽŽŽ��‘‘’’““’’““““““““““’’““““’’‘‘’’••™™˜˜˜˜’’ŽŽŽŽŽŽŽŽŠŠ……„„……„„„„„„„„ƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„ƒƒƒƒ��€€€€������‚‚‚‚‚‚ƒƒƒƒ„„„„‚‚��‚‚„„„„„„„„„„„„„„ƒƒ„„ƒƒ��——’’����ŒŒŠŠŒŒŽŽŽŽ��‘‘’’““’’““““““““““’’““““’’‘‘’’••™™˜˜˜˜’’ŽŽŽŽŽŽŽŽŠŠ……„„……„„„„„„„„ƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„ƒƒƒƒ€€€€€€������‚‚‚‚‚‚‚‚ƒƒ„„„„„„‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„„„……„„ŠŠ••’’““““ŒŒŠŠ‹‹������‘‘’’““““““””””““’’’’’’‘‘’’’’””™™››šš™™””������ŽŽ‹‹††‚‚„„„„„„„„„„„„„„ƒƒƒƒ„„„„ƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„ƒƒ€€€€€€������‚‚‚‚‚‚‚‚ƒƒ„„„„„„‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„„„……„„ŠŠ••’’““““ŒŒŠŠ‹‹������‘‘’’““““““””””““’’’’’’‘‘’’’’””™™››šš™™””������ŽŽ‹‹††‚‚„„„„„„„„„„„„„„ƒƒƒƒ„„„„ƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„ƒƒ€€€€������‚‚��‚‚‚‚‚‚ƒƒ„„„„……ƒƒ��‚‚����‚‚ƒƒ…………………………ˆˆ‘‘””••’’��ŠŠŠŠ‹‹��ŽŽ‘‘‘‘’’’’““””””““““’’‘‘’’””••——™™››››šš””������ŽŽŒŒ‡‡„„ƒƒ„„„„„„……„„ƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„‚‚ƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒ€€€€������‚‚��‚‚‚‚‚‚ƒƒ„„„„……ƒƒ��‚‚����‚‚ƒƒ…………………………ˆˆ‘‘””••’’��ŠŠŠŠ‹‹��ŽŽ‘‘‘‘’’’’““””””““““’’‘‘’’””••——™™››››šš””������ŽŽŒŒ‡‡„„ƒƒ„„„„„„……„„ƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„‚‚ƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒ€€����������‚‚‚‚‚‚ƒƒ„„„„„„……„„��‚‚‚‚‚‚‚‚‚‚„„„„………………††��””””����‹‹‰‰‹‹ŒŒŽŽ��‘‘‘‘’’’’““““““““’’’’””••””””••——˜˜——‘‘��‘‘‘‘��ŒŒ‡‡…………„„ƒƒ„„……„„ƒƒƒƒ„„„„„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„€€����������‚‚‚‚‚‚ƒƒ„„„„„„……„„��‚‚‚‚‚‚‚‚‚‚„„„„………………††��””””����‹‹‰‰‹‹ŒŒŽŽ��‘‘‘‘’’’’““““““““’’’’””••””””••——˜˜——‘‘��‘‘‘‘��ŒŒ‡‡…………„„ƒƒ„„……„„ƒƒƒƒ„„„„„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„€€��������‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„ƒƒ‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚ƒƒ„„…………ŠŠ’’““‘‘‘‘��ŠŠŠŠ‹‹ŽŽ������‘‘‘‘’’’’““’’’’’’••––““‘‘‘‘’’““’’��ŽŽ‘‘‘‘��ŒŒ‡‡………………„„ƒƒƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„€€��������‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„ƒƒ‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚ƒƒ„„…………ŠŠ’’““‘‘‘‘��ŠŠŠŠ‹‹ŽŽ������‘‘‘‘’’’’““’’’’’’••––““‘‘‘‘’’““’’��ŽŽ‘‘‘‘��ŒŒ‡‡………………„„ƒƒƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„€€€€��������‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„‚‚��‚‚‚‚ƒƒ„„‚‚‚‚‚‚„„„„††ŽŽ‘‘‘‘’’ŽŽŠŠ‰‰‹‹��ŽŽ������‘‘��‘‘’’’’’’‘‘’’””““’’‘‘‘‘��ŽŽŒŒŽŽ������‹‹††…………………………ƒƒƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚„„…………€€€€��������‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„‚‚��‚‚‚‚ƒƒ„„‚‚‚‚‚‚„„„„††ŽŽ‘‘‘‘’’ŽŽŠŠ‰‰‹‹��ŽŽ������‘‘��‘‘’’’’’’‘‘’’””““’’‘‘‘‘��ŽŽŒŒŽŽ������‹‹††…………………………ƒƒƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚„„…………€€€€��������‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚��‚‚‚‚‚‚ƒƒ„„„„ƒƒ‚‚ƒƒ††ˆˆ��’’““‘‘‹‹‰‰ŠŠŒŒ��ŽŽ��������‘‘‘‘��‘‘‘‘������������ŽŽ‹‹ŠŠŒŒ����ŽŽ‹‹††…………………………††……ƒƒ„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„€€€€��������‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚��‚‚‚‚‚‚ƒƒ„„„„ƒƒ‚‚ƒƒ††ˆˆ��’’““‘‘‹‹‰‰ŠŠŒŒ��ŽŽ��������‘‘‘‘��‘‘‘‘������������ŽŽ‹‹ŠŠŒŒ����ŽŽ‹‹††…………………………††……ƒƒ„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„€€€€������‚‚‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒ„„„„ƒƒƒƒ‚‚��‚‚‚‚‚‚ƒƒ„„„„„„„„††††‹‹‘‘””““��ˆˆŠŠŒŒ��ŽŽ��������������������ŽŽ����������‹‹‰‰‹‹‹‹ŒŒŒŒŠŠ……………………††……††††……ƒƒ„„„„„„……„„„„„„„„ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ€€€€������‚‚‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒ„„„„ƒƒƒƒ‚‚��‚‚‚‚‚‚ƒƒ„„„„„„„„††††‹‹‘‘””““��ˆˆŠŠŒŒ��ŽŽ��������������������ŽŽ����������‹‹‰‰‹‹‹‹ŒŒŒŒŠŠ……………………††……††††……ƒƒ„„„„„„……„„„„„„„„ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ€€€€������‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒ„„„„„„„„ƒƒ����‚‚‚‚‚‚ƒƒ„„„„††‡‡ˆˆ‰‰��““””��ˆˆŠŠ‹‹ŒŒ��������������ŽŽŽŽŽŽŽŽ��ŽŽ��ŽŽ����‹‹ŠŠŠŠŠŠŠŠ‹‹‰‰††…………………………††††††……„„ƒƒ„„……„„„„„„„„ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ€€€€������‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒ„„„„„„„„ƒƒ����‚‚‚‚‚‚ƒƒ„„„„††‡‡ˆˆ‰‰��““””��ˆˆŠŠ‹‹ŒŒ��������������ŽŽŽŽŽŽŽŽ��ŽŽ��ŽŽ����‹‹ŠŠŠŠŠŠŠŠ‹‹‰‰††…………………………††††††……„„ƒƒ„„……„„„„„„„„ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ€€€€€€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„‚‚������‚‚‚‚ƒƒ……‡‡ˆˆ‰‰ŠŠŠŠŒŒ��ŽŽ‰‰ŠŠŒŒŒŒŽŽ��������ŽŽŽŽ��ŒŒ��ŽŽ��’’““‘‘������ŒŒ‹‹‹‹ŠŠŠŠˆˆ………………††…………††††……††††……„„„„„„„„„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ€€€€€€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„‚‚������‚‚‚‚ƒƒ……‡‡ˆˆ‰‰ŠŠŠŠŒŒ��ŽŽ‰‰ŠŠŒŒŒŒŽŽ��������ŽŽŽŽ��ŒŒ��ŽŽ��’’““‘‘������ŒŒ‹‹‹‹ŠŠŠŠˆˆ………………††…………††††……††††……„„„„„„„„„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ€€€€����‚‚����‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒƒƒ��������‚‚„„††ˆˆ‡‡‰‰ŠŠ‡‡ˆˆŒŒ��ŠŠ‰‰ŒŒ��ŽŽ��‘‘��������������““““““””””““’’‘‘������‹‹ŠŠ††………………††…………………………††††††……„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ€€€€����‚‚����‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒƒƒ��������‚‚„„††ˆˆ‡‡‰‰ŠŠ‡‡ˆˆŒŒ��ŠŠ‰‰ŒŒ��ŽŽ��‘‘��������������““““““””””““’’‘‘������‹‹ŠŠ††………………††…………………………††††††……„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ€€€€����‚‚����‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ‚‚��€€��‚‚„„……‡‡ˆˆ‰‰ŠŠ‡‡‡‡‹‹��ŠŠ‰‰ŒŒ��ŽŽ��’’’’��ŽŽŽŽ����‘‘““’’��ŽŽ��‘‘����’’‘‘ŽŽŒŒŠŠ††………………………………………………††††††††……„„ƒƒ„„„„„„ƒƒƒƒƒƒƒƒ„„ƒƒƒƒ€€€€����‚‚����‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ‚‚��€€��‚‚„„……‡‡ˆˆ‰‰ŠŠ‡‡‡‡‹‹��ŠŠ‰‰ŒŒ��ŽŽ��’’’’��ŽŽŽŽ����‘‘““’’��ŽŽ��‘‘����’’‘‘ŽŽŒŒŠŠ††………………………………………………††††††††……„„ƒƒ„„„„„„ƒƒƒƒƒƒƒƒ„„ƒƒƒƒ€€����‚‚‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„ƒƒ������ƒƒ……††‡‡‰‰‰‰ˆˆ‡‡ŠŠŽŽ‹‹ŠŠ‹‹��ŽŽ��’’““’’������’’••˜˜——““����������””������ŠŠ††………………††……††…………………………††††††††……„„„„„„„„ƒƒ„„ƒƒ„„„„„„€€����‚‚‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„ƒƒ������ƒƒ……††‡‡‰‰‰‰ˆˆ‡‡ŠŠŽŽ‹‹ŠŠ‹‹��ŽŽ��’’““’’������’’••˜˜——““����������””������ŠŠ††………………††……††…………………………††††††††……„„„„„„„„ƒƒ„„ƒƒ„„„„„„€€����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„‚‚��‚‚ƒƒ……††††ˆˆˆˆˆˆˆˆŠŠŽŽ��‹‹ŒŒ��ŽŽ����““’’‘‘����““˜˜››œœ››šš˜˜––••••““ŽŽŒŒ��ŠŠ……††††††††††††††††……††††……††††††††††…………„„„„„„„„…………„„€€����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„‚‚��‚‚ƒƒ……††††ˆˆˆˆˆˆˆˆŠŠŽŽ��‹‹ŒŒ��ŽŽ����““’’‘‘����““˜˜››œœ››šš˜˜––••••““ŽŽŒŒ��ŠŠ……††††††††††††††††……††††……††††††††††…………„„„„„„„„…………„„€€€€��‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„‚‚����‚‚ƒƒ„„……††††‡‡‹‹ŽŽ��ŽŽŽŽŽŽ��ŽŽŽŽ��’’’’““””••””••––˜˜ššœœ����œœ™™’’����ŒŒ‰‰††††††††††‡‡‡‡‡‡††††††…………††††††††††††††„„„„„„„„…………ƒƒ€€€€��‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„‚‚����‚‚ƒƒ„„……††††‡‡‹‹ŽŽ��ŽŽŽŽŽŽ��ŽŽŽŽ��’’’’““””••””••––˜˜ššœœ����œœ™™’’����ŒŒ‰‰††††††††††‡‡‡‡‡‡††††††…………††††††††††††††„„„„„„„„…………ƒƒ€€����‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ‚‚��‚‚ƒƒ„„††††††††��šš��ŽŽ������ŽŽ������’’••——™™˜˜””‘‘‘‘““––˜˜˜˜——””ŽŽŽŽ��ŽŽˆˆ††††††††††‡‡††‡‡††††††††††††……††††††††‡‡††„„„„„„…………„„€€����‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ‚‚��‚‚ƒƒ„„††††††††��šš��ŽŽ������ŽŽ������’’••——™™˜˜””‘‘‘‘““––˜˜˜˜——””ŽŽŽŽ��ŽŽˆˆ††††††††††‡‡††‡‡††††††††††††……††††††††‡‡††„„„„„„…………„„€€������‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ‚‚����‚‚ƒƒ„„……„„„„’’¥¥™™ŽŽ‘‘““’’‘‘����‘‘‘‘””——šš™™––’’������������ŽŽŽŽ‘‘””ŽŽ‡‡††††††††††††††††††‡‡‡‡‡‡‡‡††††‡‡††††††‡‡††……„„„„„„……„„€€������‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ‚‚����‚‚ƒƒ„„……„„„„’’¥¥™™ŽŽ‘‘““’’‘‘����‘‘‘‘””——šš™™––’’������������ŽŽŽŽ‘‘””ŽŽ‡‡††††††††††††††††††‡‡‡‡‡‡‡‡††††‡‡††††††‡‡††……„„„„„„……„„€€����‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ‚‚������‚‚‚‚‚‚‚‚““««¢¢’’’’””””””’’‘‘����’’––˜˜™™™™––““’’������������““””ŒŒ††††……………………††††††††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††„„„„„„„„€€����‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ‚‚������‚‚‚‚‚‚‚‚““««¢¢’’’’””””””’’‘‘����’’––˜˜™™™™––““’’������������““””ŒŒ††††……………………††††††††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††††††††††„„„„„„„„������‚‚����ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒ„„„„„„ƒƒ��������������••®®ªª™™’’””––––••““’’‘‘‘‘””••——šššš˜˜——••““’’““••––••’’ŠŠ……††††††……††††††††††††††‡‡‡‡‡‡‡‡‡‡‡‡††††††‡‡‡‡‡‡††††„„„„������‚‚����ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒ„„„„„„ƒƒ��������������••®®ªª™™’’””––––••““’’‘‘‘‘””••——šššš˜˜——••““’’““••––••’’ŠŠ……††††††……††††††††††††††‡‡‡‡‡‡‡‡‡‡‡‡††††††‡‡‡‡‡‡††††„„„„������‚‚‚‚‚‚ƒƒ„„‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„ƒƒ����������’’¯¯¯¯¤¤””””——————––””‘‘‘‘‘‘’’••˜˜™™šššššššš™™™™šš——““ŽŽˆˆ††††††††……††††††††††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡††‡‡‡‡‡‡‡‡……������‚‚‚‚‚‚ƒƒ„„‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„ƒƒ����������’’¯¯¯¯¤¤””””——————––””‘‘‘‘‘‘’’••˜˜™™šššššššš™™™™šš——““ŽŽˆˆ††††††††……††††††††††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡††‡‡‡‡‡‡‡‡……€€����‚‚ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒ„„����������ŠŠ««°°¬¬��““˜˜™™™™™™––““’’����‘‘””––˜˜™™››šš™™™™šš––��ŠŠ‡‡††††††††††…………††††††††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††‡‡‡‡‡‡‡‡‡‡€€����‚‚ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒ„„����������ŠŠ««°°¬¬��““˜˜™™™™™™––““’’����‘‘””––˜˜™™››šš™™™™šš––��ŠŠ‡‡††††††††††…………††††††††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††‡‡‡‡‡‡‡‡‡‡€€����‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„„„ƒƒ����������„„¡¡°°¬¬ªª››˜˜šš™™››šš——““‘‘��ŽŽ��’’••˜˜™™————˜˜——’’ŒŒˆˆ‡‡‡‡††‡‡‡‡‡‡‡‡††††††……††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆ‡‡††‡‡‡‡‡‡ˆˆ‡‡€€����‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„„„ƒƒ����������„„¡¡°°¬¬ªª››˜˜šš™™››šš——““‘‘��ŽŽ��’’••˜˜™™————˜˜——’’ŒŒˆˆ‡‡‡‡††‡‡‡‡‡‡‡‡††††††……††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆ‡‡††‡‡‡‡‡‡ˆˆ‡‡€€��‚‚‚‚ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„‚‚��������€€••¬¬««©©¨¨  ››šš››œœ™™––““��ŽŽ����‘‘””••””””””’’��‹‹��ŠŠ‡‡‡‡††‡‡‡‡††‡‡‡‡††‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡ˆˆ‡‡€€��‚‚‚‚ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„‚‚��������€€••¬¬««©©¨¨  ››šš››œœ™™––““��ŽŽ����‘‘””••””””””’’��‹‹��ŠŠ‡‡‡‡††‡‡‡‡††‡‡‡‡††‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡ˆˆ‡‡€€��‚‚‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„„„„„ƒƒ‚‚������~~‡‡¢¢¬¬§§££§§ŸŸ™™››››šš˜˜––’’��ŽŽ��ŽŽ����������ŽŽŠŠ’’  œœŽŽ‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡ˆˆ‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡‡‡‡‡ˆˆ‡‡€€��‚‚‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„„„„„ƒƒ‚‚������~~‡‡¢¢¬¬§§££§§ŸŸ™™››››šš˜˜––’’��ŽŽ��ŽŽ����������ŽŽŠŠ’’  œœŽŽ‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡ˆˆ‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡‡‡‡‡ˆˆ‡‡€€��‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒƒƒ„„„„„„„„ƒƒ„„„„„„„„‚‚����€€||~~‘‘¨¨©©££¡¡¡¡šššššš™™˜˜––””’’��ŽŽŽŽŽŽŽŽ��ŽŽ����‹‹——¥¥¨¨££““ˆˆ‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††‡‡ˆˆˆˆˆˆˆˆˆˆˆˆ€€��‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒƒƒ„„„„„„„„ƒƒ„„„„„„„„‚‚����€€||~~‘‘¨¨©©££¡¡¡¡šššššš™™˜˜––””’’��ŽŽŽŽŽŽŽŽ��ŽŽ����‹‹——¥¥¨¨££““ˆˆ‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡††‡‡ˆˆˆˆˆˆˆˆˆˆˆˆ€€‚‚ƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒ„„„„„„ƒƒ„„„„„„„„„„„„ƒƒ‚‚€€}}{{{{‘‘££¥¥ŸŸŸŸžž˜˜™™˜˜——––””““‘‘������������ŽŽŽŽ‹‹––¤¤§§ªª§§——‰‰††‡‡††‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††††‡‡ˆˆ‡‡‰‰ˆˆ‡‡€€‚‚ƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒ„„„„„„ƒƒ„„„„„„„„„„„„ƒƒ‚‚€€}}{{{{‘‘££¥¥ŸŸŸŸžž˜˜™™˜˜——––””““‘‘������������ŽŽŽŽ‹‹––¤¤§§ªª§§——‰‰††‡‡††‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††††‡‡ˆˆ‡‡‰‰ˆˆ‡‡€€��‚‚‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„ƒƒƒƒ„„„„„„„„„„„„‚‚}}{{{{{{||}}ŠŠššŸŸŸŸŸŸœœ——————––““““’’‘‘������������ŒŒ‹‹••¢¢¤¤ªª­­©©˜˜ˆˆ††††††‡‡††††††‡‡‡‡‡‡ˆˆˆˆ‡‡ˆˆ‡‡‡‡ˆˆ‡‡ˆˆˆˆ‰‰ˆˆ††€€��‚‚‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„ƒƒƒƒ„„„„„„„„„„„„‚‚}}{{{{{{||}}ŠŠššŸŸŸŸŸŸœœ——————––““““’’‘‘������������ŒŒ‹‹••¢¢¤¤ªª­­©©˜˜ˆˆ††††††‡‡††††††‡‡‡‡‡‡ˆˆˆˆ‡‡ˆˆ‡‡‡‡ˆˆ‡‡ˆˆˆˆ‰‰ˆˆ††€€��ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„ƒƒ„„„„„„ƒƒ„„„„„„„„„„„„„„„„€€{{{{{{{{{{{{||„„‘‘œœ��ŸŸœœ––••••••””““’’’’‘‘����ŽŽ����ŒŒ““  ¥¥ªª¬¬­­¦¦ŽŽƒƒ††‡‡‡‡††††‡‡††††‡‡ˆˆˆˆ‡‡ˆˆˆˆ‡‡ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡€€��ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„ƒƒ„„„„„„ƒƒ„„„„„„„„„„„„„„„„€€{{{{{{{{{{{{||„„‘‘œœ��ŸŸœœ––••••••””““’’’’‘‘����ŽŽ����ŒŒ““  ¥¥ªª¬¬­­¦¦ŽŽƒƒ††‡‡‡‡††††‡‡††††‡‡ˆˆˆˆ‡‡ˆˆˆˆ‡‡ˆˆˆˆˆˆˆˆˆˆ‡‡‡‡‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„ƒƒ„„ƒƒ„„„„„„„„„„„„„„„„……„„ƒƒƒƒ‚‚€€}}zzzz{{{{zz{{{{||€€‹‹——��ŸŸšš••••••••””““’’‘‘������ŽŽŽŽŒŒ““ŸŸ§§««««¯¯¯¯––‚‚ƒƒ„„……††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆ‰‰ŠŠˆˆƒƒ……‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„ƒƒ„„ƒƒ„„„„„„„„„„„„„„„„……„„ƒƒƒƒ‚‚€€}}zzzz{{{{zz{{{{||€€‹‹——��ŸŸšš••••••••””““’’‘‘������ŽŽŽŽŒŒ““ŸŸ§§««««¯¯¯¯––‚‚ƒƒ„„……††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆ‰‰ŠŠˆˆƒƒ……€€‚‚ƒƒƒƒƒƒ„„„„„„„„……ƒƒƒƒ„„„„„„……„„„„„„„„ƒƒ‚‚��€€~~~~}}}}||{{zz{{{{{{{{{{{{{{||ƒƒ��˜˜šš””””””••••““’’‘‘����ŽŽŽŽ����‘‘��¦¦ªª®®»»··••…………„„ƒƒ……††‡‡‡‡‡‡‡‡ˆˆˆˆ‰‰‰‰‡‡……‡‡��——����||€€€€‚‚ƒƒƒƒƒƒ„„„„„„„„……ƒƒƒƒ„„„„„„……„„„„„„„„ƒƒ‚‚��€€~~~~}}}}||{{zz{{{{{{{{{{{{{{||ƒƒ��˜˜šš””””””••••““’’‘‘����ŽŽŽŽ����‘‘��¦¦ªª®®»»··••…………„„ƒƒ……††‡‡‡‡‡‡‡‡ˆˆˆˆ‰‰‰‰‡‡……‡‡��——����||€€€€‚‚ƒƒƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„„„„„……„„ƒƒ‚‚}}||||||{{||||||{{{{{{zz{{{{zzzz{{zz{{||��‡‡ˆˆŒŒ��““””““’’��������ŽŽŽŽ��’’žž¥¥¬¬ººÂ¯¯ŒŒ……††††„„ƒƒƒƒ‚‚……††‡‡……ŽŽ™™‘‘††��’’  œœŽŽŒŒ‘‘‘‘€€‚‚ƒƒƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„„„„„……„„ƒƒ‚‚}}||||||{{||||||{{{{{{zz{{{{zzzz{{zz{{||��‡‡ˆˆŒŒ��““””““’’��������ŽŽŽŽ��’’žž¥¥¬¬ººÂ¯¯ŒŒ……††††„„ƒƒƒƒ‚‚……††‡‡……ŽŽ™™‘‘††��’’  œœŽŽŒŒ‘‘‘‘��‚‚ƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„ƒƒ‚‚€€~~}}||}}||{{||||{{{{||||{{zzzz{{||{{{{{{||{{||}}}}}}~~ƒƒŠŠ��‘‘��������������ŒŒ��››¡¡¬¬³³³³ŸŸ……††……††…………„„€€€€……„„��žž““��““››��œœœœœœ��šš��‚‚ƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„ƒƒ‚‚€€~~}}||}}||{{||||{{{{||||{{zzzz{{||{{{{{{||{{||}}}}}}~~ƒƒŠŠ��‘‘��������������ŒŒ��››¡¡¬¬³³³³ŸŸ……††……††…………„„€€€€……„„��žž““��““››��œœœœœœ��šš+×þùûþþýûüþþþþþýûþþþþþùîÞßááßÞááàßáåãÛ·˜žªÄØÚ×ÖÚÜÜÙØÙÚÜÙÜÜÜßÜÛÝÝÞÙÕÔ×Ûß×ɪ‘’“‘Œ�†vu‚ªÙàÞÞßÝÝÖÐÙÙÑÐÒÔÔÚËŠs‡„y€µÑÏÑÓÔÙ×ÔÖÕÑÎÒÑÉÀÀʳ‰‡¸ÛÒÔÕ×ÛØÒÏÎÏÌÊŸq†»ÌÏÒÏÎÑÊÆÒ»}~¹ÎÌËÁ¹ºÈµ|p¯ÅËÃ1ÆÁÓäÍÕ¹ÓϺøÆËзØÄÆîкÕíáàáááàßßâææÙº˜‘§¼ÍÓÓÔÒÕÙÚØ×ÙØÚÜÚÛÜÝÞÞÝÞßÜ×ÔÝßÕÁ¦˜““—š�vvy‡£ÊÝÞÝÝÛÚÙÜÇ¿ÙÓÎÑÐÑÑÌÓÅŒxˆ†v‚¸ÐÐÔÒÖÖÒÔÔÑÎÐÐÊÄÈͼ¡…‡½ÙÓÔÖÙ×ÓÐÎÎÇɸˆqйÍÑÑÏÏÍÉÍЩv�ÄÐËÿ½ÇÄœp~¶Ï¼0±«Ä­¹ˆ¿Ãгް²‡Ê°Š»Ë¦´çãàâàÞßâäâÔº�’ž³ÍÙÛ×ÔÔÕ×ÚÑÎÙÙÔÚÜÛÜÛÜÜÝØ×ÙÚÝÛÓ» ’��—˜Š{sx‘³ÑßâàÜÛÛÛÛÛÛÖÕÚÒÑÑÐÐÑÌÑÒºˆwŠ�k~´ÐÑÕÖ×ÓÒÓÒÏÏÌÌÎÍ、{‡ÂÚÑÔØØØÒÎÎÌÍËÀ’q’ÃÐÏÎÍÎÌÊÏÏœq–ÌÑÈÆÂÊɱŠe‡Ç»-Öݦµ¾ÄžÌѰ¥­Ä¾œÑ˯¢åÏ¡ÐåßÞÝâåÝѸ�š¦½ÕÚÙ×ÈÈÖÖØÛÙÍÐÛØÖÚÚÛÛÙÜÖÓÕØÝÜͱ–ŠŠ—�“‡{w�™¿×áãÞÛÚÜÜÜÝÝÜÚÛÚ×ÓÒÒÏÐÑÑз²º…u‡‚q€¯ÉÎÓÖÕÕÕÑÒÓÌËÐÍÏÆ¿À�w‰ÆØÓרØÖÏÌÐÐÉÏÊ›z�ÄÅÊÌÍÆËÎÒÊ’p¤ÒÍÄÅÍ̹®�i”¹(¶Ú¼ÙçÑÎÝáããâàÒÝâæÚåÛÕàÞÝáåàͳ š©ÄÖÔÔÓÕÕÄÊÕÖØÚØØØØ×ÚØÕÚÛÚ×ÓØàÛɬ‘…‹—™‘�ut…§ÇÚââßÛßÞÝÞÝÝÜÚØÛÛÛÞÝßàßßÞÛØÉ¿ÐÀ†s…†u~®ÌÏÓÓÕ×ÔÒÔÎËÉËÓȾļ–xŽÊÖÑÖÕ×ÔÐÐÏÉÉÐÖxŸ¼ÇÍÎËËÐÏÔɉp«ÐÊÉÏÑÆ¾ºˆo”‡Å±½ÛåÜÑáæäâãããßàáæàÞåãáæá̬™˜•·ÖÛÖÒÒÓÖØ××ÕÙ×Ô×ÚÚ×ÖØØÙÙ×ÛÛÛצ‘„…“œ’rv�²ÏÙÙÜÚ×ÍØØÙÝÝÛÝÞÞàäçéëëììíììëëçåÞßÌ�m€‹~„²ÐÑÒÕÔÕÔÎÏÎÇÏÕÇÁÁɘt�ÆÕÒÔÖÕÖÒÑÏÍÊÈ¿ˆu ÃËÍÎÊËÐÎ×Àys³ÐÌÏÐǼ¾¯}j}­ÄØÏÖÜáàÝÜÛÙÙÛÝÛÛ×ÖÞââÝË®›š¤­½ÖÚÙר×ÙÙÙÚÖÖØÙ××ÙÛÚØÙÖ×ÛÝÝ϶žŽ‹Ž—�~{u~š¾×áß×ÔÙÝÒÅÔÍØÞÝàäçéëìììììëëëëëëìíìëèíÙšx€Š�…²ÑÒÖÒÒÕÍÐÐÏÔÕÌÅÇÊÊ»�s�É×ÓÖÒÔÔÑÐÍÏÈȹ�x²ÎÎÌÊÌÍËÎÖ°o{ºÍÎÏǽº·¡y!u®ÝÞÛáâáááàÝÜÝÞÞÝÝàãäÕ¾­››ª½ËÏÙØÔÛÝÛÙÙØÙÙרÛÝÙÖ×רÖ×ÕÙÛÊ­’‡‰’—Œ}po†£ÅÙÝÝÙ×ÚÛÛÜÛÜÜÛßãçêëììëëëëëêêëëëëêëëëëìëðèÀ—†…€‚®ÐÔÒÔØÓÆÉÒÎÎÌÈÌÆ¼¼±Šr”ÎÖÓÔÓÔÑÏÏÎÍËκ{„ÃÒÌÌÎÌÌÍÐÒ¦k„ÂÐÏʾ¾¸º¢}ÌÞÞââààááÜÙÜÝÛÜßãáÒ¸��š°ÅËÌÑÖÖÙÛÝÜÚÙÕÕÒÓ×ÙÚ×ÕÖÕÕÖÜÛÒÁ¨‘ƒˆŽ—ˆunrްÅÖá×ÏØÛÜÛ×ÚÜÞßáçèéììëëëëëëëëëëëìëëììììëëëéîóã¼”…~©ÎÑÓÙÖÈÊÓÎËÊÉÍ̺¾²ŠtœÒ×ÓÔÖÒÏÎËÏÍÊЬu’ÇÍÌÎÍÍÍÍÑÒši–ËÒËÃÇ¿¾°‰ÛàßßáâáßÜÚÞÜÛÞáÞʰ›”Ÿ¬½ÑÓÎÍÍÔØÛÜÛÙÖÔרÓÔØÙÔÓÔÔØÛÙÒºŸŽ‰Œ”™ˆxmw“³ÍÞÒÒ××ÛÝÜÜÜÛÝßáåéëìëìëëëëìëëëììëëëëëëìëëëìíìèéðñتˆ|{©ÐÑ×ÔÐÓÔÓÐËÌÍÍËÅÁ°‡qœÑÔÑÕÖÓÑÐÏËÊÉ̦w—ÄÊÍÎÍÌÍÌÓÍ‘oŸÍÑËȾ¾­‡ØáßààßÞÜÙÚÒÑáÝʬ”‘š¯ÇÐÓÔÌÊÍÑ×ÚÛÜØ××ÖÓÓ×ÖÚÙÕÐÙÜÙ˲šŽŠ�—‘†wn|ž¿ÐÔÔÙרÜÞÝßÝÛÜÞâçêììëëììëëëìëëëëìëëëëëëëìëëëìììëêçëò縋|~ªÑÔÑÊÑÕÓÓÎÌÌÉÊÈÀ¼À©€o ÔÔÒÕ××ÓÎÌÌÌÊÉœt™ÄÌÏÊÊÎÎÏ×ȇk§ÒÎÌÂÁ®‡ÙáÞÝßßÞÛʨ�¸Ê°œ�™§½ÐÐÏÖÔÉÌÍÑÔÚÝÜÜÙØÕÁÉÖÐÒÖÙÙÚɯš��“•‹~rq„¤ÅÚÞÙÔÖÛÝÜÔ×ßßÜÜáæêìëëêëëëêëìëëëëëëìëëëëëëìììììììëëêêéèîí¿‘|x¤ËÏÉÐÔÒÑÎÍÌÌÊÉÅÀ¿·¨†t©ÖÕÑÓÖÒÎÍÍÎËÊ‘sŸÄÍÇÈÎÍÒÒÖ¾{tµÒÏËŲ‡ÖßßäåâÞÅ«”u‘›”š«»ÀÈÒÑÒÙÑÍÏÎÒ×ÚÛÚÚÙÚÔÍÑÐÒ×ÚÑ앎”˜“„tmw�±ÎßßÚ×ÙÛÛÛÛÙÏÖÞÜÞäéëëìëëëëëëëëìëëëìëìììëëëëëëììììëëëëëêëêèìí¿ŒzvžÇÐÒÔÔÑÏÎÍÍÊÉÉÅ´¯·¬‡v¨ÕÒÎÒÒÏÏÍÍÏÌȾ�v¡Ç¿¿ÌÍÑÒÑÖ¹v{¾ÑÊÈ·†ØäáØ¼®«œ‹•�”¯¿ÌÔÏÅÐÑÔØÏÐÎÒÚÜÚÛÛØ××Õ×ÔÔÙÔ¼¡’�•�–„qo}›¾ÔßàÛÖÔÙÜÛÚÜÝØÚÝÝáçêëëëììëëëëëìëëìëëëëëììììëëëëëìëëëëëëëëëêêèìꮇ€wžÏ×ÔÖÖÑÏÐÎËÈÆÇ¸°´½³Šv¬ØÎÐÔÑÏÎÏÍÌÊÊÀ‰t©Á¾ÉÎÏÒÒÒØ°o‡ÆÌȸˆÞÒ®—‹ƒ€Œ��Œ ¼ÎÑÒÔÒÔÖÈÓÕÍÎÍÖÛÚÚÛÛÙÕÒÖÓÐɳ��‘–—–…ss‡¦ÆÛßÛ××ÙÚØÛÕÒÜÝÝÝÞÞäêìëëëëëëëëëëëìëëìììììììíìëìëìììììëëëëëëêêëêêéïÚ˜Š�t�ÐÕÓÖÓÐÑÏÌÊÃÃȾ»½»´†w±ÖÒÔÓÑÓÓÏÌÎÉȼƒz¢³ÅÌÍÑÓÒÕÖ¤p—ɼ­�²ž”š¥…jp¦¾ÂÓØÕÏÐÑÖØÑÑÖÏÌÉÐÙÙÚÛÚÕÖ××ÔÀ§‘ˆ�˜˜�{sz”·ÐÝÝÚØ×ÚÞÜÚÙÚÔÓÞÞÜÝàæëëëëëêëëëëëëëëìëëìììììììììëììëììëìëëëëëëêêêêêêèî¿…Š{mšÍÒÑÓÑÑÐÌÌÆÂÅÁÁ¿¸±¤†x²ÖÌÁÎÖÔÒÐÎÍÆËº}m’ÀËÍÐÑÒÑÕÒ›s¢½«s™¨ÆÔÒ§qƒº×ÚØÖÕÔÖÖ×ÒÓÚÒÌÏÌÕØØÚÚÖØÛÒ¼¡�ˆ‹•™‡qp€”µÙáÝÚרÝÜÛÔÕÚ××ÜÞ××Ûßçëëëëëëëëëìììëëëììëììììììëëëëììëìììììëëëëêêéêêéééìä˜xˆzošÌÓÎÐÑÑÌÊÊÈÄÂÁÿ°®¯}x·ÑÀÍÓÒÔÕÐÍÊÆÎµwv²ÈËÎÏÐÑÒ×Αuªµ~ÆÓÚÞÛͼÊÓÎÐÓ×ÔÓר×Ô×ÖÎÎÍÒÖÕÕÚÜÙÑ»ŸŒ‡Ž•�€qj|©ÊØÜÞÙÛÑÏÜØÚÚÍÒÛÛÛÛÛÓÕáçêêëëìëììëììëëëëëììììììëììëììììììììììëêêêêêêéêéééêéîÊ~yŠ}p–ÆÊÉÑÓÎËÉÈÄÁÃÅŹ»¢z|¼ÒËÑÓÔÖÔÏÍÈÉÓ­q‡½ÊÌÏÏÐÒÒØÉ‡{¡‡×ÛÒ×ÑÌÙÖÓÖÕÔÕÐÐÕ×ÕÕØÏËÍÎÒÔ×ÛÚÍ·žŒ‰’–Šrer‹©ÌÞßÝÙÚÝßÓÐÚרÙÙÚÜÝÜÛÛÝáèêêëëëëëìëëëëëëëëëëëëììììììììììììììììëëêêêééééééééêêêë¸qs‡~o’½ÆÎÓÐÍÉÅÇÁ¿ÄÉÊü³¦|½ÒÐÔÓÓÓÒÏÊÉÌÌ q“ÃÌÍÏÎÐÓÒØ¿€v…ÒÛÐÎÏÊÍÐ×ÕÓ××ÐÐ××ÐÖÕÊËËÏÕÚØÈ±šˆ†ŒŽ‚mdr’»ÕÞÝ×רÚÛÜÜÛÛÚÙÙÛÜÛÝÜÛÜÜáçéêêêëêëëëëëëëëìëëëëëëëìììëììëìììììììëëëêêêêééèéèééééééÞ¨on„}q‘ÁÍÌÐÐÍËÊÄ¿ÂÄÊȺ§¶®z…ÁÖÒÓÔÓÓÑÊÊËÌË¢sžÈÉÎÐÏÒÓÒÕ³z†ÖÛÐÍÊÁÌÓØÖÔÒÔÑÒÙÕÏÔÑËÍÐÕÓÀ¦“ŠˆŠˆ|j^ršÃÜà×ÑÓÚÝÜÚÙÚÚÙÙÚÙÚÜÛÝÔÔÝÛßæèéêêêêêëëëëëëëëëëêìëëëëìíìëììììììëëëìëëëêêêêéééééèèèèéçâÙ³vl‚~q�ÄÎËÏÏÏËÆÁ¿¾Ç˽¨¶Æ«w†ÃÕÑÒÓÔÓÌÌÐÌÌÌ™w¦ÈËÎÏÐÒÑÐÏ©‡ÖÕÐÑËÈÑÕÔÕÕÑÒÑÕ×ÓÔÓÐÐÐ̼¢�‰ŒŒ†wkiyœÉßßÙÖÕÔÛÕÒÛÛÛÛÚÙÚÚÛÚÙÜÝÔÔÜÝäèèéêêêëëêëëëëëëëìëëëëëëëìíìììììëëëëìëëëëëëêêéêééèéèèèèèèåØ×ºwh~~o�ÃÎÌÌÍÊÈÃÀÀÄÉÆ±¸ÈÆŸqˆÅÓÏÓÓÒÏÍÎÌÉËË’z±ÍÍÐÐÐÒÐμ‰ÔÓÑÐÍÏÕÙÔÓ×ÖÒÒÖÔÓÖÕÓDzœŽ‹‘“†uik�¤ÇÞßÙÕÖÙÚÛÜÕÔÛÜÙ×ÛÚÚÚÚÚÚÛÛÜÛÝäççèéêêêëëêêëêëëëëëëëëëëëëììëììëìììììëëëëëëëêêêéééééèèèèèèçÜÏÕ¹|h{|n‰¿ÐÊËÊÉÅÀÂÃÃɼÀÏǸ™rŽÉÕÒÕÔÓÏÏÏÍËÏÈ’¸ÑÍÏÑÒÒ˳ˆÒÕÑÍÌÎÖÖÓÕ×ÓÑÒÕÖÛׯ¬’ŠŠ��‚tkmƒ­ÎÜÝØÕÖÖÙÚÚÚÙÜÜÕÕÙ×ÚÛÚÛÚÛÜÛÛÛÜâæçèèéêêêêëêêêëëëêêêëëëëììëëëëëìììììììëëììëêêêêêéééééèèèèèèçãÕÌÔÂj~}o†¾ÒÉÇÈÇÆÄÁÃÊÄÈÓʹ¶šr’ÍÔÑÒÓÕÔÒÍÎÊÐÈ�„½ÏËÐÐÑ͵„ÎÑÍÌÍÓØÑÑÖÒÐÓØÚÔÄ©’††’•†ofr�¸ÈÕÞÖÓØÛÚ×ÚÛÛÚÚÚÚÖÖרÚÛÛÛÚÜÛÚÛÛàåæççèééêêêêêêëëëêêêëëëììììëëëìëìììììëìëëëëëëêêêëêééééééèèèèçäÛÎËÓ¿vf€~nƒ¿ÏÇÈÇÈÇÅÆÆÁÊÑÐĬ³�m•ËÐÍÒÖ×ÔÎÏÏÊÏËŒ‡¿ÌÍÎÎй„ÎÐÍÌÏ×ÕÑÒÒÏØÜÓ¸žŠ‚‡““‚ts€£ÀÑà×Ò××ÙÛÜÛÚÚÚÚÙÙÙÚÛÛרÚÚÚØØÜÜÛÛÝãæçèçèééééêêêêêêëêêëìëëëëëëëëëëëëììììììëëëëëëëëêêêééééééèèèèèåàÓÌÉͬzn{xg¸ÌÅÉÉÈÊÉ¿¸ÇÐÎÈ´±¬‘r˜ÏÒÐÔÖÕÒÓÔÏÊÔÆ‚ŠÁÎÍÍÏ·†ÑÒÎÍÐÔÐÑ×ÙØÏ·™…‡’‰{nn…«ÎßàÜÖ×ÙØÚÚÛÚÚÚÚÙØØÙÙÚÚÚÚÙÛÚÚØ×ÛÜÛÛÞâåæççèèééééêêêêêêêëëëêëëëëëëëëëìëììëëëëëëëëëêëëêéêêêééèèéèèèèæâØÍËÉÒÃixyl{®ÉÍÍÆËÎǺÂÒÐÆ¼²®¸’p ÍÑÒÒÒÔÕÕÒÐÎÔ³z�ÅÏÎиˆÏËÊÎÐÑÕÚÙÍ´•��ŠŒ~qlr�³ÒàÞÖÕ×ÚÛÙÙÚÙÛÖ×ÙÙØØÚÚÚÚÙÙÙÙÚÙÙÚÙ×ÖÙÜàâåææççèéééééêêêêêêêëêëëëëëëëëìëëëëìëëëëëëìëêêêêêêéêêéééèéèèèèæâÜÏÉËÌÕÅ�u}zix°ÈËÊÌÎÎÄÆÓÑÊÀº²¹´ŒsŸÎÓÐÒÔÔÖÓÔÓÍͯ}–ÆÎз…ÄÃÇÐØÚÕÀ¦‘�ƒ‹ˆxhf{�¿×àÞÙÕ×ÚÚÚÜÛÜÛÚÚØÙÙÙÙØÙÙÙØØÙÚÚÙØØ×ÖÖØÙßääææåçççèéééêêêêêêêëëëëëëëëìëëëëëëëììëëìëëëëëëêêêêééêééééèèèèçæãàÕÊÌÌÊÖÑ–mvwly¨ÈÌÌËÍÈËÓÏÊÅ¿·²·µ�x¨ÓÓÓÓÓÖÕÔÔÐÊЬz�ÊÒ¶x­¯ÌÜÖº—…‚†ˆ„ygg‚ªÏÞáÜ×ÖØÚÚÚÚÛÜÜÜÛÚÙÜÚÙÙÙÙØ×ÕרÙÚÚÙØÙÝßßÕÖßãäåååæççèééééêêêêêëëëëëëëëëììëëëëëëëëëëìììëëëëêêêéêêêééééééèèçæäáÚÎËÌÊÊÓÈ‹ovzt}¨ÅÊÍÐÎÍÔÑËü¸³®¸¶�{¯ÕÒÓÖÖ×ÖÖÖÏÊʤ~¥Ð¶s•–Áºœ‡€‰Ž…tjx’µÔßÞÚÕÔÙÛÙÙÛÚÙÚÛÛÚÚÚÙÙÖըרÚÙרØ×רÛßßÚȱ¶ÓÛáâäååææèèééééêêéêêêêëëëëìììëëìëëëììëëëëììììëëëëëëêêêééééééééèèçåâÝÑÊËÉËÌÔÊ‘oz‚v�«ÌÐÐÍÊÒÓÎŽ»½¶¶·°Š{²ÔÔÔÖרØÖÔÌÉË�z­º}²Ÿ‘Œˆ�Œ~to}¨ÊÜâÜÖÕ×ÙÙÚÚÙÚÜÚÚÚÜÝÚØÚÙ×ÖרÖ×ÚÙØÖÕÖÛÞÜϺ¡Š†¹×ÚââääåææççèèééêêêéêêëêëìëìììëëëìëìíìëììëëëëëëëëëëëêêêééééééèéèèèæãßÕÌËÊËÌÎÖÊ’o}‚y€¬ÍÐÊËÑÓÏËú¿¿¾µ³®‹�µÓÑÓÖÖ×ÕÓÏËÌÈ•�¥yÊ®�Œwgo�°ËãâÜÕÏØÙØÚÚÙØÚÜÜØÛÝÞÞÛÙÚØ×ØÙרØ×ÖÖÚÜÛÓÁª–Œ‰�©ÖÚÞâããäåææçççèèéêêêêëêëëëëëëëëììëëìëëììììëëëëëëëëëëêëêëêêêéééèèèèèæäàÙÎÌÉÊÇÇËÏÊ“kv{v~­ÓÎÌÒÓÏÊÆ¿¼½Á¼±¸¿‘ƒ¶ÖÔÒÕØÖÓÏÎËÎÆ�{qº²‚mlw“·ÕâßÙר×ÕÙÙÙÙÙØØÙÕ×ÙÛÜÜÙØÚÙÙ×ÖÖÖÕÔÖÜÞÚÆ®šŽŠ“�¢ŸÁßÝàáããäåååçèèèééééêêêêêëìëëëëìììëìììëëììëëëëëëëìëëëëëêëêéêéééééèèèçäáÜÒÍÊÉÇÇÌÉÎÈŽhy‚v~¯ÐÍÐÕÑÊÉÆÂÂÄÀ³ºÍ¸ƒ‰ºÓÒÔØÖÓÏÎÌÊÎÀŒw£�w~�ÃÚÜÙ×ÖÙÜÚÚÚØÙÚÚÙ×ÙÙÔÖÙ×ÙÙ×ÖØÚÙ×ÔÓÖÙÛÚп¦ˆ„Œ™Ÿœ•‰�ËâßßáâããääåæçèèèéééêêêêêêëëëëììììëëëëìëììëìëëëëëëëëëëêêêêéêêééééèèèçäâÞÕÍËÊÉÊÈÌÍÓОru{nu¬ÐÏÑÓÍÊÉÄÀÀÁ¸¼È¿¡�„ºÔÑÕÖÔÐÐÏÍËдg‹Œ¥ÎÜÝÚÕÖÚÜÜÛÚÛÙØØÙÚØÕÙÚÚÙØÖØÙØØ××ÕÕÙÜÛÓï˜�‹‹–›–‰~vžÛßßàáâãâãååææçèèèéééééêêêëëììëììëëëëëìëììëìëëëëëëëëëêêêêééêéééééèèèçåãàÙÎÊËËÅÀËÆÈÖÓ pwuiz«ÎÑÑÒÏËÆÀ½¾»ÀÊÀ¬š~‹½ÔÑÓÓÑÒÐÍËË·nµÓÛÜØÖ×ÚÙÙÛÛÚÚÚÖØÙÙÙ××ÙÚÙÙÙÚÙÙØ×ÕÖÛÝ×ȯš�Œ“šš“ˆ€zwxx~½àÝßàááâããäååææçèèééééêêêëëëëëëëëììëëëììëëëëìëëêêëêëëêêêéééêéééééééèçæäàÛÏÊËÃÇÊË´±ÍÏÔ¢qswqt£ÏÐÊÈÍÌÅÿ¼ÂÌȯ –zŠÇÖÐÑÐÏÑÎÌ̶‡×ߨÓÖØÚÚÛÚÛÜÛÛØ×ÙÙÙÙרØÙÚÙÙÙ×Õ×ÜÞØË¹ �Š’��•Šwuurtyƒ¡ÓÞÞßàááâããäååææçèèèèééêêêêëëëëëëëìëëëëëêêêêëëëëêêêëëëëêéééééèéêéééééèæäâÝÔÎÌÅÉÍËľËÊÒÓ¥xsxpp¢Í¿®ÉÐÇÄÅÇÈÌι£¢›s‰ÈÔÐÑÏÐÐÎζ†Ñ×ÖÖרÙÛÝÝÜÚØÙÙÚÙØÚÙ×Ø×ØÚØÔÖÙÜÚÓ¾£‘‰Œ—�Ÿ—„wttrqt€”«ÈØÛÞÞßàáááãääääåææççèèéêéêëëëëëìëëêëêëëëëëìììììííìëëëêëëëëìëëêéééèéèèèèæåâàÔÉÍÍËÊËÏÎÊËÌÒÖ²{s}mr Â¿ÈÏÈÃÈÍÍÍÏÁ¯¦®˜o‰ÆÓÎÑÒÒÏй…ÓÙÕØØØÚÜÛÛÜØÐÖÚÙÕÖ×ÖרØÖÕÔÙÞÜÎ²š†…“œŸ—Š�xvuuvyŠ¥ÃÖßßÙÚÞÞßàáââãääääææçççèéêêêêëëëëëëëëëëìííííìêéèåäáßÝÜÜÛÛÛÛÝßáåçéëìëêëêéééçåãâÖÊÈÈÍËËËËÊÊÍËÍ×¶yuzpršÂÊÎÌÆÆÉÏÏÎÆ´¨ª­–p‰ÉÕÐÓÕÑѼ…ÔÚØÙÙÙÚÛØÚÛÚØØÙ×ÖÖÕÕÖÕÕØÛÛÓ¿§•Œ�™¡�‘†}yqsxŠ£ºÏÜßÜÚÐÒÝÞÞßááâãããäååæççèèèêéêêêêêêëëëííìëéæâÞÚÕÐÌÇÃÀ½¼»º»¼¼½¿ÁÃÄÆÊÎÓÙÝáæéêëêéèäáÛÐÇÆÌÎËÉÌËÉÎÍÊÎ×´|txrr�¾ÌÉÇÄÁÌÑÏȽ·´¨¤˜o�ÉÐÐÓÒÒ½…ÔÛØ×ØÚÚÚØÙÙÚÚÚÙ×ÙÖÒÔÙÚÛÙË·Ÿˆ‡–  ˜Œ�}|zwx‚—³ÅÙãÙÖ×ÖØ×ÙÞßÞàááâãäääåææççèéééééééêëìíìêæáÚÔÏÉÄÀ½º·´²°®­¬«¬®®¯°±±±±²²²²µ·¼ÃÊÒÙßäæçæáØÐÍËËÊÉÉÆÄÌÍÍÍÎ׸~oyww›ÃžÄÅÊÒÐÈÂǽ¯ª±›nˆÄÑÐÓÔ»†ÔÚØØ×ØÙÙÚÙÙØ×ØØÖÕÓÕÛÜÑ¿¬›”—š¡ž‘…}{yx|ˆ“ªÇÚàÒÔÖÎÔÚÙØØÛÞßÞàâââãäåååæçççèèèèêêìíìêæàÙÒËÆÁ¿½¹¹¹·´²¯«§£Ÿœ™˜˜—˜š™––𡦍©©¥¡¢£§¯¸ÀÈÐÕÙÛÛÚØÔÒÐËÿÅÊÍÐÍÎ׺�r{yw™¿¹ÃËÉÍÐÈÁÀ»·³²· v•ÌÔÐÔ»†ÔÚרÙÚÙÙÙØÙ×ÕÕÖØÚ×ÒdzŸ’”ž¤¡—‹�zxxwzЧÇÖÝßÛÖÔÕÔØÚÚÚÙØÜßßßàáâãäååæåææçèèêêëíìéåÝÕÎÈÂÀ½»¹¶²¬¦¡œ—‘Œ‡�|ywvtsrqrrstw|‚Š“˜™™›žžŸ ¡¥§®´»ÂÉÎÓ×ÙÙÔÍÊÊËÌÍÎÏ×½zixsn”­½ÉÊÌÎÌÁ¼À¿¶º¾Æ¦yœÏÓÓ½…Ó×ÕÖÚÜÛÚØ×ÖÕÖÛÞÛγœ�“˜Ÿ¥ž�ƒ~|{ws|—´ÍÛÞÚØØ××ÙÙÙÚÛÚÚÚØÝàßßàáâãääåæåæçééêëéæáÜÕÍÇÁ»·³®¨¡›–‘Œ†�|vpljigffddddbadedfit{}~}�Š“œ¢£¥¤££§ª®´¹½ÂÉÏÒÕÖÕÒÐÏÊÌÖ¶|ozoj‡·ÉÍÑÎÎÅÀÁÀ½ÄÂÄ¿—rœÎÔ¼†Ñ×רØÙÙÖÕ×ÚÛÚÒ®—Љ‘ž¡™�€{yxvz}“¾ØàÞÚÖÒ×ÛÚÚÙÙÙÚÛØÚÙÙÞààààâããååææèééèäáÜØÓÎÆ¾´ª¡›˜’Œˆ…‚�}{yvsld_]\\\[Z[\^]YZ\[\bospjcdjs~Š”œ¥«¬¬®±³´³°°³·¿ÇÎÓÖÕÓÐÍÔ¾�kwpl—ÈÎÏÒÏÆ¿Ã½¾ÄÁÄŶŒnœÒ½†ÒØÙÙÕÕÖØÚÜÕŰŸ•�‹”š˜�ˆƒzrsy†—®·ÊáÜØÖÓÙÚÚÚÙÚÚØÙÛØØ×ØÚßáááâäææçççåãßÚ×ÔÒËû°£—އƒƒ‚��ƒƒ€}xtpmjgbYOLJNTSMLLJLMMOMLXeihaVV_hlqy€‡’£®³¶¶¶¶³°­«­°´ºÃÊÒ×Ôǽ´wh|nl›ÊÍÏÎÇÃÆ¿¼ÈÅÉÊÁ´�t©½…Ò×ÒÕÚÜÜÕÆµ¥˜—š�˜‘�‰„|wvv|›¶ÆÚÜÚ×ÖÖØ×ÑØÜÚØÛÜÚÚÔÊÒÚÕÖÛßáããääãâàÞÚÕÑÏÏÎȼ® ’‡ƒ‚‚„……ƒƒ�~zuqmiedbcdaZXXZ]YSSSNMNNNKIPVVXXRRV\djpwzwƒž¯±²±±²°¯®®­­®²¶ºÁÐ͹ͼvduqm›ÉÐÌÆÇÊÄÀÇÇÌÍÅÁº”z˜…ÔÚÕÙÙÌ·¡•’—šž—Œ…�~wsy‹�£ÅÙáßÛØÕÒ×ÚØÙÚÚÛÙÙÚÙÛÛÔÌÖÜØ×ÝáââßÜÚØÕÐÌÌÎÑÏŲŸ‘‰†‚‚…‡‡†ƒ€}zuqnkhfffhkmoqrqqrpliikjjfb_]ZYXRPOJGJNVaipy{|Š ­¯±³´³²²°¯°°°²´´ºÊÍË׺td{vo”ÄÏÄÃÉÆÄÃÀÅÌÈÁº¸�p†ÐÐÅ»ª›•”–š—Ž†|wvw}ˆ—´ÏÔÙâÚÕÖÔ×××ÚÚÚÛÜÛÚÚÜÕÒÛÙÚÛÚÛØÙßàÛ×ÔÑÏÍÌÎÑÓ̽¥Ž~~…ˆˆ‡††„�~zuqmkihkllmoqtttuutvxxvspmmoonmkgc`\XSH>?HOU^eny~„�¥¯°³µµ¶µµ¶¶´³²¶·¶ÃÍÎÍÖ¿vc~ul‘ÄÉÁÅÁÃÊ¿½ÉÌô·®€�³š‘•˜š›–Œ„zwux…˜¯ÉÛâáßÙÔÔ×ÖØÚÙÙÚÚÚÚÚÚÚÚÚÙØÚÛÛÙÙÙØÚÛÕÒÐÎÍËÏÔÔǰ—„xwz„ŒŒˆ„‚€|xtpmkjjjlqsrrrrsttustvvuuusqnmnpppokhgd`[TPRXVW^epx€ˆ•¦¬¯´···¹ºº¹····¾ÇÍÐÐÎ׿wfzuj’Äļ»ÀÎÊÆÌÌÈ»¹²—n˜ŠŽ™˜Ž€{yxuu~‘«ÃÓÝßÚÙØ×ÚÖÖÙØÛÜÙÕרÚ×ÕÙÙÚÚÜÛÙÙÙÚÙÚÛÙÓÏÍÌÍÓÖϽ¥�|wz}€ƒˆ‡…�{vronmkjlmqssstttuutsqpomiggikmmnopnnoonlkgdcbbfeWYcju€†Ž ®´¸»¼½¼»»º»º¹ÁÊËÌÏÒÐÍÙÃ}h|yo–Ä¿·¾ÊÍÍÏÌÊÀÀ»œoŸš‹‚zxywtz�©¾ÎÝÞÛÚÖËÖÛÙÙÚÛÙÛÜÛÚÚ××ÛÚרØÕØÚØÙÒÓÚÛÚ×ÑÍÌÌÑÔÑ»™�xx}�‚}}ƒƒ‚{qooonnooqrrqqqstsplifdd`YTTWZ_cfjnqommonkjjhfgjkodPVeq{€ŠŸ®·º¼¿ÁÀ¾½½¼»ÀÊÍÌÎÐÑÑÐÎÓ¾€o†}rœÀº¾ÈÆËÐÎÍÄÀ£u�ˆzvtrw•²ÐààÝÖÔÖÙÛØÚÛÙÒØÜÛÚÛÚÚÜÛÖÔÛØ×ÙÕ×ÚØØØ×ÚÛÔÌÊÊÐÖÒ¿¢~pw~�‚}~~}{}~~zplnppqssspnpqoljga^ZVTQOLMNRVZ\`djmomlllkjlljknpsuZK[jw‰œ«´¹½ÁÂÁÁÀ¾ÀÇÉËÍËËÐÑÐÑÏÈË»…s�|s�Ÿ³ÈÈÉÏÑÒËÄÅ«h„usx�‰¡½ÖàÕÑ×××ÙÙÙÛÝÜÚÛÚÚÚÛÙØÙÚÚÛ×Õ×ÕØÚÛÚÕÑÙÛÚÙÑÊÈÌÓÖŧ‘}oy€~||}}yssxzwpkpstuttpkmolfa`\WSPMGDGJMOSXZZ\_eglnmlklllmllnoqto\[eu��ž«³¸½¿¾¾¿¾ÂÉÎÍÌÍËÈÍÑÐÏÐÎÈÍĆl~vp}¦ÅÉÍÎÑÑÍÊÈ«_x|—­ÀÐÛÞÚÖÍÒÙÙÚÙØÚÚÙÛÙÛÜÜÚÛÛØÙÚÙÚÚÚ×רÙÚÛÖÎÒØÖÏÈÉÍÓ̲”…Œ„u{}~~}|{wrmkkmommptuvvusomlfa]\[YXZ[ZXTTVWTUZ[[\`dfjmnnlnpoookhfdgnlgjvƒ‘¢¬²µ¶º¿½¼ÃÊÊÊÇÉÍÍÌËÎÏÍÎÏÏÌÕÇŒo{~v’¿ÇËÍÐÑÎË̱o©ÀØààÞÚÕÕ×ÛÜÙØØØÙÜÚÚÛÚÛÚÚÚÚÛÙÚÙÙÛ×ÓØ×ØÚØØÚÕÑÖÌÇÌÏÒÕw‚‘”ƒx|}}}|xqkhfdcfilosuuvusqpmfcccdghkmnornhgec`^]__`eiiknnnprrqnha^ZY_lqr}‰—¦®°¯´·¯ºÉÈÉÊÉÅÄÌÌÍÌÌÏÍÍÍÐÏÍ×ËŒmzxu”ÁËÍÐÑÍÉηˆÚâÍÏ×ÕÖÙÙÚÚÙØ×ØÙÚÚÛÛÙÚÚÛÚÚÙÙØÙÙÙÙÖÓ×רØ×֨רÒÇËÒÓÁ�jq���xz{}{ytkeca[V_jmpstvvusqpniimpstuxxtqrtspommlheedbdgiknmnorsrnfc_XOO\oxƒ’¡­®®³±�~Œ¾ÍÇÈÉËÉÉÈËÍËÍÍÍÍÏÎÍËÓȉgyzo’ÃÐÏÑÍÇ͹ˆÕÖÁÌÚØØÙÙÙØÙØØ×ÙÚÙÛÚרÚÕÖÚØØ×ØØÖÓרÕÖÕÓÖ×Ö×ÖÎÊÎÏÄ–qhy‹uyzyzvmd`^UKLVemprtvuttqpomqtuy{yxxvsrqrpnoooonmkjighiknnnnpssmfc_XPIJ_}� ®²¯­�ŒqkƒµËÇÆËÊÈÇÊÌÌÊÊÊÍÍÌÎÍÊÔÊ‹k€xk–ÈÎÐÐÅÊ»†ÒÖÑÖÚØØÙÙÙØÙÚÓÓ×ÖØÛÚÙÚÚÓÔØÖÖ××ÖÔÒÖ×ÖÕÔÕØÒÒÕÑÍÏÏÈ¢}wgguyy{yupg_[WM@AQ^hmrtuuutsqqruxwy{{{vsrqpopnllmmnnnnnmkkknppoonqpkgcb]UKHSt™­²´»»ˆh{‚xk|®ÈÆÇÈÇÈÉÊËÊÊÊÎÍÌÍÍËÌÓÉŽm|yt™ÇÏÍÈʺ†ÒØØÙÙ××ÙÙ×ØÙØÑÓÖÓØÙØÙÚÔÖÖÔÒÕÙ×Ö××ÖÖÓÒÖÙÙÒÔ×ÐÍÑÎ¹Ž‚zgdq{zyumbZXQC9:LZbkqstuttusstw{{{|}}zsqpolllkgefikmnppmklmnpomnnmmjhhhbYNHJe™²¶ÂÌ͹“w|‚{mv¥ÃÆÆÈÊÎÍÊËÊÊÎÏÌÌÍÊÍÍÐÈ�m~�v�ÈÊÇϺ…ÓÙÕ×ØØØØ×ÖØØ×ØÙØÙÙØØØ×ÒÔ××ÔÕØØ×Ø×××ÒÒØØÖÕÔÕÑÌÏÆª�‰}mjs{yskc\WK;89CR_gnstuvvuuttx{}~~|ytrpmjgeda^\]`eilnonnonnnlllmlmkijjhd\SL`œÀËÎÐÑ×Μzu||nsžÄÊÈËÃÂËÊÊÊÌÍÌÌÍËÍÏÈÎÆ‹l�‚xŸÇÉͽ…ÕÚ×××ÙÙ×ר×ÕÖÙÙÙÙØ×Ø×Ö××רÙÖÖ×××רØ×ÕÔÒÓÖרÓÍÍ¿¨–�‡untyukb]\Q<9>AJUajostuvwwvvwz}~~~}ytqle^ZWTQQRUVW\bgjmnooooomlkmlllijmnmjieg¦¾´ÌÎÍÐÐ̯zp€st˜ÂÉÆµ¶ÉÉÊËÌÍÍÍËÈÍÐÌÈÍÆ”p|~w™Â˹‡ÕÙØ×Ö×ר××ØØØÖØØÙÙØ×Õ××ÕÕר×ÖÕÕÔÖÖÕÔÒÖØÛÛÑÄ®µÎ¿¬œ—�ypvuoe`cXD@AADKUblpstuwxxzz|}€|xtnf]XUSQMHEEJOQT[`eilmopoqpnmnnmmlnonlnpsr¢¾¬ÎÐÌÏÐÓØ¹‚o|‚rl�¿Ç¼ÂÇÇÉËËÍÍÌÌËÌÌÉÊÊÍÌŸt}~t‘¾¸…ÓÙØÖ××רØÙÙÙÙÚÙÕÖÖÕÙ×××ÖÖØ×Ö××ÕÒÓÖ×ÙÛ×ÍÀ± “†“¼Åµ§ž‘xvrqi`aM=?A?BKXckqtvvy{{{}€~|wrk`ZZ\YVURNH@>DKOTY]chlnpqqrqppqomnmiefkosyŸÐÐÌÍÎÑÐÎÓÖ¹‚m}�rk�¾ÆÄÇÄÇËÊËÍÍÍÎÌÇÆÈÌÈÌÓ©v|„v“±…ÑÖÔÔÔÕרØ×ÔÓÙÙØ×ÖÓÕØØ×ÖØ××ÖÔÔÔ×ÚÚ×ÑÆ¸¢•Ї‹Ž‘’¢¾Å¸¢Ž…�yplhZL=9@CADP[ckqvxz|~~€€~|xsj^[]]\ZZ[[VQH>D@=DKTY`lvy}€‚ƒ‚��€~zuoc^_`a`\VQNLC60126?JQV[afjntwz{|}p[OF?<=ETajvŸÊÎÍÍÏÐÏÏÐÐÎÍÕÔ¥v{„xh|¬ÃÅÈÈÉÍÎËÍÍÊÊËÍÎÌÍÏÎÒ«vy‡„ÐÙ×ØÚØ×ØÙÚÕÖÚÙ×ÖÔÓÒÔØÚ×ËÉ´¡”Šˆ‹‹•’ˆŠƒ{urnhgfdeadz›±¡‰ƒpQ<:??;?DKOU`nz�…‡ˆ‡ˆ‡†�|wtrppolljie`\XWVPICDO\a_^cknptwy~‚…€bHDA@FUZT`ˆÀÏÎÍÎÌÎÎÏÏÏÎÑÑÏÌÐÔµ€jx}psšÁÊÉËÌËÊÉÊÉÍÌÇÌÎÊÌÎÍÔ±†ÒÚØÖÖÔÓÔÔÖ×ÚÚÒȹ¦•Šˆ‰Œ�Ž‘��‰skfehjjjkklmnmnponnonpl_nƒ„€t`K>?ELOPW`p~ƒ†ˆ‰‰ˆ‰ˆ‡‚}~|zxtpnljhge`ZURSWXXY_hnpruy|€„……pJBE:-3CNeœÉÏÏÏÌÆÊËÏÏÏÐÐÐÍÏÑÑÜÇ‹kv~ro‘¾ÌËËÊÉËÌÉËÍÊÍÌÉÇÇÍϾ…Ï×ÕÓÔררÕÍñ£•�Œƒˆ™—––”Œ~smhfeiiillllmmmoppoopponnim~wrwztdNKSSPRXbt~…ˆˆˆ‰ˆ‰‹‹‰ˆ‡†…‚|yuqonkgb\WUUWWVY`gnpqvy|}…††^LLE879Di«ËÎÎÍÎËÅÈËÍÏÏÍÎÏÌÏÓÓÚÏœss{qlˆ¹ÍÉÊÉÉÌÍËÌÌÎÎÍËÊÍϺ„ÎÑÖÙÚÛÓõ§™’Ž’˜œ˜Šƒ�Œ…~xmgfhikllmnnlkmonmonoqqqpponp}rfkotwsleaWNQXhz�ˆŠŠŠ‰ŠŒŽŒŒ‹‹Š‡†ƒ�~yuokheb`_]^_``elrstwz}€�…‡ŠˆpYXWVSLQ{¶ÅÁÊÌÍÏËÍÍÎÎÎÎÎÒÍÌÒÓÎÔÓ«wr|wn…¶ÊËÉÉÌÎÌÊÌÎÎÎÍÐÎн†Ó×ÓÌ¿­œ�‰�”—�¢Ÿ›„ty{skjheflmppnmnnnnnprpopopsrqoopnuxiknquvwvpi`TRau‚‡Š‹��Œ�����Œ��Šˆ‡„|zuqonljjhhikotxzyz~~�‚�‚…ˆŒ‹|a^dhkad•ÂÆÀËÎÍÎÍÎÏÐÎÎÎÍÏÏÐÒÒÐÌÏÔ´|n|xm€«ÇÇÇÍÍÊÊÌÎÍÎÎÐÎ̼„ô ‘ŠŠ�—œ ¡›’Œ|qhfmmhhiillmmnmllljmnmnpppqrqpqpooooxsimku|vqwtqkggu‚‡ŒŒ‹ŒŒ�Ž�’’‘���ŽŠ‰‡‚€~{ywuusrstv{}|}}~�ƒƒ‚��…Š��‡lY\cmlt¬ÆÇÎÏÏÏÐÐÍÏÏÌÏÍÌÈËÑÒÒÐÒÐÐØ¹~lwxmx¢ÂÈÉËÉËÌÎÏÎÐÑÌÊ»o•‹Œ’š£¥œ“†{tols‚Œƒm\[abdfcdijjikkjmnmmnopqpoopnnoonzskno}ƒwlvwuutx�†Š��‹‰Š��’““”’‘‘�ŽŽ�‹ˆ†„ƒ�~~{z{|~~~~�ƒƒ�€€ƒ‹�’�|e^`ip‚µÈÇÏÎÎËÈËÍÍÊËÐÎÏÌÍÎÑÓÑÑÒÑÒÙÊkuxou�¾ÆÇÊËÊÌÎÎÐÐÎϺnœ ¥£��rlkq�œ¹ÌȾ°‡\PW[[Z\`cfhijjlllmnooppnopomlmm|vmqt‚ƒzv}|xzz|‚ˆŒŒŽ�‰ŠŽ�“””““•”’“”““��Ї†„‚‚€~€‚�€�€€�‚‚�€�…Œ“•“ˆtmkls…´ËÌÊÌÌ̾¾ÏÏÌÎÏÏÌÏÐÎÏÓÓÒÒÒÎÐÙÊ“puxor–½ÃÅÊËËÌÐÐÎÎÑ»w¥•„xqor}� ±ÀÈÍÙÑÁËÜÒ bJJLPTWZ]`cfffghijlmlllmnopnlk{znsx…‡…ˆ€y|}~~„ŠŒ�ŽŽŒŒŽ�“••”•˜˜˜˜˜—•“�ŽŒŠ‡†…„ƒ��‚ƒ�€€��„ƒ��‚ƒ‡‹�–•Ž~urrv‚«ÉÊÉËÌÌÊÌËÊÏÎÎÍÉÎÏÍÐÒÓÒÒ̾ÇÐ×Óœmsxps—½ÅÅÊÍÌÏÐÎÍѾbzopz‹Ÿ³ÄÑ××ÔÊÉÐÊ¿ÅÎÒÑ«nG>BIMPSVY]`abdfiklihkkjlopomx{pszˆ‹Ž‰eg|‚„‰Š‹���Œ��“””–˜š››š™—–•’‘�ŒŠˆ…„…ƒ�€�€€�‚ƒƒƒƒƒ†‰‹Ž•™“†{xy{�¢ÆÇÉËÍÌÏÒÈÆÏÏÐÍËÏÍËÎÑÏÐÏËÇÌÓÒØÒ›oqwpt•¸ÆÇÊÍÎÐÐÏѽb�œ´ÆÔÚÝÝÛ×ÔÒÏÏÕɾ¾ÄʪuR>9?FJMPTW[]_behjijkjjjlmons|rt|‰‹ŠqOcz„€‚†ˆŠŒ�ŒŒŽ‘•™›žž��œ›š˜˜—––”‘�Œ‡„†…„‚�€�€€~~€�„‰�‘™¥«¥’�}}„˜ÀÊÅÊÌÊÊÍÍÊÌÏÒÍÎÑÏÌËÎÎÏÎÏÐÏÐÓÑ×Ö¢omxupН¿ÄÉÌÎÐÏÏ»uÂÛàÞÜÛØÖÖÕÖÕÔØÑÁÀÂÿº½½¯‰`C58?EIMPQVX[_cffhhhiijjkkjxwv~‰‰z]Veuƒ‡‚€„†ˆ‰‹Š‹�—¡§©««¬¨¤£žš——™˜–•’ŽŠ‡………ƒ€~€~~}}€ƒˆ�š®»º³¤‰~~�‡�—¹ÊÉÊÊÊÌÍÉÉÎÏÎÅËÑÎÍÎÏÏÏÑÎÍÏÎÐÑÖÙ¬uo~vn‚§½ÄÇÊÏÏϺ|É×ÕÕÖÖØÙ×Ö×ÔÕÕÅÀÀ¿¾¾»½¹»­ŠkM938@EHJMPV]_aabcdfefhiiclxx~ˆ„kZaezŽ‹…€€‚„†‡ˆ‹”£¬­­®³µ³±ª£Ÿ›™š˜”‘ŽŒŠˆ…ƒ�}~~~|}€€„Š”§¸»µ°«•}�‡‹s~°ÌÉÇÉÉÉËËËÍÎÃÇÐÎÏÑÌÌÏÏÐÐÏÎÑÒÍÕÚµzlvsr†¦ÀÅÅËÏÑ»†ÔÒÑØÙÖÔÓÐÖÔÐÔʺ»¼¹¹Ã´³»´µ£ƒoXB327>CEJQUWZ\]_bdcdefgb_v{‡d]fm‡’Œ†€€�‚„†ˆŒš¦¨©«­°²²³¯¬ª¥Ÿ™—•‘Ž‹ˆ…ƒ�|}}{yy|‚‚ƒˆ“ ©¯²°¬¨™ƒ}€†ŒzeqžÃÉÅÈÊÊËÌÎÌÌÍÍÍÏÐÌÌÐÏÏÐÏÐÒÒÒÏÑØº‚ksxv�žÀÆÄÌÒ»ƒËÙרÕÑÒÐÍÔÑÑÔɽ»¼½»»²²½º¹´–|naN:018>CGJMRWY[^abbbcdcYm~}‡~ffr{Š�‹†���‚„…†�™¡¤¦¨«­¯­¯°²°­¦ž˜”‘�‹‡ƒ€€|}|xw{‚†…†ˆ�™Ÿ¡£©ª¦£™„}„‰ƒwddŒºËÉÈÇÊÎÍÉËÎÍÍÍÍÏÏÎÏÐÑÐÏÑÓÓÒÐÏ×È™ppwpuœÀÃÅκ‚ÌÜÙÙÔÏÖÖÒÏÒÕÓÁ»ÁÀ»°º½½½º´¥‹{siXD5/16=BGJNTVX[^^]`cd^ezyƒ�mn|{��‹‡ƒ€€‚„…†�–�£¦¦©««¨ª­¯¯®ª£š”�Œ‰†„€~€|xx~…Љ††Œ”™� ¢£ Ÿ™ƒy~�ˆwwja|®ÉÇÅÈËËËËËÍÏÏÎÍÌÌÍÎÐÎÍÐÒÐÐÑÏÏ×Ò¢olupl‹­¼Çµ†ÖÚÖ×ÖÕÖÖÔÐÔØÐ¼·¿ÀÂú°¸½»»³®Ÿ†}tj^N?3/29?CGKPSVYYZ]adb`s|‡|wvq†Ž‰„�‚ƒ…†‹“˜ ¤¥§¨§¤¦©ªª©§¢œ–�Ї†ƒ~�ƒ€ytvyzzz{~�ƒ‡�–››šœ—�v{€†{fmwp_n�ÂÊÅÈÌÍËÊÎÎÑÑÊÇÍÏÎÌÊÎÐÑÐÐÐÎÏÎÒÓ®whvneƒ²Ç²…ÕÛØ×ÕÕÔÔ××ÙÕÈÃÁÀÁÀ¿½²¸»¹¹¹¶±‘~zsmdWH90-3:ACHKOTVWZ^bb]e||„‰‹�…mu‹‹„‚‚�„†…‰�”™ž¢£¢¡¡¡¤¥¤£¢¡�–�‹‰†‚€�„„€ulmmgO?I[ltuz„�‘���{sy~…}a]hvsdh�ºÊÉÊËÊÈÉËÆÊÌÇÉÎÐÎÌÏÐÐÑÑÏÎÐÑÎÏÔ´|kysp‡°¶…ÔØÕÖÕÕÖÕÔØ×¿»ÇÅÄ¿¹½»¶·º¸¹º·£‡~zvogYLB6..4:>DIMPSUY\^_\q|u~Š”‘~o�‹„‚�‚†‡‡‹Ž�’•˜™™™™›�žžž�›˜“�‹‰…€~‚„ƒ‚xh`b[?.2;I^lqv}€€}qpx}…y`^\drvkd{ªÈÉÇÉÅÀÊÇÊÈÇÊËÍÎÏÎÏÏÏÑÐÏÐÐÎÌÍÔÁ‚hvsj~Ÿ†ÒÔÔ×רÙ××Ú͸ÀÇÄÅÄÄÀ¾¾¹µ¹¼¼½µ±™ƒ}xsnh_UK>2-.4;@CHMOSUV\\bxvr}Ž•‘‰ˆ‡„��ƒ…‡Š�Ž��Ž�‘“’’’“•••”‘�ŽŒ‡„�}}�ƒ…„€tcYTLEEE=?Ujoqsrtqjnv}„v^^[Y`qvobnžÄÇÄÇÆÊÐÍÈÍÌÊÉÌÌÎÏÏÍÏÐÎÎÍÍÏÐÐÖ‡jstmq†ÓÙÖØÙÙÚÙÚÚÎÈËÇÃÃÅÂÁ¿ÁÀ»¹½¿½·¶«�‚|wqnic\QE91,/7<8;d€„‡…�€zvx|zx{…”žŸš–—™™œ£¤ •†}‚�™ž�š•�Š…ƒ„‚€„…ƒ€}wqr{�vlq}uYRQNOONONKU^`][\]_`aa`^]]\Z[]Y_nxobx«ËÊÂÄÆÈÈÇÇÉËϼ†×ßÛØÍÉÎÑÐÐÒÎÌÉËÎÊÊËÌÍÉÈÉÈÈÈÉÉÈÉÈÅÅÀ»½½»°”‡…„€|zrsurnkhfc^WPF@>:;Z{‚†„€€{srxywv|Š˜Ÿž˜••—–˜š—‘��™  žžžš•”“‘�ˆ…„ˆˆ…ƒƒƒ~|‚ƒzss|mVVUSTROMPSQTSLHKU^___`b`_]ZZ\ZWYfsocl™ÂÉÅÃÅÅÅÈÅÅλ…×ÞØÕÌÎÐÑÅÇÒÑÑÌÊÍÌÎÍÊÊÉÉÈÈÈÇÉÉÉÉÉÆÅÅÀ½½¼½«�‹ˆ‚~{wvvuqolid]^XFAED2Eq~ƒ„�}toruusu€�šœ—��”•’“’Ž‘˜›Ÿ¡žšœ�™––“މ‡‡†„ƒƒ�~z|‚„{wvxgZ[XVVSTTVZSLJFDIV^_`_`cbba^\ZZ[YU_otgdˆ¶ÆÂÀÁÂÇÅÇ̹‡×ÝØÒËÏÐÐÈÈÒÓÎÎÑÎÎÐÍÊÉÊÈÅÊËÇÉÌÇÇÊÆ¿»½½½½¼¸œ‰‡„‚~{wurplieehZG@Vy]8]z�†…�}xqpstsqv‚‘™—‘����‘‘�”˜›��œ™˜™—’‘ŽŠ‡ƒ~zxvtsqqv~‚~xzu`ZYZ[WTVUUVUOJKPX_][ZWWZ\[]\\]\Z[YW]gunbw¦ÄÅÂÃÅÈÌ͹‡ÙÞØÍÌÐÑÒÓÎÎÏÌÍÏÐÎÍÎÍÎÍÆÇÈÁÄÇËÅÄÈȽ¶»¿½»º·¦‰†‡…„�~wturookkgZRB`�–XIq†‡„€{topttqpxˆ”–‘‹†ˆŽ‘•™šš�Ÿž›–�Ž�Œˆ„~|vrommmlou}�€}}n\ZXZ]YUVTSVVSQU[]YQOMNNOPLNX\]]]\\\YXbrqcl™ÄÊÃÃÇÉι†ØÞÓËÌÎÑÓÒÍÌÏÒÎÊÑÍËÎÌÌÌÊÌÈÂÆÈÉÅÇÉÊÄÃý»¼»µ­“ŠŒˆ†„vuz{uoljd^XDd€�H`y…Šˆƒ€zsopqqpuŠ�އ‚�…‰‘œžžœž¢ž—�‡‰Šƒ|xsqpmjjjiiow~�€�{e\[[[ZXVUTSWVU[]YTNIJMNOOKHJRQQY^[Z[]^Y_ntfdŒºÇÂÂÆÌ¸†ÖØÎÊÌÍÑÓÐÎÍËÐÎËÎËÍÍÍÌÌÍËÊÍËËÊÉÉÊÈÄÁÃÀ¾¾¼¹´©–�‹‡†�||{{vnjjga[Ps†~�]Qo‚Љ„‚|uopqpqx‚‹�„~|„Œ—£¨¢ žœš“‹ŠŠ†€yspnjgedfkry~€ƒ…wc]\]]\[YYXXWW[a]UPQQNOLNNJJKJINX^]]]]]\Z[fsnez©ÄÅÄ˺‡ÖÔÉÊËÏÒÔÒÏÍÉÌÏËÃÉÎÏÎÍÍËËËËÌÍÎËÊÉÈùÁ¿¾¿¿º¹¤ŽŒ‰‡ƒ€�~ytpmomdcd€Šw‘�Tg}ˆŠ„�€€|uqqpoqy„‰„{y~†Œ“ž¥¨¥ œ˜˜—’�Œ‡€zqjfc`bgms{}�Ž‹sa]]]]_^\\[[[[^\VTRQSROPQONONLJNXadb_]YY[YYewzfk–¼ÆÉ¹†ÖÕÈÉÉÎÒËÈÎËÍÎÍËÉÌÍÎÍÍÌÉÊÈÉËʾÃÊÉËËÆÁ¾ÀÀ¿¼º»´™‹‰…€€‚€~ysqsphfkƒ�x—jg{„Š…ƒ…ƒ�}tqrqmrz‚‚|wx�‹’•�¥¥¦¡š˜˜•‘�ŽŠ„�}{zwy|€‚~‚�Œn^]__]^^]]^^^]YUUTTSRSRTTPRSRPKKRZaa_^]ZY[\]csyfbƒ°Æµ†ÔÒÊËËËÒÇ¿ÊÇËÐËÌÍÊÍÍÌËÊËÉÆÈÊȹÀÉÉËËÉÁÁøµ·ºª�ˆƒ�‚„‚�€zuvslfg‚�}m•†k|�‡‰‡‰Š…‚|vvsoory~xvz‡�‘–œ£§¥Ÿ™–••––˜š���›——™›šŠ�ˆ„i\_``^^__^__[YWWXWWWUTSSRPQRSRMKO[bca_^[YXX_\Yjxncx¢°†ÓÎÊÐÑÎÏÑÎÏÍÂÃÅÈÌÎÊËÎËÈÊÊÇÈÉÊËÊÊËÊÉÆÄÄÃú³´¸¸ �‰‚‚…‚€~~}zwpkg}Ž‚h†�xxƒ†ŠŠŠ��‡€ywvsnow|}}yw}‰�‘—žŸ ¡žž�œœž¢§¨¦ œš›šš›•…€„|d[]_````_]]^^\[ZZ[[YWVUTUSOQSRMIP]a^_`_^ZWWXYYXarrioˆ„ÏÌËÑÔÓÒÓÒÏÎÉÀÂÈÌÈÇÍÐÎÊÊËÊÈÈÊÊËÊËÊÉÇÅÅÃÄÁ¿¼¾»½²—�ˆƒ„‚€}|~~{tomzŠƒii—“w�……†‡�‘Žƒ{xwupntz||xvw�ŠŽ‘“–—� ¢¢¢¡¢¢Ÿ ž™••–““•™Ž�†zb_^``__`_^^^_]\Z[][ZYWWWXYWWUSPNPQNLPW[]]]ZWUWWR[ktlcƒËÌËÍÒÒÒÑѽ»ÑÎÊËÊÅÉÏÏÎËÂÈËÊÊËÊÊËËËÊÇÅÅÆÄÀÀÂÀ¾¾»¥�ŽŠ‡ƒ€~||~|yspy†‚l[uœ‡}‡†�‚†Ž‘‰}wvtrmouxusssxƒˆ�“—œ¢¡¡£¢¢¡›˜—˜”�“–””–�†‰t_``_^^_^^_`_]]]]][ZZ[XUZZYYYUQTVQJFKRWZ\_c`ZXVVWWWaok†ÊËÎÎÐÑÎÐѾ¹ÊÏÐÌÈÍÍÎÍËËÄÉÊÌÍËÊÊËËÊÊÈÇÆÆÁ¼¼¼»ÀÀ½´™�ŽŠ„‚€~}}z{wrw……p`\…œƒ‡Œ…€‚ˆ‘Ž�ywtqmlnqsqnmnsz„ŒŽ“˜œžžžžŸžš˜”“��Ž�•’�‹‹‡jY[]^_^^^_`a`__^^^[]\]ZZ\\YTUVSRQNKIMUYZ\Z\a^[[Z[^ZU^lƒÉÌÌÔÓÐÐÌËÍÍËÌÏÍÌÐÏÎÍÌÌÍÍËÌÌÊËÌÊÉÉËÊÈÇÆÄ¾»¹»ÁÁ¾¿®”��Šˆƒ‚ƒ�~}zww‚†tc[i˜–‡�‹ƒ�ƒ‹�Š~xurmhhkqnihiou}†‰ŒŽŽ•˜™�š——™“ŽŒŠŠ‹ŽŒ‰ˆ‰€bWY\\\\]___^_a_]^^\]]]]_][ZWWXVRPNLJHHHIRXX[]]]\[]^\Z^€ÈÏÍÐÐÌÎÇÉÍÌËÌËÌÑÑÐÏÎÎÌÊËËÌËÌÎÌÊÉÉËËÉÉÇǽ»Á¿¾¾¼¸¡‘��ˆ…„„„‚�€{{ƒve_Y{ ’ˆ‰…‚€‚ŠŠƒzrpnhgfikifhmos|„ˆŠˆŒ�“˜”’“‘‘�Œ‡‰Œ‡‡‡††t]YZ[\ZZ\\\[[]]_```^\^][\\[ZZXUSSRQPOONLFLW[\]^^[Z\\]\W�ÉÏÒÉÈÎÎÍÌÍÊÊÎÍËÏÒÐÏÍËÎËÈËËËÌÍËËÌËÌËÉÈÈÆ¿ÀÄþ»¿»º±˜�Žˆ†‡†„„„ƒ€~ƒzf\Xb‰ –Œ„€��„†}okljgdchiggklouz�…†…‡‰ŠŒŽŠˆ‹�‹‰Š‰†…‚ƒ�iZ[YXYY[[YYXXXX[^_^]^][XYZXXYXVUSRRTVUSPMOY^^^^]]^_`][Y‚ÎÒÏÎÐÓÎÎÎÎÐÏÍÎÐÑÒÏÌÍÍÊÈËËÊËËËËËËÌÍÊÈÉÉÇÄÅþ¼¾¿¾¼¼¨’�ŠˆŒŠ†……„ƒ€�„|g\XWg†—š•ˆ�}{‚|ofeggedecacgjkpu{ƒ††ƒƒ‡‡�€†ˆŠŒˆ„€{‚}_WXVVUVYYYWVSRTUXXXYYYZZZZVUVVVUVVVTUVRMJP[`_^__`aaa_\ZƒÎÒÑÓÓÑÎÎÍÌÏÏÎÎÐÏÏÎÍÏÎÅÉÏÍÍÎÍÌËÊÉËÈÁÅÉÊÇÅÄÅþ¿½¿¿·›ŽŒŠ‹‹„…‡†„€}xk_XV]dp�‹‘ˆ}uxzyl]Z`ccefb^_`cgjptx}ƒ†ƒ~~yvx|€…ˆ‚yxx~pVVVVUUTUXXVWVQPQQQPRSXZXUUTQQSXXXXWSRXWRLR]^\]a`[Z]`_]]ƒÌÎÍÒÑÏÏÐÎÍÎÌÊËÍÏÌÊÍÍÏËÉÌÎÎËÌÌÌËÌÌÆÃÆÉÉÆÄÃÄÆÃÁ¿¿Á¿¿«’ŽŒŠ‹‡ˆ‰‡ƒ†|pxn`XWZ_`cb{‰€vquwr^SW]`aedb_\]befjotz‚~xuutsruyyuppsv`QSSSTVUTSPPRRNLLNSTSTWURQUWURTYXUVVTTVTQQY`^[[WVWTX__^X…ÑÑÍÒÒÐÑÑÐÐÎËÈÈÉÍÍÍÍÎÎÍÆÈÎÎÌÌËÌËÌÎËÊÅÆÈÄÃÅÃÅÄÀ¾ÀÁ¿º¡��‹‹‹ŒŠ‡‰“ŒrsqcWTV]^ba`}‡}rosuiSMV]^^adb]YY]`ejlsy|}xsqqljjmmmkjniOKPNMONOLJJHGHIJJNUVWXXWUXZ[\ZZYXXWUTVTQRY`][\YPOX\ZZ\[W„ÏÔÓÔÓÑÒÒÎÌÌËÍÎÉÉÍÏÎÍÌÎÊÉÌÎÏÎÌÌËÌÌËÊÈÉÇÆÆÆÅÄÄÁÁÂÁ¾¾²–‘�Œ‹ŒŠˆ——•ŽxodYTTYZ[fai…†xjjpn]NMU[Z[]`^ZWX[]achmpppplhddeddefihcXHFJKJFDBCFHGIKLJLPPPQQUYZZYYYXVXZYVTUTU\a_VW[YVXY^^[]WS‚ÍÔÕÕÑÐÐÊËÌÍÍÎÏÍÎÏÏÎÌËÍÌËËÊÉÍÎÊÉÌËÉÉËËÇÇÄÄÈÆÆÀ¿ÃÂÿ½º¦–’ŽŒŒ‰‹™˜‹›™}bYVVWZVZhaq‰ƒqahphZOMTYXWZ[ZXWWWY\`bdfeffbabaaaafaVYe^JBHGDBACDGHJKMNOPQQPQQVXWVSTVUTUVUUVWY`bZTUYYVXYYZYXQK„ÏÒÏÐÏÏÏÇÊÍÎÐÏÎÎÐÑÐÍÎÎËËÌÌÉÉËËÊÇÇËÉÇÉÊÇÃ»ÄÆÁÃÃÁÃÃÂÁÀ¼¶Ÿ’’��Љ‹™‹‰ž�tWRWVVWT_ebzˆ�k\dg_XOKRXYWVUUTSVWXZ[\]ab`_aa`]\]UIEKVffNAEHIJKGEGHHLPRRSVWUPOSTRSUZZY[[XWXZ\ab_[[YVUSWWXWTPO…ÏÑÌÍÍÐÑÎÌÏÏÏÑÑÎÏÎÌÍÏÏÍÌÌÊÌÈ¿ÈÌÉÈÌËÈÊÇÁÅÄÄÁ¾¿ÆÅÅÃÁÁ¾»«”’‘Œ’’‚…‘†‰›‹gROTTVST_bf}†�dT^]YVMIOUTTQOOPRTVUVVVY\ZYZXTSUJ;:@GMWghN>EKMMLLONNKMOOOOMJJKORSTWYZ[[[[^``bddfdc\XVVYXWVYZRƒÏÔÍÊËÎÐÎÍËÊÍÑÒÍÌÌÌÍÍËÌÌËÉÍÈÁÉÉÉËÉÇÆÉÆÃÆÇÆÆÃÃÂÀÆÅÃÂÁ¼º²œ‘�—¦¥Žs…�…‡��iQJOSQQU_`k�…|^PVUVUMHJOUTPPPNPUSPQRQRSPNNSdeA5:=BKS[jmO:?CEGIMPSPOMIGHIIIKOQRSSSSVXX\bccfggefd]YWYZWUSW\W„ÐÑÌËÉÈÇÇËÉÇÊÎÏÌÊÎÏÏÎÍÎÍËÈÍËÉÆÆËËÇÆÆÉÇÈÆÆÈÈÄÄÂÂÈÆÄÃÀ¼·²¨––¤­©ŸŒ‚‹�ƒƒ‚ymTEGOOPV]ar�€y[KKMRSNIHKPRSQOOPPMMMOOMNR]n~sC68>CIRZ`npP9?DHJKKJNSVYZ[TLLNPOOQSTUY\WVUTWTRSRTVX[`fc„ÎÏÌÊÇÊÊÌÉÅÍÎËËÌÌÌËÍÍÍÏÍÍÊËÊÊËËÉÉÊ̽¼ÊÈÈÇÇÄÀÁÅÈÇÆÈ¾­·½º¯¨¥£•—¦ª­£‘‡‹—Œpkfpym^LDGNUXn|ka]YNDCLQOKJKMLKMPUYZ]elpsw|pB039CJRY_fmptw‚¡”ubJ=AGKLJKOQUXXSIGJLMMKPQNPSRQOUXSPW^^`d_ZX\‚ÎÐÌÊÈÌËÌÌÌÐÏÍÎÊÈÌÎËÉÎÍÌÏÑÎÈÊËÌÉÊÉÉÂÂÈÆÉÇÅÄÄÆÊÉÆÅžª©©¦¥¦¥¤™’›œ££�†…“�}vifhmofVLEHO\~‚k[YYULILPPQOOOMPSVY]bhlotwzqC.28CLUY^jv|}b@]~ЇtQA>CJLKMORSSUSKLRPQQOOOQPU\[^]YXXY^^YZ`hZƒÍÌÉËÉÉÊÌÌÍËÊÊÍÌÉÍÍËÌÎÍËÌÏÌËËËËÊÇÄÇÍÉÅÅÈÉÇÇÇÈɽ±°¯®¬£�—𢡡›Š�‰„„‚ƒ‡��…vspddllmh[RJIbyfYXWUPMOSVSRPQSWX\aehlptxyrE-18DNUZj}‰Œ‡a:0EJJHIJKIJNUWT[n Ã­‹¡°¢€vªßÔËÚØÂ�ÇÉÃÃÄÈÊÉÈÄËÍËËÊÉÇÆÉÍÍÉËÌÊÉÌÌÆÄÄÀÀ¾¼½¸°­¬©©­´°£™•˜�¥§¡‘�‡‘¢˜�–˜¡¦“„wuy}zsrx~qg^ahnpw}‰’™Ÿ�zdMHKKOSVXZ]^adfhknqqmjN.,5CXw„ˆ‹ˆ†wSAADHLH<6Hh}�žŠ\DA=:CJP`et‡“|Pa|ÀéÀ¡§—wv±ÓË»¸»·¡‚ÈÇÃÃÆÊÌÍÌÅÉËÅÂÈÈÉËÌÌÍÉÇÈÉÆÈËÈÆÄÀ»¶³¯®°«®¯«­³°¤•�‘— §§¡’ŠŠ‚�—�ŒŒ˜ž£¬†{Œ•�…‚‹‘yu‚‹……„|ww‚�š£ª‘h\[\^abbdfhkosvz{xusY:17Sz����‘‹•{PLNQRSTL>?Nd�¤œreŽ’‰�’�·ÉÆ©“�ŠÄÙÁ»»²­½Æºµ·µ²³§‚ÇÆÆÄÁÇÉÊÉÉÉÉÄÃÉÉÊÊÊÉÈÉÈÈÈÈÊÇÁ¼·³¯¬©«¯®«­¯±¶µª›ŽŠ�›£¦§¤—xƒ‡zŒ�Šˆ�—~la\gg`ZU[^RNMX`ahplbZPIT[p{ZEDCCDDDFHHJNQSUURQP?,()C_c[MS_\ib?8:;;<=@=2+/=Usv_e’|ggdi{„�|ˆsm�€|}|ƒ~vy{{|}~vƒƒˆˆˆˆ‰‰‰‰ˆˆ‰‰‰‰‰‰‡‡ˆˆ‚‚yyzzzzzzyyvvppttzzxxuuvvuuvvwwxxxxyyyyzzxxvvuuppppuuvvuuyy€€~~yyyyxxvvwwxxxxww{{xxvvssrrvvxxxxwwvvwwuuuuyysssswwxxxxuuttyywwqqssttttuuxxssssuussttuuqqvvƒƒˆˆˆˆ‰‰‰‰ˆˆ‰‰‰‰‰‰‡‡ˆˆ‚‚yyzzzzzzyyvvppttzzxxuuvvuuvvwwxxxxyyyyzzxxvvuuppppuuvvuuyy€€~~yyyyxxvvwwxxxxww{{xxvvssrrvvxxxxwwvvwwuuuuyysssswwxxxxuuttyywwqqssttttuuxxssssuussttuuqqvv††’’““““’’””““““““‘‘‘‘‡‡xxzzxxuussuuwwwwuuuuvvwwvvwwwwxxyyxxxxwwttssssttuuvvzz}}}}{{yyyyzzxxxxxxzzzzyyxxzzyyvvrrrrwwxxwwwwvvuuuuuuxxttttxxxxwwuuvvzzvvppssuuttvvxxssttttttvvttuu††’’““““’’””““““““‘‘‘‘‡‡xxzzxxuussuuwwwwuuuuvvwwvvwwwwxxyyxxxxwwttssssttuuvvzz}}}}{{yyyyzzxxxxxxzzzzyyxxzzyyvvrrrrwwxxwwwwvvuuuuuuxxttttxxxxwwuuvvzzvvppssuuttvvxxssttttttvvttuu€€‚‚„„ƒƒƒƒ‚‚€€����€€��xxuurrsswwxxvvuuvvvvvvwwxxvvvvxxxxuuttssssttuuxx||||{{yyxxyyzz{{||}}~~~~~~~~{{vvssttwwxxxxuuuuvvttuuxxssttwwwwvvuuuuyyttqquusssswwxxrrttuuttuuvv€€‚‚„„ƒƒƒƒ‚‚€€����€€��xxuurrsswwxxvvuuvvvvvvwwxxvvvvxxxxuuttssssttuuxx||||{{yyxxyyzz{{||}}~~~~~~~~{{vvssttwwxxxxuuuuvvttuuxxssttwwwwvvuuuuyyttqquusssswwxxrrttuuttuuvv||||||||zzxxyyzzxxvvttssttvvwwwwwwwwvvvvwwwwvvwwwwvvuurrrrssuuvvxx||}}{{yyxxyyzz{{}}€€€€€€€€��ƒƒ��zzttsswwxxvvuuvvuuttuuxxssttwwwwvvuuvvxxttssuuttssxxxxqqttttssvv||||||||zzxxyyzzxxvvttssttvvwwwwwwwwvvvvwwwwvvwwwwvvuurrrrssuuvvxx||}}{{yyxxyyzz{{}}€€€€€€€€��ƒƒ��zzttsswwxxvvuuvvuuttuuxxssttwwwwvvuuvvxxttssuuttssxxxxqqttttssvv}}||||{{xxxxyyvvrrssvvwwttttvvxxxxvvuuvvwwvvvvvvssrrrrssuuww{{}}||zzyyyyzzzz||~~€€€€€€€€€€‚‚„„~~ttssxxwwvvvvuuuuttvvxxssuuwwvvvvuuvvyyssrrttttttzzvvrruussuu}}||||{{xxxxyyvvrrssvvwwttttvvxxxxvvuuvvwwvvvvvvssrrrrssuuww{{}}||zzyyyyzzzz||~~€€€€€€€€€€‚‚„„~~ttssxxwwvvvvuuuuttvvxxssuuwwvvvvuuvvyyssrrttttttzzvvrruussuu}}||{{wwssttssrruuwwvvttrruuwwxxxxuuttuuvvuuttrrrrttuuww{{||{{zzyyxxyyzz||~~€€€€€€€€€€„„€€ttssvvwwwwuuuuttssuuwwrruuwwwwuuuuwwxxrrqqssttwwzzttrrttvv}}||{{wwssttssrruuwwvvttrruuwwxxxxuuttuuvvuuttrrrrttuuww{{||{{zzyyxxyyzz||~~€€€€€€€€€€„„€€ttssvvwwwwuuuuttssuuwwrruuwwwwuuuuwwxxrrqqssttwwzzttrrttvv€€||wwuurrrrvvwwwwvvuuvvttsswwxxxxwwuuttssrrrrssttuuyy||||{{xxxxyyyyyy{{~~€€€€€€€€€€€€€€€€€€€€€€ƒƒ~~sssswwxxvvuuuuttssuuvvrruuvvvvvvuuxxxxrrqqttvvxxzzttrrvv€€||wwuurrrrvvwwwwvvuuvvttsswwxxxxwwuuttssrrrrssttuuyy||||{{xxxxyyyyyy{{~~€€€€€€€€€€€€€€€€€€€€€€ƒƒ~~sssswwxxvvuuuuttssuuvvrruuvvvvvvuuxxxxrrqqttvvxxzzttrrvv~~wwuuttvvxxyyxxuuuuvvvvrrttwwxxxxuurrqqqqrrttvvyy||||zzyyxxxxxxyyzz||€€€€€€€€€€€€€€��‚‚zzsssswwwwvvuuttssssuuvvssuuvvwwwwuuxxxxrrrruuvvyyyyrruu~~wwuuttvvxxyyxxuuuuvvvvrrttwwxxxxuurrqqqqrrttvvyy||||zzyyxxxxxxyyzz||€€€€€€€€€€€€€€��‚‚zzsssswwwwvvuuttssssuuvvssuuvvwwwwuuxxxxrrrruuvvyyyyrruu~~zzyyvvxxxxvvuuuuvvvvttssvvwwvvssqqrrssttvv{{}}||zzxxyyxxxxyyyyyy||€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚wwttssvvwwvvuussssttvvvvrruuwwwwwwvvyyyyqquuvvvvxxwwtt~~zzyyvvxxxxvvuuuuvvvvttssvvwwvvssqqrrssttvv{{}}||zzxxyyxxxxyyyyyy||€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚wwttssvvwwvvuussssttvvvvrruuwwwwwwvvyyyyqquuvvvvxxwwttzzuuttvvvvvvuuvvvvuussttuussqqpprrttyy||||{{yyyyzzyyyyyyyyyyzz||€€€€€€€€€€€€€€€€€€��{{vvttrrvvwwvvttssttttvvwwssvvwwwwwwvvzzwwrruuuuuuwwxxzzuuttvvvvvvuuvvvvuussttuussqqpprrttyy||||{{yyyyzzyyyyyyyyyyzz||€€€€€€€€€€€€€€€€€€��{{vvttrrvvwwvvttssttttvvwwssvvwwwwwwvvzzwwrruuuuuuwwxx€€zzuuuuxxwwvvvvvvvvttqqqqqqqqrrssxx}}}}zzxxxxyyyyyyyyyyzzyyyy||€€€€€€€€€€€€€€€€€€€€~~{{xxttrrvvwwuussssttttxxvvrrvvxxwwvvvvyyvvrruuuuuuxx€€zzuuuuxxwwvvvvvvvvttqqqqqqqqrrssxx}}}}zzxxxxyyyyyyyyyyzzyyyy||€€€€€€€€€€€€€€€€€€€€~~{{xxttrrvvwwuussssttttxxvvrrvvxxwwvvvvyyvvrruuuuuuxx~~yyttvvwwwwvvvvvvssppppqqrrttww{{||zzxxyyyyyyyyxxxxyyzzyyyyzz€€€€€€€€€€€€€€€€}}zz{{wwttssvvuuttssttuuvvxxuusswwxxxxwwvvzzuurrttuuvv~~yyttvvwwwwvvvvvvssppppqqrrttww{{||zzxxyyyyyyyyxxxxyyzzyyyyzz€€€€€€€€€€€€€€€€}}zz{{wwttssvvuuttssttuuvvxxuusswwxxxxwwvvzzuurrttuuvv~~xxttwwwwwwuussqqqqrrrruuyy{{{{yyxxyyyyyyxxxxyyyyyyyyyyzzzz}}€€€€€€€€xxxxzzwwttrrttuuuuttttvvuuvvvvssvvxxxxxxwwzzssqqttww~~xxttwwwwwwuussqqqqrrrruuyy{{{{yyxxyyyyyyxxxxyyyyyyyyyyzzzz}}€€€€€€€€xxxxzzwwttrrttuuuuttttvvuuvvvvssvvxxxxxxwwzzssqqttww~~vvuuxxvvssqqppqqssvvzz||zzyyyyyyzzyyxxxxxxyyxxyyyyyyyyyy{{€€€€€€€€{{vvyy{{xxttrruuvvuuuuvvuuttwwuurrwwxxyyxxxxxxrrrrww~~vvuuxxvvssqqppqqssvvzz||zzyyyyyyzzyyxxxxxxyyxxyyyyyyyyyy{{€€€€€€€€{{vvyy{{xxttrruuvvuuuuvvuuttwwuurrwwxxyyxxxxxxrrrrww||uuvvttrrqqssttww{{{{zzxxyyzzzzzzyyyyxxxxxxxxxxyyzzzzxxxx}}€€€€€€€€€€€€wwuuyy||xxttrruuwwvvwwuuttttwwuussxxzzzzyyxxwwrrvv||uuvvttrrqqssttww{{{{zzxxyyzzzzzzyyyyxxxxxxxxxxyyzzzzxxxx}}€€€€€€€€€€€€wwuuyy||xxttrruuwwvvwwuuttttwwuussxxzzzzyyxxwwrrvv}}uurrrrssvvzz||{{yyxxyyxxyyyy{{zzxxxxxxxxxxyyyyxxwwuuuuzz€€€€€€€€€€€€zzvvvvyy{{wwssqquuwwwwvvttttttwwttttyyzzzzwwwwwwtt}}uurrrrssvvzz||{{yyxxyyxxyyyy{{zzxxxxxxxxxxyyyyxxwwuuuuzz€€€€€€€€€€€€zzvvvvyy{{wwssqquuwwwwvvttttttwwttttyyzzzzwwwwwwtt~~rrssww{{}}}}zzxxxxxxyyyyyyzzzzyyxxyyxxxxxxwwuuttttuuyy€€€€€€€€€€€€€€€€€€}}wwvvvvyy{{wwttrruuxxwwvvuuttttxxttttyyzzwwuuwwyy~~rrssww{{}}}}zzxxxxxxyyyyyyzzzzyyxxyyxxxxxxwwuuttttuuyy€€€€€€€€€€€€€€€€€€}}wwvvvvyy{{wwttrruuxxwwvvuuttttxxttttyyzzwwuuwwyy||vv||}}{{zzzzzzyyxxyyxxyyyyyyyyyyxxyywwvvttttttvvvvuu}}��€€€€€€€€€€€€€€€€xxuuvvvvyy{{xxttrrvvxxvvvvttttvvwwrruuyyxxwwuuxx||vv||}}{{zzzzzzyyxxyyxxyyyyyyyyyyxxyywwvvttttttvvvvuu}}��€€€€€€€€€€€€€€€€xxuuvvvvyy{{xxttrrvvxxvvvvttttvvwwrruuyyxxwwuuxx||{{zzzzzzzzyyxxyyyyxxyyyyyyyyxxvvttttuuttuuuuuuxx{{€€��€€€€€€zzvvvvvvwwyy||xxttrruuvvwwuuvvwwvvuussuuxxwwvvww||{{zzzzzzzzyyxxyyyyxxyyyyyyyyxxvvttttuuttuuuuuuxx{{€€��€€€€€€zzvvvvvvwwyy||xxttrruuvvwwuuvvwwvvuussuuxxwwvvww€€{{zzzz{{{{yyyyxxxxxxxxyyxxwwuuttttttuuuuttvvxx{{}}}}€€~~~~}}||zzzzyyyyyyyyzz{{||}}~~€€||uuvvvvwwwwyy{{yyuurruuxxuuvvxxvvttvvssttwwwwyy€€{{zzzz{{{{yyyyxxxxxxxxyyxxwwuuttttttuuuuttvvxx{{}}}}€€~~~~}}||zzzzyyyyyyyyzz{{||}}~~€€||uuvvvvwwwwyy{{yyuurruuxxuuvvxxvvttvvssttwwwwyy||zz{{{{zzyyyyxxwwwwxxvvssssttuuuuuuuuww{{||||||{{{{~~}}||zzxxvvuuttssrrqqqqqqrrqqrrrrssttuuvvyy{{}}}}xxwwvvvvvvvvxx||zzuurruuuuuuxxvvttuuvvssttwwyy||zz{{{{zzyyyyxxwwwwxxvvssssttuuuuuuuuww{{||||||{{{{~~}}||zzxxvvuuttssrrqqqqqqrrqqrrrrssttuuvvyy{{}}}}xxwwvvvvvvvvxx||zzuurruuuuuuxxvvttuuvvssttwwyy{{zz{{zzyyyyyyxxuussssssssttttttwwzz{{||||{{zz{{{{}}€€€€€€~~}}zzwwttrrqqppnnkkkkkkiiiiiiiijjiijjkknnppqqqqqqrrssttuuvvwwwwwwwwwwyy||yyvvrrssvvwwuuttttuuvvssttyy{{zz{{zzyyyyyyxxuussssssssttttttwwzz{{||||{{zz{{{{}}€€€€€€~~}}zzwwttrrqqppnnkkkkkkiiiiiiiijjiijjkknnppqqqqqqrrssttuuvvwwwwwwwwwwyy||yyvvrrssvvwwuuttttuuvvssttyy{{zz{{yyxxwwvvssqqrrttssssttwwyy}}}}{{zz{{{{{{{{{{~~€€~~}}||yyuuqqlljjjjiiiihhffeeggjjkkllnnoooooommkknnmmiihhiillooppqqrrrrssttvvwwwwyy{{yyuussuuyyvvttttttvvwwrrww{{zz{{yyxxwwvvssqqrrttssssttwwyy}}}}{{zz{{{{{{{{{{~~€€~~}}||yyuuqqlljjjjiiiihhffeeggjjkkllnnoooooommkknnmmiihhiillooppqqrrrrssttvvwwwwyy{{yyuussuuyyvvttttttvvwwrrww{{zzyyvvttssssssssttttuuyy{{||||{{zz{{{{{{{{zzzz{{~~€€~~~~}}||zzxxuurrmmffccaabbcceegghhkknnpprrttssssttuuttttttrrrroohhddddffmmrrrrssssssrrrrssvvxx||yyuussvvwwuuuuuuuuvvttss{{zzyyvvttssssssssttttuuyy{{||||{{zz{{{{{{{{zzzz{{~~€€~~~~}}||zzxxuurrmmffccaabbcceegghhkknnpprrttssssttuuttttttrrrroohhddddffmmrrrrssssssrrrrssvvxx||yyuussvvwwuuuuuuuuvvttss~~wwuussssssttssttvvyy{{||}}{{zzzz{{{{{{{{{{{{zzzz{{~~}}{{zzyywwssmmggjjiibb``bbccggkkpprrrrqqqqrrrrqqqqqqqqqqrrssssssttqqkkeeeemmpprrrrssttssssrrssvvzz~~zzuuttuuuuuuvvuuuussvv~~wwuussssssttssttvvyy{{||}}{{zzzz{{{{{{{{{{{{zzzz{{~~}}{{zzyywwssmmggjjiibb``bbccggkkpprrrrqqqqrrrrqqqqqqqqqqrrssssssttqqkkeeeemmpprrrrssttssssrrssvvzz~~zzuuttuuuuuuvvuuuussvv||ttttssttttuuxxzz{{{{{{zzzzzzzzzzzzzzzz{{zzzzzzzz{{{{yyyyvvppjjddaabbhhkkeeeejjnnrrssqqppppqqrrrrqqppqqooppooppqqqqqqqqrrppjjeemmqqqqssssssttttssuuwwyyzz}}yyvvssssttvvvvvvssuu||ttttssttttuuxxzz{{{{{{zzzzzzzzzzzzzzzz{{zzzzzzzz{{{{yyyyvvppjjddaabbhhkkeeeejjnnrrssqqppppqqrrrrqqppqqooppooppqqqqqqqqrrppjjeemmqqqqssssssttttssuuwwyyzz}}yyvvssssttvvvvvvssuu||ttssuuww{{||{{{{zzzz{{zz{{{{zzzzzzzzzz{{zzzzzz{{zzyywwsskkddccaa````hhppnnppttttssrrqqrrrrssuuuuuuuuttssrrqqqqqqppppppooppppjjllqqrrrrssssttttuuvvwwyyxxyy{{yyuussssvvwwxxttvv||ttssuuww{{||{{{{zzzz{{zz{{{{zzzzzzzzzz{{zzzzzz{{zzyywwsskkddccaa````hhppnnppttttssrrqqrrrrssuuuuuuuuttssrrqqqqqqppppppooppppjjllqqrrrrssssttttuuvvwwyyxxyy{{yyuussssvvwwxxttvv||wwzz{{||{{zzzzzz{{{{zzzz{{{{zzzzyyyyzz{{yyzzzzyywwttqqqqiiccbbaabbddmmttssssssssqqqqssttuuwwxxyyyyyywwuuuussrrrrrrrrqqqqppppmmnnqqrrrrrrssttvvvvvvvvxxxxwwyy||yyvvssttwwwwuuvv||wwzz{{||{{zzzzzz{{{{zzzz{{{{zzzzyyyyzz{{yyzzzzyywwttqqqqiiccbbaabbddmmttssssssssqqqqssttuuwwxxyyyyyywwuuuussrrrrrrrrqqqqppppmmnnqqrrrrrrssttvvvvvvvvxxxxwwyy||yyvvssttwwwwuuvv€€||{{{{zz{{zzzzzz{{zz{{zzzzzzzzzzyyzzzzzzyyyyyywwrroossooeecccccciippttttssssssrrssttvvvvvvvvwwxxyyyyxxxxvvttttssrrsssssssssspppprrrrrrssssuuwwvvwwvvxxxxxxxxyy||yyvvssttxxvvww€€||{{{{zz{{zzzzzz{{zz{{zzzzzzzzzzyyzzzzzzyyyyyywwrroossooeecccccciippttttssssssrrssttvvvvvvvvwwxxyyyyxxxxvvttttssrrsssssssssspppprrrrrrssssuuwwvvwwvvxxxxxxxxyy||yyvvssttxxvvww€€{{zz{{zz{{zzyyyy{{{{{{zzyyzzzzzzzzyyyyzzyyxxxxssnnoommffddddggmmuuvvuuttssssrrssttvvvvuuttttttuuvvwwxxxxwwvvuuttttttttttvvvvttrrrrssvvwwwwttttvvwwvvwwwwxxxxxxyy||zzuurrttuuww€€{{zz{{zz{{zzyyyy{{{{{{zzyyzzzzzzzzyyyyzzyyxxxxssnnoommffddddggmmuuvvuuttssssrrssttvvvvuuttttttuuvvwwxxxxwwvvuuttttttttttvvvvttrrrrssvvwwwwttttvvwwvvwwwwxxxxxxyy||zzuurrttuuww€€||zzzzzzzzzzyyzzzzzzyyyyyyyyzzzzzzyyyyzzyyxxuuppppppkkeeffjjqqwwyyvvttttssssssttvvvvwwuuttttttuuuuwwxxxxwwvvuuttuuttttvvvvwwwwssssvvzz{{yywwuuuuwwvvvvwwwwxxwwwwxxzzyyttrrssww€€||zzzzzzzzzzyyzzzzzzyyyyyyyyzzzzzzyyyyzzyyxxuuppppppkkeeffjjqqwwyyvvttttssssssttvvvvwwuuttttttuuuuwwxxxxwwvvuuttuuttttvvvvwwwwssssvvzz{{yywwuuuuwwvvvvwwwwxxwwwwxxzzyyttrrssww||zzzzzzzzzzzzzzyyzzyyyyyyyyyyyyzzyyxxxxwwuuttpprrrrmmggllrrwwzzxxttttttttssttuuvvwwvvuuuuuuuuwwvvuuwwxxvvvvuuttuuttttuuuuvvwwuuvvxxxxzz||zzwwuuttvvvvvvvvxxwwwwwwwwzzyyuuqquu||zzzzzzzzzzzzzzyyzzyyyyyyyyyyyyzzyyxxxxwwuuttpprrrrmmggllrrwwzzxxttttttttssttuuvvwwvvuuuuuuuuwwvvuuwwxxvvvvuuttuuttttuuuuvvwwuuvvxxxxzz||zzwwuuttvvvvvvvvxxwwwwwwwwzzyyuuqquu{{yyzzzzzzzzzzyyxxyyyyzzzzyyyyxxwwvvuuuuvvvvvvrrrrttppkkppvvyyyywwttuuttttuuuuuuuuuuttuuvvwwvvwwxxwwxxyywwuuuuvvvvuuttttttttuuuuwwvvwwxxzz{{yywwuuttuuvvwwwwwwwwwwwwwwzzyytttt{{yyzzzzzzzzzzyyxxyyyyzzzzyyyyxxwwvvuuuuvvvvvvrrrrttppkkppvvyyyywwttuuttttuuuuuuuuuuttuuvvwwvvwwxxwwxxyywwuuuuvvvvuuttttttttuuuuwwvvwwxxzz{{yywwuuttuuvvwwwwwwwwwwwwwwzzyytttt{{zzzzzzxxyyzzyyyyyyyyyyxxwwuuuuuuvvwwwwwwvvvvuussttttqqrrxxzzzzwwttuuttuuuuuuuuttttuuuuvvwwxxyy{{zzyyyy{{yyvvuuttvvvvvvuussssttwwwwvvxxxxxx{{zzwwuussvvwwwwwwwwwwwwwwwwyyxxvv{{zzzzzzxxyyzzyyyyyyyyyyxxwwuuuuuuvvwwwwwwvvvvuussttttqqrrxxzzzzwwttuuttuuuuuuuuttttuuuuvvwwxxyy{{zzyyyy{{yyvvuuttvvvvvvuussssttwwwwvvxxxxxx{{zzwwuussvvwwwwwwwwwwwwwwwwyyxxvv{{zzzzzzyyyyyyyyxxvvuuuuuuuuvvwwwwwwvvvvvvvvvvvvvvssssssvvyyyyzzwwuuuuuuuuuuttttssttuuuuxxxxzz{{||{{wwxxzzxxvvttttwwxxxxxxvvrrssvvwwwwwwwwwwxxzzzzwwuussuuwwvvvvvvwwwwvvvvxxyy{{zzzzzzyyyyyyyyxxvvuuuuuuuuvvwwwwwwvvvvvvvvvvvvvvssssssvvyyyyzzwwuuuuuuuuuuttttssttuuuuxxxxzz{{||{{wwxxzzxxvvttttwwxxxxxxvvrrssvvwwwwwwwwwwxxzzzzwwuussuuwwvvvvvvwwwwvvvvxxyy{{yyyyyyxxxxvvuuttuuuuwwwwwwvvvvvvwwwwvvwwwwvvvvvvttttuuuuwwyyxxvvuuttuuttuuttssssttttuuvvvvvvuuvvxxwwxxxxuuttttttvvyyyyzzyyttttxxwwvvwwxxwwwwwwzzzzwwvvssvvwwwwwwwwxxwwvvvvyy{{yyyyyyxxxxvvuuttuuuuwwwwwwvvvvvvwwwwvvwwwwvvvvvvttttuuuuwwyyxxvvuuttuuttuuttssssttttuuvvvvvvuuvvxxwwxxxxuuttttttvvyyyyzzyyttttxxwwvvwwxxwwwwwwzzzzwwvvssvvwwwwwwwwxxwwvvvvyyzzxxxxvvuuuuuuuuuuwwvvuuuuvvvvvvwwwwwwvvwwwwwwwwvvvvrrrrssttuuuuuuvvuuuuttttssssrrrrssttssssssttuuwwxxwwvvssssttttttxxwwzzzzuuuuwwwwwwwwxxwwwwwwxxzzzzxxvvttttvvwwxxxxwwwwvvxxzzxxxxvvuuuuuuuuuuwwvvuuuuvvvvvvwwwwwwvvwwwwwwwwvvvvrrrrssttuuuuuuvvuuuuttttssssrrrrssttssssssttuuwwxxwwvvssssttttttxxwwzzzzuuuuwwwwwwwwxxwwwwwwxxzzzzxxvvttttvvwwxxxxwwwwvvxx~~vvuuvvuuvvuuvvvvuuvvvvvvvvwwvvvvvvwwwwwwwwwwwwvvwwuuqqssssssttttvvwwvvttttssrrrrqqrrrrrrrrssssttttttuuuuttttuuttttttxxvvuuxxuuuuwwwwwwwwwwwwwwwwxxwwxxzzyywwttttwwwwwwwwwwvvxx~~vvuuvvuuvvuuvvvvuuvvvvvvvvwwvvvvvvwwwwwwwwwwwwvvwwuuqqssssssttttvvwwvvttttssrrrrqqrrrrrrrrssssttttttuuuuttttuuttttttxxvvuuxxuuuuwwwwwwwwwwwwwwwwxxwwxxzzyywwttttwwwwwwwwwwvvxx}}vvvvvvuuwwwwyyzzxxvvvvwwvvwwvvvvwwvvwwwwwwwwvvvvxxuuqqssrrssssssvvwwuuttttttssrrrrqqqqrrrrssssssssttttttttttuuttttuuwwzzwwwwuuuuwwwwwwwwwwwwwwvvwwxxwwww{{zzvvttttvvwwwwwwvvxx}}vvvvvvuuwwwwyyzzxxvvvvwwvvwwvvvvwwvvwwwwwwwwvvvvxxuuqqssrrssssssvvwwuuttttttssrrrrqqqqrrrrssssssssttttttttttuuttttuuwwzzwwwwuuuuwwwwwwwwwwwwwwvvwwxxwwww{{zzvvttttvvwwwwwwvvxx}}vvwwyyzz{{zzzzyyyyxxuuxxyyyyyywwvvvvvvvvvvvvvvvvwwuuppssssppqqssuuvvuussssttssrrqqqqrrrrrrssssssttttttttttttuuttttttuuxxxxxxvvvvwwwwwwwwwwwwwwvvwwwwvvvvyy||yywwttttuuvvwwwwyy}}vvwwyyzz{{zzzzyyyyxxuuxxyyyyyywwvvvvvvvvvvvvvvvvwwuuppssssppqqssuuvvuussssttssrrqqqqrrrrrrssssssttttttttttttuuttttttuuxxxxxxvvvvwwwwwwwwwwwwwwvvwwwwvvvvyy||yywwttttuuvvwwwwyy~~||}}}}||{{zzyyxxxxwwvvvvyy{{{{yyxxwwwwvvvvvvvvvvvvvvqqssqqoossttuuvvuuttttssrrqqppppqqrrrrssssssttttttssttvvvvttttrrrruuxxwwxxuuuuwwvvvvwwwwwwvvwwwwwwvvwwyy{{zzwwttssttvvvvyy~~||}}}}||{{zzyyxxxxwwvvvvyy{{{{yyxxwwwwvvvvvvvvvvvvvvqqssqqoossttuuvvuuttttssrrqqppppqqrrrrssssssttttttssttvvvvttttrrrruuxxwwxxuuuuwwvvvvwwwwwwvvwwwwwwvvwwyy{{zzwwttssttvvvvyy}}||{{{{{{zzxxwwxxwwwwvvuuxx{{||{{yyyyvvvvwwvvuuvvvvssrrppppuussttvvwwuuuurrppoonnnnooqqrrssttttttssssttuuvvuuttrrppoosswwvvyyxxttuuvvvvwwwwvvvvwwwwwwwwwwyyyyzzzzwwttrrttuuxx}}||{{{{{{zzxxwwxxwwwwvvuuxx{{||{{yyyyvvvvwwvvuuvvvvssrrppppuussttvvwwuuuurrppoonnnnooqqrrssttttttssssttuuvvuuttrrppoosswwvvyyxxttuuvvvvwwwwvvvvwwwwwwwwwwyyyyzzzzwwttrrttuuxx}}||zzzzzzzzwwxxwwvvvvvvttuuyyyy{{||{{xxwwwwwwuuuuuussssrrrrttrrssvvwwvvuurrppppoooonnooqqrrttttttssssuuvvttttssqqppoorrvvuuxxyywwttttvvwwvvvvvvwwwwvvwwwwyyxxwwzzzzwwttrrssww}}||zzzzzzzzwwxxwwvvvvvvttuuyyyy{{||{{xxwwwwwwuuuuuussssrrrrttrrssvvwwvvuurrppppoooonnooqqrrttttttssssuuvvttttssqqppoorrvvuuxxyywwttttvvwwvvvvvvwwwwvvwwwwyyxxwwzzzzwwttrrssww}}{{zzzz{{yywwyywwuuuuttttuuxxyyxxyy||||yywwwwvvvvuuttttrrssssrrssuuwwvvvvttrrqqqqpppppppprrssssssssssvvuuuuuussssrrqqrruuttwwwwwwwwuuttuuvvvvvvwwwwvvwwxxxxxxwwxxyyyyvvttqquu}}{{zzzz{{yywwyywwuuuuttttuuxxyyxxyy||||yywwwwvvvvuuttttrrssssrrssuuwwvvvvttrrqqqqpppppppprrssssssssssvvuuuuuussssrrqqrruuttwwwwwwwwuuttuuvvvvvvwwwwvvwwxxxxxxwwxxyyyyvvttqquu||zz{{{{zzwwxxxxwwwwuuuuvvvvvvyyyyyyyy{{}}||zzxxwwwwuuuussttssrrssuuwwvvvvvvttttssrrrrrrrrrrssssssrrttvvuuvvyyxxvvuuttuuuusswwwwttvvxxvvttuuuuvvwwwwvvwwwwxxwwwwwwxxwwyywwtttt||zz{{{{zzwwxxxxwwwwuuuuvvvvvvyyyyyyyy{{}}||zzxxwwwwuuuussttssrrssuuwwvvvvvvttttssrrrrrrrrrrssssssrrttvvuuvvyyxxvvuuttuuuusswwwwttvvxxvvttuuuuvvwwwwvvwwwwxxwwwwwwxxwwyywwtttt||{{||||zzxxxxwwwwwwwwwwvvvvttxxzzyyyyyyyy{{||{{zzxxvvuuuuuussqqrruuwwwwvvvvvvuuttssssssssssssssssssuuvvvvwwwwwwuuttvvxxuurrvvwwuuttuuxxwwttttvvvvvvvvvvwwwwvvwwwwwwwwwwxxwwvv||{{||||zzxxxxwwwwwwwwwwvvvvttxxzzyyyyyyyy{{||{{zzxxvvuuuuuussqqrruuwwwwvvvvvvuuttssssssssssssssssssuuvvvvwwwwwwuuttvvxxuurrvvwwuuttuuxxwwttttvvvvvvvvvvwwwwvvwwwwwwwwwwxxwwvv€€}}||}}||yyxxyyyyxxwwwwwwwwvvuuvvyyzzyyxxxxxxyy||{{yyvvuuvvvvttrrqqsswwwwvvuuuuvvttssttttssssssssttttuuvvvvvvwwwwttuuyy{{wwttvvvvuuuuttuuvvxxuuttuuvvvvvvvvvvvvwwwwwwwwwwvvxxyy€€}}||}}||yyxxyyyyxxwwwwwwwwvvuuvvyyzzyyxxxxxxyy||{{yyvvuuvvvvttrrqqsswwwwvvuuuuvvttssttttssssssssttttuuvvvvvvwwwwttuuyy{{wwttvvvvuuuuttuuvvxxuuttuuvvvvvvvvvvvvwwwwwwwwwwvvxxyy€€~~}}}}||yyyyyyyyyywwwwvvvvvvvvuuwwzzzzyyyyxxwwxxvvvvuuuuttvvuusspprrvvvvvvttttuuttssttssssrrqqrrttuuuuuuuuuuvvvvuuvvyyzzyyvvvvvvuuuuttttttwwxxvvttttuuuuuuvvvvwwwwwwvvvvvvuuxx€€~~}}}}||yyyyyyyyyywwwwvvvvvvvvuuwwzzzzyyyyxxwwxxvvvvuuuuttvvuusspprrvvvvvvttttuuttssttssssrrqqrrttuuuuuuuuuuvvvvuuvvyyzzyyvvvvvvuuuuttttttwwxxvvttttuuuuuuvvvvwwwwwwvvvvvvuuxx}}||||{{yyzzzzyyxxwwwwwwvvuuvvvvvvyyzzzzyyxxxxxxuussssttuuxxxxssqqssvvvvvvuuttttttssssrrqqppppqqssttuuuuttttttuuwwwwxxyyxxxxxxvvuuttuuttttttuuwwwwuuuuvvvvvvuuvvwwvvvvvvvvuuww}}||||{{yyzzzzyyxxwwwwwwvvuuvvvvvvyyzzzzyyxxxxxxuussssttuuxxxxssqqssvvvvvvuuttttttssssrrqqppppqqssttuuuuttttttuuwwwwxxyyxxxxxxvvuuttuuttttttuuwwwwuuuuvvvvvvuuvvwwvvvvvvvvuuww}}||{{zzyyzzzzyyxxwwwwwwvvvvvvwwuuwwyyzzzzzzxxxxuuttrrrruuxx{{uurrssttuuvvuussttttssssppooqqrrssttuuuuttssssttuuwwwwwwwwwwxxwwuuuuuuuuttttttuuttvvwwuuttuuvvuuvvvvvvuuuuuuttxx}}||{{zzyyzzzzyyxxwwwwwwvvvvvvwwuuwwyyzzzzzzxxxxuuttrrrruuxx{{uurrssttuuvvuussttttssssppooqqrrssttuuuuttssssttuuwwwwwwwwwwxxwwuuuuuuuuttttttuuttvvwwuuttuuvvuuvvvvvvuuuuuuttxx€€}}||zzyy{{{{zzzzyyxxwwwwwwwwvvvvvvvvxxzzzzzzyywwttssssrruuzz}}vvssssuuvvuuuussrrrrssrroonnqqssttuuvvvvvvvvvvvvwwxxyyyyvvvvxxwwuuuuuuuuuuuuuuttttttuuwwvvuuuuuuvvvvvvuuttttttxx€€}}||zzyy{{{{zzzzyyxxwwwwwwwwvvvvvvvvxxzzzzzzyywwttssssrruuzz}}vvssssuuvvuuuussrrrrssrroonnqqssttuuvvvvvvvvvvvvwwxxyyyyvvvvxxwwuuuuuuuuuuuuuuttttttuuwwvvuuuuuuvvvvvvuuttttttxx€€}}||zzzz{{{{zzzzzzxxxxxxwwvvvvwwvvvvwwzz{{zzyywwvvssssssuuzz||xxssssttvvuuvvttrrqqrrqqnnnnppssttuuxxxxwwwwxxwwwwxxzz}}wwssxxwwuuuuuuuuuuttuuttttttttttwwwwttttuuvvvvuuttttttww€€}}||zzzz{{{{zzzzzzxxxxxxwwvvvvwwvvvvwwzz{{zzyywwvvssssssuuzz||xxssssttvvuuvvttrrqqrrqqnnnnppssttuuxxxxwwwwxxwwwwxxzz}}wwssxxwwuuuuuuuuuuttuuttttttttttwwwwttttuuvvvvuuttttttww€€||{{yy{{{{{{zzyyzzxxxxxxxxwwwwwwvvvvuuxx{{yyyyxxwwuuttttvvxxzzzzuussssuuuuvvvvssqqrrrroommppssssrrssuuvvvvwwwwvvww{{}}wwsswwwwttttuuuuuuuuuuuuuuttttssssvvwwuussuuvvuuuuttttww€€||{{yy{{{{{{zzyyzzxxxxxxxxwwwwwwvvvvuuxx{{yyyyxxwwuuttttvvxxzzzzuussssuuuuvvvvssqqrrrroommppssssrrssuuvvvvwwwwvvww{{}}wwsswwwwttttuuuuuuuuuuuuuuttttssssvvwwuussuuvvuuuuttttww€€}}{{zz{{{{{{zzzzyyyyxxxxxxwwwwvvvvvvvvvvxxyyyyxxwwvvttttvvvvxxzzwwrrssttuuvvwwuuqqrrrrqqooppqqpppppprrssuuvvvvvvvvxxzzwwssvvuussttttuuuuuuuuuuttttttssssttuuvvuuttuuuuttssssww€€}}{{zz{{{{{{zzzzyyyyxxxxxxwwwwvvvvvvvvvvxxyyyyxxwwvvttttvvvvxxzzwwrrssttuuvvwwuuqqrrrrqqooppqqpppppprrssuuvvvvvvvvxxzzwwssvvuussttttuuuuuuuuuuttttttssssttuuvvuuttuuuuttssssww}}zzzz{{{{{{zzzzyyyyxxxxxxxxxxwwvvwwvvvvwwzzyyxxwwwwvvvvvvttzz}}xxttssssttuuvvvvttqqrrqqppoonnnnppqqrrssuuttuuttttuuwwwwuuuuttssssssttttttttuuuuuuttttttttttttvvvvuuttssssssvv}}zzzz{{{{{{zzzzyyyyxxxxxxxxxxwwvvwwvvvvwwzzyyxxwwwwvvvvvvttzz}}xxttssssttuuvvvvttqqrrqqppoonnnnppqqrrssuuttuuttttuuwwwwuuuuttssssssttttttttuuuuuuttttttttttttvvvvuuttssssssvv€€||zz||||zz{{{{zzyyyyyyyyxxxxxxxxvvwwwwvvvvyyzzyyxxwwvvuuuuss~~„„zzttrrssssuuuuvvuurrrrrrppmmllllnnqqssttuuuuuuuuuuuuvvvvvvuussssssssssssttttttuuttuuttttttuussrruuvvuussssssvv€€||zz||||zz{{{{zzyyyyyyyyxxxxxxxxvvwwwwvvvvyyzzyyxxwwvvuuuuss~~„„zzttrrssssuuuuvvuurrrrrrppmmllllnnqqssttuuuuuuuuuuuuvvvvvvuussssssssssssttttttuuttuuttttttuussrruuvvuussssssvv{{zz}}||{{{{{{zzyyyyyyxxxxxxxxxxwwwwwwvvuuwwzzzzzzyywwvvvvuu~~††~~ttqqqqrrssttuuuussrrssrrookkllmmnnppssssttssuuuuuuuuuuvvuussssttttssssttttttttssttttuuttttttssssttvvuussrrvv{{zz}}||{{{{{{zzyyyyyyxxxxxxxxxxwwwwwwvvuuwwzzzzzzyywwvvvvuu~~††~~ttqqqqrrssttuuuussrrssrrookkllmmnnppssssttssuuuuuuuuuuvvuussssttttssssttttttttssttttuuttttttssssttvvuussrrvv€€{{zz||||{{zzzzyyxxyyyyxxxxxxxxxxxxwwwwwwvvvvyyzzzzzzyyyyyyvv~~‡‡„„vvppppqqrrssttttssrrrrrrppnnmmllllmmnnoooopprrssssuuuuvvuuttttttttssttssssssssssssssttttttttssssssttuuuurrtt€€{{zz||||{{zzzzyyxxyyyyxxxxxxxxxxxxwwwwwwvvvvyyzzzzzzyyyyyyvv~~‡‡„„vvppppqqrrssttttssrrrrrrppnnmmllllmmnnoooopprrssssuuuuvvuuttttttttssttssssssssssssssttttttttssssssttuuuurrtt{{{{}}||{{zz{{zzxxyyyyxxxxxxxxxxxxxxxxwwvvwwwwzz{{{{zzzzzzxx~~……ˆˆ}}ppppqqppqqssttssrrqqrrrrqqoonnmmllllllmmppqqrrrruuvvvvuuuuttttttssttssssrrssrrssrrrrttttttssttttssrrssuutt{{{{}}||{{zz{{zzxxyyyyxxxxxxxxxxxxxxxxwwvvwwwwzz{{{{zzzzzzxx~~……ˆˆ}}ppppqqppqqssttssrrqqrrrrqqoonnmmllllllmmppqqrrrruuvvvvuuuuttttttssttssssrrssrrssrrrrttttttssttttssrrssuutt||||}}{{zzzzyyzzzzyyxxyyxxxxxxxxxxxxxxxxwwwwvvxx{{{{{{{{{{yy}}„„ˆˆ‡‡vvooqqppoorrssssssqqrrssrrqqppnnmmmmmmmmppqqqqrrttvvvvttttttttttttssssrrssssrrssssssssssttttttttrrqqrrrrss||||}}{{zzzzyyzzzzyyxxyyxxxxxxxxxxxxxxxxwwwwvvxx{{{{{{{{{{yy}}„„ˆˆ‡‡vvooqqppoorrssssssqqrrssrrqqppnnmmmmmmmmppqqqqrrttvvvvttttttttttttssssrrssssrrssssssssssttttttttrrqqrrrrss||||||zzzzzzzzzzzzyyyyyyxxxxxxxxyyxxxxwwwwwwwwwwzz||||||||zz{{ƒƒ‡‡ŠŠ‚‚rrnnppppqqrrrrssrrrrttssssrrqqppoooooopprrrrrruuwwuuttttttttuuuuttssssttssssssssssssssssuuttttssrrqqqqpp||||||zzzzzzzzzzzzyyyyyyxxxxxxxxyyxxxxwwwwwwwwwwzz||||||||zz{{ƒƒ‡‡ŠŠ‚‚rrnnppppqqrrrrssrrrrttssssrrqqppoooooopprrrrrruuwwuuttttttttuuuuttssssttssssssssssssssssuuttttssrrqqqqpp€€}}||{{zz{{zzzzzzzzyyyyyyxxxxxxxxyyxxwwxxxxxxwwvvxx{{||||||{{{{‚‚ˆˆ‰‰ŠŠ€€ttppppqqqqrrrrrrrrssssssrrrrqqqqppppqqrrssttvvwwuussttssssttssssttssssttssssssssssssrrssssssssrrrrqqqq€€}}||{{zz{{zzzzzzzzyyyyyyxxxxxxxxyyxxwwxxxxxxwwvvxx{{||||||{{{{‚‚ˆˆ‰‰ŠŠ€€ttppppqqqqrrrrrrrrssssssrrrrqqqqppppqqrrssttvvwwuussttssssttssssttssssttssssssssssssrrssssssssrrrrqqqq€€}}}}{{{{{{zzzzzzyyyyyyyyyyyyxxyyxxxxxxxxxxxxwwvvwwzz||||||||||��‡‡ˆˆŠŠŠŠ‡‡zzppqqqqrrssssrrssssssssssrrrrrrrrssssttuuvvvvttssttttttttssssssssssssssssssssssssssssssssttssrrqqrr€€}}}}{{{{{{zzzzzzyyyyyyyyyyyyxxyyxxxxxxxxxxxxwwvvwwzz||||||||||��‡‡ˆˆŠŠŠŠ‡‡zzppqqqqrrssssrrssssssssssrrrrrrrrssssttuuvvvvttssttttttttssssssssssssssssssssssssssssssssttssrrqqrr€€}}||{{{{{{zzyyzzzzyyyyyyyyyyyyyyxxxxwwxxxxxxwwvvwwxx{{}}||}}��……‡‡‰‰ŠŠŠŠ……ssooqqrrttttssrrssssssssssrrssssssttuuuuzzyyuuttuuuuuuttttttttssssrrssssssssssrrrrrrssssssrrrrqqrr€€}}||{{{{{{zzyyzzzzyyyyyyyyyyyyyyxxxxwwxxxxxxwwvvwwxx{{}}||}}��……‡‡‰‰ŠŠŠŠ……ssooqqrrttttssrrssssssssssrrssssssttuuuuzzyyuuttuuuuuuttttttttssssrrssssssssssrrrrrrssssssrrrrqqrr€€}}{{{{{{zzzzzzzzzzyyyyxxxxyyyyyyxxxxwwxxxxxxxxwwwwwwyy||||}}‚‚‚‚€€……ˆˆ‰‰ŠŠŠŠ~~oopprrssuuttssssssssssssssssssssttuuyyƒƒ„„{{vvvvvvuuttttssttssttssssrrssssssrrrrssrrrrrrrrqqqqrr€€}}{{{{{{zzzzzzzzzzyyyyxxxxyyyyyyxxxxwwxxxxxxxxwwwwwwyy||||}}‚‚‚‚€€……ˆˆ‰‰ŠŠŠŠ~~oopprrssuuttssssssssssssssssssssttuuyyƒƒ„„{{vvvvvvuuttttssttssttssssrrssssssrrrrssrrrrrrrrqqqqrr€€}}zz{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxxxxxwwvvwwzz||„„„„ƒƒ��„„‰‰ŠŠŠŠ‰‰zznnqqssttttttttssttssssttssttuuttxx‚‚‡‡‡‡wwvvvvuuuuttttttttssssrrrrrrssssssssssssrrrrqqqqrr€€}}zz{{{{{{zzzzzzzzzzzzyyyyyyyyyyxxxxxxxxxxxxxxxxwwvvwwzz||„„„„ƒƒ��„„‰‰ŠŠŠŠ‰‰zznnqqssttttttttssttssssttssttuuttxx‚‚‡‡‡‡wwvvvvuuuuttttttttssssrrrrrrssssssssssssrrrrqqqqrr€€}}zzzz{{{{zzzzyyzzyyyyyyxxxxxxxxyyxxxxxxxxwwwwwwwwvvvvzz€€‚‚‚‚„„ƒƒƒƒ‚‚ƒƒ‡‡ŠŠ‹‹††uummssttrrssttssttttttttttuuttww{{~~€€……‰‰ˆˆwwuuuuuuttttttssrrssssrrrrssssrrssrrrrqqqqqqpprr€€}}zzzz{{{{zzzzyyzzyyyyyyxxxxxxxxyyxxxxxxxxwwwwwwwwvvvvzz€€‚‚‚‚„„ƒƒƒƒ‚‚ƒƒ‡‡ŠŠ‹‹††uummssttrrssttssttttttttttuuttww{{~~€€……‰‰ˆˆwwuuuuuuttttttssrrssssrrrrssssrrssrrrrqqqqqqpprr||zzzz{{zzzzzzzzzzyyyyyyxxxxxxxxyyyyxxxxwwwwxxwwwwvvvv}}ƒƒ„„ƒƒƒƒƒƒƒƒ„„„„‚‚……‰‰‹‹‚‚rrnnssssssssssssuuuuuuttttuuwwzz}}€€……‰‰‹‹‡‡wwrruuvvttttttssssttssrrssrrrrqqrrqqqqrrqqrrqqqq||zzzz{{zzzzzzzzzzyyyyyyxxxxxxxxyyyyxxxxwwwwxxwwwwvvvv}}ƒƒ„„ƒƒƒƒƒƒƒƒ„„„„‚‚……‰‰‹‹‚‚rrnnssssssssssssuuuuuuttttuuwwzz}}€€……‰‰‹‹‡‡wwrruuvvttttttssssttssrrssrrrrqqrrqqqqrrqqrrqqqq€€}}{{||{{zzzzzzzzzzyyyyzzyyyyyyxxyyyyyyyywwxxyyxxxx{{}}��„„„„……„„„„„„„„††„„‚‚ƒƒ‡‡ŠŠ~~nnqqssttrrrrssttttttttttuuww{{}}††ˆˆˆˆ‰‰}}ssssttuuuuuussssssttttttssrrrrrrrrrrrrppqquuuu€€}}{{||{{zzzzzzzzzzyyyyzzyyyyyyxxyyyyyyyywwxxyyxxxx{{}}��„„„„……„„„„„„„„††„„‚‚ƒƒ‡‡ŠŠ~~nnqqssttrrrrssttttttttttuuww{{}}††ˆˆˆˆ‰‰}}ssssttuuuuuussssssttttttssrrrrrrrrrrrrppqquuuu€€}}{{{{{{zzzzyyyyyyyyyyyyyyzzzzxxxxxxxxzzzz||~~~~‚‚‚‚ƒƒ„„„„„„„„……„„„„††…………ƒƒ‚‚ƒƒ€€rrooqqssssssttttssssssttuuww{{~~€€……††††ˆˆ~~vvuuqqttuuuuttssttttssssssrrssttssnnffjjzzƒƒ��€€}}{{{{{{zzzzyyyyyyyyyyyyyyzzzzxxxxxxxxzzzz||~~~~‚‚‚‚ƒƒ„„„„„„„„……„„„„††…………ƒƒ‚‚ƒƒ€€rrooqqssssssttttssssssttuuww{{~~€€……††††ˆˆ~~vvuuqqttuuuuttssttttssssssrrssttssnnffjjzzƒƒ��€€||{{||{{zzzzyyxxyyyyyyxxyyyyxxwwxxyy{{��‚‚‚‚‚‚ƒƒƒƒ��‚‚ƒƒ„„„„„„ƒƒ„„………………„„…………‚‚��}}xxttrrrrttssssssssssuuvvvvzz}}~~ƒƒ……ˆˆ††zzuuuuuuvvttuuwwuuuussssnneejjrr~~pp[[\\oowwrrpp€€||{{||{{zzzzyyxxyyyyyyxxyyyyxxwwxxyy{{��‚‚‚‚‚‚ƒƒƒƒ��‚‚ƒƒ„„„„„„ƒƒ„„………………„„…………‚‚��}}xxttrrrrttssssssssssuuvvvvzz}}~~ƒƒ……ˆˆ††zzuuuuuuvvttuuwwuuuussssnneejjrr~~pp[[\\oowwrrpp€€||||||{{zzzzyyxxxxyyxxxxyyyyyy{{}}��‚‚ƒƒ‚‚‚‚‚‚‚‚„„ƒƒ��€€ƒƒ„„……††„„ƒƒ„„ƒƒ„„„„„„……ƒƒ‚‚��ƒƒ��zzttssttuuuuuuuuvvwwxxyy}}ƒƒ‰‰‰‰ƒƒyyvvvvvvwwxxww{{{{yyttuujjZZhhrrppbbZZ]]__]][[^^€€||||||{{zzzzyyxxxxyyxxxxyyyyyy{{}}��‚‚ƒƒ‚‚‚‚‚‚‚‚„„ƒƒ��€€ƒƒ„„……††„„ƒƒ„„ƒƒ„„„„„„……ƒƒ‚‚��ƒƒ��zzttssttuuuuuuuuvvwwxxyy}}ƒƒ‰‰‰‰ƒƒyyvvvvvvwwxxww{{{{yyttuujjZZhhrrppbbZZ]]__]][[^^xxjjmmhhiikkjjhhggmmkkvv„„‚‚‚‚‚‚ƒƒƒƒ……††……………………„„„„„„„„„„ƒƒƒƒ„„„„„„„„††††…………„„……„„ƒƒƒƒƒƒƒƒ„„„„„„ƒƒƒƒ„„„„„„„„……„„ƒƒƒƒ„„„„„„……††……„„„„„„ƒƒ„„……………………………………††……††„„„„††††ˆˆ‡‡ƒƒ„„xxjjmmhhiikkjjhhggmmkkvv„„‚‚‚‚‚‚ƒƒƒƒ……††……………………„„„„„„„„„„ƒƒƒƒ„„„„„„„„††††…………„„……„„ƒƒƒƒƒƒƒƒ„„„„„„ƒƒƒƒ„„„„„„„„……„„ƒƒƒƒ„„„„„„……††……„„„„„„ƒƒ„„……………………………………††……††„„„„††††ˆˆ‡‡ƒƒ„„ssPPQQNNQQKKMMNNOOSSUUgg††‚‚ƒƒƒƒ„„…………………………………………„„„„„„„„„„„„„„………………††………………„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„…………„„„„ƒƒ„„………………††……„„„„ƒƒƒƒ„„…………††…………††††††††††…………††††ˆˆ††ƒƒssPPQQNNQQKKMMNNOOSSUUgg††‚‚ƒƒƒƒ„„…………………………………………„„„„„„„„„„„„„„………………††………………„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„…………„„„„ƒƒ„„………………††……„„„„ƒƒƒƒ„„…………††…………††††††††††…………††††ˆˆ††ƒƒ}}ssttssttttuussttvvuuyy„„ƒƒ„„…………„„„„„„…………„„„„„„„„„„ƒƒƒƒ„„……………………………………„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚��€€��€€€€‚‚‚‚ƒƒƒƒ„„……„„„„ƒƒƒƒ„„………………††……„„„„ƒƒ„„„„…………††……††……††††……††„„…………‡‡ˆˆ……}}ssttssttttuussttvvuuyy„„ƒƒ„„…………„„„„„„…………„„„„„„„„„„ƒƒƒƒ„„……………………………………„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚��€€��€€€€‚‚‚‚ƒƒƒƒ„„……„„„„ƒƒƒƒ„„………………††……„„„„ƒƒ„„„„…………††……††……††††……††„„…………‡‡ˆˆ……��ƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚ƒƒ„„……………………„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„„„……††……………………„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚������€€€€��€€€€€€€€������ƒƒ„„„„„„ƒƒ„„„„„„„„……………………„„„„„„…………††………………††††……††……„„……††ˆˆˆˆ��ƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚ƒƒ„„……………………„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„„„……††……………………„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚������€€€€��€€€€€€€€������ƒƒ„„„„„„ƒƒ„„„„„„„„……………………„„„„„„…………††………………††††……††……„„……††ˆˆˆˆ��‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒ„„………………††††„„ƒƒƒƒƒƒ„„„„„„„„„„„„…………††…………………………„„„„„„ƒƒƒƒƒƒ‚‚������������������€€€€��€€��€€��€€‚‚„„……ƒƒ„„„„„„……„„……††……„„……„„„„………………††……††††††……††……„„††‡‡††��‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒ„„………………††††„„ƒƒƒƒƒƒ„„„„„„„„„„„„…………††…………………………„„„„„„ƒƒƒƒƒƒ‚‚������������������€€€€��€€��€€��€€‚‚„„……ƒƒ„„„„„„……„„……††……„„……„„„„………………††……††††††……††……„„††‡‡††€€����‚‚ƒƒ„„………………………………„„††……ƒƒƒƒƒƒ„„……„„„„……………………………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚��€€��€€€€������������������€€������€€€€‚‚„„„„„„„„„„„„…………††††…………„„„„„„…………††††††††††…………††…………††††€€����‚‚ƒƒ„„………………………………„„††……ƒƒƒƒƒƒ„„……„„„„……………………………………„„„„„„„„ƒƒƒƒƒƒ‚‚‚‚��€€��€€€€������������������€€������€€€€‚‚„„„„„„„„„„„„…………††††…………„„„„„„…………††††††††††…………††…………††††€€��ƒƒƒƒ……††…………„„…………„„…………„„ƒƒƒƒƒƒ„„………………††……………………„„„„ƒƒƒƒ„„ƒƒƒƒƒƒ‚‚����€€€€������€€����€€������������€€��€€��€€��‚‚„„„„ƒƒƒƒ„„„„……††††††…………„„„„………………††††……††………………††………………€€��ƒƒƒƒ……††…………„„…………„„…………„„ƒƒƒƒƒƒ„„………………††……………………„„„„ƒƒƒƒ„„ƒƒƒƒƒƒ‚‚����€€€€������€€����€€������������€€��€€��€€��‚‚„„„„ƒƒƒƒ„„„„……††††††…………„„„„………………††††……††………………††………………��ƒƒ„„„„…………………………„„„„„„…………„„ƒƒƒƒ„„…………††…………„„„„„„„„„„„„ƒƒ„„„„ƒƒ‚‚‚‚��€€��€€��€€€€������€€€€��€€��€€����€€€€��€€€€€€€€ƒƒ„„„„„„„„„„„„……††††††………………………………††††††………………„„……††…………��ƒƒ„„„„…………………………„„„„„„…………„„ƒƒƒƒ„„…………††…………„„„„„„„„„„„„ƒƒ„„„„ƒƒ‚‚‚‚��€€��€€��€€€€������€€€€��€€��€€����€€€€��€€€€€€€€ƒƒ„„„„„„„„„„„„……††††††………………………………††††††………………„„……††…………��ƒƒƒƒ„„…………„„„„„„„„„„„„……„„ƒƒƒƒ„„……††………………„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒ‚‚��������€€����€€€€��������€€€€€€������€€€€��€€€€€€€€‚‚„„„„„„„„„„„„……††††††††………………„„„„……††††††……††……„„……††……��ƒƒƒƒ„„…………„„„„„„„„„„„„……„„ƒƒƒƒ„„……††………………„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒ‚‚��������€€����€€€€��������€€€€€€������€€€€��€€€€€€€€‚‚„„„„„„„„„„„„……††††††††………………„„„„……††††††……††……„„……††……€€��„„…………„„„„„„„„ƒƒ„„„„„„„„„„……………………„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚��������€€€€€€€€€€€€��������€€€€€€������€€€€€€€€€€€€€€��ƒƒƒƒ„„……„„„„…………††……††††…………„„„„„„……………………††…………„„††††€€��„„…………„„„„„„„„ƒƒ„„„„„„„„„„……………………„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚��������€€€€€€€€€€€€��������€€€€€€������€€€€€€€€€€€€€€��ƒƒƒƒ„„……„„„„…………††……††††…………„„„„„„……………………††…………„„††††€€‚‚„„……„„ƒƒ„„„„„„„„„„……††……………………„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚������€€€€����€€��€€€€€€����€€€€€€��€€€€€€��€€€€€€€€€€€€€€ƒƒ„„„„„„„„„„„„……††††……††††……„„„„„„………………††…………………………††€€‚‚„„……„„ƒƒ„„„„„„„„„„……††……………………„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚������€€€€����€€��€€€€€€����€€€€€€��€€€€€€��€€€€€€€€€€€€€€ƒƒ„„„„„„„„„„„„……††††……††††……„„„„„„………………††…………………………††€€‚‚„„„„ƒƒƒƒƒƒ„„ƒƒ„„…………††……„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒ„„ƒƒƒƒ‚‚‚‚ƒƒ‚‚��€€��€€€€��€€€€€€€€€€€€������€€€€����€€������€€€€€€€€€€€€€€��ƒƒƒƒƒƒ„„„„„„……††††……††……††……„„„„„„„„…………††…………………………€€‚‚„„„„ƒƒƒƒƒƒ„„ƒƒ„„…………††……„„„„ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒ„„ƒƒƒƒ‚‚‚‚ƒƒ‚‚��€€��€€€€��€€€€€€€€€€€€������€€€€����€€������€€€€€€€€€€€€€€��ƒƒƒƒƒƒ„„„„„„……††††……††……††……„„„„„„„„…………††…………………………€€ƒƒ……„„ƒƒƒƒ„„…………………………„„ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚��€€€€€€€€€€��€€��€€€€€€€€��€€��€€€€€€��€€������€€€€€€€€€€€€€€€€‚‚„„„„„„„„„„…………††††…………††††……„„„„ƒƒ„„„„……………………††„„€€ƒƒ……„„ƒƒƒƒ„„…………………………„„ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚‚��€€€€€€€€€€��€€��€€€€€€€€��€€��€€€€€€��€€������€€€€€€€€€€€€€€€€‚‚„„„„„„„„„„…………††††…………††††……„„„„ƒƒ„„„„……………………††„„€€„„„„ƒƒƒƒ„„…………………………„„‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚€€€€€€€€€€€€€€€€€€€€��€€€€������€€����€€€€������€€€€��€€€€€€€€€€��„„ƒƒ„„„„„„……………………††……††‡‡††……„„„„ƒƒ„„„„…………………………€€„„„„ƒƒƒƒ„„…………………………„„‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚€€€€€€€€€€€€€€€€€€€€��€€€€������€€����€€€€������€€€€��€€€€€€€€€€��„„ƒƒ„„„„„„……………………††……††‡‡††……„„„„ƒƒ„„„„…………………………��……„„„„…………††……„„ƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒ‚‚ƒƒ‚‚ƒƒƒƒ‚‚€€€€€€€€��€€€€€€€€€€��€€������€€€€����€€��������€€€€��€€€€€€€€€€ƒƒ„„„„ƒƒ„„………………„„……„„††‡‡‡‡††……„„„„ƒƒƒƒ„„……††††……��……„„„„…………††……„„ƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒ‚‚ƒƒ‚‚ƒƒƒƒ‚‚€€€€€€€€��€€€€€€€€€€��€€������€€€€����€€��������€€€€��€€€€€€€€€€ƒƒ„„„„ƒƒ„„………………„„……„„††‡‡‡‡††……„„„„ƒƒƒƒ„„……††††……‚‚……………………„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚ƒƒ„„ƒƒ��€€€€€€€€��€€€€€€€€€€��€€��€€€€€€€€€€����€€€€€€€€€€��€€€€€€€€€€€€€€‚‚„„„„„„„„„„…………„„„„„„……‡‡‡‡‡‡‡‡……„„ƒƒ‚‚ƒƒ„„††††„„‚‚……………………„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚ƒƒ„„ƒƒ��€€€€€€€€��€€€€€€€€€€��€€��€€€€€€€€€€����€€€€€€€€€€��€€€€€€€€€€€€€€‚‚„„„„„„„„„„…………„„„„„„……‡‡‡‡‡‡‡‡……„„ƒƒ‚‚ƒƒ„„††††„„‚‚…………„„ƒƒ‚‚‚‚ƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„��€€€€€€€€€€€€€€��€€€€€€��€€€€��€€��������������€€€€€€��€€€€€€€€€€€€��„„„„„„„„„„„„„„„„„„ƒƒ„„††††‡‡‡‡…………„„ƒƒ‚‚ƒƒ……††††‚‚…………„„ƒƒ‚‚‚‚ƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„��€€€€€€€€€€€€€€��€€€€€€��€€€€��€€��������������€€€€€€��€€€€€€€€€€€€��„„„„„„„„„„„„„„„„„„ƒƒ„„††††‡‡‡‡…………„„ƒƒ‚‚ƒƒ……††††‚‚„„ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„……„„„„„„„„‚‚€€€€€€€€€€€€��€€€€€€€€����������������€€����€€��€€€€€€����€€€€€€€€ƒƒ„„……„„ƒƒ„„„„„„„„„„„„……††††††††††„„ƒƒƒƒ„„„„…………‚‚„„ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„……„„„„„„„„‚‚€€€€€€€€€€€€��€€€€€€€€����������������€€����€€��€€€€€€����€€€€€€€€ƒƒ„„……„„ƒƒ„„„„„„„„„„„„……††††††††††„„ƒƒƒƒ„„„„…………����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒ„„„„„„„„„„„„ƒƒƒƒ��€€€€€€€€€€€€€€��€€€€€€€€€€��€€€€������€€€€€€��€€��€€€€€€����€€€€€€€€‚‚„„„„„„„„ƒƒ„„„„„„„„………………………………††††„„ƒƒƒƒ„„……„„����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚ƒƒƒƒ„„„„„„„„„„„„ƒƒƒƒ��€€€€€€€€€€€€€€��€€€€€€€€€€��€€€€������€€€€€€��€€��€€€€€€����€€€€€€€€‚‚„„„„„„„„ƒƒ„„„„„„„„………………………………††††„„ƒƒƒƒ„„……„„����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„„„„„„„„„„„ƒƒ‚‚‚‚€€€€€€€€€€€€€€��€€€€€€€€€€€€������������‚‚‚‚ƒƒ‚‚ƒƒ‚‚‚‚����€€€€��€€€€��„„ƒƒ„„„„„„ƒƒ„„ƒƒ„„……„„„„……„„„„††‡‡††„„„„„„„„„„����‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„„„„„„„„„„„ƒƒ‚‚‚‚€€€€€€€€€€€€€€��€€€€€€€€€€€€������������‚‚‚‚ƒƒ‚‚ƒƒ‚‚‚‚����€€€€��€€€€��„„ƒƒ„„„„„„ƒƒ„„ƒƒ„„……„„„„……„„„„††‡‡††„„„„„„„„„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚„„„„„„„„„„„„„„„„ƒƒƒƒ‚‚‚‚‚‚��€€€€€€€€€€€€€€€€€€€€€€€€€€€€����‚‚ƒƒ…………††‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ‡‡‡‡††††……ƒƒƒƒ��€€��„„„„„„„„„„„„„„ƒƒƒƒ„„„„„„††……ƒƒ……††††††„„„„„„ƒƒ€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚„„„„„„„„„„„„„„„„ƒƒƒƒ‚‚‚‚‚‚��€€€€€€€€€€€€€€€€€€€€€€€€€€€€����‚‚ƒƒ…………††‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ‡‡‡‡††††……ƒƒƒƒ��€€��„„„„„„„„„„„„„„ƒƒƒƒ„„„„„„††……ƒƒ……††††††„„„„„„ƒƒ€€��‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„……„„„„„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚��€€€€€€€€€€€€€€€€€€€€����‚‚ƒƒ……‡‡ˆˆ‰‰‹‹ŒŒ��������ŽŽŽŽ��������‹‹ŠŠ‰‰ˆˆˆˆ‡‡‡‡††…………„„„„„„„„„„ƒƒƒƒ„„„„„„††……„„……††††††…………„„ƒƒ€€��‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„……„„„„„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚��€€€€€€€€€€€€€€€€€€€€����‚‚ƒƒ……‡‡ˆˆ‰‰‹‹ŒŒ��������ŽŽŽŽ��������‹‹ŠŠ‰‰ˆˆˆˆ‡‡‡‡††…………„„„„„„„„„„ƒƒƒƒ„„„„„„††……„„……††††††…………„„ƒƒ€€��‚‚��‚‚‚‚ƒƒƒƒ„„…………„„„„††……„„„„ƒƒ‚‚��‚‚����‚‚‚‚����€€€€€€€€€€��€€��‚‚‚‚„„††ŠŠŒŒŒŒ��ŽŽ����‘‘������ŽŽŽŽ������ŽŽŽŽŒŒŒŒŽŽŽŽ��ŒŒŒŒŠŠ‰‰‰‰ˆˆ††††……ƒƒƒƒƒƒ„„„„„„……„„ƒƒ„„……††……††……„„„„€€��‚‚��‚‚‚‚ƒƒƒƒ„„…………„„„„††……„„„„ƒƒ‚‚��‚‚����‚‚‚‚����€€€€€€€€€€��€€��‚‚‚‚„„††ŠŠŒŒŒŒ��ŽŽ����‘‘������ŽŽŽŽ������ŽŽŽŽŒŒŒŒŽŽŽŽ��ŒŒŒŒŠŠ‰‰‰‰ˆˆ††††……ƒƒƒƒƒƒ„„„„„„……„„ƒƒ„„……††……††……„„„„€€��‚‚‚‚ƒƒ„„„„…………„„„„„„„„„„‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€����‚‚ƒƒ„„‡‡ŠŠŽŽ‘‘““’’’’‘‘‘‘����������ŽŽ������ŽŽŽŽŽŽŽŽ��ŒŒŽŽ��’’‘‘��‹‹ŠŠ‰‰‰‰‰‰‰‰ˆˆ‡‡††……„„„„„„„„„„ƒƒ„„……………………††††……€€��‚‚‚‚ƒƒ„„„„…………„„„„„„„„„„‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€����‚‚ƒƒ„„‡‡ŠŠŽŽ‘‘““’’’’‘‘‘‘����������ŽŽ������ŽŽŽŽŽŽŽŽ��ŒŒŽŽ��’’‘‘��‹‹ŠŠ‰‰‰‰‰‰‰‰ˆˆ‡‡††……„„„„„„„„„„ƒƒ„„……………………††††……€€‚‚ƒƒ„„„„……„„„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚��‚‚��‚‚‚‚‚‚‚‚��€€��‚‚‚‚ƒƒ„„††‰‰��ŽŽ��’’““““’’����������‘‘‘‘‘‘‘‘’’’’’’““““’’““““‘‘ŽŽŽŽ��’’��ŒŒŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ„„ƒƒƒƒ„„„„„„„„…………………………‡‡††€€‚‚ƒƒ„„„„……„„„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚��‚‚��‚‚‚‚‚‚‚‚��€€��‚‚‚‚ƒƒ„„††‰‰��ŽŽ��’’““““’’����������‘‘‘‘‘‘‘‘’’’’’’““““’’““““‘‘ŽŽŽŽ��’’��ŒŒŠŠŠŠ‰‰‰‰‰‰ˆˆˆˆˆˆˆˆ„„ƒƒƒƒ„„„„„„„„…………………………‡‡††��ƒƒƒƒƒƒ„„„„„„ƒƒ‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��‚‚��‚‚ƒƒƒƒ„„‡‡‹‹ŽŽ‘‘’’��ŽŽ‘‘‘‘����ŽŽŽŽ��������������‘‘‘‘‘‘’’““““””””““’’‘‘‘‘’’‘‘‹‹‰‰ŠŠ‰‰‰‰ˆˆˆˆˆˆˆˆ††ƒƒ‚‚‚‚ƒƒ„„ƒƒ„„…………„„„„……‡‡††��ƒƒƒƒƒƒ„„„„„„ƒƒ‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚��‚‚��‚‚ƒƒƒƒ„„‡‡‹‹ŽŽ‘‘’’��ŽŽ‘‘‘‘����ŽŽŽŽ��������������‘‘‘‘‘‘’’““““””””““’’‘‘‘‘’’‘‘‹‹‰‰ŠŠ‰‰‰‰ˆˆˆˆˆˆˆˆ††ƒƒ‚‚‚‚ƒƒ„„ƒƒ„„…………„„„„……‡‡††��„„ƒƒƒƒƒƒ‚‚‚‚������‚‚������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚����‚‚ƒƒ„„††‰‰ŽŽ‘‘’’’’’’��ŒŒ��ŽŽ��ŽŽ������ŽŽ����������ŽŽ������‘‘’’““““’’’’’’’’����ŒŒŠŠŠŠ‰‰ˆˆˆˆˆˆ‡‡††„„„„ƒƒƒƒƒƒƒƒƒƒ„„„„……„„ƒƒ„„††……��„„ƒƒƒƒƒƒ‚‚‚‚������‚‚������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚����‚‚ƒƒ„„††‰‰ŽŽ‘‘’’’’’’��ŒŒ��ŽŽ��ŽŽ������ŽŽ����������ŽŽ������‘‘’’““““’’’’’’’’����ŒŒŠŠŠŠ‰‰ˆˆˆˆˆˆ‡‡††„„„„ƒƒƒƒƒƒƒƒƒƒ„„„„……„„ƒƒ„„††……��ƒƒ‚‚��������‚‚‚‚��������‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„……‡‡ˆˆ��‘‘’’’’‘‘��ŽŽ‹‹ŒŒŽŽŽŽŽŽ��ŽŽ����ŒŒ‹‹ŠŠ‹‹‹‹ŒŒ��������‘‘’’’’‘‘‘‘’’������ŒŒŠŠŠŠˆˆ‰‰ˆˆ††……„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„„„„„ƒƒƒƒ„„……��ƒƒ‚‚��������‚‚‚‚��������‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„……‡‡ˆˆ��‘‘’’’’‘‘��ŽŽ‹‹ŒŒŽŽŽŽŽŽ��ŽŽ����ŒŒ‹‹ŠŠ‹‹‹‹ŒŒ��������‘‘’’’’‘‘‘‘’’������ŒŒŠŠŠŠˆˆ‰‰ˆˆ††……„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„„„„„ƒƒƒƒ„„……��������‚‚����‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††ˆˆˆˆŠŠ����‘‘��ŽŽŒŒŒŒ��ŽŽ��ŽŽŽŽŽŽ��������ŒŒŒŒŒŒ‹‹‹‹ŒŒ����������‘‘‘‘‘‘����ŽŽ��‹‹ŠŠŠŠŠŠˆˆ††……„„„„„„„„„„„„ƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒ„„„„��������‚‚����‚‚‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††ˆˆˆˆŠŠ����‘‘��ŽŽŒŒŒŒ��ŽŽ��ŽŽŽŽŽŽ��������ŒŒŒŒŒŒ‹‹‹‹ŒŒ����������‘‘‘‘‘‘����ŽŽ��‹‹ŠŠŠŠŠŠˆˆ††……„„„„„„„„„„„„ƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒ„„„„€€��‚‚��‚‚����‚‚‚‚‚‚��‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††ˆˆˆˆŠŠŽŽ������ŒŒ‰‰‹‹��ŽŽŽŽ��ŽŽŽŽ������ŽŽŽŽŽŽŽŽŽŽ��ŒŒŒŒŒŒŒŒŽŽ������‘‘����ŽŽŒŒ‹‹ŠŠŠŠˆˆ‡‡„„„„„„ƒƒ„„„„„„„„„„ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„€€��‚‚��‚‚����‚‚‚‚‚‚��‚‚‚‚‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„††ˆˆˆˆŠŠŽŽ������ŒŒ‰‰‹‹��ŽŽŽŽ��ŽŽŽŽ������ŽŽŽŽŽŽŽŽŽŽ��ŒŒŒŒŒŒŒŒŽŽ������‘‘����ŽŽŒŒ‹‹ŠŠŠŠˆˆ‡‡„„„„„„ƒƒ„„„„„„„„„„ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„€€��‚‚��‚‚����‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚����‚‚‚‚��‚‚‚‚„„‡‡ˆˆˆˆŒŒŽŽŽŽŒŒŠŠ‡‡ˆˆŒŒ��ŽŽŽŽŽŽ������ŒŒ����������ŽŽŽŽ��ŒŒ��ŒŒŒŒ����������ŽŽŒŒ‹‹ŠŠ‰‰‡‡„„ƒƒƒƒƒƒ„„ƒƒ„„„„„„ƒƒ„„ƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„ƒƒ€€��‚‚��‚‚����‚‚‚‚��‚‚‚‚‚‚‚‚‚‚‚‚����‚‚‚‚��‚‚‚‚„„‡‡ˆˆˆˆŒŒŽŽŽŽŒŒŠŠ‡‡ˆˆŒŒ��ŽŽŽŽŽŽ������ŒŒ����������ŽŽŽŽ��ŒŒ��ŒŒŒŒ����������ŽŽŒŒ‹‹ŠŠ‰‰‡‡„„ƒƒƒƒƒƒ„„ƒƒ„„„„„„ƒƒ„„ƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„ƒƒ€€��‚‚��������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ……‡‡‡‡‡‡‹‹ŒŒ‹‹ˆˆˆˆ‡‡‰‰ŒŒŒŒ��ŽŽŽŽ��ŒŒ����ŽŽ��������������ŽŽ����ŽŽ��������ŽŽŒŒ‹‹‹‹‹‹ˆˆ„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„…………„„ƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„„„€€��‚‚��������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ……‡‡‡‡‡‡‹‹ŒŒ‹‹ˆˆˆˆ‡‡‰‰ŒŒŒŒ��ŽŽŽŽ��ŒŒ����ŽŽ��������������ŽŽ����ŽŽ��������ŽŽŒŒ‹‹‹‹‹‹ˆˆ„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„…………„„ƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„„„€€����‚‚‚‚‚‚��‚‚‚‚‚‚����‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒƒƒ„„ƒƒ……‡‡‡‡††‰‰‹‹ŠŠˆˆ‡‡ˆˆ‰‰‹‹������ŒŒŒŒ����ŽŽ������������ŽŽŽŽ������ŽŽŽŽ��������ŒŒŽŽ����ˆˆ„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„……„„„„ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„€€����‚‚‚‚‚‚��‚‚‚‚‚‚����‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒƒƒ„„ƒƒ……‡‡‡‡††‰‰‹‹ŠŠˆˆ‡‡ˆˆ‰‰‹‹������ŒŒŒŒ����ŽŽ������������ŽŽŽŽ������ŽŽŽŽ��������ŒŒŽŽ����ˆˆ„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„……„„„„ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„„„ƒƒƒƒ„„ƒƒ„„……‡‡††††ˆˆ‰‰‡‡‡‡ˆˆŠŠ‹‹��ŽŽ����ŒŒ��ŽŽ����������ŒŒ‰‰‰‰‹‹ŽŽŽŽŒŒŒŒŽŽ����ŽŽ����������‰‰ƒƒ„„„„„„„„ƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒƒƒ„„„„„„„„„„„„„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„„„„„ƒƒƒƒ„„ƒƒ„„……‡‡††††ˆˆ‰‰‡‡‡‡ˆˆŠŠ‹‹��ŽŽ����ŒŒ��ŽŽ����������ŒŒ‰‰‰‰‹‹ŽŽŽŽŒŒŒŒŽŽ����ŽŽ����������‰‰ƒƒ„„„„„„„„ƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒƒƒ„„„„„„„„„„„„„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„ƒƒƒƒƒƒ„„„„ƒƒ„„„„„„„„„„……††ˆˆˆˆ‡‡‡‡ˆˆ‰‰‹‹ŒŒŽŽ��������ŽŽ������ŽŽ��ŒŒ‰‰ˆˆŠŠ����‹‹ŒŒ����‘‘������ŽŽŽŽ��ŠŠ„„ƒƒƒƒ„„„„ƒƒ‚‚ƒƒ„„ƒƒ„„„„„„ƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ„„„„€€������‚‚‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒƒ„„„„ƒƒƒƒƒƒ„„„„ƒƒ„„„„„„„„„„……††ˆˆˆˆ‡‡‡‡ˆˆ‰‰‹‹ŒŒŽŽ��������ŽŽ������ŽŽ��ŒŒ‰‰ˆˆŠŠ����‹‹ŒŒ����‘‘������ŽŽŽŽ��ŠŠ„„ƒƒƒƒ„„„„ƒƒ‚‚ƒƒ„„ƒƒ„„„„„„ƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒ„„„„€€��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„……‰‰����ŒŒ‰‰‰‰ŠŠ‹‹ŒŒ��������ŽŽ����ŽŽŽŽŽŽ������ŽŽŽŽ��������‘‘‘‘’’����‹‹‰‰‹‹ŽŽˆˆƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ€€��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„……‰‰����ŒŒ‰‰‰‰ŠŠ‹‹ŒŒ��������ŽŽ����ŽŽŽŽŽŽ������ŽŽŽŽ��������‘‘‘‘’’����‹‹‰‰‹‹ŽŽˆˆƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ€€��‚‚‚‚ƒƒ„„„„„„ƒƒƒƒ„„ƒƒ„„„„„„„„…………„„„„……„„„„„„„„„„††‘‘––’’����‹‹ŒŒŒŒ��ŽŽŽŽŽŽ��������������������������ŽŽ��‘‘‘‘‘‘‘‘‘‘ŽŽ��ŠŠ‹‹‹‹††„„„„„„„„„„ƒƒ„„ƒƒƒƒƒƒ„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ€€��‚‚‚‚ƒƒ„„„„„„ƒƒƒƒ„„ƒƒ„„„„„„„„…………„„„„……„„„„„„„„„„††‘‘––’’����‹‹ŒŒŒŒ��ŽŽŽŽŽŽ��������������������������ŽŽ��‘‘‘‘‘‘‘‘‘‘ŽŽ��ŠŠ‹‹‹‹††„„„„„„„„„„ƒƒ„„ƒƒƒƒƒƒ„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ��‚‚ƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„„„…………„„„„„„……„„„„„„ƒƒˆˆ––••����ŽŽŒŒ‹‹ŒŒ������������’’‘‘‘‘‘‘‘‘����������������‘‘��‘‘‘‘’’������ŠŠ‰‰„„„„„„„„„„ƒƒƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ„„��‚‚ƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„„„…………„„„„„„……„„„„„„ƒƒˆˆ––••����ŽŽŒŒ‹‹ŒŒ������������’’‘‘‘‘‘‘‘‘����������������‘‘��‘‘‘‘’’������ŠŠ‰‰„„„„„„„„„„ƒƒƒƒƒƒ„„ƒƒƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒ„„��‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„……„„ƒƒ‰‰––””��������‹‹‹‹ŽŽ��������‘‘’’’’““““’’’’‘‘‘‘‘‘����‘‘‘‘‘‘‘‘’’““““‘‘����‹‹‡‡ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ��‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚ƒƒ„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„……„„ƒƒ‰‰––””��������‹‹‹‹ŽŽ��������‘‘’’’’““““’’’’‘‘‘‘‘‘����‘‘‘‘‘‘‘‘’’““““‘‘����‹‹‡‡ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒ€€‚‚‚‚‚‚��������‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„ƒƒ‰‰••””‘‘����ŽŽ‹‹‹‹����������‘‘’’““““””““““““’’’’‘‘‘‘’’’’‘‘‘‘’’””••””������ˆˆƒƒƒƒ„„ƒƒ„„ƒƒƒƒƒƒ„„ƒƒ‚‚ƒƒƒƒ‚‚‚‚ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ‚‚€€‚‚‚‚‚‚��������‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„„„„„„„„„ƒƒ‰‰••””‘‘����ŽŽ‹‹‹‹����������‘‘’’““““””““““““’’’’‘‘‘‘’’’’‘‘‘‘’’””••””������ˆˆƒƒƒƒ„„ƒƒ„„ƒƒƒƒƒƒ„„ƒƒ‚‚ƒƒƒƒ‚‚‚‚ƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ‚‚€€€€€€€€€€������‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„ƒƒˆˆ““””““““’’ŽŽ‹‹ŠŠŒŒŽŽ����‘‘““••••••••””““““““’’’’’’““’’‘‘’’““••——˜˜””ŽŽ��‰‰„„„„ƒƒ„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„„ƒƒƒƒ„„„„ƒƒƒƒƒƒ€€€€€€€€€€������‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„„„ƒƒˆˆ““””““““’’ŽŽ‹‹ŠŠŒŒŽŽ����‘‘““••••••••””““““““’’’’’’““’’‘‘’’““••——˜˜””ŽŽ��‰‰„„„„ƒƒ„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„„ƒƒƒƒ„„„„ƒƒƒƒƒƒ€€€€€€����‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„„„„„„„††��””””••‘‘����ŠŠ‹‹��ŽŽ��““••––————––••””““““““’’’’‘‘’’““““””——™™šš——��ŽŽŠŠ„„ƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ‚‚‚‚ƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒ€€€€€€����‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„„„‚‚‚‚‚‚‚‚ƒƒ„„„„„„„„„„„„„„††��””””••‘‘����ŠŠ‹‹��ŽŽ��““••––————––••””““““““’’’’‘‘’’““““””——™™šš——��ŽŽŠŠ„„ƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ‚‚‚‚ƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒ€€€€€€����‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒ„„ƒƒ��‚‚����‚‚ƒƒ„„……„„„„…………ŒŒ““••““��‘‘ŽŽ‹‹‹‹ŒŒ����““””––––————––””””““““’’’’’’””••••––˜˜šš››——��ŽŽŒŒ……ƒƒ„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚ƒƒƒƒ„„ƒƒƒƒƒƒ€€€€€€����‚‚‚‚‚‚‚‚ƒƒƒƒ„„ƒƒ„„ƒƒ��‚‚����‚‚ƒƒ„„……„„„„…………ŒŒ““••““��‘‘ŽŽ‹‹‹‹ŒŒ����““””––––————––””””““““’’’’’’””••••––˜˜šš››——��ŽŽŒŒ……ƒƒ„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚ƒƒƒƒ„„ƒƒƒƒƒƒ€€€€������‚‚��‚‚��‚‚ƒƒ„„„„……„„����‚‚������ƒƒ„„„„„„„„……‰‰��••’’’’’’ŽŽ‹‹ŠŠ‹‹ŒŒŽŽ‘‘““””””••––——””““’’’’’’’’““––““‘‘’’’’••——””����ŒŒ††ƒƒƒƒ„„„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„„„„„„„„ƒƒ€€€€������‚‚��‚‚��‚‚ƒƒ„„„„……„„����‚‚������ƒƒ„„„„„„„„……‰‰��••’’’’’’ŽŽ‹‹ŠŠ‹‹ŒŒŽŽ‘‘““””””••––——””““’’’’’’’’““––““‘‘’’’’••——””����ŒŒ††ƒƒƒƒ„„„„„„ƒƒƒƒƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒ„„„„„„„„ƒƒ€€��������‚‚ƒƒ‚‚‚‚‚‚ƒƒ„„„„„„„„ƒƒ����‚‚ƒƒ‚‚‚‚‚‚ƒƒ„„„„……††ŒŒ””’’““““��ŒŒŠŠ‹‹ŒŒŒŒ��‘‘’’’’““””””““‘‘‘‘’’““’’””––””������‘‘‘‘������ŒŒ‡‡……„„ƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„…………„„€€��������‚‚ƒƒ‚‚‚‚‚‚ƒƒ„„„„„„„„ƒƒ����‚‚ƒƒ‚‚‚‚‚‚ƒƒ„„„„……††ŒŒ””’’““““��ŒŒŠŠ‹‹ŒŒŒŒ��‘‘’’’’““””””““‘‘‘‘’’““’’””––””������‘‘‘‘������ŒŒ‡‡……„„ƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„…………„„€€€€��������‚‚‚‚ƒƒ‚‚ƒƒƒƒ„„„„„„„„‚‚€€��‚‚‚‚ƒƒ‚‚��ƒƒ„„…………ˆˆ��’’””””’’��ŠŠ‹‹ŒŒŒŒŽŽ������’’’’‘‘‘‘‘‘‘‘‘‘’’‘‘’’’’““’’������ŽŽŒŒ����‹‹††……††……ƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„€€€€��������‚‚‚‚ƒƒ‚‚ƒƒƒƒ„„„„„„„„‚‚€€��‚‚‚‚ƒƒ‚‚��ƒƒ„„…………ˆˆ��’’””””’’��ŠŠ‹‹ŒŒŒŒŽŽ������’’’’‘‘‘‘‘‘‘‘‘‘’’‘‘’’’’““’’������ŽŽŒŒ����‹‹††……††……ƒƒ„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„€€€€€€€€€€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒ„„ƒƒ����‚‚��ƒƒ„„ƒƒ‚‚ƒƒ……††‡‡ŠŠ‘‘””••””��ŠŠ‹‹ŒŒ������ŽŽ����������‘‘‘‘‘‘‘‘‘‘‘‘��ŽŽŽŽŽŽ��ŽŽŠŠ‰‰��ŽŽŠŠ††……………………„„„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚ƒƒ‚‚‚‚ƒƒ€€€€€€€€€€��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒ„„ƒƒ����‚‚��ƒƒ„„ƒƒ‚‚ƒƒ……††‡‡ŠŠ‘‘””••””��ŠŠ‹‹ŒŒ������ŽŽ����������‘‘‘‘‘‘‘‘‘‘‘‘��ŽŽŽŽŽŽ��ŽŽŠŠ‰‰��ŽŽŠŠ††……………………„„„„„„„„„„„„„„„„ƒƒƒƒƒƒƒƒ„„ƒƒ‚‚ƒƒ‚‚‚‚ƒƒ€€€€������‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„‚‚��‚‚��‚‚ƒƒƒƒ„„……††‡‡‡‡‡‡ŒŒ““––––’’‹‹‹‹ŒŒ����������������’’““’’‘‘��������������ŒŒŒŒ‰‰ˆˆ‰‰‹‹‰‰††††…………††……„„„„„„„„„„„„……„„„„ƒƒƒƒ‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒ€€€€������‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„‚‚��‚‚��‚‚ƒƒƒƒ„„……††‡‡‡‡‡‡ŒŒ““––––’’‹‹‹‹ŒŒ����������������’’““’’‘‘��������������ŒŒŒŒ‰‰ˆˆ‰‰‹‹‰‰††††…………††……„„„„„„„„„„„„……„„„„ƒƒƒƒ‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒ€€€€������‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„��������‚‚ƒƒ„„††ˆˆ‰‰‰‰‰‰‰‰��““““��‹‹ŠŠ‹‹��ŽŽŽŽŽŽ����‘‘’’““””““��ŽŽ����������ŽŽ��ŒŒ‰‰ˆˆ‰‰‰‰‡‡……††††……††††…………ƒƒ„„„„„„„„„„„„„„„„‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ€€€€������‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„��������‚‚ƒƒ„„††ˆˆ‰‰‰‰‰‰‰‰��““““��‹‹ŠŠ‹‹��ŽŽŽŽŽŽ����‘‘’’““””““��ŽŽ����������ŽŽ��ŒŒ‰‰ˆˆ‰‰‰‰‡‡……††††……††††…………ƒƒ„„„„„„„„„„„„„„„„‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ€€€€������‚‚��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ��������‚‚„„††ˆˆ‰‰‹‹ŠŠˆˆˆˆ��ŽŽŽŽ‹‹‹‹‹‹������ŽŽ��‘‘’’““““’’‘‘ŽŽ��ŽŽŽŽ��’’’’’’��ŽŽŒŒ‰‰ŠŠˆˆ††…………††………………††………………ƒƒ„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ€€€€������‚‚��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ��������‚‚„„††ˆˆ‰‰‹‹ŠŠˆˆˆˆ��ŽŽŽŽ‹‹‹‹‹‹������ŽŽ��‘‘’’““““’’‘‘ŽŽ��ŽŽŽŽ��’’’’’’��ŽŽŒŒ‰‰ŠŠˆˆ††…………††………………††………………ƒƒ„„„„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ��€€����‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒ��€€����‚‚„„‡‡ˆˆŠŠŠŠŠŠ††……‹‹ŽŽ��ŒŒ‹‹‹‹����������‘‘””””““‘‘��ŽŽŽŽ��““””””••””’’��ŽŽŒŒ‹‹‰‰††…………………………††††††††††……„„„„ƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ��€€����‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒ��€€����‚‚„„‡‡ˆˆŠŠŠŠŠŠ††……‹‹ŽŽ��ŒŒ‹‹‹‹����������‘‘””””““‘‘��ŽŽŽŽ��““””””••””’’��ŽŽŒŒ‹‹‰‰††…………………………††††††††††……„„„„ƒƒ„„„„ƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒ€€€€����‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„‚‚������‚‚„„††ˆˆŠŠŠŠˆˆ††……‰‰ŽŽ����ŒŒŒŒ����‘‘����‘‘””••““����‘‘““––——————™™˜˜••‘‘����ŒŒˆˆ………………††…………††††††††††††……„„„„„„„„„„ƒƒƒƒƒƒ„„„„„„ƒƒ€€€€����‚‚��‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„‚‚������‚‚„„††ˆˆŠŠŠŠˆˆ††……‰‰ŽŽ����ŒŒŒŒ����‘‘����‘‘””••““����‘‘““––——————™™˜˜••‘‘����ŒŒˆˆ………………††…………††††††††††††……„„„„„„„„„„ƒƒƒƒƒƒ„„„„„„ƒƒ€€��‚‚‚‚‚‚‚‚��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒ„„„„„„ƒƒ‚‚��‚‚‚‚„„……‡‡ˆˆ‰‰ˆˆ‡‡‡‡ˆˆ����ŽŽ��������‘‘‘‘����““””““����““––™™ššššššœœ››˜˜““��ŒŒŽŽˆˆ……………………………………††††††††††††††……„„„„„„ƒƒƒƒƒƒ„„„„„„ƒƒ€€��‚‚‚‚‚‚‚‚��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒ„„ƒƒ„„„„„„ƒƒ‚‚��‚‚‚‚„„……‡‡ˆˆ‰‰ˆˆ‡‡‡‡ˆˆ����ŽŽ��������‘‘‘‘����““””““����““––™™ššššššœœ››˜˜““��ŒŒŽŽˆˆ……………………………………††††††††††††††……„„„„„„ƒƒƒƒƒƒ„„„„„„ƒƒ€€����‚‚��‚‚��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„‚‚��‚‚„„……††‡‡ˆˆˆˆˆˆˆˆˆˆ��‘‘��������ŽŽ��‘‘����’’““’’��’’••——˜˜˜˜˜˜™™šššš™™””��‹‹��‰‰……††††††††………………††††……††††††††……„„„„ƒƒƒƒƒƒ„„„„„„ƒƒ€€����‚‚��‚‚��‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„‚‚��‚‚„„……††‡‡ˆˆˆˆˆˆˆˆˆˆ��‘‘��������ŽŽ��‘‘����’’““’’��’’••——˜˜˜˜˜˜™™šššš™™””��‹‹��‰‰……††††††††………………††††……††††††††……„„„„ƒƒƒƒƒƒ„„„„„„ƒƒ€€€€������‚‚‚‚‚‚‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒ„„‚‚����‚‚„„…………††‡‡‰‰��““����‘‘‘‘‘‘��������‘‘‘‘’’’’““””••––••””’’‘‘’’’’’’’’��‹‹‹‹‹‹ˆˆ††††††††††……††……††††…………††††††††††„„„„ƒƒƒƒ„„„„„„ƒƒ€€€€������‚‚‚‚‚‚‚‚��‚‚ƒƒƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒ„„‚‚����‚‚„„…………††‡‡‰‰��““����‘‘‘‘‘‘��������‘‘‘‘’’’’““””••––••””’’‘‘’’’’’’’’��‹‹‹‹‹‹ˆˆ††††††††††……††……††††…………††††††††††„„„„ƒƒƒƒ„„„„„„ƒƒ€€€€������‚‚‚‚‚‚‚‚ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒ‚‚��‚‚ƒƒ„„……‡‡ˆˆˆˆ’’¥¥››‘‘””““’’’’����������‘‘‘‘““––˜˜˜˜••’’��ŽŽŽŽŽŽŽŽŽŽ��‹‹ŒŒŠŠ††††††††††††††††††††††††††……††††††††††……ƒƒ„„„„„„„„ƒƒ€€€€������‚‚‚‚‚‚‚‚ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒ„„„„ƒƒƒƒƒƒƒƒ‚‚��‚‚ƒƒ„„……‡‡ˆˆˆˆ’’¥¥››‘‘””““’’’’����������‘‘‘‘““––˜˜˜˜••’’��ŽŽŽŽŽŽŽŽŽŽ��‹‹ŒŒŠŠ††††††††††††††††††††††††††……††††††††††……ƒƒ„„„„„„„„ƒƒ€€����������‚‚‚‚‚‚ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚����‚‚ƒƒ…………††……••¬¬¥¥––––––””““““’’‘‘‘‘������’’––˜˜˜˜——””’’����������ŽŽŒŒŒŒ‰‰††††††††††††††……‡‡††††‡‡††††††‡‡††††††††……„„„„……„„„„€€����������‚‚‚‚‚‚ƒƒ‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚����‚‚ƒƒ…………††……••¬¬¥¥––––––””““““’’‘‘‘‘������’’––˜˜˜˜——””’’����������ŽŽŒŒŒŒ‰‰††††††††††††††……‡‡††††‡‡††††††‡‡††††††††……„„„„……„„„„€€��‚‚‚‚��‚‚‚‚‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ‚‚������‚‚‚‚ƒƒ„„––±±¬¬œœ––™™––””““’’’’’’������’’””——˜˜˜˜——––––––––””””’’��ŒŒ‰‰…………††††††††††††‡‡††‡‡‡‡††‡‡‡‡‡‡††††††††††……„„„„„„„„€€��‚‚‚‚��‚‚‚‚‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ‚‚������‚‚‚‚ƒƒ„„––±±¬¬œœ––™™––””““’’’’’’������’’””——˜˜˜˜——––––––––””””’’��ŒŒ‰‰…………††††††††††††‡‡††‡‡‡‡††‡‡‡‡‡‡††††††††††……„„„„„„„„€€��‚‚����‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„ƒƒ����������‚‚‚‚’’³³°°££™™™™˜˜——””““““““‘‘����‘‘‘‘““••——˜˜˜˜™™™™šš™™˜˜––��ŠŠˆˆ………………††††††††††††††‡‡‡‡‡‡‡‡‡‡††††††††††††††††……„„„„€€��‚‚����‚‚ƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒƒƒƒƒƒƒ„„ƒƒ����������‚‚‚‚’’³³°°££™™™™˜˜——””““““““‘‘����‘‘‘‘““••——˜˜˜˜™™™™šš™™˜˜––��ŠŠˆˆ………………††††††††††††††‡‡‡‡‡‡‡‡‡‡††††††††††††††††……„„„„������‚‚‚‚‚‚ƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒƒƒ„„„„„„„„‚‚��������‚‚��ŒŒ¯¯³³©©¡¡™™šš™™––””””””““‘‘��������‘‘””––——˜˜˜˜™™————––��‰‰‡‡††††……††††††††††††††‡‡††‡‡‡‡‡‡‡‡††‡‡††††††††‡‡‡‡††……������‚‚‚‚‚‚ƒƒ„„ƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒƒƒ„„„„„„„„‚‚��������‚‚��ŒŒ¯¯³³©©¡¡™™šš™™––””””””““‘‘��������‘‘””––——˜˜˜˜™™————––��‰‰‡‡††††……††††††††††††††‡‡††‡‡‡‡‡‡‡‡††‡‡††††††††‡‡‡‡††……������‚‚‚‚‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒ„„„„„„ƒƒ„„ƒƒ������������……¦¦´´ªª©©  šš™™˜˜••••––••““‘‘����������’’““••––––••••””��ˆˆ††††††††††††………………††††††††‡‡‡‡ˆˆ‡‡††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡������‚‚‚‚‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒ„„ƒƒ„„„„„„ƒƒ„„ƒƒ������������……¦¦´´ªª©©  šš™™˜˜••••––••““‘‘����������’’““••––––••••””��ˆˆ††††††††††††………………††††††††‡‡‡‡ˆˆ‡‡††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡������‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„„„„„ƒƒƒƒ„„„„ƒƒ��€€����€€��››²²««¨¨¨¨¢¢››˜˜——••————””’’‘‘��ŽŽŽŽŽŽ����’’““““’’““��‹‹‡‡……††‡‡††††††††††††††††……††‡‡‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡������‚‚ƒƒ‚‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ„„„„„„ƒƒƒƒ„„„„ƒƒ��€€����€€��››²²««¨¨¨¨¢¢››˜˜——••————””’’‘‘��ŽŽŽŽŽŽ����’’““““’’““��‹‹‡‡……††‡‡††††††††††††††††……††‡‡‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡€€����‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒ„„„„„„‚‚��������€€��ªª®®©©££§§¤¤™™˜˜––˜˜˜˜••““’’����ŽŽ��ŽŽŽŽ������������ŠŠ‡‡††††††‡‡††††††‡‡‡‡‡‡††††‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡€€����‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„„„ƒƒƒƒƒƒ„„„„„„‚‚��������€€��ªª®®©©££§§¤¤™™˜˜––˜˜˜˜••““’’����ŽŽ��ŽŽŽŽ������������ŠŠ‡‡††††††‡‡††††††‡‡‡‡‡‡††††‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡€€����‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„ƒƒ��€€����~~„„��­­ªª¤¤  ££��˜˜————˜˜––””““’’����ŽŽ��ŒŒ����ŽŽ��ŒŒŒŒ‘‘ŽŽ‡‡††††††††††‡‡‡‡‡‡‡‡‡‡‡‡††††††‡‡‡‡‡‡‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡€€����‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„ƒƒƒƒ„„„„„„ƒƒ��€€����~~„„��­­ªª¤¤  ££��˜˜————˜˜––””““’’����ŽŽ��ŒŒ����ŽŽ��ŒŒŒŒ‘‘ŽŽ‡‡††††††††††‡‡‡‡‡‡‡‡‡‡‡‡††††††‡‡‡‡‡‡‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡€€��‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚‚‚ƒƒƒƒƒƒ„„„„ƒƒ„„„„„„„„„„ƒƒƒƒ„„„„„„‚‚��€€€€||||‰‰  ©©¦¦¢¢ŸŸ  ››™™——––––••““’’‘‘������ŽŽ����������““¢¢¢¢‘‘‡‡††††††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆ‡‡ˆˆ‡‡‡‡€€��‚‚ƒƒƒƒƒƒ‚‚ƒƒƒƒ‚‚‚‚ƒƒƒƒƒƒ„„„„ƒƒ„„„„„„„„„„ƒƒƒƒ„„„„„„‚‚��€€€€||||‰‰  ©©¦¦¢¢ŸŸ  ››™™——––––••““’’‘‘������ŽŽ����������““¢¢¢¢‘‘‡‡††††††‡‡††††‡‡‡‡‡‡‡‡‡‡‡‡††‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆ‡‡ˆˆ‡‡‡‡€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„„„‚‚€€}}||{{||……™™¥¥££  ŸŸŸŸ™™™™˜˜””••””’’‘‘‘‘��������������’’ŸŸ¦¦ªª¦¦””‡‡††††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆ‡‡€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„„„„„ƒƒ„„„„ƒƒ„„„„„„„„„„„„„„„„‚‚€€}}||{{||……™™¥¥££  ŸŸŸŸ™™™™˜˜””••””’’‘‘‘‘��������������’’ŸŸ¦¦ªª¦¦””‡‡††††††‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆ‡‡‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆ‡‡€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒ„„„„„„„„……„„„„„„„„„„„„„„„„„„……‚‚}}{{{{{{{{||����œœ¡¡ŸŸ  œœ––™™––••””’’‘‘‘‘‘‘����‘‘��ŽŽŒŒ““  ¤¤©©¬¬§§””‡‡††††††‡‡‡‡††‡‡‡‡‡‡ˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆ‡‡€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚ƒƒƒƒƒƒ„„„„„„„„……„„„„„„„„„„„„„„„„„„……‚‚}}{{{{{{{{||����œœ¡¡ŸŸ  œœ––™™––••””’’‘‘‘‘‘‘����‘‘��ŽŽŒŒ““  ¤¤©©¬¬§§””‡‡††††††‡‡‡‡††‡‡‡‡‡‡ˆˆˆˆ‡‡‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆˆˆ‡‡€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„„„……„„„„„„……„„€€{{{{{{{{{{{{{{}}‡‡––ŸŸžžŸŸ˜˜••––––””’’‘‘‘‘‘‘‘‘��������‹‹‘‘žž¤¤ªª««¬¬££‹‹„„††††‡‡††††††‡‡‡‡‡‡ˆˆˆˆˆˆ‡‡‡‡ˆˆˆˆˆˆ‡‡ˆˆˆˆˆˆ‡‡€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ„„ƒƒ„„„„„„„„„„„„„„„„……„„„„„„……„„€€{{{{{{{{{{{{{{}}‡‡––ŸŸžžŸŸ˜˜••––––””’’‘‘‘‘‘‘‘‘��������‹‹‘‘žž¤¤ªª««¬¬££‹‹„„††††‡‡††††††‡‡‡‡‡‡ˆˆˆˆˆˆ‡‡‡‡ˆˆˆˆˆˆ‡‡ˆˆˆˆˆˆ‡‡€€‚‚ƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒƒƒ„„„„ƒƒ„„„„„„„„„„„„„„…………ƒƒƒƒƒƒ‚‚€€}}zz{{{{{{{{{{{{{{||‚‚��˜˜ŸŸ��••””””••””““’’‘‘‘‘��������ŒŒ��œœ¥¥ªªªª±±¬¬��‚‚ƒƒ……‡‡‡‡††‡‡††††‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ‰‰ˆˆ‰‰‰‰ˆˆ††††€€‚‚ƒƒƒƒƒƒ„„ƒƒ„„„„ƒƒƒƒ„„„„ƒƒ„„„„„„„„„„„„„„…………ƒƒƒƒƒƒ‚‚€€}}zz{{{{{{{{{{{{{{||‚‚��˜˜ŸŸ��••””””••””““’’‘‘‘‘��������ŒŒ��œœ¥¥ªªªª±±¬¬��‚‚ƒƒ……‡‡‡‡††‡‡††††‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ‰‰ˆˆ‰‰‰‰ˆˆ††††€€‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„ƒƒƒƒ„„„„„„……„„„„……ƒƒ‚‚‚‚€€~~||}}||zzzz{{{{{{zz{{zz{{{{}}ƒƒŒŒ••““’’““””““““’’‘‘������ŽŽŽŽ����™™¥¥©©°°¾¾°°��……„„„„„„……††‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ††‡‡ŒŒ““��„„||~~€€‚‚ƒƒƒƒƒƒƒƒ„„„„„„„„„„ƒƒƒƒ„„„„„„……„„„„……ƒƒ‚‚‚‚€€~~||}}||zzzz{{{{{{zz{{zz{{{{}}ƒƒŒŒ••““’’““””““““’’‘‘������ŽŽŽŽ����™™¥¥©©°°¾¾°°��……„„„„„„……††‡‡‡‡‡‡‡‡‡‡ˆˆˆˆˆˆˆˆ††‡‡ŒŒ““��„„||~~€€‚‚ƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„…………„„ƒƒ‚‚}}||||||||{{||||{{{{zz{{{{{{{{{{zz{{{{zz}}‚‚††ŠŠ��’’““’’������ŽŽ��������™™££®®½½ÁÁ¥¥ˆˆ††††††„„ƒƒƒƒƒƒ††††‡‡††ŒŒ””��‡‡€€��œœœœ��††ŠŠ‹‹€€‚‚ƒƒƒƒƒƒ„„„„„„„„„„„„„„„„„„„„…………„„ƒƒ‚‚}}||||||||{{||||{{{{zz{{{{{{{{{{zz{{{{zz}}‚‚††ŠŠ��’’““’’������ŽŽ��������™™££®®½½ÁÁ¥¥ˆˆ††††††„„ƒƒƒƒƒƒ††††‡‡††ŒŒ””��‡‡€€��œœœœ��††ŠŠ‹‹��ƒƒƒƒƒƒ„„…………„„„„„„……„„„„„„„„ƒƒ‚‚€€~~}}}}||||||||||{{||}}||{{{{{{{{||{{{{{{||||{{||}}}}}}~~ƒƒŠŠ����ŽŽŽŽŽŽ��‹‹‹‹ŒŒŽŽ——¡¡®®³³±±––‚‚………………††„„‚‚€€��‚‚††„„ŽŽ��’’‰‰ŒŒ˜˜��››˜˜ššœœ™™��ƒƒƒƒƒƒ„„…………„„„„„„……„„„„„„„„ƒƒ‚‚€€~~}}}}||||||||||{{||}}||{{{{{{{{||{{{{{{||||{{||}}}}}}~~ƒƒŠŠ����ŽŽŽŽŽŽ��‹‹‹‹ŒŒŽŽ——¡¡®®³³±±––‚‚………………††„„‚‚€€��‚‚††„„ŽŽ��’’‰‰ŒŒ˜˜��››˜˜ššœœ™™ \ No newline at end of file diff --git a/bin/q_matrix.cfg b/bin/q_matrix.cfg new file mode 100644 index 0000000..147b061 --- /dev/null +++ b/bin/q_matrix.cfg @@ -0,0 +1,118 @@ +# This is the configuration file for initialising the Q matrix. +# Altogether 6 matrix for 4x4 block and 2 matrix for 8x8 block +# The values range from 1 to 255 +# If first value of matrix is equal to 0, default values will be used for that matrix +#################################################################################### + +INTRA4X4_LUMA = +17,17,16,16, +17,16,15,15, +16,15,15,15, +16,15,15,15 + +INTRA4X4_CHROMAU = + 6,12,19,26, +12,19,26,31, +19,26,31,35, +26,31,35,39 + +INTRA4X4_CHROMAV = + 6,12,19,26, +12,19,26,31, +19,26,31,35, +26,31,35,40 + +INTER4X4_LUMA = +17,17,16,16, +17,16,15,15, +16,15,15,15, +16,15,15,14 + +INTER4X4_CHROMAU = + 9,13,18,21, +13,18,21,24, +18,21,24,27, +21,24,27,30 + +INTER4X4_CHROMAU = + 0,13,18,21, +13,18,21,24, +18,21,24,27, +21,24,27,30 + +INTER4X4_CHROMAV = + 9,13,18,21, +13,18,21,24, +18,21,24,27, +21,24,27,27 + +INTRA8X8_LUMA = +16,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 + + +INTER8X8_LUMA = +15,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 + +INTRA8X8_CHROMAU = +14,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 + +INTER8X8_CHROMAU = +13,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 + +INTER8X8_CHROMAU = + 0,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 + +INTRA8X8_CHROMAV = +12,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 + +INTER8X8_CHROMAV = +11,16,17,16,16,16,16,16, +16,17,16,16,16,15,15,15, +17,16,16,16,15,15,15,15, +16,16,16,15,15,15,15,15, +16,16,15,15,15,15,15,15, +16,15,15,15,15,15,15,16, +16,15,15,15,15,15,16,16, +16,15,15,15,15,16,16,16 diff --git a/bin/q_matrix2.cfg b/bin/q_matrix2.cfg new file mode 100644 index 0000000..3ab068c --- /dev/null +++ b/bin/q_matrix2.cfg @@ -0,0 +1,61 @@ +# This is the configuration file for initialising the Q matrix. +# Altogether 6 matrix for 4x4 block and 2 matrix for 8x8 block +# The values range from 1 to 255 +# If first value of matrix is equal to 0, default values will be used for that matrix +#################################################################################### + +INTRA4X4_LUMA = + 7,16,22,24, +16,22,24,28, +18,22,27,33, +22,24,32,47 + +INTRA4X4_CHROMAU = + 7,16,22,24, +16,22,24,28, +18,22,27,33, +22,24,32,47 + +INTRA4X4_CHROMAV = + 7,16,22,24, +16,22,24,28, +18,22,27,33, +22,24,32,47 + +INTER4X4_LUMA = +13,15,17,18, +15,17,18,20, +17,18,21,22, +18,20,22,25 + +INTER4X4_CHROMAU = +13,15,17,18, +15,17,18,20, +17,18,21,22, +18,20,22,25 + +INTER4X4_CHROMAV = +13,15,17,18, +15,17,18,20, +17,18,21,22, +18,20,22,25 + +INTRA8X8_LUMA = + 7,13,16,18,22,22,24,28, +13,13,18,20,22,24,28,31, +16,18,22,22,24,28,28,32, +18,18,22,22,24,28,31,33, +18,22,22,24,27,29,33,40, +22,22,24,27,29,33,40,48, +22,22,24,28,32,38,47,57, +22,24,29,32,38,47,57,69 + +INTER8X8_LUMA = +13,14,15,16,17,17,18,19, +14,15,16,17,17,18,19,20, +15,16,17,17,18,19,20,21, +16,17,17,18,19,20,21,22, +17,17,18,19,21,22,22,23, +17,18,19,20,22,22,23,25, +18,19,20,22,22,23,25,26, +19,20,21,22,23,25,26,27 diff --git a/bin/q_matrix_def.cfg b/bin/q_matrix_def.cfg new file mode 100644 index 0000000..046d2d2 --- /dev/null +++ b/bin/q_matrix_def.cfg @@ -0,0 +1,61 @@ +# This is the configuration file for initialising the Q matrix. +# Altogether 6 matrix for 4x4 block and 2 matrix for 8x8 block +# The values range from 1 to 255 +# If first value of matrix is equal to 0, default values will be used for that matrix +#################################################################################### + +INTRA4X4_LUMA = + 0,12,19,26, +12,19,26,31, +19,26,31,35, +26,31,35,39 + +INTRA4X4_CHROMAU = + 0,12,19,26, +12,19,26,31, +19,26,31,35, +26,31,35,39 + +INTRA4X4_CHROMAV = + 0,12,19,26, +12,19,26,31, +19,26,31,35, +26,31,35,39 + +INTER4X4_LUMA = + 0,13,18,21, +13,18,21,24, +18,21,24,27, +21,24,27,30 + +INTER4X4_CHROMAU = + 0,13,18,21, +13,18,21,24, +18,21,24,27, +21,24,27,30 + +INTER4X4_CHROMAV = + 0,13,18,21, +13,18,21,24, +18,21,24,27, +21,24,27,30 + +INTRA8X8_LUMA = + 0,10,13,16,19,24,26,28 +10,12,16,19,24,26,28,31 +13,16,19,24,26,28,31,33 +16,19,24,26,28,31,33,35 +19,24,26,28,31,33,35,37 +24,26,28,31,33,35,37,39 +26,28,31,33,35,37,39,42 +28,31,33,35,37,39,42,44 + +INTER8X8_LUMA = + 0,12,14,16,18,19,21,22, +12,13,16,18,19,21,22,24, +14,16,18,19,21,22,24,25, +16,18,19,21,22,24,25,27, +18,19,21,22,24,25,27,28, +19,21,22,24,25,27,28,30, +21,22,24,25,27,28,30,31, +22,24,25,27,28,30,31,33 diff --git a/bin/q_offset.cfg b/bin/q_offset.cfg new file mode 100644 index 0000000..ef46109 --- /dev/null +++ b/bin/q_offset.cfg @@ -0,0 +1,147 @@ +# This is the configuration file for initialising the Q Offset matrices. +# Altogether 6 matrix for 4x4 block and 2 matrix for 8x8 block +# The values can take any value, positive or negative and represent the numerator of +# a fractional offset which is in the form of value/2048 (extended from 1024) +# FOR THE 444 COMMON CASE, THE OFFSET MATRICES FOR LUMA WILL BE USED THE STARTING POINT +# FOR ALL THREE CHANNELS. +#################################################################################### + +INTRA4X4_LUMA_INTRA = +1024,742,742,742, +742,742,742,742, +742,742,742,742, +742,742,742,742 + +INTRA4X4_CHROMAU_INTRA = +742,742,742,742, +742,742,742,742, +742,742,742,742, +742,742,742,742 + +INTRA4X4_CHROMAV_INTRA = +742,742,742,742, +742,742,742,742, +742,742,742,742, +742,742,742,742 + +INTRA4X4_LUMA_INTERP = +400,400,400,400, +400,400,400,400, +400,400,400,400, +400,400,400,400 + +INTRA4X4_CHROMAU_INTERP = +400,400,400,400, +400,400,400,400, +400,400,400,400, +400,400,400,400 + +INTRA4X4_CHROMAV_INTERP = +400,400,400,400, +400,400,400,400, +400,400,400,400, +400,400,400,400 + +INTRA4X4_LUMA_INTERB = +400,400,400,400, +400,400,400,400, +400,400,400,400, +400,400,400,400 + +INTRA4X4_CHROMAU_INTERB = +400,400,400,400, +400,400,400,400, +400,400,400,400, +400,400,400,400 + +INTRA4X4_CHROMAV_INTERB = +400,400,400,400, +400,400,400,400, +400,400,400,400, +400,400,400,400 + +INTER4X4_LUMA_INTERP = +342,342,342,342, +342,342,342,342, +342,342,342,342, +342,342,342,342 + +INTER4X4_CHROMAU_INTERP = +342,342,342,342, +342,342,342,342, +342,342,342,342, +342,342,342,342 + +INTER4X4_CHROMAV_INTERP = +342,342,342,342, +342,342,342,342, +342,342,342,342, +342,342,342,342 + +INTER4X4_LUMA_INTERB = +342,342,342,342, +342,342,342,342, +342,342,342,342, +342,342,342,342 + +INTER4X4_CHROMAU_INTERB = +342,342,342,342, +342,342,342,342, +342,342,342,342, +342,342,342,342 + +INTER4X4_CHROMAV_INTERB = +342,342,342,342, +342,342,342,342, +342,342,342,342, +342,342,342,342 + +INTRA8X8_LUMA_INTRA = +1024,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742 + +INTRA8X8_LUMA_INTERP = +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742 + +INTRA8X8_LUMA_INTERB = +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742, +742,742,742,742,742,742,742,742 + +INTER8X8_LUMA_INTERP = +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342 + +INTER8X8_LUMA_INTERB = +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342, +342,342,342,342,342,342,342,342 diff --git a/bin/sg0conf.cfg b/bin/sg0conf.cfg new file mode 100644 index 0000000..a1d8d15 --- /dev/null +++ b/bin/sg0conf.cfg @@ -0,0 +1,9 @@ +24 +20 +10 +15 + + + +each line contains one run_length_minus1 + diff --git a/bin/sg2conf.cfg b/bin/sg2conf.cfg new file mode 100644 index 0000000..30a66da --- /dev/null +++ b/bin/sg2conf.cfg @@ -0,0 +1,11 @@ +24 +122 +58 +108 + + + +odd number of rows: top left mapunit number +even number of rows: bottom right of mapunit number + + diff --git a/bin/sg6conf.cfg b/bin/sg6conf.cfg new file mode 100644 index 0000000..ada326f --- /dev/null +++ b/bin/sg6conf.cfg @@ -0,0 +1,396 @@ +0 +1 +1 +0 +1 +1 +1 +1 +1 +0 +1 +1 +1 +1 +1 +0 +1 +1 +1 +1 +1 +1 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +1 +1 +1 +1 +0 +1 +1 +1 +0 +1 +0 +1 +1 +1 +1 +1 +1 +0 +1 +1 +1 +1 +0 +0 +0 +1 +1 +0 +0 +1 +1 +1 +0 +1 +1 +1 +0 +1 +0 +0 +1 +1 +1 +0 +0 +1 +1 +1 +1 +0 +1 +0 +0 +1 +0 +0 +1 +1 +1 +1 +0 +0 +0 +0 +1 +1 +0 +1 +0 +0 +1 +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +0 +1 +1 +0 +1 +1 +0 +1 +1 +0 +1 +0 +1 +1 +1 +1 +0 +0 +0 +1 +0 +1 +1 +0 +0 +1 +1 +1 +1 +0 +1 +1 +0 +1 +1 +0 +1 +0 +1 +1 +1 +0 +1 +1 +0 +1 +1 +1 +0 +1 +1 +0 +0 +1 +1 +1 +0 +0 +1 +1 +1 +0 +0 +1 +0 +1 +1 +0 +0 +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +0 +0 +1 +0 +0 +0 +1 +1 +1 +1 +0 +1 +0 +0 +1 +1 +0 +0 +1 +1 +0 +0 +0 +0 +0 +1 +1 +0 +0 +0 +1 +1 +1 +1 +0 +0 +1 +1 +1 +1 +0 +0 +1 +0 +1 +1 +1 +1 +1 +0 +1 +1 +1 +1 +0 +1 +1 +1 +1 +1 +0 +1 +1 +0 +0 +1 +1 +0 +1 +1 +1 +1 +0 +0 +1 +0 +1 +1 +1 +0 +0 +1 +1 +1 +1 +1 +0 +1 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +0 +1 +0 +0 +0 +1 +1 +0 +1 +1 +1 +1 +1 +0 +0 +0 +1 +0 +1 +0 +1 +1 +0 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +1 +1 +0 +1 +1 +0 +1 +0 +0 +1 +1 +1 +1 +0 +1 +1 +1 +0 +1 +1 +1 +0 +0 +0 +1 +0 +0 +1 +0 +1 +1 +0 diff --git a/disclaimer.txt b/disclaimer.txt new file mode 100644 index 0000000..7d84da2 --- /dev/null +++ b/disclaimer.txt @@ -0,0 +1,25 @@ +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any + * license fee or royalty on an "as is" basis. The ITU-T + * disclaims any and all warranties, whether express, implied, or + * statutory, including any implied warranties of merchantability + * or of fitness for a particular purpose. In no event shall the + * copyright-holder be liable for any incidental, punitive, or + * consequential damages of any kind whatsoever arising from the + * use of these programs. + * + * This disclaimer of warranty extends to the user of these programs + * and user's customers, employees, agents, transferees, successors, + * and assigns. + * + * The ITU-T does not represent or warrant that the programs furnished + * hereunder are free of infringement of any third-party patents. + * Commercial implementations of ITU-T standards, including shareware, + * may be subject to royalty fees to patent holders. Information + * regarding the ITU patent policy is available from the ITU + * Web site at http://www.itu.int. + * + */ + diff --git a/doc/JM Reference Software Manual.pdf b/doc/JM Reference Software Manual.pdf new file mode 100644 index 0000000..d1b1d0b Binary files /dev/null and b/doc/JM Reference Software Manual.pdf differ diff --git a/doc/coding_style.doc b/doc/coding_style.doc new file mode 100644 index 0000000..f48935b Binary files /dev/null and b/doc/coding_style.doc differ diff --git a/doc/doxygen.txt b/doc/doxygen.txt new file mode 100644 index 0000000..5376fad --- /dev/null +++ b/doc/doxygen.txt @@ -0,0 +1,18 @@ +Doxygen usage information +------------------------- + +Doxygen can be downloaded from http://www.doxygen.org + + Note: for generating graphs you will also need "dot" which is part of + the ATT Graphviz tools available at + http://www.graphviz.org/ + + +For generation of the TML reference software documentation run + +doxygen lencod.dox +doxygen ldecod.dox + +in this directory. + +The documentation will be genrated into the directories lenc/ and ldec/ diff --git a/doc/foot.html b/doc/foot.html new file mode 100644 index 0000000..1475df6 --- /dev/null +++ b/doc/foot.html @@ -0,0 +1,2 @@ +
+Documentation generated with DoxyGen
diff --git a/doc/ldecod.dox b/doc/ldecod.dox new file mode 100644 index 0000000..8148cac --- /dev/null +++ b/doc/ldecod.dox @@ -0,0 +1,234 @@ +# Doxyfile 1.5.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "H.264/AVC Reference Software Decoder " +PROJECT_NUMBER = +OUTPUT_DIRECTORY = ./ldec +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = NO +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = YES +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = warning.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../ldecod/ \ + ../lcommon/ +INPUT_ENCODING = ISO-8859-1 +FILE_PATTERNS = *.c \ + *.h +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = ./foot.html +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 5 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/doc/lencod.dox b/doc/lencod.dox new file mode 100644 index 0000000..195126f --- /dev/null +++ b/doc/lencod.dox @@ -0,0 +1,234 @@ +# Doxyfile 1.5.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "H.264/AVC Reference Software Encoder " +PROJECT_NUMBER = +OUTPUT_DIRECTORY = ./lenc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = NO +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = YES +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = warning.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../lencod/ \ + ../lcommon/ +INPUT_ENCODING = ISO-8859-1 +FILE_PATTERNS = *.c \ + *.h +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = ./foot.html +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 5 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/jm_vc10.sln b/jm_vc10.sln new file mode 100644 index 0000000..e702b7b --- /dev/null +++ b/jm_vc10.sln @@ -0,0 +1,59 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldecod", "ldecod_vc10.vcxproj", "{5499B067-CF32-4141-A757-E0A29866994A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "outside_debug", "outside_debug", "{47CBCC62-2112-4673-83A3-7DA41A90E32E}" + ProjectSection(SolutionItems) = preProject + ..\jm_debug_mvc\decoder_config_jmvc_decoder.cfg = ..\jm_debug_mvc\decoder_config_jmvc_decoder.cfg + ..\jm_debug\zdecoder_config.cfg = ..\jm_debug\zdecoder_config.cfg + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lencod", "lencod_vc10.vcxproj", "{9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtpdump", "rtpdump\rtpdump_vc10.vcxproj", "{BE2D5D97-BD3F-489B-A346-123834DDDBBD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtp_loss", "rtp_loss\rtp_loss_vc10.vcxproj", "{5160AFF8-033C-4944-8AD7-6E960344640F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|Win32.ActiveCfg = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|Win32.Build.0 = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.ActiveCfg = Debug|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.Build.0 = Debug|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|Win32.ActiveCfg = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|Win32.Build.0 = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|x64.ActiveCfg = Release|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|x64.Build.0 = Release|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|Win32.Build.0 = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.ActiveCfg = Debug|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.Build.0 = Debug|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|Win32.ActiveCfg = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|Win32.Build.0 = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|x64.ActiveCfg = Release|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|x64.Build.0 = Release|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|Win32.Build.0 = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|x64.ActiveCfg = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|Win32.ActiveCfg = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|Win32.Build.0 = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|x64.ActiveCfg = Release|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|x64.Build.0 = Release|x64 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Debug|Win32.ActiveCfg = Debug|Win32 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Debug|Win32.Build.0 = Debug|Win32 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Debug|x64.ActiveCfg = Debug|Win32 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Release|Win32.ActiveCfg = Release|Win32 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Release|Win32.Build.0 = Release|Win32 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Release|x64.ActiveCfg = Release|Win32 + {5160AFF8-033C-4944-8AD7-6E960344640F}.Release|x64.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/jm_vc7.sln b/jm_vc7.sln new file mode 100644 index 0000000..2815fd1 --- /dev/null +++ b/jm_vc7.sln @@ -0,0 +1,47 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldecod", "ldecod_vc7.vcproj", "{5499B067-CF32-4141-A757-E0A29866994A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lencod", "lencod_vc7.vcproj", "{9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtpdump", "rtpdump\rtpdump_vc7.vcproj", "{BE2D5D97-BD3F-489B-A346-123834DDDBBD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtp_loss", "rtp_loss\rtp_loss_vc7.vcproj", "{BE2D5D97-BD3F-489B-A346-123834DDDBBD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5499B067-CF32-4141-A757-E0A29866994A}.Debug.ActiveCfg = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug.Build.0 = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release.ActiveCfg = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release.Build.0 = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug.ActiveCfg = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug.Build.0 = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release.ActiveCfg = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release.Build.0 = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug.ActiveCfg = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug.Build.0 = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release.ActiveCfg = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release.Build.0 = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug.ActiveCfg = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug.Build.0 = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release.ActiveCfg = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/jm_vc8.sln b/jm_vc8.sln new file mode 100644 index 0000000..799da8e --- /dev/null +++ b/jm_vc8.sln @@ -0,0 +1,57 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldecod", "ldecod_vc8.vcproj", "{5499B067-CF32-4141-A757-E0A29866994A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lencod", "lencod_vc8.vcproj", "{9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtpdump", "rtpdump\rtpdump_vc8.vcproj", "{BE2D5D97-BD3F-489B-A346-123834DDDBBD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtp_loss", "rtp_loss\rtp_loss_vc8.vcproj", "{50C36073-1189-4F75-B0BE-45186CF200A6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|Win32.ActiveCfg = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|Win32.Build.0 = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.ActiveCfg = Debug|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.Build.0 = Debug|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.Build.2 = ReleaseMMX|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|Win32.ActiveCfg = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|Win32.Build.0 = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|x64.ActiveCfg = Release|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|x64.Build.0 = Release|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|Win32.Build.0 = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.ActiveCfg = Debug|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.Build.0 = Debug|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.Build.2 = Matlab|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|Win32.ActiveCfg = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|Win32.Build.0 = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|x64.ActiveCfg = Release|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|x64.Build.0 = Release|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|Win32.Build.0 = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|x64.ActiveCfg = Debug|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|x64.Build.0 = Debug|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|Win32.ActiveCfg = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|Win32.Build.0 = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|x64.ActiveCfg = Release|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|x64.Build.0 = Release|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|Win32.ActiveCfg = Debug|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|Win32.Build.0 = Debug|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|x64.ActiveCfg = Debug|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|x64.Build.0 = Debug|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|Win32.ActiveCfg = Release|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|Win32.Build.0 = Release|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|x64.ActiveCfg = Release|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/jm_vc9.sln b/jm_vc9.sln new file mode 100644 index 0000000..badf233 --- /dev/null +++ b/jm_vc9.sln @@ -0,0 +1,61 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lencod", "lencod_vc9.vcproj", "{9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtpdump", "rtpdump\rtpdump_vc9.vcproj", "{BE2D5D97-BD3F-489B-A346-123834DDDBBD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtp_loss", "rtp_loss\rtp_loss_vc9.vcproj", "{50C36073-1189-4F75-B0BE-45186CF200A6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldecod", "ldecod_vc9.vcproj", "{5499B067-CF32-4141-A757-E0A29866994A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|Win32.Build.0 = Debug|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.ActiveCfg = Debug|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Debug|x64.Build.0 = Debug|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|Win32.ActiveCfg = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|Win32.Build.0 = Release|Win32 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|x64.ActiveCfg = Release|x64 + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA}.Release|x64.Build.0 = Release|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|Win32.Build.0 = Debug|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|x64.ActiveCfg = Debug|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Debug|x64.Build.0 = Debug|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|Win32.ActiveCfg = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|Win32.Build.0 = Release|Win32 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|x64.ActiveCfg = Release|x64 + {BE2D5D97-BD3F-489B-A346-123834DDDBBD}.Release|x64.Build.0 = Release|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|Win32.ActiveCfg = Debug|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|Win32.Build.0 = Debug|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|x64.ActiveCfg = Debug|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Debug|x64.Build.0 = Debug|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|Win32.ActiveCfg = Release|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|Win32.Build.0 = Release|Win32 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|x64.ActiveCfg = Release|x64 + {50C36073-1189-4F75-B0BE-45186CF200A6}.Release|x64.Build.0 = Release|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|Win32.ActiveCfg = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|Win32.Build.0 = Debug|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.ActiveCfg = Debug|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Debug|x64.Build.0 = Debug|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|Win32.ActiveCfg = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|Win32.Build.0 = Release|Win32 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|x64.ActiveCfg = Release|x64 + {5499B067-CF32-4141-A757-E0A29866994A}.Release|x64.Build.0 = Release|x64 + {F0A0C825-4281-41C9-8737-1163C5FEFD6E}.Debug|Win32.ActiveCfg = Debug|Win32 + {F0A0C825-4281-41C9-8737-1163C5FEFD6E}.Debug|Win32.Build.0 = Debug|Win32 + {F0A0C825-4281-41C9-8737-1163C5FEFD6E}.Debug|x64.ActiveCfg = Debug|Win32 + {F0A0C825-4281-41C9-8737-1163C5FEFD6E}.Release|Win32.ActiveCfg = Release|Win32 + {F0A0C825-4281-41C9-8737-1163C5FEFD6E}.Release|Win32.Build.0 = Release|Win32 + {F0A0C825-4281-41C9-8737-1163C5FEFD6E}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lcommon/inc/blk_prediction.h b/lcommon/inc/blk_prediction.h new file mode 100644 index 0000000..288584b --- /dev/null +++ b/lcommon/inc/blk_prediction.h @@ -0,0 +1,25 @@ + +/*! + ************************************************************************ + * \file + * blk_prediction.h + * + * \brief + * block prediction header + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#ifndef _BLK_PREDICTION_H_ +#define _BLK_PREDICTION_H_ +#include "mbuffer.h" + +extern void compute_residue (imgpel **curImg, imgpel **mb_pred, int **mb_rres, int mb_x, int opix_x, int width, int height); +extern void sample_reconstruct (imgpel **curImg, imgpel **mb_pred, int **mb_rres, int mb_x, int opix_x, int width, int height, int max_imgpel_value, int dq_bits); +#endif + diff --git a/lcommon/inc/config_common.h b/lcommon/inc/config_common.h new file mode 100644 index 0000000..3b03aef --- /dev/null +++ b/lcommon/inc/config_common.h @@ -0,0 +1,35 @@ + +/*! + ************************************************************************ + * \file config_common.h + * + * \brief + * Common Config parsing functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Tourapis + * + ************************************************************************ + */ +#ifndef _CONFIG_COMMON_H_ +#define _CONFIG_COMMON_H_ + +//! Maps parameter name to its address, type etc. +typedef struct { + char *TokenName; //!< name + void *Place; //!< address + int Type; //!< type: 0-int, 1-char[], 2-double + double Default; //!< default value + int param_limits; //!< 0: no limits, 1: both min and max, 2: only min (i.e. no negatives), 3: special case for QPs since min needs bitdepth_qp_scale + double min_limit; + double max_limit; + int char_size; //!< Dimension of type char[] +} Mapping; + +extern char *GetConfigFileContent (char *Filename); +extern int InitParams (Mapping *Map); +extern int TestParams(Mapping *Map, int bitdepth_qp_scale[3]); +extern int DisplayParams(Mapping *Map, char *message); +extern void ParseContent (InputParameters *p_Inp, Mapping *Map, char *buf, int bufsize); +#endif \ No newline at end of file diff --git a/lcommon/inc/ctx_tables.h b/lcommon/inc/ctx_tables.h new file mode 100644 index 0000000..511e9b1 --- /dev/null +++ b/lcommon/inc/ctx_tables.h @@ -0,0 +1,994 @@ + +/*! + ************************************************************************************* + * \file ctx_tables.h + * + * \brief + * CABAC context initialization tables + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Heiko Schwarz + ************************************************************************************** + */ + +#define CTX_UNUSED {0,64} +#define CTX_UNDEF {0,63} + +#ifdef CONTEXT_INI_C + + +#define NUM_CTX_MODELS_I 1 +#define NUM_CTX_MODELS_P 3 + + +static const char INIT_MB_TYPE_I[1][3][11][2] = +{ + //----- model 0 ----- + { + { { 20, -15} , { 2, 54} , { 3, 74} , CTX_UNUSED , { -28, 127} , { -23, 104} , { -6, 53} , { -1, 54} , { 7, 51} , CTX_UNUSED , CTX_UNUSED }, + { { 20, -15} , { 2, 54} , { 3, 74} , { 20, -15} , { 2, 54} , { 3, 74} , { -28, 127} , { -23, 104} , { -6, 53} , { -1, 54} , { 7, 51} }, // SI (unused at the moment) + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; +static const char INIT_MB_TYPE_P[3][3][11][2] = +{ + //----- model 0 ----- + { + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 23, 33} , { 23, 2} , { 21, 0} , CTX_UNUSED , { 1, 9} , { 0, 49} , { -37, 118} , { 5, 57} , { -13, 78} , { -11, 65} , { 1, 62} }, + { { 26, 67} , { 16, 90} , { 9, 104} , CTX_UNUSED , { -46, 127} , { -20, 104} , { 1, 67} , { 18, 64} , { 9, 43} , { 29, 0} , CTX_UNUSED } + }, + //----- model 1 ----- + { + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 22, 25} , { 34, 0} , { 16, 0} , CTX_UNUSED , { -2, 9} , { 4, 41} , { -29, 118} , { 2, 65} , { -6, 71} , { -13, 79} , { 5, 52} }, + { { 57, 2} , { 41, 36} , { 26, 69} , CTX_UNUSED , { -45, 127} , { -15, 101} , { -4, 76} , { 26, 34} , { 19, 22} , { 40, 0} , CTX_UNUSED } + }, + //----- model 2 ----- + { + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 29, 16} , { 25, 0} , { 14, 0} , CTX_UNUSED , { -10, 51} , { -3, 62} , { -27, 99} , { 26, 16} , { -4, 85} , { -24, 102} , { 5, 57} }, + { { 54, 0} , { 37, 42} , { 12, 97} , CTX_UNUSED , { -32, 127} , { -22, 117} , { -2, 74} , { 20, 40} , { 20, 10} , { 29, 0} , CTX_UNUSED } + } +}; + +static const char INIT_B8_TYPE_I[1][2][9][2] = +{ + //----- model 0 ----- + { + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_B8_TYPE_P[3][2][9][2] = +{ + //----- model 0 ----- + { + { CTX_UNUSED , { 12, 49} , CTX_UNUSED , { -4, 73} , { 17, 50} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -6, 86} , { -17, 95} , { -6, 61} , { 9, 45} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 1 ----- + { + { CTX_UNUSED , { 9, 50} , CTX_UNUSED , { -3, 70} , { 10, 54} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 6, 69} , { -13, 90} , { 0, 52} , { 8, 43} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 2 ----- + { + { CTX_UNUSED , { 6, 57} , CTX_UNUSED , { -17, 73} , { 14, 57} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -6, 93} , { -14, 88} , { -6, 44} , { 4, 55} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_MV_RES_I[1][2][10][2] = +{ + //----- model 0 ----- + { + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_MV_RES_P[3][2][10][2] = +{ + //----- model 0 ----- + { + { { -3, 69} , CTX_UNUSED , { -6, 81} , { -11, 96} , CTX_UNUSED , { 0, 58} , CTX_UNUSED , { -3, 76} , { -10, 94} , CTX_UNUSED }, + { { 6, 55} , { 7, 67} , { -5, 86} , { 2, 88} , CTX_UNUSED , { 5, 54} , { 4, 69} , { -3, 81} , { 0, 88} , CTX_UNUSED } + }, + //----- model 1 ----- + { + { { -2, 69} , CTX_UNUSED , { -5, 82} , { -10, 96} , CTX_UNUSED , { 1, 56} , CTX_UNUSED , { -3, 74} , { -6, 85} , CTX_UNUSED }, + { { 2, 59} , { 2, 75} , { -3, 87} , { -3, 100} , CTX_UNUSED , { 0, 59} , { -3, 81} , { -7, 86} , { -5, 95} , CTX_UNUSED } + }, + //----- model 2 ----- + { + { { -11, 89} , CTX_UNUSED , { -15, 103} , { -21, 116} , CTX_UNUSED , { 1, 63} , CTX_UNUSED , { -5, 85} , { -13, 106} , CTX_UNUSED }, + { { 19, 57} , { 20, 58} , { 4, 84} , { 6, 96} , CTX_UNUSED , { 5, 63} , { 6, 75} , { -3, 90} , { -1, 101} , CTX_UNUSED } + } +}; + +static const char INIT_REF_NO_I[1][2][6][2] = +{ + //----- model 0 ----- + { + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_REF_NO_P[3][2][6][2] = +{ + //----- model 0 ----- + { + { { -7, 67} , { -5, 74} , { -4, 74} , { -5, 80} , { -7, 72} , { 1, 58} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 1 ----- + { + { { -1, 66} , { -1, 77} , { 1, 70} , { -2, 86} , { -5, 72} , { 0, 61} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 2 ----- + { + { { 3, 55} , { -4, 79} , { -2, 75} , { -12, 97} , { -7, 50} , { 1, 60} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + + +static const char INIT_TRANSFORM_SIZE_I[1][1][3][2]= +{ + //----- model 0 ----- + { + { { 31, 21} , { 31, 31} , { 25, 50} }, +// { { 0, 41} , { 0, 63} , { 0, 63} }, + } +}; + +static const char INIT_TRANSFORM_SIZE_P[3][1][3][2]= +{ + //----- model 0 ----- + { + { { 12, 40} , { 11, 51} , { 14, 59} }, +// { { 0, 41} , { 0, 63} , { 0, 63} }, + }, + //----- model 1 ----- + { + { { 25, 32} , { 21, 49} , { 21, 54} }, +// { { 0, 41} , { 0, 63} , { 0, 63} }, + }, + //----- model 2 ----- + { + { { 21, 33} , { 19, 50} , { 17, 61} }, +// { { 0, 41} , { 0, 63} , { 0, 63} }, + } +}; + +static const char INIT_DELTA_QP_I[1][1][4][2]= +{ + //----- model 0 ----- + { + { { 0, 41} , { 0, 63} , { 0, 63} , { 0, 63} }, + } +}; +static const char INIT_DELTA_QP_P[3][1][4][2]= +{ + //----- model 0 ----- + { + { { 0, 41} , { 0, 63} , { 0, 63} , { 0, 63} }, + }, + //----- model 1 ----- + { + { { 0, 41} , { 0, 63} , { 0, 63} , { 0, 63} }, + }, + //----- model 2 ----- + { + { { 0, 41} , { 0, 63} , { 0, 63} , { 0, 63} }, + } +}; + +static const char INIT_MB_AFF_I[1][1][4][2] = +{ + //----- model 0 ----- + { + { { 0, 11} , { 1, 55} , { 0, 69} , CTX_UNUSED } + } +}; +static const char INIT_MB_AFF_P[3][1][4][2] = +{ + //----- model 0 ----- + { + { { 0, 45} , { -4, 78} , { -3, 96} , CTX_UNUSED } + }, + //----- model 1 ----- + { + { { 13, 15} , { 7, 51} , { 2, 80} , CTX_UNUSED } + }, + //----- model 2 ----- + { + { { 7, 34} , { -9, 88} , { -20, 127} , CTX_UNUSED } + } +}; + +static const char INIT_IPR_I[1][1][2][2] = +{ + //----- model 0 ----- + { + { { 13, 41} , { 3, 62} } + } +}; + +static const char INIT_IPR_P[3][1][2][2] = +{ + //----- model 0 ----- + { + { { 13, 41} , { 3, 62} } + }, + //----- model 1 ----- + { + { { 13, 41} , { 3, 62} } + }, + //----- model 2 ----- + { + { { 13, 41} , { 3, 62} } + } +}; + +static const char INIT_CIPR_I[1][1][4][2] = +{ + //----- model 0 ----- + { + { { -9, 83} , { 4, 86} , { 0, 97} , { -7, 72} } + } +}; + +static const char INIT_CIPR_P[3][1][4][2] = +{ + //----- model 0 ----- + { + { { -9, 83} , { 4, 86} , { 0, 97} , { -7, 72} } + }, + //----- model 1 ----- + { + { { -9, 83} , { 4, 86} , { 0, 97} , { -7, 72} } + }, + //----- model 2 ----- + { + { { -9, 83} , { 4, 86} , { 0, 97} , { -7, 72} } + } +}; + +static const char INIT_CBP_I[1][3][4][2] = +{ + //----- model 0 ----- + { + { { -17, 127} , { -13, 102} , { 0, 82} , { -7, 74} }, + { { -21, 107} , { -27, 127} , { -31, 127} , { -24, 127} }, + { { -18, 95} , { -27, 127} , { -21, 114} , { -30, 127} } + } +}; + +static const char INIT_CBP_P[3][3][4][2] = +{ + //----- model 0 ----- + { + { { -27, 126} , { -28, 98} , { -25, 101} , { -23, 67} }, + { { -28, 82} , { -20, 94} , { -16, 83} , { -22, 110} }, + { { -21, 91} , { -18, 102} , { -13, 93} , { -29, 127} } + }, + //----- model 1 ----- + { + { { -39, 127} , { -18, 91} , { -17, 96} , { -26, 81} }, + { { -35, 98} , { -24, 102} , { -23, 97} , { -27, 119} }, + { { -24, 99} , { -21, 110} , { -18, 102} , { -36, 127} } + }, + //----- model 2 ----- + { + { { -36, 127} , { -17, 91} , { -14, 95} , { -25, 84} }, + { { -25, 86} , { -12, 89} , { -17, 91} , { -31, 127} }, + { { -14, 76} , { -18, 103} , { -13, 90} , { -37, 127} } + } +}; + +static const char INIT_BCBP_I[1][22][4][2] = +{ + //----- model 0 ----- + { + { { -17, 123} , { -12, 115} , { -16, 122} , { -11, 115} }, + { { -12, 63} , { -2, 68} , { -15, 84} , { -13, 104} }, + { { -3, 70} , { -8, 93} , { -10, 90} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -3, 70} , { -8, 93} , { -10, 90} , { -30, 127} }, + { { -1, 74} , { -6, 97} , { -7, 91} , { -20, 127} }, + { { -4, 56} , { -5, 82} , { -7, 76} , { -22, 125} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cb in the 4:4:4 common mode + { { -17, 123} , { -12, 115} , { -16, 122} , { -11, 115} }, + { { -12, 63} , { -2, 68} , { -15, 84} , { -13, 104} }, + { { -3, 70} , { -8, 93} , { -10, 90} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -3, 70} , { -8, 93} , { -10, 90} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cr in the 4:4:4 common mode + { { -17, 123} , { -12, 115} , { -16, 122} , { -11, 115} }, + { { -12, 63} , { -2, 68} , { -15, 84} , { -13, 104} }, + { { -3, 70} , { -8, 93} , { -10, 90} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -3, 70} , { -8, 93} , { -10, 90} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_BCBP_P[3][22][4][2] = +{ + //----- model 0 ----- + { + { { -7, 92} , { -5, 89} , { -7, 96} , { -13, 108} }, + { { -3, 46} , { -1, 65} , { -1, 57} , { -9, 93} }, + { { -3, 74} , { -9, 92} , { -8, 87} , { -23, 126} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -3, 74} , { -9, 92} , { -8, 87} , { -23, 126} }, + { { 5, 54} , { 6, 60} , { 6, 59} , { 6, 69} }, + { { -1, 48} , { 0, 68} , { -4, 69} , { -8, 88} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cb in the 4:4:4 common mode + { { -7, 92} , { -5, 89} , { -7, 96} , { -13, 108} }, + { { -3, 46} , { -1, 65} , { -1, 57} , { -9, 93} }, + { { -3, 74} , { -9, 92} , { -8, 87} , { -23, 126} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -3, 74} , { -9, 92} , { -8, 87} , { -23, 126} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cr in the 4:4:4 common mode + { { -7, 92} , { -5, 89} , { -7, 96} , { -13, 108} }, + { { -3, 46} , { -1, 65} , { -1, 57} , { -9, 93} }, + { { -3, 74} , { -9, 92} , { -8, 87} , { -23, 126} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -3, 74} , { -9, 92} , { -8, 87} , { -23, 126} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 1 ----- + { + { { 0, 80} , { -5, 89} , { -7, 94} , { -4, 92} }, + { { 0, 39} , { 0, 65} , { -15, 84} , { -35, 127} }, + { { -2, 73} , { -12, 104} , { -9, 91} , { -31, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -2, 73} , { -12, 104} , { -9, 91} , { -31, 127} }, + { { 3, 55} , { 7, 56} , { 7, 55} , { 8, 61} }, + { { -3, 53} , { 0, 68} , { -7, 74} , { -9, 88} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cb in the 4:4:4 common mode + { { 0, 80} , { -5, 89} , { -7, 94} , { -4, 92} }, + { { 0, 39} , { 0, 65} , { -15, 84} , { -35, 127} }, + { { -2, 73} , { -12, 104} , { -9, 91} , { -31, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -2, 73} , { -12, 104} , { -9, 91} , { -31, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cr in the 4:4:4 common mode + { { 0, 80} , { -5, 89} , { -7, 94} , { -4, 92} }, + { { 0, 39} , { 0, 65} , { -15, 84} , { -35, 127} }, + { { -2, 73} , { -12, 104} , { -9, 91} , { -31, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -2, 73} , { -12, 104} , { -9, 91} , { -31, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 2 ----- + { + { { 11, 80} , { 5, 76} , { 2, 84} , { 5, 78} }, + { { -6, 55} , { 4, 61} , { -14, 83} , { -37, 127} }, + { { -5, 79} , { -11, 104} , { -11, 91} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -5, 79} , { -11, 104} , { -11, 91} , { -30, 127} }, + { { 0, 65} , { -2, 79} , { 0, 72} , { -4, 92} }, + { { -6, 56} , { 3, 68} , { -8, 71} , { -13, 98} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cb in the 4:4:4 common mode + { { 11, 80} , { 5, 76} , { 2, 84} , { 5, 78} }, + { { -6, 55} , { 4, 61} , { -14, 83} , { -37, 127} }, + { { -5, 79} , { -11, 104} , { -11, 91} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -5, 79} , { -11, 104} , { -11, 91} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + // Cr in the 4:4:4 common mode + { { 11, 80} , { 5, 76} , { 2, 84} , { 5, 78} }, + { { -6, 55} , { 4, 61} , { -14, 83} , { -37, 127} }, + { { -5, 79} , { -11, 104} , { -11, 91} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -5, 79} , { -11, 104} , { -11, 91} , { -30, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_MAP_I[1][22][15][2] = +{ + //----- model 0 ----- + { + { { -7, 93} , { -11, 87} , { -3, 77} , { -5, 71} , { -4, 63} , { -4, 68} , { -12, 84} , { -7, 62} , { -7, 65} , { 8, 61} , { 5, 56} , { -2, 66} , { 1, 64} , { 0, 61} , { -2, 78} }, + { CTX_UNUSED , { 1, 50} , { 7, 52} , { 10, 35} , { 0, 44} , { 11, 38} , { 1, 45} , { 0, 46} , { 5, 44} , { 31, 17} , { 1, 51} , { 7, 50} , { 28, 19} , { 16, 33} , { 14, 62} }, + { { -17, 120} , { -20, 112} , { -18, 114} , { -11, 85} , { -15, 92} , { -14, 89} , { -26, 71} , { -15, 81} , { -14, 80} , { 0, 68} , { -14, 70} , { -24, 56} , { -23, 68} , { -24, 50} , { -11, 74} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -13, 108} , { -15, 100} , { -13, 101} , { -13, 91} , { -12, 94} , { -10, 88} , { -16, 84} , { -10, 86} , { -7, 83} , { -13, 87} , { -19, 94} , { 1, 70} , { 0, 72} , { -5, 74} , { 18, 59} }, + { { -8, 102} , { -15, 100} , { 0, 95} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { -4, 75} , { 2, 72} , { -11, 75} , { -3, 71} , { 15, 46} , { -13, 69} , { 0, 62} , { 0, 65} , { 21, 37} , { -15, 72} , { 9, 57} , { 16, 54} , { 0, 62} , { 12, 72} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -7, 93} , { -11, 87} , { -3, 77} , { -5, 71} , { -4, 63} , { -4, 68} , { -12, 84} , { -7, 62} , { -7, 65} , { 8, 61} , { 5, 56} , { -2, 66} , { 1, 64} , { 0, 61} , { -2, 78} }, + { CTX_UNUSED , { 1, 50} , { 7, 52} , { 10, 35} , { 0, 44} , { 11, 38} , { 1, 45} , { 0, 46} , { 5, 44} , { 31, 17} , { 1, 51} , { 7, 50} , { 28, 19} , { 16, 33} , { 14, 62} }, + { { -17, 120} , { -20, 112} , { -18, 114} , { -11, 85} , { -15, 92} , { -14, 89} , { -26, 71} , { -15, 81} , { -14, 80} , { 0, 68} , { -14, 70} , { -24, 56} , { -23, 68} , { -24, 50} , { -11, 74} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -13, 108} , { -15, 100} , { -13, 101} , { -13, 91} , { -12, 94} , { -10, 88} , { -16, 84} , { -10, 86} , { -7, 83} , { -13, 87} , { -19, 94} , { 1, 70} , { 0, 72} , { -5, 74} , { 18, 59} }, + //Cr in the 4:4:4 common mode + { { -7, 93} , { -11, 87} , { -3, 77} , { -5, 71} , { -4, 63} , { -4, 68} , { -12, 84} , { -7, 62} , { -7, 65} , { 8, 61} , { 5, 56} , { -2, 66} , { 1, 64} , { 0, 61} , { -2, 78} }, + { CTX_UNUSED , { 1, 50} , { 7, 52} , { 10, 35} , { 0, 44} , { 11, 38} , { 1, 45} , { 0, 46} , { 5, 44} , { 31, 17} , { 1, 51} , { 7, 50} , { 28, 19} , { 16, 33} , { 14, 62} }, + { { -17, 120} , { -20, 112} , { -18, 114} , { -11, 85} , { -15, 92} , { -14, 89} , { -26, 71} , { -15, 81} , { -14, 80} , { 0, 68} , { -14, 70} , { -24, 56} , { -23, 68} , { -24, 50} , { -11, 74} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -13, 108} , { -15, 100} , { -13, 101} , { -13, 91} , { -12, 94} , { -10, 88} , { -16, 84} , { -10, 86} , { -7, 83} , { -13, 87} , { -19, 94} , { 1, 70} , { 0, 72} , { -5, 74} , { 18, 59} } + } +}; + +static const char INIT_MAP_P[3][22][15][2] = +{ + //----- model 0 ----- + { + { { -2, 85} , { -6, 78} , { -1, 75} , { -7, 77} , { 2, 54} , { 5, 50} , { -3, 68} , { 1, 50} , { 6, 42} , { -4, 81} , { 1, 63} , { -4, 70} , { 0, 67} , { 2, 57} , { -2, 76} }, + { CTX_UNUSED , { 11, 35} , { 4, 64} , { 1, 61} , { 11, 35} , { 18, 25} , { 12, 24} , { 13, 29} , { 13, 36} , { -10, 93} , { -7, 73} , { -2, 73} , { 13, 46} , { 9, 49} , { -7, 100} }, + { { -4, 79} , { -7, 71} , { -5, 69} , { -9, 70} , { -8, 66} , { -10, 68} , { -19, 73} , { -12, 69} , { -16, 70} , { -15, 67} , { -20, 62} , { -19, 70} , { -16, 66} , { -22, 65} , { -20, 63} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 9, 53} , { 2, 53} , { 5, 53} , { -2, 61} , { 0, 56} , { 0, 56} , { -13, 63} , { -5, 60} , { -1, 62} , { 4, 57} , { -6, 69} , { 4, 57} , { 14, 39} , { 4, 51} , { 13, 68} }, + { { 3, 64} , { 1, 61} , { 9, 63} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 7, 50} , { 16, 39} , { 5, 44} , { 4, 52} , { 11, 48} , { -5, 60} , { -1, 59} , { 0, 59} , { 22, 33} , { 5, 44} , { 14, 43} , { -1, 78} , { 0, 60} , { 9, 69} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -2, 85} , { -6, 78} , { -1, 75} , { -7, 77} , { 2, 54} , { 5, 50} , { -3, 68} , { 1, 50} , { 6, 42} , { -4, 81} , { 1, 63} , { -4, 70} , { 0, 67} , { 2, 57} , { -2, 76} }, + { CTX_UNUSED , { 11, 35} , { 4, 64} , { 1, 61} , { 11, 35} , { 18, 25} , { 12, 24} , { 13, 29} , { 13, 36} , { -10, 93} , { -7, 73} , { -2, 73} , { 13, 46} , { 9, 49} , { -7, 100} }, + { { -4, 79} , { -7, 71} , { -5, 69} , { -9, 70} , { -8, 66} , { -10, 68} , { -19, 73} , { -12, 69} , { -16, 70} , { -15, 67} , { -20, 62} , { -19, 70} , { -16, 66} , { -22, 65} , { -20, 63} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 9, 53} , { 2, 53} , { 5, 53} , { -2, 61} , { 0, 56} , { 0, 56} , { -13, 63} , { -5, 60} , { -1, 62} , { 4, 57} , { -6, 69} , { 4, 57} , { 14, 39} , { 4, 51} , { 13, 68} }, + //Cr in the 4:4:4 common mode + { { -2, 85} , { -6, 78} , { -1, 75} , { -7, 77} , { 2, 54} , { 5, 50} , { -3, 68} , { 1, 50} , { 6, 42} , { -4, 81} , { 1, 63} , { -4, 70} , { 0, 67} , { 2, 57} , { -2, 76} }, + { CTX_UNUSED , { 11, 35} , { 4, 64} , { 1, 61} , { 11, 35} , { 18, 25} , { 12, 24} , { 13, 29} , { 13, 36} , { -10, 93} , { -7, 73} , { -2, 73} , { 13, 46} , { 9, 49} , { -7, 100} }, + { { -4, 79} , { -7, 71} , { -5, 69} , { -9, 70} , { -8, 66} , { -10, 68} , { -19, 73} , { -12, 69} , { -16, 70} , { -15, 67} , { -20, 62} , { -19, 70} , { -16, 66} , { -22, 65} , { -20, 63} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 9, 53} , { 2, 53} , { 5, 53} , { -2, 61} , { 0, 56} , { 0, 56} , { -13, 63} , { -5, 60} , { -1, 62} , { 4, 57} , { -6, 69} , { 4, 57} , { 14, 39} , { 4, 51} , { 13, 68} } + }, + //----- model 1 ----- + { + { { -13, 103} , { -13, 91} , { -9, 89} , { -14, 92} , { -8, 76} , { -12, 87} , { -23, 110} , { -24, 105} , { -10, 78} , { -20, 112} , { -17, 99} , { -78, 127} , { -70, 127} , { -50, 127} , { -46, 127} }, + { CTX_UNUSED , { -4, 66} , { -5, 78} , { -4, 71} , { -8, 72} , { 2, 59} , { -1, 55} , { -7, 70} , { -6, 75} , { -8, 89} , { -34, 119} , { -3, 75} , { 32, 20} , { 30, 22} , { -44, 127} }, + { { -5, 85} , { -6, 81} , { -10, 77} , { -7, 81} , { -17, 80} , { -18, 73} , { -4, 74} , { -10, 83} , { -9, 71} , { -9, 67} , { -1, 61} , { -8, 66} , { -14, 66} , { 0, 59} , { 2, 59} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 0, 54} , { -5, 61} , { 0, 58} , { -1, 60} , { -3, 61} , { -8, 67} , { -25, 84} , { -14, 74} , { -5, 65} , { 5, 52} , { 2, 57} , { 0, 61} , { -9, 69} , { -11, 70} , { 18, 55} }, + { { -4, 71} , { 0, 58} , { 7, 61} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 9, 41} , { 18, 25} , { 9, 32} , { 5, 43} , { 9, 47} , { 0, 44} , { 0, 51} , { 2, 46} , { 19, 38} , { -4, 66} , { 15, 38} , { 12, 42} , { 9, 34} , { 0, 89} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -13, 103} , { -13, 91} , { -9, 89} , { -14, 92} , { -8, 76} , { -12, 87} , { -23, 110} , { -24, 105} , { -10, 78} , { -20, 112} , { -17, 99} , { -78, 127} , { -70, 127} , { -50, 127} , { -46, 127} }, + { CTX_UNUSED , { -4, 66} , { -5, 78} , { -4, 71} , { -8, 72} , { 2, 59} , { -1, 55} , { -7, 70} , { -6, 75} , { -8, 89} , { -34, 119} , { -3, 75} , { 32, 20} , { 30, 22} , { -44, 127} }, + { { -5, 85} , { -6, 81} , { -10, 77} , { -7, 81} , { -17, 80} , { -18, 73} , { -4, 74} , { -10, 83} , { -9, 71} , { -9, 67} , { -1, 61} , { -8, 66} , { -14, 66} , { 0, 59} , { 2, 59} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 0, 54} , { -5, 61} , { 0, 58} , { -1, 60} , { -3, 61} , { -8, 67} , { -25, 84} , { -14, 74} , { -5, 65} , { 5, 52} , { 2, 57} , { 0, 61} , { -9, 69} , { -11, 70} , { 18, 55} }, + //Cr in the 4:4:4 common mode + { { -13, 103} , { -13, 91} , { -9, 89} , { -14, 92} , { -8, 76} , { -12, 87} , { -23, 110} , { -24, 105} , { -10, 78} , { -20, 112} , { -17, 99} , { -78, 127} , { -70, 127} , { -50, 127} , { -46, 127} }, + { CTX_UNUSED , { -4, 66} , { -5, 78} , { -4, 71} , { -8, 72} , { 2, 59} , { -1, 55} , { -7, 70} , { -6, 75} , { -8, 89} , { -34, 119} , { -3, 75} , { 32, 20} , { 30, 22} , { -44, 127} }, + { { -5, 85} , { -6, 81} , { -10, 77} , { -7, 81} , { -17, 80} , { -18, 73} , { -4, 74} , { -10, 83} , { -9, 71} , { -9, 67} , { -1, 61} , { -8, 66} , { -14, 66} , { 0, 59} , { 2, 59} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 0, 54} , { -5, 61} , { 0, 58} , { -1, 60} , { -3, 61} , { -8, 67} , { -25, 84} , { -14, 74} , { -5, 65} , { 5, 52} , { 2, 57} , { 0, 61} , { -9, 69} , { -11, 70} , { 18, 55} } + }, + //----- model 2 ----- + { + { { -4, 86} , { -12, 88} , { -5, 82} , { -3, 72} , { -4, 67} , { -8, 72} , { -16, 89} , { -9, 69} , { -1, 59} , { 5, 66} , { 4, 57} , { -4, 71} , { -2, 71} , { 2, 58} , { -1, 74} }, + { CTX_UNUSED , { -4, 44} , { -1, 69} , { 0, 62} , { -7, 51} , { -4, 47} , { -6, 42} , { -3, 41} , { -6, 53} , { 8, 76} , { -9, 78} , { -11, 83} , { 9, 52} , { 0, 67} , { -5, 90} }, + { { -3, 78} , { -8, 74} , { -9, 72} , { -10, 72} , { -18, 75} , { -12, 71} , { -11, 63} , { -5, 70} , { -17, 75} , { -14, 72} , { -16, 67} , { -8, 53} , { -14, 59} , { -9, 52} , { -11, 68} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 67} , { -15, 72} , { -5, 75} , { -8, 80} , { -21, 83} , { -21, 64} , { -13, 31} , { -25, 64} , { -29, 94} , { 9, 75} , { 17, 63} , { -8, 74} , { -5, 35} , { -2, 27} , { 13, 91} }, + { { 3, 65} , { -7, 69} , { 8, 77} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { -10, 66} , { 3, 62} , { -3, 68} , { -20, 81} , { 0, 30} , { 1, 7} , { -3, 23} , { -21, 74} , { 16, 66} , { -23, 124} , { 17, 37} , { 44, -18} , { 50, -34} , { -22, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -4, 86} , { -12, 88} , { -5, 82} , { -3, 72} , { -4, 67} , { -8, 72} , { -16, 89} , { -9, 69} , { -1, 59} , { 5, 66} , { 4, 57} , { -4, 71} , { -2, 71} , { 2, 58} , { -1, 74} }, + { CTX_UNUSED , { -4, 44} , { -1, 69} , { 0, 62} , { -7, 51} , { -4, 47} , { -6, 42} , { -3, 41} , { -6, 53} , { 8, 76} , { -9, 78} , { -11, 83} , { 9, 52} , { 0, 67} , { -5, 90} }, + { { -3, 78} , { -8, 74} , { -9, 72} , { -10, 72} , { -18, 75} , { -12, 71} , { -11, 63} , { -5, 70} , { -17, 75} , { -14, 72} , { -16, 67} , { -8, 53} , { -14, 59} , { -9, 52} , { -11, 68} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 67} , { -15, 72} , { -5, 75} , { -8, 80} , { -21, 83} , { -21, 64} , { -13, 31} , { -25, 64} , { -29, 94} , { 9, 75} , { 17, 63} , { -8, 74} , { -5, 35} , { -2, 27} , { 13, 91} }, + //Cr in the 4:4:4 common mode + { { -4, 86} , { -12, 88} , { -5, 82} , { -3, 72} , { -4, 67} , { -8, 72} , { -16, 89} , { -9, 69} , { -1, 59} , { 5, 66} , { 4, 57} , { -4, 71} , { -2, 71} , { 2, 58} , { -1, 74} }, + { CTX_UNUSED , { -4, 44} , { -1, 69} , { 0, 62} , { -7, 51} , { -4, 47} , { -6, 42} , { -3, 41} , { -6, 53} , { 8, 76} , { -9, 78} , { -11, 83} , { 9, 52} , { 0, 67} , { -5, 90} }, + { { -3, 78} , { -8, 74} , { -9, 72} , { -10, 72} , { -18, 75} , { -12, 71} , { -11, 63} , { -5, 70} , { -17, 75} , { -14, 72} , { -16, 67} , { -8, 53} , { -14, 59} , { -9, 52} , { -11, 68} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 67} , { -15, 72} , { -5, 75} , { -8, 80} , { -21, 83} , { -21, 64} , { -13, 31} , { -25, 64} , { -29, 94} , { 9, 75} , { 17, 63} , { -8, 74} , { -5, 35} , { -2, 27} , { 13, 91} } + } +}; + +static const char INIT_LAST_I[1][22][15][2] = +{ + //----- model 0 ----- + { + { { 24, 0} , { 15, 9} , { 8, 25} , { 13, 18} , { 15, 9} , { 13, 19} , { 10, 37} , { 12, 18} , { 6, 29} , { 20, 33} , { 15, 30} , { 4, 45} , { 1, 58} , { 0, 62} , { 7, 61} }, + { CTX_UNUSED , { 12, 38} , { 11, 45} , { 15, 39} , { 11, 42} , { 13, 44} , { 16, 45} , { 12, 41} , { 10, 49} , { 30, 34} , { 18, 42} , { 10, 55} , { 17, 51} , { 17, 46} , { 0, 89} }, + { { 23, -13} , { 26, -13} , { 40, -15} , { 49, -14} , { 44, 3} , { 45, 6} , { 44, 34} , { 33, 54} , { 19, 82} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 26, -19} , { 22, -17} , { 26, -17} , { 30, -25} , { 28, -20} , { 33, -23} , { 37, -27} , { 33, -23} , { 40, -28} , { 38, -17} , { 33, -11} , { 40, -15} , { 41, -6} , { 38, 1} , { 41, 17} }, + { { 30, -6} , { 27, 3} , { 26, 22} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 37, -16} , { 35, -4} , { 38, -8} , { 38, -3} , { 37, 3} , { 38, 5} , { 42, 0} , { 35, 16} , { 39, 22} , { 14, 48} , { 27, 37} , { 21, 60} , { 12, 68} , { 2, 97} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { 24, 0} , { 15, 9} , { 8, 25} , { 13, 18} , { 15, 9} , { 13, 19} , { 10, 37} , { 12, 18} , { 6, 29} , { 20, 33} , { 15, 30} , { 4, 45} , { 1, 58} , { 0, 62} , { 7, 61} }, + { CTX_UNUSED , { 12, 38} , { 11, 45} , { 15, 39} , { 11, 42} , { 13, 44} , { 16, 45} , { 12, 41} , { 10, 49} , { 30, 34} , { 18, 42} , { 10, 55} , { 17, 51} , { 17, 46} , { 0, 89} }, + { { 23, -13} , { 26, -13} , { 40, -15} , { 49, -14} , { 44, 3} , { 45, 6} , { 44, 34} , { 33, 54} , { 19, 82} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 26, -19} , { 22, -17} , { 26, -17} , { 30, -25} , { 28, -20} , { 33, -23} , { 37, -27} , { 33, -23} , { 40, -28} , { 38, -17} , { 33, -11} , { 40, -15} , { 41, -6} , { 38, 1} , { 41, 17} }, + //Cr in the 4:4:4 common mode + { { 24, 0} , { 15, 9} , { 8, 25} , { 13, 18} , { 15, 9} , { 13, 19} , { 10, 37} , { 12, 18} , { 6, 29} , { 20, 33} , { 15, 30} , { 4, 45} , { 1, 58} , { 0, 62} , { 7, 61} }, + { CTX_UNUSED , { 12, 38} , { 11, 45} , { 15, 39} , { 11, 42} , { 13, 44} , { 16, 45} , { 12, 41} , { 10, 49} , { 30, 34} , { 18, 42} , { 10, 55} , { 17, 51} , { 17, 46} , { 0, 89} }, + { { 23, -13} , { 26, -13} , { 40, -15} , { 49, -14} , { 44, 3} , { 45, 6} , { 44, 34} , { 33, 54} , { 19, 82} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 26, -19} , { 22, -17} , { 26, -17} , { 30, -25} , { 28, -20} , { 33, -23} , { 37, -27} , { 33, -23} , { 40, -28} , { 38, -17} , { 33, -11} , { 40, -15} , { 41, -6} , { 38, 1} , { 41, 17} } + } +}; + +static const char INIT_LAST_P[3][22][15][2] = +{ + //----- model 0 ----- + { + { { 11, 28} , { 2, 40} , { 3, 44} , { 0, 49} , { 0, 46} , { 2, 44} , { 2, 51} , { 0, 47} , { 4, 39} , { 2, 62} , { 6, 46} , { 0, 54} , { 3, 54} , { 2, 58} , { 4, 63} }, + { CTX_UNUSED , { 6, 51} , { 6, 57} , { 7, 53} , { 6, 52} , { 6, 55} , { 11, 45} , { 14, 36} , { 8, 53} , { -1, 82} , { 7, 55} , { -3, 78} , { 15, 46} , { 22, 31} , { -1, 84} }, + { { 9, -2} , { 26, -9} , { 33, -9} , { 39, -7} , { 41, -2} , { 45, 3} , { 49, 9} , { 45, 27} , { 36, 59} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 25, 7} , { 30, -7} , { 28, 3} , { 28, 4} , { 32, 0} , { 34, -1} , { 30, 6} , { 30, 6} , { 32, 9} , { 31, 19} , { 26, 27} , { 26, 30} , { 37, 20} , { 28, 34} , { 17, 70} }, + { { 1, 67} , { 5, 59} , { 9, 67} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 16, 30} , { 18, 32} , { 18, 35} , { 22, 29} , { 24, 31} , { 23, 38} , { 18, 43} , { 20, 41} , { 11, 63} , { 9, 59} , { 9, 64} , { -1, 94} , { -2, 89} , { -9, 108} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { 11, 28} , { 2, 40} , { 3, 44} , { 0, 49} , { 0, 46} , { 2, 44} , { 2, 51} , { 0, 47} , { 4, 39} , { 2, 62} , { 6, 46} , { 0, 54} , { 3, 54} , { 2, 58} , { 4, 63} }, + { CTX_UNUSED , { 6, 51} , { 6, 57} , { 7, 53} , { 6, 52} , { 6, 55} , { 11, 45} , { 14, 36} , { 8, 53} , { -1, 82} , { 7, 55} , { -3, 78} , { 15, 46} , { 22, 31} , { -1, 84} }, + { { 9, -2} , { 26, -9} , { 33, -9} , { 39, -7} , { 41, -2} , { 45, 3} , { 49, 9} , { 45, 27} , { 36, 59} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 25, 7} , { 30, -7} , { 28, 3} , { 28, 4} , { 32, 0} , { 34, -1} , { 30, 6} , { 30, 6} , { 32, 9} , { 31, 19} , { 26, 27} , { 26, 30} , { 37, 20} , { 28, 34} , { 17, 70} }, + //Cr in the 4:4:4 common mode + { { 11, 28} , { 2, 40} , { 3, 44} , { 0, 49} , { 0, 46} , { 2, 44} , { 2, 51} , { 0, 47} , { 4, 39} , { 2, 62} , { 6, 46} , { 0, 54} , { 3, 54} , { 2, 58} , { 4, 63} }, + { CTX_UNUSED , { 6, 51} , { 6, 57} , { 7, 53} , { 6, 52} , { 6, 55} , { 11, 45} , { 14, 36} , { 8, 53} , { -1, 82} , { 7, 55} , { -3, 78} , { 15, 46} , { 22, 31} , { -1, 84} }, + { { 9, -2} , { 26, -9} , { 33, -9} , { 39, -7} , { 41, -2} , { 45, 3} , { 49, 9} , { 45, 27} , { 36, 59} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 25, 7} , { 30, -7} , { 28, 3} , { 28, 4} , { 32, 0} , { 34, -1} , { 30, 6} , { 30, 6} , { 32, 9} , { 31, 19} , { 26, 27} , { 26, 30} , { 37, 20} , { 28, 34} , { 17, 70} } + }, + //----- model 1 ----- + { + { { 4, 45} , { 10, 28} , { 10, 31} , { 33, -11} , { 52, -43} , { 18, 15} , { 28, 0} , { 35, -22} , { 38, -25} , { 34, 0} , { 39, -18} , { 32, -12} , { 102, -94} , { 0, 0} , { 56, -15} }, + { CTX_UNUSED , { 33, -4} , { 29, 10} , { 37, -5} , { 51, -29} , { 39, -9} , { 52, -34} , { 69, -58} , { 67, -63} , { 44, -5} , { 32, 7} , { 55, -29} , { 32, 1} , { 0, 0} , { 27, 36} }, + { { 17, -10} , { 32, -13} , { 42, -9} , { 49, -5} , { 53, 0} , { 64, 3} , { 68, 10} , { 66, 27} , { 47, 57} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 33, -25} , { 34, -30} , { 36, -28} , { 38, -28} , { 38, -27} , { 34, -18} , { 35, -16} , { 34, -14} , { 32, -8} , { 37, -6} , { 35, 0} , { 30, 10} , { 28, 18} , { 26, 25} , { 29, 41} }, + { { 0, 75} , { 2, 72} , { 8, 77} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 14, 35} , { 18, 31} , { 17, 35} , { 21, 30} , { 17, 45} , { 20, 42} , { 18, 45} , { 27, 26} , { 16, 54} , { 7, 66} , { 16, 56} , { 11, 73} , { 10, 67} , { -10, 116} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { 4, 45} , { 10, 28} , { 10, 31} , { 33, -11} , { 52, -43} , { 18, 15} , { 28, 0} , { 35, -22} , { 38, -25} , { 34, 0} , { 39, -18} , { 32, -12} , { 102, -94} , { 0, 0} , { 56, -15} }, + { CTX_UNUSED , { 33, -4} , { 29, 10} , { 37, -5} , { 51, -29} , { 39, -9} , { 52, -34} , { 69, -58} , { 67, -63} , { 44, -5} , { 32, 7} , { 55, -29} , { 32, 1} , { 0, 0} , { 27, 36} }, + { { 17, -10} , { 32, -13} , { 42, -9} , { 49, -5} , { 53, 0} , { 64, 3} , { 68, 10} , { 66, 27} , { 47, 57} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 33, -25} , { 34, -30} , { 36, -28} , { 38, -28} , { 38, -27} , { 34, -18} , { 35, -16} , { 34, -14} , { 32, -8} , { 37, -6} , { 35, 0} , { 30, 10} , { 28, 18} , { 26, 25} , { 29, 41} }, + //Cr in the 4:4:4 common mode + { { 4, 45} , { 10, 28} , { 10, 31} , { 33, -11} , { 52, -43} , { 18, 15} , { 28, 0} , { 35, -22} , { 38, -25} , { 34, 0} , { 39, -18} , { 32, -12} , { 102, -94} , { 0, 0} , { 56, -15} }, + { CTX_UNUSED , { 33, -4} , { 29, 10} , { 37, -5} , { 51, -29} , { 39, -9} , { 52, -34} , { 69, -58} , { 67, -63} , { 44, -5} , { 32, 7} , { 55, -29} , { 32, 1} , { 0, 0} , { 27, 36} }, + { { 17, -10} , { 32, -13} , { 42, -9} , { 49, -5} , { 53, 0} , { 64, 3} , { 68, 10} , { 66, 27} , { 47, 57} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 33, -25} , { 34, -30} , { 36, -28} , { 38, -28} , { 38, -27} , { 34, -18} , { 35, -16} , { 34, -14} , { 32, -8} , { 37, -6} , { 35, 0} , { 30, 10} , { 28, 18} , { 26, 25} , { 29, 41} } + }, + //----- model 2 ----- + { + { { 4, 39} , { 0, 42} , { 7, 34} , { 11, 29} , { 8, 31} , { 6, 37} , { 7, 42} , { 3, 40} , { 8, 33} , { 13, 43} , { 13, 36} , { 4, 47} , { 3, 55} , { 2, 58} , { 6, 60} }, + { CTX_UNUSED , { 8, 44} , { 11, 44} , { 14, 42} , { 7, 48} , { 4, 56} , { 4, 52} , { 13, 37} , { 9, 49} , { 19, 58} , { 10, 48} , { 12, 45} , { 0, 69} , { 20, 33} , { 8, 63} }, + { { 9, -2} , { 30, -10} , { 31, -4} , { 33, -1} , { 33, 7} , { 31, 12} , { 37, 23} , { 31, 38} , { 20, 64} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 35, -18} , { 33, -25} , { 28, -3} , { 24, 10} , { 27, 0} , { 34, -14} , { 52, -44} , { 39, -24} , { 19, 17} , { 31, 25} , { 36, 29} , { 24, 33} , { 34, 15} , { 30, 20} , { 22, 73} }, + { { 20, 34} , { 19, 31} , { 27, 44} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 19, 16} , { 15, 36} , { 15, 36} , { 21, 28} , { 25, 21} , { 30, 20} , { 31, 12} , { 27, 16} , { 24, 42} , { 0, 93} , { 14, 56} , { 15, 57} , { 26, 38} , { -24, 127} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { 4, 39} , { 0, 42} , { 7, 34} , { 11, 29} , { 8, 31} , { 6, 37} , { 7, 42} , { 3, 40} , { 8, 33} , { 13, 43} , { 13, 36} , { 4, 47} , { 3, 55} , { 2, 58} , { 6, 60} }, + { CTX_UNUSED , { 8, 44} , { 11, 44} , { 14, 42} , { 7, 48} , { 4, 56} , { 4, 52} , { 13, 37} , { 9, 49} , { 19, 58} , { 10, 48} , { 12, 45} , { 0, 69} , { 20, 33} , { 8, 63} }, + { { 9, -2} , { 30, -10} , { 31, -4} , { 33, -1} , { 33, 7} , { 31, 12} , { 37, 23} , { 31, 38} , { 20, 64} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 35, -18} , { 33, -25} , { 28, -3} , { 24, 10} , { 27, 0} , { 34, -14} , { 52, -44} , { 39, -24} , { 19, 17} , { 31, 25} , { 36, 29} , { 24, 33} , { 34, 15} , { 30, 20} , { 22, 73} }, + //Cr in the 4:4:4 common mode + { { 4, 39} , { 0, 42} , { 7, 34} , { 11, 29} , { 8, 31} , { 6, 37} , { 7, 42} , { 3, 40} , { 8, 33} , { 13, 43} , { 13, 36} , { 4, 47} , { 3, 55} , { 2, 58} , { 6, 60} }, + { CTX_UNUSED , { 8, 44} , { 11, 44} , { 14, 42} , { 7, 48} , { 4, 56} , { 4, 52} , { 13, 37} , { 9, 49} , { 19, 58} , { 10, 48} , { 12, 45} , { 0, 69} , { 20, 33} , { 8, 63} }, + { { 9, -2} , { 30, -10} , { 31, -4} , { 33, -1} , { 33, 7} , { 31, 12} , { 37, 23} , { 31, 38} , { 20, 64} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 35, -18} , { 33, -25} , { 28, -3} , { 24, 10} , { 27, 0} , { 34, -14} , { 52, -44} , { 39, -24} , { 19, 17} , { 31, 25} , { 36, 29} , { 24, 33} , { 34, 15} , { 30, 20} , { 22, 73} } + } +}; + +static const char INIT_ONE_I[1][22][5][2] = +{ + //----- model 0 ----- + { + { { -3, 71} , { -6, 42} , { -5, 50} , { -3, 54} , { -2, 62} }, + { { -5, 67} , { -5, 27} , { -3, 39} , { -2, 44} , { 0, 46} }, + { { -3, 75} , { -1, 23} , { 1, 34} , { 1, 43} , { 0, 54} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 92} , { -15, 55} , { -10, 60} , { -6, 62} , { -4, 65} }, + { { -11, 97} , { -20, 84} , { -11, 79} , { -6, 73} , { -4, 74} }, + { { -8, 78} , { -5, 33} , { -4, 48} , { -2, 53} , { -3, 62} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -3, 71} , { -6, 42} , { -5, 50} , { -3, 54} , { -2, 62} }, + { { -5, 67} , { -5, 27} , { -3, 39} , { -2, 44} , { 0, 46} }, + { { -3, 75} , { -1, 23} , { 1, 34} , { 1, 43} , { 0, 54} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 92} , { -15, 55} , { -10, 60} , { -6, 62} , { -4, 65} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -3, 71} , { -6, 42} , { -5, 50} , { -3, 54} , { -2, 62} }, + { { -5, 67} , { -5, 27} , { -3, 39} , { -2, 44} , { 0, 46} }, + { { -3, 75} , { -1, 23} , { 1, 34} , { 1, 43} , { 0, 54} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 92} , { -15, 55} , { -10, 60} , { -6, 62} , { -4, 65} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_ONE_P[3][22][5][2] = +{ + //----- model 0 ----- + { + { { -6, 76} , { -2, 44} , { 0, 45} , { 0, 52} , { -3, 64} }, + { { -9, 77} , { 3, 24} , { 0, 42} , { 0, 48} , { 0, 55} }, + { { -6, 66} , { -7, 35} , { -7, 42} , { -8, 45} , { -5, 48} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 58} , { -3, 29} , { -1, 36} , { 1, 38} , { 2, 43} }, + { { 0, 70} , { -4, 29} , { 5, 31} , { 7, 42} , { 1, 59} }, + { { 0, 58} , { 8, 5} , { 10, 14} , { 14, 18} , { 13, 27} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -6, 76} , { -2, 44} , { 0, 45} , { 0, 52} , { -3, 64} }, + { { -9, 77} , { 3, 24} , { 0, 42} , { 0, 48} , { 0, 55} }, + { { -6, 66} , { -7, 35} , { -7, 42} , { -8, 45} , { -5, 48} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 58} , { -3, 29} , { -1, 36} , { 1, 38} , { 2, 43} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -6, 76} , { -2, 44} , { 0, 45} , { 0, 52} , { -3, 64} }, + { { -9, 77} , { 3, 24} , { 0, 42} , { 0, 48} , { 0, 55} }, + { { -6, 66} , { -7, 35} , { -7, 42} , { -8, 45} , { -5, 48} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 58} , { -3, 29} , { -1, 36} , { 1, 38} , { 2, 43} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 1 ----- + { + { { -23, 112} , { -15, 71} , { -7, 61} , { 0, 53} , { -5, 66} }, + { { -21, 101} , { -3, 39} , { -5, 53} , { -7, 61} , { -11, 75} }, + { { -5, 71} , { 0, 24} , { -1, 36} , { -2, 42} , { -2, 52} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -11, 76} , { -10, 44} , { -10, 52} , { -10, 57} , { -9, 58} }, + { { 2, 66} , { -9, 34} , { 1, 32} , { 11, 31} , { 5, 52} }, + { { 3, 52} , { 7, 4} , { 10, 8} , { 17, 8} , { 16, 19} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -23, 112} , { -15, 71} , { -7, 61} , { 0, 53} , { -5, 66} }, + { { -21, 101} , { -3, 39} , { -5, 53} , { -7, 61} , { -11, 75} }, + { { -5, 71} , { 0, 24} , { -1, 36} , { -2, 42} , { -2, 52} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -11, 76} , { -10, 44} , { -10, 52} , { -10, 57} , { -9, 58} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -23, 112} , { -15, 71} , { -7, 61} , { 0, 53} , { -5, 66} }, + { { -21, 101} , { -3, 39} , { -5, 53} , { -7, 61} , { -11, 75} }, + { { -5, 71} , { 0, 24} , { -1, 36} , { -2, 42} , { -2, 52} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -11, 76} , { -10, 44} , { -10, 52} , { -10, 57} , { -9, 58} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + }, + //----- model 2 ----- + { + { { -24, 115} , { -22, 82} , { -9, 62} , { 0, 53} , { 0, 59} }, + { { -21, 100} , { -14, 57} , { -12, 67} , { -11, 71} , { -10, 77} }, + { { -9, 71} , { -7, 37} , { -8, 44} , { -11, 49} , { -10, 56} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -10, 82} , { -8, 48} , { -8, 61} , { -8, 66} , { -7, 70} }, + { { -4, 79} , { -22, 69} , { -16, 75} , { -2, 58} , { 1, 58} }, + { { -13, 81} , { -6, 38} , { -13, 62} , { -6, 58} , { -2, 59} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -24, 115} , { -22, 82} , { -9, 62} , { 0, 53} , { 0, 59} }, + { { -21, 100} , { -14, 57} , { -12, 67} , { -11, 71} , { -10, 77} }, + { { -9, 71} , { -7, 37} , { -8, 44} , { -11, 49} , { -10, 56} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -10, 82} , { -8, 48} , { -8, 61} , { -8, 66} , { -7, 70} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -24, 115} , { -22, 82} , { -9, 62} , { 0, 53} , { 0, 59} }, + { { -21, 100} , { -14, 57} , { -12, 67} , { -11, 71} , { -10, 77} }, + { { -9, 71} , { -7, 37} , { -8, 44} , { -11, 49} , { -10, 56} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -10, 82} , { -8, 48} , { -8, 61} , { -8, 66} , { -7, 70} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_ABS_I[1][22][5][2] = +{ + //----- model 0 ----- + { + { { 0, 58} , { 1, 63} , { -2, 72} , { -1, 74} , { -9, 91} }, + { { -16, 64} , { -8, 68} , { -10, 78} , { -6, 77} , { -10, 86} }, + { { -2, 55} , { 0, 61} , { 1, 64} , { 0, 68} , { -9, 92} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 73} , { -8, 76} , { -7, 80} , { -9, 88} , { -17, 110} }, + { { -13, 86} , { -13, 96} , { -11, 97} , { -19, 117} , CTX_UNUSED }, + { { -13, 71} , { -10, 79} , { -12, 86} , { -13, 90} , { -14, 97} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { 0, 58} , { 1, 63} , { -2, 72} , { -1, 74} , { -9, 91} }, + { { -16, 64} , { -8, 68} , { -10, 78} , { -6, 77} , { -10, 86} }, + { { -2, 55} , { 0, 61} , { 1, 64} , { 0, 68} , { -9, 92} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 73} , { -8, 76} , { -7, 80} , { -9, 88} , { -17, 110} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { 0, 58} , { 1, 63} , { -2, 72} , { -1, 74} , { -9, 91} }, + { { -16, 64} , { -8, 68} , { -10, 78} , { -6, 77} , { -10, 86} }, + { { -2, 55} , { 0, 61} , { 1, 64} , { 0, 68} , { -9, 92} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 73} , { -8, 76} , { -7, 80} , { -9, 88} , { -17, 110} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + +static const char INIT_ABS_P[3][22][5][2] = +{ + //----- model 0 ----- + { + { { -2, 59} , { -4, 70} , { -4, 75} , { -8, 82} , { -17, 102} }, + { { -6, 59} , { -7, 71} , { -12, 83} , { -11, 87} , { -30, 119} }, + { { -12, 56} , { -6, 60} , { -5, 62} , { -8, 66} , { -8, 76} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -6, 55} , { 0, 58} , { 0, 64} , { -3, 74} , { -10, 90} }, + { { -2, 58} , { -3, 72} , { -3, 81} , { -11, 97} , CTX_UNUSED }, + { { 2, 40} , { 0, 58} , { -3, 70} , { -6, 79} , { -8, 85} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -2, 59} , { -4, 70} , { -4, 75} , { -8, 82} , { -17, 102} }, + { { -6, 59} , { -7, 71} , { -12, 83} , { -11, 87} , { -30, 119} }, + { { -12, 56} , { -6, 60} , { -5, 62} , { -8, 66} , { -8, 76} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -6, 55} , { 0, 58} , { 0, 64} , { -3, 74} , { -10, 90} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -2, 59} , { -4, 70} , { -4, 75} , { -8, 82} , { -17, 102} }, + { { -6, 59} , { -7, 71} , { -12, 83} , { -11, 87} , { -30, 119} }, + { { -12, 56} , { -6, 60} , { -5, 62} , { -8, 66} , { -8, 76} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -6, 55} , { 0, 58} , { 0, 64} , { -3, 74} , { -10, 90} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + }, + //----- model 1 ----- + { + { { -11, 77} , { -9, 80} , { -9, 84} , { -10, 87} , { -34, 127} }, + { { -15, 77} , { -17, 91} , { -25, 107} , { -25, 111} , { -28, 122} }, + { { -9, 57} , { -6, 63} , { -4, 65} , { -4, 67} , { -7, 82} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -16, 72} , { -7, 69} , { -4, 69} , { -5, 74} , { -9, 86} }, + { { -2, 55} , { -2, 67} , { 0, 73} , { -8, 89} , CTX_UNUSED }, + { { 3, 37} , { -1, 61} , { -5, 73} , { -1, 70} , { -4, 78} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -11, 77} , { -9, 80} , { -9, 84} , { -10, 87} , { -34, 127} }, + { { -15, 77} , { -17, 91} , { -25, 107} , { -25, 111} , { -28, 122} }, + { { -9, 57} , { -6, 63} , { -4, 65} , { -4, 67} , { -7, 82} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -16, 72} , { -7, 69} , { -4, 69} , { -5, 74} , { -9, 86} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -11, 77} , { -9, 80} , { -9, 84} , { -10, 87} , { -34, 127} }, + { { -15, 77} , { -17, 91} , { -25, 107} , { -25, 111} , { -28, 122} }, + { { -9, 57} , { -6, 63} , { -4, 65} , { -4, 67} , { -7, 82} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -16, 72} , { -7, 69} , { -4, 69} , { -5, 74} , { -9, 86} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + }, + //----- model 2 ----- + { + { { -14, 85} , { -13, 89} , { -13, 94} , { -11, 92} , { -29, 127} }, + { { -21, 85} , { -16, 88} , { -23, 104} , { -15, 98} , { -37, 127} }, + { { -12, 59} , { -8, 63} , { -9, 67} , { -6, 68} , { -10, 79} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -14, 75} , { -10, 79} , { -9, 83} , { -12, 92} , { -18, 108} }, + { { -13, 78} , { -9, 83} , { -4, 81} , { -13, 99} , CTX_UNUSED }, + { { -16, 73} , { -10, 76} , { -13, 86} , { -9, 83} , { -10, 87} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cb in the 4:4:4 common mode + { { -14, 85} , { -13, 89} , { -13, 94} , { -11, 92} , { -29, 127} }, + { { -21, 85} , { -16, 88} , { -23, 104} , { -15, 98} , { -37, 127} }, + { { -12, 59} , { -8, 63} , { -9, 67} , { -6, 68} , { -10, 79} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -14, 75} , { -10, 79} , { -9, 83} , { -12, 92} , { -18, 108} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + //Cr in the 4:4:4 common mode + { { -14, 85} , { -13, 89} , { -13, 94} , { -11, 92} , { -29, 127} }, + { { -21, 85} , { -16, 88} , { -23, 104} , { -15, 98} , { -37, 127} }, + { { -12, 59} , { -8, 63} , { -9, 67} , { -6, 68} , { -10, 79} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -14, 75} , { -10, 79} , { -9, 83} , { -12, 92} , { -18, 108} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED } + } +}; + + + +#if ENABLE_FIELD_CTX +static const char INIT_FLD_MAP_I[1][8][15][2] = +{ + //----- model 0 ----- + { + { { -6, 93} , { -6, 84} , { -8, 79} , { 0, 66} , { -1, 71} , { 0, 62} , { -2, 60} , { -2, 59} , { -5, 75} , { -3, 62} , { -4, 58} , { -9, 66} , { -1, 79} , { 0, 71} , { 3, 68} }, + { CTX_UNUSED , { 10, 44} , { -7, 62} , { 15, 36} , { 14, 40} , { 16, 27} , { 12, 29} , { 1, 44} , { 20, 36} , { 18, 32} , { 5, 42} , { 1, 48} , { 10, 62} , { 17, 46} , { 9, 64} }, + { { -14, 106} , { -13, 97} , { -15, 90} , { -12, 90} , { -18, 88} , { -10, 73} , { -9, 79} , { -14, 86} , { -10, 73} , { -10, 70} , { -10, 69} , { -5, 66} , { -9, 64} , { -5, 58} , { 2, 59} }, +// { { -1, 73} , { -7, 73} , { -6, 76} , { -7, 71} , { -9, 72} , { -5, 65} , { -14, 83} , { -8, 72} , { -10, 75} , { -5, 64} , { -4, 59} , { -13, 79} , { -9, 69} , { -8, 66} , { 3, 55} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -12, 104} , { -11, 97} , { -16, 96} , { -7, 88} , { -8, 85} , { -7, 85} , { -9, 85} , { -13, 88} , { 4, 66} , { -3, 77} , { -3, 76} , { -6, 76} , { 10, 58} , { -1, 76} , { -1, 83} }, + { { -7, 99} , { -14, 95} , { 2, 95} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 0, 76} , { -5, 74} , { 0, 70} , { -11, 75} , { 1, 68} , { 0, 65} , { -14, 73} , { 3, 62} , { 4, 62} , { -1, 68} , { -13, 75} , { 11, 55} , { 5, 64} , { 12, 70} } + } +}; + +static const char INIT_FLD_MAP_P[3][8][15][2] = +{ + //----- model 0 ----- + { + { { -13, 106} , { -16, 106} , { -10, 87} , { -21, 114} , { -18, 110} , { -14, 98} , { -22, 110} , { -21, 106} , { -18, 103} , { -21, 107} , { -23, 108} , { -26, 112} , { -10, 96} , { -12, 95} , { -5, 91} }, + { CTX_UNUSED , { -9, 93} , { -22, 94} , { -5, 86} , { 9, 67} , { -4, 80} , { -10, 85} , { -1, 70} , { 7, 60} , { 9, 58} , { 5, 61} , { 12, 50} , { 15, 50} , { 18, 49} , { 17, 54} }, + { { -5, 85} , { -6, 81} , { -10, 77} , { -7, 81} , { -17, 80} , { -18, 73} , { -4, 74} , { -10, 83} , { -9, 71} , { -9, 67} , { -1, 61} , { -8, 66} , { -14, 66} , { 0, 59} , { 2, 59} }, +// { { -4, 60} , { -3, 49} , { -2, 50} , { -4, 49} , { -5, 48} , { -2, 46} , { -7, 54} , { -1, 45} , { -4, 49} , { 4, 39} , { 0, 42} , { 2, 43} , { 0, 44} , { 5, 32} , { 15, 30} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 10, 41} , { 7, 46} , { -1, 51} , { 7, 49} , { 8, 52} , { 9, 41} , { 6, 47} , { 2, 55} , { 13, 41} , { 10, 44} , { 6, 50} , { 5, 53} , { 13, 49} , { 4, 63} , { 6, 64} }, + { { -2, 69} , { -2, 59} , { 6, 70} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 10, 44} , { 9, 31} , { 12, 43} , { 3, 53} , { 14, 34} , { 10, 38} , { -3, 52} , { 13, 40} , { 17, 32} , { 7, 44} , { 7, 38} , { 13, 50} , { 10, 57} , { 26, 43} } + }, + //----- model 1 ----- + { + { { -21, 126} , { -23, 124} , { -20, 110} , { -26, 126} , { -25, 124} , { -17, 105} , { -27, 121} , { -27, 117} , { -17, 102} , { -26, 117} , { -27, 116} , { -33, 122} , { -10, 95} , { -14, 100} , { -8, 95} }, + { CTX_UNUSED , { -17, 111} , { -28, 114} , { -6, 89} , { -2, 80} , { -4, 82} , { -9, 85} , { -8, 81} , { -1, 72} , { 5, 64} , { 1, 67} , { 9, 56} , { 0, 69} , { 1, 69} , { 7, 69} }, + { { -3, 81} , { -3, 76} , { -7, 72} , { -6, 78} , { -12, 72} , { -14, 68} , { -3, 70} , { -6, 76} , { -5, 66} , { -5, 62} , { 0, 57} , { -4, 61} , { -9, 60} , { 1, 54} , { 2, 58} }, +// { { -4, 60} , { -3, 49} , { -2, 50} , { -4, 49} , { -5, 48} , { -2, 46} , { -7, 54} , { -1, 45} , { -4, 49} , { 4, 39} , { 0, 42} , { 2, 43} , { 0, 44} , { 5, 32} , { 15, 30} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { -7, 69} , { -6, 67} , { -16, 77} , { -2, 64} , { 2, 61} , { -6, 67} , { -3, 64} , { 2, 57} , { -3, 65} , { -3, 66} , { 0, 62} , { 9, 51} , { -1, 66} , { -2, 71} , { -2, 75} }, + { { -1, 70} , { -9, 72} , { 14, 60} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 16, 37} , { 0, 47} , { 18, 35} , { 11, 37} , { 12, 41} , { 10, 41} , { 2, 48} , { 12, 41} , { 13, 41} , { 0, 59} , { 3, 50} , { 19, 40} , { 3, 66} , { 18, 50} } + }, + //----- model 2 ----- + { + { { -22, 127} , { -25, 127} , { -25, 120} , { -27, 127} , { -19, 114} , { -23, 117} , { -25, 118} , { -26, 117} , { -24, 113} , { -28, 118} , { -31, 120} , { -37, 124} , { -10, 94} , { -15, 102} , { -10, 99} }, + { CTX_UNUSED , { -13, 106} , { -50, 127} , { -5, 92} , { 17, 57} , { -5, 86} , { -13, 94} , { -12, 91} , { -2, 77} , { 0, 71} , { -1, 73} , { 4, 64} , { -7, 81} , { 5, 64} , { 15, 57} }, + { { -3, 78} , { -8, 74} , { -9, 72} , { -10, 72} , { -18, 75} , { -12, 71} , { -11, 63} , { -5, 70} , { -17, 75} , { -14, 72} , { -16, 67} , { -8, 53} , { -14, 59} , { -9, 52} , { -11, 68} }, +// { { -4, 60} , { -3, 49} , { -2, 50} , { -4, 49} , { -5, 48} , { -2, 46} , { -7, 54} , { -1, 45} , { -4, 49} , { 4, 39} , { 0, 42} , { 2, 43} , { 0, 44} , { 5, 32} , { 15, 30} }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 1, 67} , { 0, 68} , { -10, 67} , { 1, 68} , { 0, 77} , { 2, 64} , { 0, 68} , { -5, 78} , { 7, 55} , { 5, 59} , { 2, 65} , { 14, 54} , { 15, 44} , { 5, 60} , { 2, 70} }, + { { -2, 76} , { -18, 86} , { 12, 70} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 5, 64} , { -12, 70} , { 11, 55} , { 5, 56} , { 0, 69} , { 2, 65} , { -6, 74} , { 5, 54} , { 7, 54} , { -6, 76} , { -11, 82} , { -2, 77} , { -2, 77} , { 25, 42} } + } +}; + +static const char INIT_FLD_LAST_I[1][8][15][2] = +{ + //----- model 0 ----- + { + { { 15, 6} , { 6, 19} , { 7, 16} , { 12, 14} , { 18, 13} , { 13, 11} , { 13, 15} , { 15, 16} , { 12, 23} , { 13, 23} , { 15, 20} , { 14, 26} , { 14, 44} , { 17, 40} , { 17, 47} }, + { CTX_UNUSED , { 24, 17} , { 21, 21} , { 25, 22} , { 31, 27} , { 22, 29} , { 19, 35} , { 14, 50} , { 10, 57} , { 7, 63} , { -2, 77} , { -4, 82} , { -3, 94} , { 9, 69} , { -12, 109} }, + { { 21, -10} , { 24, -11} , { 28, -8} , { 28, -1} , { 29, 3} , { 29, 9} , { 35, 20} , { 29, 36} , { 14, 67} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, +// { { 12, 33} , { 5, 38} , { 9, 34} , { 18, 22} , { 19, 22} , { 23, 19} , { 26, 16} , { 14, 44} , { 40, 14} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 36, -35} , { 36, -34} , { 32, -26} , { 37, -30} , { 44, -32} , { 34, -18} , { 34, -15} , { 40, -15} , { 33, -7} , { 35, -5} , { 33, 0} , { 38, 2} , { 33, 13} , { 23, 35} , { 13, 58} }, + { { 29, -3} , { 26, 0} , { 22, 30} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 31, -7} , { 35, -15} , { 34, -3} , { 34, 3} , { 36, -1} , { 34, 5} , { 32, 11} , { 35, 5} , { 34, 12} , { 39, 11} , { 30, 29} , { 34, 26} , { 29, 39} , { 19, 66} } + } +}; + +static const char INIT_FLD_LAST_P[3][8][15][2] = +{ + //----- model 0 ----- + { + { { 14, 11} , { 11, 14} , { 9, 11} , { 18, 11} , { 21, 9} , { 23, -2} , { 32, -15} , { 32, -15} , { 34, -21} , { 39, -23} , { 42, -33} , { 41, -31} , { 46, -28} , { 38, -12} , { 21, 29} }, + { CTX_UNUSED , { 45, -24} , { 53, -45} , { 48, -26} , { 65, -43} , { 43, -19} , { 39, -10} , { 30, 9} , { 18, 26} , { 20, 27} , { 0, 57} , { -14, 82} , { -5, 75} , { -19, 97} , { -35, 125} }, + { { 21, -13} , { 33, -14} , { 39, -7} , { 46, -2} , { 51, 2} , { 60, 6} , { 61, 17} , { 55, 34} , { 42, 62} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, +// { { 17, 27} , { 23, 13} , { 24, 16} , { 22, 25} , { 23, 27} , { 23, 32} , { 17, 43} , { 17, 49} , { 2, 70} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 27, 0} , { 28, 0} , { 31, -4} , { 27, 6} , { 34, 8} , { 30, 10} , { 24, 22} , { 33, 19} , { 22, 32} , { 26, 31} , { 21, 41} , { 26, 44} , { 23, 47} , { 16, 65} , { 14, 71} }, + { { 8, 60} , { 6, 63} , { 17, 65} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 21, 24} , { 23, 20} , { 26, 23} , { 27, 32} , { 28, 23} , { 28, 24} , { 23, 40} , { 24, 32} , { 28, 29} , { 23, 42} , { 19, 57} , { 22, 53} , { 22, 61} , { 11, 86} } + }, + //----- model 1 ----- + { + { { 19, -6} , { 18, -6} , { 14, 0} , { 26, -12} , { 31, -16} , { 33, -25} , { 33, -22} , { 37, -28} , { 39, -30} , { 42, -30} , { 47, -42} , { 45, -36} , { 49, -34} , { 41, -17} , { 32, 9} }, + { CTX_UNUSED , { 69, -71} , { 63, -63} , { 66, -64} , { 77, -74} , { 54, -39} , { 52, -35} , { 41, -10} , { 36, 0} , { 40, -1} , { 30, 14} , { 28, 26} , { 23, 37} , { 12, 55} , { 11, 65} }, + { { 17, -10} , { 32, -13} , { 42, -9} , { 49, -5} , { 53, 0} , { 64, 3} , { 68, 10} , { 66, 27} , { 47, 57} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, +// { { 17, 27} , { 23, 13} , { 24, 16} , { 22, 25} , { 23, 27} , { 23, 32} , { 17, 43} , { 17, 49} , { 2, 70} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 37, -33} , { 39, -36} , { 40, -37} , { 38, -30} , { 46, -33} , { 42, -30} , { 40, -24} , { 49, -29} , { 38, -12} , { 40, -10} , { 38, -3} , { 46, -5} , { 31, 20} , { 29, 30} , { 25, 44} }, + { { 12, 48} , { 11, 49} , { 26, 45} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 22, 22} , { 23, 22} , { 27, 21} , { 33, 20} , { 26, 28} , { 30, 24} , { 27, 34} , { 18, 42} , { 25, 39} , { 18, 50} , { 12, 70} , { 21, 54} , { 14, 71} , { 11, 83} } + }, + //----- model 2 ----- + { + { { 17, -13} , { 16, -9} , { 17, -12} , { 27, -21} , { 37, -30} , { 41, -40} , { 42, -41} , { 48, -47} , { 39, -32} , { 46, -40} , { 52, -51} , { 46, -41} , { 52, -39} , { 43, -19} , { 32, 11} }, + { CTX_UNUSED , { 61, -55} , { 56, -46} , { 62, -50} , { 81, -67} , { 45, -20} , { 35, -2} , { 28, 15} , { 34, 1} , { 39, 1} , { 30, 17} , { 20, 38} , { 18, 45} , { 15, 54} , { 0, 79} }, + { { 9, -2} , { 30, -10} , { 31, -4} , { 33, -1} , { 33, 7} , { 31, 12} , { 37, 23} , { 31, 38} , { 20, 64} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, +// { { 17, 27} , { 23, 13} , { 24, 16} , { 22, 25} , { 23, 27} , { 23, 32} , { 17, 43} , { 17, 49} , { 2, 70} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { { 36, -16} , { 37, -14} , { 37, -17} , { 32, 1} , { 34, 15} , { 29, 15} , { 24, 25} , { 34, 22} , { 31, 16} , { 35, 18} , { 31, 28} , { 33, 41} , { 36, 28} , { 27, 47} , { 21, 62} }, + { { 18, 31} , { 19, 26} , { 36, 24} , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED , CTX_UNUSED }, + { CTX_UNUSED , { 24, 23} , { 27, 16} , { 24, 30} , { 31, 29} , { 22, 41} , { 22, 42} , { 16, 60} , { 15, 52} , { 14, 60} , { 3, 78} , { -16, 123} , { 21, 53} , { 22, 56} , { 25, 61} } + } +}; +#endif + + +#endif + diff --git a/lcommon/inc/distortion.h b/lcommon/inc/distortion.h new file mode 100644 index 0000000..dccf196 --- /dev/null +++ b/lcommon/inc/distortion.h @@ -0,0 +1,31 @@ +/*! + ************************************************************************** + * \file distortion.h + * \brief + * Distortion data header file + * \date 2.23.2009, + * + * \author + * Alexis Michael Tourapis + * + ************************************************************************** + */ + +#ifndef _DISTORTION_H_ +#define _DISTORTION_H_ + +// Distortion data structure. Could be extended in the future to support +// other data +typedef struct distortion_data +{ + int i4x4rd[4][4]; //! i4x4 rd cost + distblk i4x4 [4][4]; //! i4x4 cost + distblk i8x8 [2][2]; //! i8x8 cost + int i8x8rd[2][2]; //! i8x8 rd cost + int i16x16; + int i16x16rd; + double rd_cost; +} DistortionData; + +#endif + diff --git a/lcommon/inc/enc_statistics.h b/lcommon/inc/enc_statistics.h new file mode 100644 index 0000000..40befe6 --- /dev/null +++ b/lcommon/inc/enc_statistics.h @@ -0,0 +1,70 @@ +/*! + ************************************************************************** + * \file enc_statistics.h + * + * \brief + * statistics reports for the encoding process. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Tourapis + * - Karsten Suehring + * + ************************************************************************** + */ + +#ifndef _ENC_STATISTICS_H_ +#define _ENC_STATISTICS_H_ +#include "global.h" + +struct stat_parameters +{ + float bitrate; //!< average bit rate for the sequence except first frame + int64 bit_ctr; //!< counter for bit usage + int64 bit_ctr_n; //!< bit usage for the current frame + int64 bit_ctr_emulation_prevention; //!< stored bits needed to prevent start code emulation + int bit_slice; //!< number of bits in current slice + int stored_bit_slice; //!< keep number of bits in current slice (to restore status in case of MB re-encoding) + int b8_mode_0_use [NUM_SLICE_TYPES][2]; + int64 mode_use_transform[NUM_SLICE_TYPES][MAXMODE][2]; + int64 intra_chroma_mode[4]; + + // B pictures + int NumberBFrames; + + int frame_counter; + int64 quant [NUM_SLICE_TYPES]; + int64 num_macroblocks [NUM_SLICE_TYPES]; + int frame_ctr [NUM_SLICE_TYPES]; + int64 bit_counter [NUM_SLICE_TYPES]; + float bitrate_st [NUM_SLICE_TYPES]; + int64 mode_use [NUM_SLICE_TYPES][MAXMODE]; //!< Macroblock mode usage for Intra frames + int64 bit_use_mode [NUM_SLICE_TYPES][MAXMODE]; //!< statistics of bit usage + int64 bit_use_mb_type [NUM_SLICE_TYPES]; + int64 bit_use_header [NUM_SLICE_TYPES]; + int64 tmp_bit_use_cbp [NUM_SLICE_TYPES]; + int64 bit_use_coeffC [NUM_SLICE_TYPES]; + int64 bit_use_coeff [3][NUM_SLICE_TYPES]; + int64 bit_use_delta_quant [NUM_SLICE_TYPES]; + int64 bit_use_stuffing_bits[NUM_SLICE_TYPES]; + + int bit_ctr_parametersets; + int bit_ctr_parametersets_n; + int64 bit_ctr_filler_data; + int64 bit_ctr_filler_data_n; + +#if (MVC_EXTENSION_ENABLE) + float bitrate_v[2]; //!< average bit rate for the sequence except first frame + int64 bit_ctr_v[2]; //!< counter for bit usage + int64 bit_ctr_n_v[2]; //!< bit usage for the current frame + int64 bit_ctr_emulationprevention_v[2]; //!< stored bits needed to prevent start code emulation + int64 bit_counter_v[2][NUM_SLICE_TYPES]; + int bit_ctr_parametersets_v[2]; + int bit_ctr_parametersets_n_v[2]; + int64 bit_ctr_filler_data_v[2]; + int64 bit_ctr_filler_data_n_v[2]; +#endif +}; +typedef struct stat_parameters StatParameters; + +#endif diff --git a/lcommon/inc/fast_memory.h b/lcommon/inc/fast_memory.h new file mode 100644 index 0000000..f2b921e --- /dev/null +++ b/lcommon/inc/fast_memory.h @@ -0,0 +1,37 @@ +/*! + ************************************************************************** + * \file fast_memory.h + * + * \brief + * Memory handling operations + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Chris Vogt + * + ************************************************************************** + */ + +#ifndef _FAST_MEMORY_H_ +#define _FAST_MEMORY_H_ + +#include "typedefs.h" + + +static inline void fast_memset(void *dst,int value,int width) +{ + memset(dst,value,width); +} + +static inline void fast_memcpy(void *dst,void *src,int width) +{ + memcpy(dst,src,width); +} + +static inline void fast_memset_zero(void *dst, int width) +{ + memset(dst,0,width); +} + +#endif + diff --git a/lcommon/inc/frame.h b/lcommon/inc/frame.h new file mode 100644 index 0000000..9a48bf6 --- /dev/null +++ b/lcommon/inc/frame.h @@ -0,0 +1,66 @@ +/*! + ************************************************************************ + * \file frame.h + * + * \brief + * headers for frame format related information + * + * \author + * + ************************************************************************ + */ +#ifndef _FRAME_H_ +#define _FRAME_H_ + +typedef enum { + CM_UNKNOWN = -1, + CM_YUV = 0, + CM_RGB = 1, + CM_XYZ = 2 +} ColorModel; + +typedef enum { + CF_UNKNOWN = -1, //!< Unknown color format + YUV400 = 0, //!< Monochrome + YUV420 = 1, //!< 4:2:0 + YUV422 = 2, //!< 4:2:2 + YUV444 = 3 //!< 4:4:4 +} ColorFormat; + +typedef enum { + PF_UNKNOWN = -1, //!< Unknown color ordering + UYVY = 0, //!< UYVY + YUY2 = 1, //!< YUY2 + YUYV = 1, //!< YUYV + YVYU = 2, //!< YVYU + BGR = 3, //!< BGR + V210 = 4 //!< Video Clarity 422 format (10 bits) +} PixelFormat; + + +typedef struct frame_format +{ + ColorFormat yuv_format; //!< YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) + ColorModel color_model; //!< 4:4:4 format (0: YUV, 1: RGB, 2: XYZ) + PixelFormat pixel_format; //!< pixel format support for certain interleaved yuv sources + double frame_rate; //!< frame rate + int width[3]; //!< component frame width + int height[3]; //!< component frame height + int auto_crop_right; //!< luma component auto crop right + int auto_crop_bottom; //!< luma component auto crop bottom + int auto_crop_right_cr; //!< chroma component auto crop right + int auto_crop_bottom_cr; //!< chroma component auto crop bottom + int width_crop; //!< width after cropping consideration + int height_crop; //!< height after cropping consideration + int mb_width; //!< luma component frame width + int mb_height; //!< luma component frame height + int size_cmp[3]; //!< component sizes (width * height) + int size; //!< total image size (sum of size_cmp) + int bit_depth[3]; //!< component bit depth + int max_value[3]; //!< component max value + int max_value_sq[3]; //!< component max value squared + int pic_unit_size_on_disk; //!< picture sample unit size on storage medium + int pic_unit_size_shift3; //!< pic_unit_size_on_disk >> 3 +} FrameFormat; + +#endif diff --git a/lcommon/inc/ifunctions.h b/lcommon/inc/ifunctions.h new file mode 100644 index 0000000..74e7c36 --- /dev/null +++ b/lcommon/inc/ifunctions.h @@ -0,0 +1,448 @@ + +/*! + ************************************************************************ + * \file + * ifunctions.h + * + * \brief + * define some inline functions that are used within the encoder. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Tourapis + * + ************************************************************************ + */ + +#ifndef _IFUNCTIONS_H_ +#define _IFUNCTIONS_H_ + +# if !(defined(WIN32) || defined(WIN64)) && (__STDC_VERSION__ < 199901L) +#define static +#define inline +#endif +#include +#include + + +static inline short smin(short a, short b) +{ + return (short) (((a) < (b)) ? (a) : (b)); +} + +static inline short smax(short a, short b) +{ + return (short) (((a) > (b)) ? (a) : (b)); +} + +static inline int imin(int a, int b) +{ + return ((a) < (b)) ? (a) : (b); +} + +static inline int imin3(int a, int b, int c) +{ + return ((a) < (b)) ? imin(a, c) : imin(b, c); +} + +static inline int imax(int a, int b) +{ + return ((a) > (b)) ? (a) : (b); +} + +static inline int imedian(int a,int b,int c) +{ + if (a > b) // a > b + { + if (b > c) + return(b); // a > b > c + else if (a > c) + return(c); // a > c > b + else + return(a); // c > a > b + } + else // b > a + { + if (a > c) + return(a); // b > a > c + else if (b > c) + return(c); // b > c > a + else + return(b); // c > b > a + } +} + +static inline int imedian_old(int a, int b, int c) +{ + return (a + b + c - imin(a, imin(b, c)) - imax(a, imax(b ,c))); +} + +static inline double dmin(double a, double b) +{ + return ((a) < (b)) ? (a) : (b); +} + +static inline double dmax(double a, double b) +{ + return ((a) > (b)) ? (a) : (b); +} + +static inline int64 i64min(int64 a, int64 b) +{ + return ((a) < (b)) ? (a) : (b); +} + +static inline int64 i64max(int64 a, int64 b) +{ + return ((a) > (b)) ? (a) : (b); +} + +static inline distblk distblkmin(distblk a, distblk b) +{ + return ((a) < (b)) ? (a) : (b); +} + +static inline distblk distblkmax(distblk a, distblk b) +{ + return ((a) > (b)) ? (a) : (b); +} + +static inline short sabs(short x) +{ + static const short SHORT_BITS = (sizeof(short) * CHAR_BIT) - 1; + short y = (short) (x >> SHORT_BITS); + return (short) ((x ^ y) - y); +} + +static inline int iabs(int x) +{ + static const int INT_BITS = (sizeof(int) * CHAR_BIT) - 1; + int y = x >> INT_BITS; + return (x ^ y) - y; +} + +static inline double dabs(double x) +{ + return ((x) < 0) ? -(x) : (x); +} + +static inline int64 i64abs(int64 x) +{ + static const int64 INT64_BITS = (sizeof(int64) * CHAR_BIT) - 1; + int64 y = x >> INT64_BITS; + return (x ^ y) - y; +} + +static inline double dabs2(double x) +{ + return (x) * (x); +} + +static inline int iabs2(int x) +{ + return (x) * (x); +} + +static inline int64 i64abs2(int64 x) +{ + return (x) * (x); +} + +static inline int isign(int x) +{ + return ( (x > 0) - (x < 0)); +} + +static inline int isignab(int a, int b) +{ + return ((b) < 0) ? -iabs(a) : iabs(a); +} + +static inline int rshift_rnd(int x, int a) +{ + return (a > 0) ? ((x + (1 << (a-1) )) >> a) : (x << (-a)); +} + +static inline int rshift_rnd_sign(int x, int a) +{ + return (x > 0) ? ( ( x + (1 << (a-1)) ) >> a ) : (-( ( iabs(x) + (1 << (a-1)) ) >> a )); +} + +static inline unsigned int rshift_rnd_us(unsigned int x, unsigned int a) +{ + return (a > 0) ? ((x + (1 << (a-1))) >> a) : x; +} + +static inline int rshift_rnd_sf(int x, int a) +{ + return ((x + (1 << (a-1) )) >> a); +} + +static inline int shift_off_sf(int x, int o, int a) +{ + return ((x + o) >> a); +} + +static inline unsigned int rshift_rnd_us_sf(unsigned int x, unsigned int a) +{ + return ((x + (1 << (a-1))) >> a); +} + +static inline int iClip1(int high, int x) +{ + x = imax(x, 0); + x = imin(x, high); + + return x; +} + +static inline int iClip3(int low, int high, int x) +{ + x = imax(x, low); + x = imin(x, high); + + return x; +} + +static inline short sClip3(short low, short high, short x) +{ + x = smax(x, low); + x = smin(x, high); + + return x; +} + +static inline double dClip3(double low, double high, double x) +{ + x = dmax(x, low); + x = dmin(x, high); + + return x; +} + + +//! Edited by Joao Carreira +static inline double abs_ivec( int x, int y) +{ + return sqrt( iabs2(x) + iabs2(y) ); +} +static inline double abs_dvec( double x, double y) +{ + return sqrt( dabs2(x) + dabs2(y) ); +} +static inline int i_min_max( int n, int min, int max) +{ + return imin( imax( min, n ) , max); +} + +static inline unsigned int ui_min_position( unsigned int *vector, unsigned int n_elem, int *min_value, int *min_pos) +{ + unsigned int i, aux_min_value = vector[0], aux_min_pos = 0; + if(min_pos) *min_pos = 0; + for(i=1;i aux_value )//MAX + { + aux_value = vector[i]; + aux_pos = i; + if( aux_value == 0 ) + break; + } + } + if(pos) *pos = aux_pos; + if(value) *value = aux_value; + return aux_pos; +} + + + + + + +static inline distblk weighted_cost(int factor, int bits) +{ +#if JCOST_CALC_SCALEUP + return (((distblk)(factor))*((distblk)(bits))); +#else +#if (USE_RND_COST) + return (rshift_rnd_sf((lambda) * (bits), LAMBDA_ACCURACY_BITS)); +#else + return (((factor)*(bits))>>LAMBDA_ACCURACY_BITS); +#endif +#endif +} + +static inline int RSD(int x) +{ + return ((x&2)?(x|1):(x&(~1))); +} + +static inline int power2(int x) +{ + return 1 << (x); +} + + +static const int64 po2[64] = {0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000,0x8000, + 0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000,0x800000,0x1000000,0x2000000,0x4000000,0x8000000, + 0x10000000,0x20000000,0x40000000,0x80000000,0x100000000,0x200000000,0x400000000,0x800000000, + 0x1000000000,0x2000000000,0x4000000000,0x8000000000,0x10000000000,0x20000000000,0x40000000000,0x80000000000, + 0x100000000000,0x200000000000,0x400000000000,0x800000000000, + 0x1000000000000,0x2000000000000,0x4000000000000,0x8000000000000, + 0x10000000000000,0x20000000000000,0x40000000000000,0x80000000000000, + 0x100000000000000,0x200000000000000,0x400000000000000,0x800000000000000, + 0x1000000000000000,0x2000000000000000,0x4000000000000000,0x8000000000000000}; + +static inline int64 i64_power2(int x) +{ + return((x > 63) ? 0 : po2[x]); +} + +static inline int float2int (float x) +{ + return (int)((x < 0) ? (x - 0.5f) : (x + 0.5f)); +} + +static inline int get_bit(int64 x,int n) +{ + return (int)(((x >> n) & 1)); +} + +#if ZEROSNR +static inline float psnr(int max_sample_sq, int samples, float sse_distortion ) +{ + return (float) (10.0 * log10(max_sample_sq * (double) ((double) samples / (sse_distortion < 1.0 ? 1.0 : sse_distortion)))); +} +#else +static inline float psnr(int max_sample_sq, int samples, float sse_distortion ) +{ + return (float) (sse_distortion == 0.0 ? 0.0 : (10.0 * log10(max_sample_sq * (double) ((double) samples / sse_distortion)))); +} +#endif + +static inline int CheckCost_Shift(int64 mcost, int64 min_mcost) +{ + if((mcost<= min_mcost) + return 1; + else + return 0; +} + +static inline int CheckCost(int64 mcost, int64 min_mcost) +{ + return ((mcost) >= (min_mcost)); +} + +static inline void down_scale(distblk *pblkdistCost) +{ +#if JCOST_CALC_SCALEUP + *pblkdistCost = (*pblkdistCost)>>LAMBDA_ACCURACY_BITS; +#endif +} + +static inline void up_scale(distblk *pblkdistCost) +{ +#if JCOST_CALC_SCALEUP + *pblkdistCost = (*pblkdistCost)<>LAMBDA_ACCURACY_BITS)); +#else + return ((int)blkdistCost); +#endif +} + +/*! + ************************************************************************ + * \brief + * calculate RoundLog2(uiVal) + ************************************************************************ + */ +static inline int RoundLog2 (int iValue) +{ + int iRet = 0; + int iValue_square = iValue * iValue; + while ((1 << (iRet + 1)) <= iValue_square) + ++iRet; + + iRet = (iRet + 1) >> 1; + return iRet; +} + +static inline void free_pointer(void *pointer) +{ + if (pointer != NULL) + { + free(pointer); + pointer = NULL; + } +} + +static inline void i32_swap(int x, int y) +{ + int temp = x; + x = y; + y = temp; +} + +# if !(defined(WIN32) || defined(WIN64)) && (__STDC_VERSION__ < 199901L) +#undef static +#undef inline +#endif + +#endif + diff --git a/lcommon/inc/img_io.h b/lcommon/inc/img_io.h new file mode 100644 index 0000000..2c910f0 --- /dev/null +++ b/lcommon/inc/img_io.h @@ -0,0 +1,30 @@ +/*! + ************************************************************************************* + * \file img_io.h + * + * \brief + * image I/O related functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ +#include "global.h" + +#ifndef _IMG_IO_H_ +#define _IMG_IO_H_ + +#include "io_video.h" +#include "io_raw.h" +#include "io_tiff.h" + +extern int ParseSizeFromString (VideoDataFile *input_file, int *xlen, int *ylen, double *fps); +extern void ParseFrameNoFormatFromString (VideoDataFile *input_file); +extern void OpenFrameFile (VideoDataFile *input_file, int FrameNumberInFile); +extern void OpenFiles (VideoDataFile *input_file); +extern void CloseFiles (VideoDataFile *input_file); +extern VideoFileType ParseVideoType (VideoDataFile *input_file); + +#endif + diff --git a/lcommon/inc/img_process.h b/lcommon/inc/img_process.h new file mode 100644 index 0000000..e351e03 --- /dev/null +++ b/lcommon/inc/img_process.h @@ -0,0 +1,25 @@ +/*! + ************************************************************************ + * \file img_process.h + * + * \brief + * Input data Image Processing functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************ + */ + +#ifndef _IMG_PROCESS_H_ +#define _IMG_PROCESS_H_ + + +extern int init_process_image ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void clear_process_image( VideoParameters *p_Vid, InputParameters *p_Inp); +extern void process_image ( VideoParameters *p_Vid, InputParameters *p_Inp ); + + + +#endif diff --git a/lcommon/inc/img_process_types.h b/lcommon/inc/img_process_types.h new file mode 100644 index 0000000..431aa7c --- /dev/null +++ b/lcommon/inc/img_process_types.h @@ -0,0 +1,24 @@ +/*! + ************************************************************************ + * \file img_process_types.h + * + * \brief + * Input data Image Processing Types + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Athanasios Leontaris + * - Yuwen He + ************************************************************************ + */ + +#ifndef _IMG_PROCESS_TYPES_H_ +#define _IMG_PROCESS_TYPES_H_ + +#define DEMUX_META_DEBUG 1 +#define MAX_NUM_PARTITIONS 512 +#define NUM_VIEWS 2 +#define NUM_COMPONENTS 3 + +#endif diff --git a/lcommon/inc/input.h b/lcommon/inc/input.h new file mode 100644 index 0000000..3ad6e6e --- /dev/null +++ b/lcommon/inc/input.h @@ -0,0 +1,25 @@ +/*! + ************************************************************************ + * \file input.h + * + * \brief + * Input related definitions + * + * \author + * + ************************************************************************ + */ + +#ifndef _INPUT_H_ +#define _INPUT_H_ + +extern int testEndian(void); +extern void initInput(VideoParameters *p_Vid, FrameFormat *source, FrameFormat *output); +extern void AllocateFrameMemory (VideoParameters *p_Vid, InputParameters *p_Inp, FrameFormat *source); +extern void DeleteFrameMemory (VideoParameters *p_Vid); + +extern int read_one_frame (VideoParameters *p_Vid, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, FrameFormat *output, imgpel **pImage[3]); +extern void pad_borders ( FrameFormat output, int img_size_x, int img_size_y, int img_size_x_cr, int img_size_y_cr, imgpel **pImage[3]); + +#endif + diff --git a/lcommon/inc/io_image.h b/lcommon/inc/io_image.h new file mode 100644 index 0000000..910fd68 --- /dev/null +++ b/lcommon/inc/io_image.h @@ -0,0 +1,45 @@ +/*! + ************************************************************************ + * \file io_image.h + * + * \brief + * Image I/O + * + * \author + * - Alexis Michael Tourapis + * + ************************************************************************ + */ + +#ifndef _IO_IMAGE_H_ +#define _IO_IMAGE_H_ + +#include "defines.h" +#include "frame.h" + +typedef struct image_data +{ + FrameFormat format; //!< image format + // Standard data + imgpel **frm_data[MAX_PLANE]; //!< Frame Data + imgpel **top_data[MAX_PLANE]; //!< pointers to top field data + imgpel **bot_data[MAX_PLANE]; //!< pointers to bottom field data + + imgpel **frm_data_buf[2][MAX_PLANE]; //!< Frame Data + imgpel **top_data_buf[2][MAX_PLANE]; //!< pointers to top field data + imgpel **bot_data_buf[2][MAX_PLANE]; //!< pointers to bottom field data + + //! Optional data (could also add uint8 data in case imgpel is of type uint16) + //! These can be useful for enabling input/conversion of content of different types + //! while keeping optimal processing size. + uint16 **frm_uint16[MAX_PLANE]; //!< optional frame Data for uint16 + uint16 **top_uint16[MAX_PLANE]; //!< optional pointers to top field data + uint16 **bot_uint16[MAX_PLANE]; //!< optional pointers to bottom field data + + int frm_stride[MAX_PLANE]; + int top_stride[MAX_PLANE]; + int bot_stride[MAX_PLANE]; +} ImageData; + +#endif + diff --git a/lcommon/inc/io_raw.h b/lcommon/inc/io_raw.h new file mode 100644 index 0000000..91ffa0e --- /dev/null +++ b/lcommon/inc/io_raw.h @@ -0,0 +1,22 @@ + +/*! + ************************************************************************ + * \file io_raw.h + * + * \brief + * I/O functions related to raw images + * + * \author + * - Alexis Michael Tourapis + * + ************************************************************************ + */ + +#ifndef _IO_RAW_H_ +#define _IO_RAW_H_ + +extern int ReadFrameConcatenated (InputParameters *p_Inp, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, unsigned char *buf); +extern int ReadFrameSeparate (InputParameters *p_Inp, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, unsigned char *buf); + +#endif + diff --git a/lcommon/inc/io_tiff.h b/lcommon/inc/io_tiff.h new file mode 100644 index 0000000..c6cd9b0 --- /dev/null +++ b/lcommon/inc/io_tiff.h @@ -0,0 +1,24 @@ +/*! +************************************************************************ +* \file io_tiff.h +* +* \brief +* I/O functions related to tiff images +* Part of code was based on libtiff (see http://www.libtiff.org/) +* +* \author +* - Larry Luther +* - Alexis Michael Tourapis +* +************************************************************************ +*/ + +#ifndef _IO_TIFF_H_ +#define _IO_TIFF_H_ +// See TIFF 6.0 Specification +// http://partners.adobe.com/public/developer/tiff/index.html + + +extern int ReadTIFFImage (InputParameters *p_Inp, VideoDataFile *input_file, int FrameNoInFile, FrameFormat *source, unsigned char *buf); + +#endif diff --git a/lcommon/inc/io_video.h b/lcommon/inc/io_video.h new file mode 100644 index 0000000..4275944 --- /dev/null +++ b/lcommon/inc/io_video.h @@ -0,0 +1,63 @@ +/*! + ************************************************************************ + * \file io_video.h + * + * \brief + * Video I/O + * + * \author + * - Alexis Michael Tourapis + * + ************************************************************************ + */ + +#ifndef _IO_VIDEO_H_ +#define _IO_VIDEO_H_ + +#include "frame.h" + +typedef struct video_size { + char* name; + int x_size; + int y_size; +} VIDEO_SIZE; + +typedef enum { + VIDEO_UNKNOWN = -1, + VIDEO_YUV = 0, + VIDEO_RGB = 1, + VIDEO_XYZ = 2, + VIDEO_TIFF = 3, + VIDEO_AVI = 4 +} VideoFileType; + +typedef struct video_data_file +{ + //char* fname; //!< video file name + char fname[FILE_NAME_SIZE]; //!< video file name + char fhead[FILE_NAME_SIZE]; //!< header of video file + char ftail[FILE_NAME_SIZE]; //!< tail of video file + int f_num; //!< video file number + VideoFileType vdtype; //!< File format + FrameFormat format; //!< video format information + int is_concatenated; //!< Single or multifile input? + int is_interleaved; //!< Support for interleaved and non-interleaved input sources + int zero_pad; //!< Used when separate image files are used as input. Enables zero padding for file numbering + int num_digits; //!< Number of digits for file numbering + int start_frame; //!< start frame + int end_frame; //!< end frame + int nframes; //!< number of frames + int crop_x_size; //!< crop information (x component) + int crop_y_size; //!< crop information (y component) + int crop_x_offset; //!< crop offset (x component); + int crop_y_offset; //!< crop offset (y component); + + // AVI related information to be added here + int* avi; + //avi_t* avi; + //int header; + //char compressor[8]; +} VideoDataFile; + +#endif + diff --git a/lcommon/inc/lagrangian.h b/lcommon/inc/lagrangian.h new file mode 100644 index 0000000..abd742e --- /dev/null +++ b/lcommon/inc/lagrangian.h @@ -0,0 +1,25 @@ +/*! + ************************************************************************** + * \file lagrangian.h + * \brief + * Distortion data header file + * \date 2.23.2009, + * + * \author + * Alexis Michael Tourapis + * + ************************************************************************** + */ + +#ifndef _LAGRANGIAN_H_ +#define _LAGRANGIAN_H_ + +typedef struct lambda_params +{ + double md; //!< Mode decision Lambda + double me[3]; //!< Motion Estimation Lambda + int mf[3]; //!< Integer formatted Motion Estimation Lambda +} LambdaParams; + +#endif + diff --git a/lcommon/inc/mb_access.h b/lcommon/inc/mb_access.h new file mode 100644 index 0000000..8cc7601 --- /dev/null +++ b/lcommon/inc/mb_access.h @@ -0,0 +1,33 @@ + +/*! + ************************************************************************************* + * \file mb_access.h + * + * \brief + * Functions for macroblock neighborhoods + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#ifndef _MB_ACCESS_H_ +#define _MB_ACCESS_H_ + +extern void CheckAvailabilityOfNeighbors(Macroblock *currMB); +extern void CheckAvailabilityOfNeighborsMBAFF(Macroblock *currMB); +extern void CheckAvailabilityOfNeighborsNormal(Macroblock *currMB); + +extern void getAffNeighbour (Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix); +extern void getNonAffNeighbour (Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix); +extern void get4x4Neighbour (Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix); +extern void get4x4NeighbourBase (Macroblock *currMB, int block_x, int block_y, int mb_size[2], PixelPos *pix); +extern Boolean mb_is_available (int mbAddr, Macroblock *currMB); +extern void get_mb_pos (VideoParameters *p_Vid, int mb_addr, int mb_size[2], short *x, short *y); +extern void get_mb_block_pos_normal (BlockPos *PicPos, int mb_addr, short *x, short *y); +extern void get_mb_block_pos_mbaff (BlockPos *PicPos, int mb_addr, short *x, short *y); + + +#endif diff --git a/lcommon/inc/mbuffer_common.h b/lcommon/inc/mbuffer_common.h new file mode 100644 index 0000000..5c546cf --- /dev/null +++ b/lcommon/inc/mbuffer_common.h @@ -0,0 +1,225 @@ +/*! +*********************************************************************** +* \file +* mbuffer_common.h +* +* \brief +* Frame buffer functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Karsten Suehring +* - Alexis Michael Tourapis +* - Yuwen He +*********************************************************************** +*/ +#ifndef _MBUFFER_COMMON_H_ +#define _MBUFFER_COMMON_H_ + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by picture number for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_pic_by_pic_num_desc( const void *arg1, const void *arg2 ) +{ + int pic_num1 = (*(StorablePicture**)arg1)->pic_num; + int pic_num2 = (*(StorablePicture**)arg2)->pic_num; + + if (pic_num1 < pic_num2) + return 1; + if (pic_num1 > pic_num2) + return -1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by picture number for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_pic_by_lt_pic_num_asc( const void *arg1, const void *arg2 ) +{ + int long_term_pic_num1 = (*(StorablePicture**)arg1)->long_term_pic_num; + int long_term_pic_num2 = (*(StorablePicture**)arg2)->long_term_pic_num; + + if ( long_term_pic_num1 < long_term_pic_num2) + return -1; + if ( long_term_pic_num1 > long_term_pic_num2) + return 1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * compares two frame stores by pic_num for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_fs_by_frame_num_desc( const void *arg1, const void *arg2 ) +{ + int frame_num_wrap1 = (*(FrameStore**)arg1)->frame_num_wrap; + int frame_num_wrap2 = (*(FrameStore**)arg2)->frame_num_wrap; + if ( frame_num_wrap1 < frame_num_wrap2) + return 1; + if ( frame_num_wrap1 > frame_num_wrap2) + return -1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two frame stores by lt_pic_num for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_fs_by_lt_pic_idx_asc( const void *arg1, const void *arg2 ) +{ + int long_term_frame_idx1 = (*(FrameStore**)arg1)->long_term_frame_idx; + int long_term_frame_idx2 = (*(FrameStore**)arg2)->long_term_frame_idx; + + if ( long_term_frame_idx1 < long_term_frame_idx2) + return -1; + else if ( long_term_frame_idx1 > long_term_frame_idx2) + return 1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by poc for qsort in ascending order + * + ************************************************************************ + */ +static inline int compare_pic_by_poc_asc( const void *arg1, const void *arg2 ) +{ + int poc1 = (*(StorablePicture**)arg1)->poc; + int poc2 = (*(StorablePicture**)arg2)->poc; + + if ( poc1 < poc2) + return -1; + else if ( poc1 > poc2) + return 1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two stored pictures by poc for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_pic_by_poc_desc( const void *arg1, const void *arg2 ) +{ + int poc1 = (*(StorablePicture**)arg1)->poc; + int poc2 = (*(StorablePicture**)arg2)->poc; + + if (poc1 < poc2) + return 1; + else if (poc1 > poc2) + return -1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two frame stores by poc for qsort in ascending order + * + ************************************************************************ + */ +static inline int compare_fs_by_poc_asc( const void *arg1, const void *arg2 ) +{ + int poc1 = (*(FrameStore**)arg1)->poc; + int poc2 = (*(FrameStore**)arg2)->poc; + + if (poc1 < poc2) + return -1; + else if (poc1 > poc2) + return 1; + else + return 0; +} + + +/*! + ************************************************************************ + * \brief + * compares two frame stores by poc for qsort in descending order + * + ************************************************************************ + */ +static inline int compare_fs_by_poc_desc( const void *arg1, const void *arg2 ) +{ + int poc1 = (*(FrameStore**)arg1)->poc; + int poc2 = (*(FrameStore**)arg2)->poc; + + if (poc1 < poc2) + return 1; + else if (poc1 > poc2) + return -1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * returns true, if picture is short term reference picture + * + ************************************************************************ + */ +static inline int is_short_ref(StorablePicture *s) +{ + return ((s->used_for_reference) && (!(s->is_long_term))); +} + + +/*! + ************************************************************************ + * \brief + * returns true, if picture is long term reference picture + * + ************************************************************************ + */ +static inline int is_long_ref(StorablePicture *s) +{ + return ((s->used_for_reference) && (s->is_long_term)); +} + + +extern void gen_pic_list_from_frame_list(PictureStructure currStructure, FrameStore **fs_list, int list_idx, StorablePicture **list, char *list_size, int long_term); +extern StorablePicture* get_long_term_pic(Slice *currSlice, DecodedPictureBuffer *p_Dpb, int LongtermPicNum); +extern void update_ref_list(DecodedPictureBuffer *p_Dpb); +extern void update_ltref_list(DecodedPictureBuffer *p_Dpb); +extern void mm_mark_current_picture_long_term(DecodedPictureBuffer *p_Dpb, StorablePicture *p, int long_term_frame_idx); +extern void mm_unmark_short_term_for_reference(DecodedPictureBuffer *p_Dpb, StorablePicture *p, int difference_of_pic_nums_minus1); +extern void mm_unmark_long_term_for_reference(DecodedPictureBuffer *p_Dpb, StorablePicture *p, int long_term_pic_num); +extern void mm_assign_long_term_frame_idx(DecodedPictureBuffer *p_Dpb, StorablePicture* p, int difference_of_pic_nums_minus1, int long_term_frame_idx); +extern void mm_update_max_long_term_frame_idx(DecodedPictureBuffer *p_Dpb, int max_long_term_frame_idx_plus1); +extern void mm_unmark_all_short_term_for_reference (DecodedPictureBuffer *p_Dpb); +extern void mm_unmark_all_long_term_for_reference (DecodedPictureBuffer *p_Dpb); +extern int is_used_for_reference (FrameStore* fs); +extern void get_smallest_poc(DecodedPictureBuffer *p_Dpb, int *poc,int * pos); +extern int remove_unused_frame_from_dpb(DecodedPictureBuffer *p_Dpb); + +#endif + diff --git a/lcommon/inc/memalloc.h b/lcommon/inc/memalloc.h new file mode 100644 index 0000000..f2ce1c7 --- /dev/null +++ b/lcommon/inc/memalloc.h @@ -0,0 +1,217 @@ +/*! + ************************************************************************ + * \file memalloc.h + * + * \brief + * Memory allocation and free helper funtions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + * - Yuwen He + * + ************************************************************************ + */ + +#ifndef _MEMALLOC_H_ +#define _MEMALLOC_H_ + +#include "global.h" +#include "mbuffer.h" +#include "distortion.h" +#include "lagrangian.h" +#include "quant_params.h" + +extern int get_mem2Ddist(DistortionData ***array2D, int dim0, int dim1); + +extern int get_mem2Dlm (LambdaParams ***array2D, int dim0, int dim1); +extern int get_mem2Dolm (LambdaParams ***array2D, int dim0, int dim1, int offset); + +extern int get_mem2Dmp (PicMotionParams ***array2D, int dim0, int dim1); +extern int get_mem3Dmp (PicMotionParams ****array3D, int dim0, int dim1, int dim2); + +extern int get_mem2Dquant(LevelQuantParams ***array2D, int dim0, int dim1); +extern int get_mem3Dquant(LevelQuantParams ****array3D, int dim0, int dim1, int dim2); +extern int get_mem4Dquant(LevelQuantParams *****array4D, int dim0, int dim1, int dim2, int dim3); +extern int get_mem5Dquant(LevelQuantParams ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4); + +extern int get_mem2Dmv (MotionVector ***array2D, int dim0, int dim1); +extern int get_mem3Dmv (MotionVector ****array3D, int dim0, int dim1, int dim2); +extern int get_mem4Dmv (MotionVector *****array4D, int dim0, int dim1, int dim2, int dim3); +extern int get_mem5Dmv (MotionVector ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4); +extern int get_mem6Dmv (MotionVector *******array6D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5); +extern int get_mem7Dmv (MotionVector ********array7D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5, int dim6); + +extern byte** new_mem2D(int dim0, int dim1); +extern int get_mem2D(byte ***array2D, int dim0, int dim1); +extern int get_mem3D(byte ****array3D, int dim0, int dim1, int dim2); +extern int get_mem4D(byte *****array4D, int dim0, int dim1, int dim2, int dim3); + +extern int** new_mem2Dint(int dim0, int dim1); +extern int get_mem2Dint(int ***array2D, int dim0, int dim1); +extern int get_mem2Dint_pad(int ***array2D, int dim0, int dim1, int iPadY, int iPadX); +extern int get_mem2Dint64(int64 ***array2D, int dim0, int dim1); +extern int get_mem3Dint(int ****array3D, int dim0, int dim1, int dim2); +extern int get_mem3Dint64(int64 ****array3D, int dim0, int dim1, int dim2); +extern int get_mem4Dint(int *****array4D, int dim0, int dim1, int dim2, int dim3); +extern int get_mem4Dint64(int64 *****array4D, int dim0, int dim1, int dim2, int dim3); +extern int get_mem5Dint(int ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4); + +extern uint16** new_mem2Duint16(int dim0, int dim1); +extern int get_mem2Duint16(uint16 ***array2D, int dim0, int dim1); +extern int get_mem3Duint16(uint16 ****array3D,int dim0, int dim1, int dim2); + +extern int get_mem2Ddistblk(distblk ***array2D, int dim0, int dim1); +extern int get_mem3Ddistblk(distblk ****array3D, int dim0, int dim1, int dim2); +extern int get_mem4Ddistblk(distblk *****array4D, int dim0, int dim1, int dim2, int dim3); + +extern int get_mem2Dshort(short ***array2D, int dim0, int dim1); +extern int get_mem3Dshort(short ****array3D, int dim0, int dim1, int dim2); +extern int get_mem4Dshort(short *****array4D, int dim0, int dim1, int dim2, int dim3); +extern int get_mem5Dshort(short ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4); +extern int get_mem6Dshort(short *******array6D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5); +extern int get_mem7Dshort(short ********array7D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5, int dim6); + +extern int get_mem1Dpel(imgpel **array2D, int dim0); +extern int get_mem2Dpel(imgpel ***array2D, int dim0, int dim1); +extern int get_mem2Dpel_pad(imgpel ***array2D, int dim0, int dim1, int iPadY, int iPadX); + +extern int get_mem3Dpel (imgpel ****array3D, int dim0, int dim1, int dim2); +extern int get_mem3Dpel_pad(imgpel ****array3D, int dim0, int dim1, int dim2, int iPadY, int iPadX); +extern int get_mem4Dpel (imgpel *****array4D, int dim0, int dim1, int dim2, int dim3); +extern int get_mem4Dpel_pad(imgpel *****array4D, int dim0, int dim1, int dim2, int dim3, int iPadY, int iPadX); +extern int get_mem5Dpel (imgpel ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4); +extern int get_mem5Dpel_pad(imgpel ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4, int iPadY, int iPadX); +extern int get_mem2Ddouble (double ***array2D, int dim0, int dim1); + +extern int get_mem1Dodouble(double **array1D, int dim0, int offset); +extern int get_mem2Dodouble(double ***array2D, int dim0, int dim1, int offset); +extern int get_mem3Dodouble(double ****array2D, int dim0, int dim1, int dim2, int offset); + +extern int get_mem2Doint (int ***array2D, int dim0, int dim1, int offset); +extern int get_mem3Doint (int ****array3D, int dim0, int dim1, int dim2, int offset); + +extern int get_mem2Dwp (WPParams ***array2D, int dim0, int dim1); + +extern int get_offset_mem2Dshort(short ***array2D, int rows, int columns, int offset_y, int offset_x); + +extern void free_offset_mem2Dshort(short **array2D, int columns, int offset_x, int offset_y); + +extern void free_mem2Ddist (DistortionData **array2D); + +extern void free_mem2Dlm (LambdaParams **array2D); +extern void free_mem2Dolm (LambdaParams **array2D, int offset); + +extern void free_mem2Dmp (PicMotionParams **array2D); +extern void free_mem3Dmp (PicMotionParams ***array2D); + +extern void free_mem2Dquant(LevelQuantParams **array2D); +extern void free_mem3Dquant(LevelQuantParams ***array2D); +extern void free_mem4Dquant(LevelQuantParams ****array2D); +extern void free_mem5Dquant(LevelQuantParams *****array2D); + +extern void free_mem2Dmv (MotionVector **array2D); +extern void free_mem3Dmv (MotionVector ***array2D); +extern void free_mem4Dmv (MotionVector ****array2D); +extern void free_mem5Dmv (MotionVector *****array2D); +extern void free_mem6Dmv (MotionVector ******array2D); +extern void free_mem7Dmv (MotionVector *******array7D); + +extern int get_mem2D_spp(StorablePicturePtr ***array3D, int dim0, int dim1); +extern int get_mem3D_spp(StorablePicturePtr ****array3D, int dim0, int dim1, int dim2); + +extern void free_mem2D_spp (StorablePicturePtr **array2D); +extern void free_mem3D_spp (StorablePicturePtr ***array2D); + +extern void free_mem2D (byte **array2D); +extern void free_mem3D (byte ***array3D); +extern void free_mem4D (byte ****array4D); + +extern void free_mem2Dint (int **array2D); +extern void free_mem2Dint_pad(int **array2D, int iPadY, int iPadX); +extern void free_mem3Dint (int ***array3D); +extern void free_mem4Dint (int ****array4D); +extern void free_mem5Dint (int *****array5D); + +extern void free_mem2Duint16(uint16 **array2D); +extern void free_mem3Duint16(uint16 ***array3D); + +extern void free_mem2Dint64(int64 **array2D); +extern void free_mem3Dint64(int64 ***array3D); +extern void free_mem4Dint64(int64 ****array4D); + +extern void free_mem2Ddistblk(distblk **array2D); +extern void free_mem3Ddistblk(distblk ***array3D); +extern void free_mem4Ddistblk(distblk ****array4D); + +extern void free_mem2Dshort(short **array2D); +extern void free_mem3Dshort(short ***array3D); +extern void free_mem4Dshort(short ****array4D); +extern void free_mem5Dshort(short *****array5D); +extern void free_mem6Dshort(short ******array6D); +extern void free_mem7Dshort(short *******array7D); + +extern void free_mem1Dpel (imgpel *array1D); +extern void free_mem2Dpel (imgpel **array2D); +extern void free_mem2Dpel_pad(imgpel **array2D, int iPadY, int iPadX); +extern void free_mem3Dpel (imgpel ***array3D); +extern void free_mem3Dpel_pad(imgpel ***array3D, int iDim12, int iPadY, int iPadX); +extern void free_mem4Dpel (imgpel ****array4D); +extern void free_mem4Dpel_pad(imgpel ****array4D, int iFrames, int iPadY, int iPadX); +extern void free_mem5Dpel (imgpel *****array5D); +extern void free_mem5Dpel_pad(imgpel *****array5D, int iFrames, int iPadY, int iPadX); +extern void free_mem2Ddouble (double **array2D); +extern void free_mem3Ddouble (double ***array3D); + +extern void free_mem1Dodouble(double *array1D, int offset); +extern void free_mem2Dodouble(double **array2D, int offset); +extern void free_mem3Dodouble(double ***array3D, int rows, int columns, int offset); +extern void free_mem2Doint (int **array2D, int offset); +extern void free_mem3Doint (int ***array3D, int rows, int columns, int offset); + +extern int init_top_bot_planes(imgpel **imgFrame, int height, imgpel ***imgTopField, imgpel ***imgBotField); +extern void free_top_bot_planes(imgpel **imgTopField, imgpel **imgBotField); + +extern void free_mem2Dwp (WPParams **array2D); + +extern void copy2DImage(imgpel **dst_img, imgpel **src_img, int size_x, int size_y); +extern void no_mem_exit(char *where); +extern int malloc_mem2Dpel_2SLayers(imgpel ***buf0, int imgtype0, imgpel ***buf1, int imgtype1, int height, int width); +extern int malloc_mem3Dpel_2SLayers(imgpel ****buf0, int imgtype0, imgpel ****buf1, int imgtype1, int frames, int height, int width); + +extern void free_mem2Dpel_2SLayers(imgpel ***buf0, imgpel ***buf1); +extern void free_mem3Dpel_2SLayers(imgpel ****buf0, imgpel ****buf1); + + +static inline void* mem_malloc(size_t nitems) +{ + void *d; + if((d = malloc(nitems)) == NULL) + { + no_mem_exit("malloc failed.\n"); + return NULL; + } + return d; +} + +/*! + ************************************************************************ + * \brief + * allocate and set memory aligned at SSE_MEMORY_ALIGNMENT + * + ************************************************************************/ +static inline void* mem_calloc(size_t nitems, size_t size) +{ + size_t padded_size = nitems * size; + void *d = mem_malloc(padded_size); + memset(d, 0, (int)padded_size); + return d; +} + +static inline void mem_free(void *a) +{ + free_pointer(a); +} + +#endif \ No newline at end of file diff --git a/lcommon/inc/mv_prediction.h b/lcommon/inc/mv_prediction.h new file mode 100644 index 0000000..f57ad57 --- /dev/null +++ b/lcommon/inc/mv_prediction.h @@ -0,0 +1,19 @@ +/*! + ************************************************************************************* + * \file mv_prediction.h + * + * \brief + * Declarations for Motion Vector Prediction + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#ifndef _MV_PREDICTION_H_ +#define _MV_PREDICTION_H_ + +extern void init_motion_vector_prediction(Macroblock *currMB, int mb_aff_frame_flag); + +#endif diff --git a/lcommon/inc/nalucommon.h b/lcommon/inc/nalucommon.h new file mode 100644 index 0000000..9585b93 --- /dev/null +++ b/lcommon/inc/nalucommon.h @@ -0,0 +1,91 @@ + +/*! + ************************************************************************************** + * \file + * nalucommon.h + * \brief + * NALU handling common to encoder and decoder + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * - Karsten Suehring + *************************************************************************************** + */ + +#ifndef _NALUCOMMON_H_ +#define _NALUCOMMON_H_ + +#include "defines.h" + +#define MAXRBSPSIZE 64000 +#define MAXNALUSIZE 64000 + +//! values for nal_unit_type +typedef enum { + NALU_TYPE_SLICE = 1, + NALU_TYPE_DPA = 2, + NALU_TYPE_DPB = 3, + NALU_TYPE_DPC = 4, + NALU_TYPE_IDR = 5, + NALU_TYPE_SEI = 6, + NALU_TYPE_SPS = 7, + NALU_TYPE_PPS = 8, + NALU_TYPE_AUD = 9, + NALU_TYPE_EOSEQ = 10, + NALU_TYPE_EOSTREAM = 11, + NALU_TYPE_FILL = 12, +#if (MVC_EXTENSION_ENABLE) + NALU_TYPE_PREFIX = 14, + NALU_TYPE_SUB_SPS = 15, + NALU_TYPE_SLC_EXT = 20, + NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit +#endif +} NaluType; + +//! values for nal_ref_idc +typedef enum { + NALU_PRIORITY_HIGHEST = 3, + NALU_PRIORITY_HIGH = 2, + NALU_PRIORITY_LOW = 1, + NALU_PRIORITY_DISPOSABLE = 0 +} NalRefIdc; + +//! NAL unit structure +typedef struct nalu_t +{ + int startcodeprefix_len; //!< 4 for parameter sets and first slice in picture, 3 for everything else (suggested) + unsigned len; //!< Length of the NAL unit (Excluding the start code, which does not belong to the NALU) + unsigned max_size; //!< NAL Unit Buffer size + int forbidden_bit; //!< should be always FALSE + NaluType nal_unit_type; //!< NALU_TYPE_xxxx + NalRefIdc nal_reference_idc; //!< NALU_PRIORITY_xxxx + byte *buf; //!< contains the first byte followed by the EBSP + uint16 lost_packets; //!< true, if packet loss is detected +#if (MVC_EXTENSION_ENABLE) + int svc_extension_flag; //!< should be always 0, for MVC + int non_idr_flag; //!< 0 = current is IDR + int priority_id; //!< a lower value of priority_id specifies a higher priority + int view_id; //!< view identifier for the NAL unit + int temporal_id; //!< temporal identifier for the NAL unit + int anchor_pic_flag; //!< anchor access unit + int inter_view_flag; //!< inter-view prediction enable + int reserved_one_bit; //!< shall be equal to 1 +#endif + + //! Edited by Joao Carreira + int position; + +} NALU_t; + +//! allocate one NAL Unit +extern NALU_t *AllocNALU(int); + +//! free one NAL Unit +extern void FreeNALU(NALU_t *n); + +#if (MVC_EXTENSION_ENABLE) +extern void nal_unit_header_svc_extension(); +extern void prefix_nal_unit_svc(); +#endif + +#endif diff --git a/lcommon/inc/parsetcommon.h b/lcommon/inc/parsetcommon.h new file mode 100644 index 0000000..2f4a592 --- /dev/null +++ b/lcommon/inc/parsetcommon.h @@ -0,0 +1,274 @@ + +/*! + ************************************************************************************** + * \file + * parsetcommon.h + * \brief + * Picture and Sequence Parameter Sets, structures common to encoder and decoder + * + * \date 25 November 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + *************************************************************************************** + */ + + + +// In the MPEG-4 AVC/H.264 syntax, frequently flags are used that indicate the presence of +// certain pieces of information in the NALU. Here, these flags are also +// present. In the encoder, those bits indicate that the values signaled to +// be present are meaningful and that this part of the syntax should be +// written to the NALU. In the decoder, the flag indicates that information +// was received from the decoded NALU and should be used henceforth. +// The structure names were chosen as indicated in the MPEG-4 AVC/H.264 syntax + +#ifndef _PARSETCOMMON_H_ +#define _PARSETCOMMON_H_ + +#include "defines.h" + +#define MAXIMUMPARSETRBSPSIZE 1500 +#define MAXIMUMPARSETNALUSIZE 1500 + +#define MAXSPS 32 +#define MAXPPS 256 + +#define MAXIMUMVALUEOFcpb_cnt 32 +typedef struct +{ + unsigned int cpb_cnt_minus1; // ue(v) + unsigned int bit_rate_scale; // u(4) + unsigned int cpb_size_scale; // u(4) + unsigned int bit_rate_value_minus1 [MAXIMUMVALUEOFcpb_cnt]; // ue(v) + unsigned int cpb_size_value_minus1 [MAXIMUMVALUEOFcpb_cnt]; // ue(v) + unsigned int cbr_flag [MAXIMUMVALUEOFcpb_cnt]; // u(1) + unsigned int initial_cpb_removal_delay_length_minus1; // u(5) + unsigned int cpb_removal_delay_length_minus1; // u(5) + unsigned int dpb_output_delay_length_minus1; // u(5) + unsigned int time_offset_length; // u(5) +} hrd_parameters_t; + + +typedef struct +{ + Boolean aspect_ratio_info_present_flag; // u(1) + unsigned int aspect_ratio_idc; // u(8) + unsigned short sar_width; // u(16) + unsigned short sar_height; // u(16) + Boolean overscan_info_present_flag; // u(1) + Boolean overscan_appropriate_flag; // u(1) + Boolean video_signal_type_present_flag; // u(1) + unsigned int video_format; // u(3) + Boolean video_full_range_flag; // u(1) + Boolean colour_description_present_flag; // u(1) + unsigned int colour_primaries; // u(8) + unsigned int transfer_characteristics; // u(8) + unsigned int matrix_coefficients; // u(8) + Boolean chroma_location_info_present_flag; // u(1) + unsigned int chroma_sample_loc_type_top_field; // ue(v) + unsigned int chroma_sample_loc_type_bottom_field; // ue(v) + Boolean timing_info_present_flag; // u(1) + unsigned int num_units_in_tick; // u(32) + unsigned int time_scale; // u(32) + Boolean fixed_frame_rate_flag; // u(1) + Boolean nal_hrd_parameters_present_flag; // u(1) + hrd_parameters_t nal_hrd_parameters; // hrd_paramters_t + Boolean vcl_hrd_parameters_present_flag; // u(1) + hrd_parameters_t vcl_hrd_parameters; // hrd_paramters_t + // if ((nal_hrd_parameters_present_flag || (vcl_hrd_parameters_present_flag)) + Boolean low_delay_hrd_flag; // u(1) + Boolean pic_struct_present_flag; // u(1) + Boolean bitstream_restriction_flag; // u(1) + Boolean motion_vectors_over_pic_boundaries_flag; // u(1) + unsigned int max_bytes_per_pic_denom; // ue(v) + unsigned int max_bits_per_mb_denom; // ue(v) + unsigned int log2_max_mv_length_vertical; // ue(v) + unsigned int log2_max_mv_length_horizontal; // ue(v) + unsigned int num_reorder_frames; // ue(v) + unsigned int max_dec_frame_buffering; // ue(v) +} vui_seq_parameters_t; + + +#define MAXnum_slice_groups_minus1 8 +typedef struct +{ + Boolean Valid; // indicates the parameter set is valid + unsigned int pic_parameter_set_id; // ue(v) + unsigned int seq_parameter_set_id; // ue(v) + Boolean entropy_coding_mode_flag; // u(1) + Boolean transform_8x8_mode_flag; // u(1) + + Boolean pic_scaling_matrix_present_flag; // u(1) + int pic_scaling_list_present_flag[12]; // u(1) + int ScalingList4x4[6][16]; // se(v) + int ScalingList8x8[6][64]; // se(v) + Boolean UseDefaultScalingMatrix4x4Flag[6]; + Boolean UseDefaultScalingMatrix8x8Flag[6]; + + // if( pic_order_cnt_type < 2 ) in the sequence parameter set + Boolean bottom_field_pic_order_in_frame_present_flag; // u(1) + unsigned int num_slice_groups_minus1; // ue(v) + unsigned int slice_group_map_type; // ue(v) + // if( slice_group_map_type = = 0 ) + unsigned int run_length_minus1[MAXnum_slice_groups_minus1]; // ue(v) + // else if( slice_group_map_type = = 2 ) + unsigned int top_left[MAXnum_slice_groups_minus1]; // ue(v) + unsigned int bottom_right[MAXnum_slice_groups_minus1]; // ue(v) + // else if( slice_group_map_type = = 3 || 4 || 5 + Boolean slice_group_change_direction_flag; // u(1) + unsigned int slice_group_change_rate_minus1; // ue(v) + // else if( slice_group_map_type = = 6 ) + unsigned int pic_size_in_map_units_minus1; // ue(v) + byte *slice_group_id; // complete MBAmap u(v) + + int num_ref_idx_l0_default_active_minus1; // ue(v) + int num_ref_idx_l1_default_active_minus1; // ue(v) + Boolean weighted_pred_flag; // u(1) + unsigned int weighted_bipred_idc; // u(2) + int pic_init_qp_minus26; // se(v) + int pic_init_qs_minus26; // se(v) + int chroma_qp_index_offset; // se(v) + + int cb_qp_index_offset; // se(v) + int cr_qp_index_offset; // se(v) + int second_chroma_qp_index_offset; // se(v) + + Boolean deblocking_filter_control_present_flag; // u(1) + Boolean constrained_intra_pred_flag; // u(1) + Boolean redundant_pic_cnt_present_flag; // u(1) + Boolean vui_pic_parameters_flag; // u(1) +} pic_parameter_set_rbsp_t; + + +#define MAXnum_ref_frames_in_pic_order_cnt_cycle 256 +typedef struct +{ + Boolean Valid; // indicates the parameter set is valid + + unsigned int profile_idc; // u(8) + Boolean constrained_set0_flag; // u(1) + Boolean constrained_set1_flag; // u(1) + Boolean constrained_set2_flag; // u(1) + Boolean constrained_set3_flag; // u(1) +#if (MVC_EXTENSION_ENABLE) + Boolean constrained_set4_flag; // u(1) + Boolean constrained_set5_flag; // u(2) +#endif + unsigned int level_idc; // u(8) + unsigned int seq_parameter_set_id; // ue(v) + unsigned int chroma_format_idc; // ue(v) + + Boolean seq_scaling_matrix_present_flag; // u(1) + int seq_scaling_list_present_flag[12]; // u(1) + int ScalingList4x4[6][16]; // se(v) + int ScalingList8x8[6][64]; // se(v) + Boolean UseDefaultScalingMatrix4x4Flag[6]; + Boolean UseDefaultScalingMatrix8x8Flag[6]; + + unsigned int bit_depth_luma_minus8; // ue(v) + unsigned int bit_depth_chroma_minus8; // ue(v) + unsigned int log2_max_frame_num_minus4; // ue(v) + unsigned int pic_order_cnt_type; + // if( pic_order_cnt_type == 0 ) + unsigned int log2_max_pic_order_cnt_lsb_minus4; // ue(v) + // else if( pic_order_cnt_type == 1 ) + Boolean delta_pic_order_always_zero_flag; // u(1) + int offset_for_non_ref_pic; // se(v) + int offset_for_top_to_bottom_field; // se(v) + unsigned int num_ref_frames_in_pic_order_cnt_cycle; // ue(v) + // for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) + int offset_for_ref_frame[MAXnum_ref_frames_in_pic_order_cnt_cycle]; // se(v) + unsigned int num_ref_frames; // ue(v) + Boolean gaps_in_frame_num_value_allowed_flag; // u(1) + unsigned int pic_width_in_mbs_minus1; // ue(v) + unsigned int pic_height_in_map_units_minus1; // ue(v) + Boolean frame_mbs_only_flag; // u(1) + // if( !frame_mbs_only_flag ) + Boolean mb_adaptive_frame_field_flag; // u(1) + Boolean direct_8x8_inference_flag; // u(1) + Boolean frame_cropping_flag; // u(1) + unsigned int frame_crop_left_offset; // ue(v) + unsigned int frame_crop_right_offset; // ue(v) + unsigned int frame_crop_top_offset; // ue(v) + unsigned int frame_crop_bottom_offset; // ue(v) + Boolean vui_parameters_present_flag; // u(1) + vui_seq_parameters_t vui_seq_parameters; // vui_seq_parameters_t + unsigned separate_colour_plane_flag; // u(1) +#if (MVC_EXTENSION_ENABLE) + int max_dec_frame_buffering; +#endif + int lossless_qpprime_flag; +} seq_parameter_set_rbsp_t; + +#if (MVC_EXTENSION_ENABLE) +typedef struct mvcvui_tag +{ + int num_ops_minus1; + char *temporal_id; + int *num_target_output_views_minus1; + int **view_id; + char *timing_info_present_flag; + int *num_units_in_tick; + int *time_scale; + char *fixed_frame_rate_flag; + char *nal_hrd_parameters_present_flag; + char *vcl_hrd_parameters_present_flag; + char *low_delay_hrd_flag; + char *pic_struct_present_flag; + + //hrd parameters; + char cpb_cnt_minus1; + char bit_rate_scale; + char cpb_size_scale; + int bit_rate_value_minus1[32]; + int cpb_size_value_minus1[32]; + char cbr_flag[32]; + char initial_cpb_removal_delay_length_minus1; + char cpb_removal_delay_length_minus1; + char dpb_output_delay_length_minus1; + char time_offset_length; +}MVCVUI_t; + +typedef struct +{ + seq_parameter_set_rbsp_t sps; + + unsigned int bit_equal_to_one; + int num_views_minus1; + int *view_id; + int *num_anchor_refs_l0; + int **anchor_ref_l0; + int *num_anchor_refs_l1; + int **anchor_ref_l1; + + int *num_non_anchor_refs_l0; + int **non_anchor_ref_l0; + int *num_non_anchor_refs_l1; + int **non_anchor_ref_l1; + + int num_level_values_signalled_minus1; + int *level_idc; + int *num_applicable_ops_minus1; + int **applicable_op_temporal_id; + int **applicable_op_num_target_views_minus1; + int ***applicable_op_target_view_id; + int **applicable_op_num_views_minus1; + + unsigned int mvc_vui_parameters_present_flag; + Boolean Valid; // indicates the parameter set is valid + MVCVUI_t MVCVUIParams; +} subset_seq_parameter_set_rbsp_t; + +#endif + +pic_parameter_set_rbsp_t *AllocPPS (void); +seq_parameter_set_rbsp_t *AllocSPS (void); + +void FreePPS (pic_parameter_set_rbsp_t *pps); +void FreeSPS (seq_parameter_set_rbsp_t *sps); + +int sps_is_equal(seq_parameter_set_rbsp_t *sps1, seq_parameter_set_rbsp_t *sps2); +int pps_is_equal(pic_parameter_set_rbsp_t *pps1, pic_parameter_set_rbsp_t *pps2); + +#endif diff --git a/lcommon/inc/quant_params.h b/lcommon/inc/quant_params.h new file mode 100644 index 0000000..10fda89 --- /dev/null +++ b/lcommon/inc/quant_params.h @@ -0,0 +1,54 @@ +/*! + *************************************************************************** + * \file + * quant_params.h + * + * \author + * Alexis Michael Tourapis + * + * \brief + * Headerfile for Quantization parameters + ************************************************************************** + */ + +#ifndef _QUANT_PARAMS_H_ +#define _QUANT_PARAMS_H_ + +typedef struct level_quant_params { + int OffsetComp; + int ScaleComp; + int InvScaleComp; +} LevelQuantParams; + +typedef struct quant_params { + int AdaptRndWeight; + int AdaptRndCrWeight; + + LevelQuantParams *****q_params_4x4; + LevelQuantParams *****q_params_8x8; + + int *qp_per_matrix; + int *qp_rem_matrix; + + short **OffsetList4x4input; + short **OffsetList8x8input; + short ***OffsetList4x4; + short ***OffsetList8x8; +} QuantParameters; + +typedef struct quant_methods { + int block_y; + int block_x; + int qp; + int* ACLevel; + int* ACRun; + int **fadjust; + LevelQuantParams **q_params; + int *coeff_cost; + const byte (*pos_scan)[2]; + const byte *c_cost; + char type; +} QuantMethods; + +#endif + diff --git a/lcommon/inc/report.h b/lcommon/inc/report.h new file mode 100644 index 0000000..fb61e09 --- /dev/null +++ b/lcommon/inc/report.h @@ -0,0 +1,25 @@ + +/*! + ************************************************************************ + * \file report.h + * + * \brief + * headers for frame format related information + * + * \author + * + ************************************************************************ + */ +#ifndef _REPORT_H_ +#define _REPORT_H_ +#include "contributors.h" +#include "global.h" +#include "enc_statistics.h" + +extern void report ( VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats ); +extern void information_init ( VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats ); +extern void report_frame_statistic( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void report_stats_on_error (void); + +#endif + diff --git a/lcommon/inc/transcode_common.h b/lcommon/inc/transcode_common.h new file mode 100644 index 0000000..294e1ad --- /dev/null +++ b/lcommon/inc/transcode_common.h @@ -0,0 +1,33 @@ +/*! +************************************************************************ +* \file transcode_common.h +* +* \brief +* Common Structs to decoder and encoder to transcode a MVC Stream +* +* \author +* - João Carreira +* +************************************************************************ +*/ + +#ifndef _TRANSCODE_COMMON_H +#define _TRANSCODE_COMMON_H + +#include "mbuffer.h" + +typedef struct trans_common_t +{ + int poc; + int view_id; + int frame_width; + int frame_height; + PicMotionParams **pp_mv_info; + +} TRANS_FRAME_NODE_T; + + +extern int write_trans_node( int pfile, TRANS_FRAME_NODE_T node); +extern int read_trans_node( int pfile, TRANS_FRAME_NODE_T *node); + +#endif \ No newline at end of file diff --git a/lcommon/inc/transform.h b/lcommon/inc/transform.h new file mode 100644 index 0000000..13d8c78 --- /dev/null +++ b/lcommon/inc/transform.h @@ -0,0 +1,32 @@ + +/*! + *************************************************************************** + * + * \file transform.h + * + * \brief + * prototypes of transform functions + * + * \date + * 10 July 2007 + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * Alexis Michael Tourapis + **************************************************************************/ + +#ifndef _TRANSFORM_H_ +#define _TRANSFORM_H_ + +extern void forward4x4 (int **block , int **tblock, int pos_y, int pos_x); +extern void inverse4x4 (int **tblock, int **block , int pos_y, int pos_x); +extern void forward8x8 (int **block , int **tblock, int pos_y, int pos_x); +extern void inverse8x8 (int **tblock, int **block , int pos_x); +extern void hadamard4x4 (int **block , int **tblock); +extern void ihadamard4x4 (int **tblock, int **block); +extern void hadamard4x2 (int **block , int **tblock); +extern void ihadamard4x2 (int **tblock, int **block); +extern void hadamard2x2 (int **block , int tblock[4]); +extern void ihadamard2x2 (int block[4], int tblock[4]); + +#endif //_TRANSFORM_H_ diff --git a/lcommon/inc/typedefs.h b/lcommon/inc/typedefs.h new file mode 100644 index 0000000..e57bf1a --- /dev/null +++ b/lcommon/inc/typedefs.h @@ -0,0 +1,75 @@ +/*! + ************************************************************************************* + * \file typedefs.h + * + * \brief + * Common type definitions + * Currently only supports Windows and Linux operating systems. + * Need to add support for other "older systems such as VAX, DECC, Unix Alpha etc + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#ifndef _TYPEDEFS_H_ +#define _TYPEDEFS_H_ + +#include "win32.h" + +typedef unsigned char byte; //!< byte type definition +typedef unsigned char uint8; //!< type definition for unsigned char (same as byte, 8 bits) +typedef unsigned short uint16; //!< type definition for unsigned short (16 bits) +typedef unsigned int uint32; //!< type definition for unsigned int (32 bits) + +typedef char int8; +typedef short int16; +typedef int int32; + +#if IMGTYPE == 0 +typedef byte imgpel; //!< pixel type +typedef uint16 distpel; //!< distortion type (for pixels) +typedef int32 distblk; //!< distortion type (for Macroblock) +typedef int32 transpel; //!< transformed coefficient type +#else +typedef uint16 imgpel; +typedef uint32 distpel; +typedef int64 distblk; +typedef int32 transpel; +#endif + +#define MAX_IMG_PEL ( (imgpel)~((imgpel)0) ) + +//! Boolean Type +#ifdef FALSE +# define Boolean int +#else +typedef enum { + FALSE, + TRUE +} Boolean; +#endif + +#ifndef MAXINT64 +#define MAXINT64 0x7fffffffffffffff +#endif + +/* +#define MAXUINT8 0xff +#define MAXUINT16 0xffff +#define MAXUINT32 0xffffffff +#define MAXUINT64 0xffffffffffffffff + +#define MAXINT8 0x7f +#define MININT8 (-MAXINT8) +#define MAXINT16 0x7fff +#define MININT16 (-MAXINT16) +#define MAXINT32 0x7fffffff +#define MININT32 (-MAXINT32) +#define MAXINT64 0x7fffffffffffffff +#define MININT64 (-MAXINT64) +*/ + +#endif + diff --git a/lcommon/inc/types.h b/lcommon/inc/types.h new file mode 100644 index 0000000..e22841a --- /dev/null +++ b/lcommon/inc/types.h @@ -0,0 +1,203 @@ +/*! + ************************************************************************ + * \file + * types.h + * + * \brief + * type definitions. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * + ************************************************************************ + */ +#ifndef _TYPES_H_ +#define _TYPES_H_ + +/*********************************************************************** + * T y p e d e f i n i t i o n s f o r T M L + *********************************************************************** + */ + +typedef enum +{ + // YUV + PLANE_Y = 0, // PLANE_Y + PLANE_U = 1, // PLANE_Cb + PLANE_V = 2, // PLANE_Cr + // RGB + PLANE_G = 0, + PLANE_B = 1, + PLANE_R = 2 +} ColorPlane; + +enum { + LIST_0 = 0, + LIST_1 = 1, + BI_PRED = 2, + BI_PRED_L0 = 3, + BI_PRED_L1 = 4 +}; + +enum { + ERROR_SAD = 0, + ERROR_SSE = 1, + ERROR_SATD = 2, + ERROR_PSATD = 3 +}; + +enum { + ME_Y_ONLY = 0, + ME_YUV_FP = 1, + ME_YUV_FP_SP = 2 +}; + + +enum { + DISTORTION_MSE = 0 +}; + + +//! Data Partitioning Modes +typedef enum +{ + PAR_DP_1, //!< no data partitioning is supported + PAR_DP_3 //!< data partitioning with 3 partitions +} PAR_DP_TYPE; + + +//! Output File Types +typedef enum +{ + PAR_OF_ANNEXB, //!< Annex B byte stream format + PAR_OF_RTP //!< RTP packets in outfile +} PAR_OF_TYPE; + +//! Field Coding Types +typedef enum +{ + FRAME_CODING = 0, + FIELD_CODING = 1, + ADAPTIVE_CODING = 2, + FRAME_MB_PAIR_CODING = 3 +} CodingType; + + +//! definition of H.264 syntax elements +typedef enum +{ + SE_HEADER, + SE_PTYPE, + SE_MBTYPE, + SE_REFFRAME, + SE_INTRAPREDMODE, + SE_MVD, + SE_CBP, + SE_LUM_DC_INTRA, + SE_CHR_DC_INTRA, + SE_LUM_AC_INTRA, + SE_CHR_AC_INTRA, + SE_LUM_DC_INTER, + SE_CHR_DC_INTER, + SE_LUM_AC_INTER, + SE_CHR_AC_INTER, + SE_DELTA_QUANT, + SE_BFRAME, + SE_EOS, + SE_MAX_ELEMENTS = 20 //!< number of maximum syntax elements +} SE_type; // substituting the definitions in elements.h + + +typedef enum +{ + NO_SLICES, + FIXED_MB, + FIXED_RATE, + CALL_BACK +} SliceMode; + + +typedef enum +{ + CAVLC, + CABAC +} SymbolMode; + +typedef enum +{ + FULL_SEARCH = -1, + FAST_FULL_SEARCH = 0, + UM_HEX = 1, + UM_HEX_SIMPLE = 2, + EPZS = 3 +} SearchType; + + +typedef enum +{ + FRAME, + TOP_FIELD, + BOTTOM_FIELD +} PictureStructure; //!< New enum for field processing + +typedef enum +{ + P_SLICE = 0, + B_SLICE = 1, + I_SLICE = 2, + SP_SLICE = 3, + SI_SLICE = 4, + NUM_SLICE_TYPES = 5 +} SliceType; + +//Motion Estimation levels +typedef enum +{ + F_PEL, //!< Full Pel refinement + H_PEL, //!< Half Pel refinement + Q_PEL //!< Quarter Pel refinement +} MELevel; + +typedef enum +{ + FAST_ACCESS = 0, //!< Fast/safe reference access + UMV_ACCESS = 1 //!< unconstrained reference access +} REF_ACCESS_TYPE; + +typedef enum +{ + IS_LUMA = 0, + IS_CHROMA = 1 +} Component_Type; + +typedef enum +{ + RC_MODE_0 = 0, + RC_MODE_1 = 1, + RC_MODE_2 = 2, + RC_MODE_3 = 3 +} RCModeType; + + +typedef enum { + SSE = 0, + SSE_RGB = 1, + PSNR = 2, + PSNR_RGB = 3, + SSIM = 4, + SSIM_RGB = 5, + MS_SSIM = 6, + MS_SSIM_RGB = 7, + TOTAL_DIST_TYPES = 8 +} distortion_types; + +typedef enum { + WP_MCPREC_PLUS0 = 4, + WP_MCPREC_PLUS1 = 5, + WP_MCPREC_MINUS0 = 6, + WP_MCPREC_MINUS1 = 7, + WP_MCPREC_MINUS_PLUS0 = 8, + WP_REGULAR = 9 +} weighted_prediction_types; + +#endif diff --git a/lcommon/inc/vui_params.h b/lcommon/inc/vui_params.h new file mode 100644 index 0000000..366ade1 --- /dev/null +++ b/lcommon/inc/vui_params.h @@ -0,0 +1,74 @@ +/*! + ************************************************************************ + * \file vui_params.h + * + * \brief + * Input parameters related definitions + * + * \author + * + ************************************************************************ + */ + +#ifndef _VUI_PARAMS_H_ +#define _VUI_PARAMS_H_ + +// VUI Parameters +typedef struct vui_parameters +{ + int aspect_ratio_info_present_flag; + int aspect_ratio_idc; + int sar_width; + int sar_height; + int overscan_info_present_flag; + int overscan_appropriate_flag; + int video_signal_type_present_flag; + int video_format; + int video_full_range_flag; + int colour_description_present_flag; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + int chroma_location_info_present_flag; + int chroma_sample_loc_type_top_field; + int chroma_sample_loc_type_bottom_field; + int timing_info_present_flag; + int num_units_in_tick; + int time_scale; + int fixed_frame_rate_flag; + int nal_hrd_parameters_present_flag; + int nal_cpb_cnt_minus1; + int nal_bit_rate_scale; + int nal_cpb_size_scale; + int nal_bit_rate_value_minus1; + int nal_cpb_size_value_minus1; + int nal_vbr_cbr_flag; + int nal_initial_cpb_removal_delay_length_minus1; + int nal_cpb_removal_delay_length_minus1; + int nal_dpb_output_delay_length_minus1; + int nal_time_offset_length; + int vcl_hrd_parameters_present_flag; + int vcl_cpb_cnt_minus1; + int vcl_bit_rate_scale; + int vcl_cpb_size_scale; + int vcl_bit_rate_value_minus1; + int vcl_cpb_size_value_minus1; + int vcl_vbr_cbr_flag; + int vcl_initial_cpb_removal_delay_length_minus1; + int vcl_cpb_removal_delay_length_minus1; + int vcl_dpb_output_delay_length_minus1; + int vcl_time_offset_length; + int low_delay_hrd_flag; + int pic_struct_present_flag; + int bitstream_restriction_flag; + int motion_vectors_over_pic_boundaries_flag; + int max_bytes_per_pic_denom; + int max_bits_per_mb_denom; + int log2_max_mv_length_vertical; + int log2_max_mv_length_horizontal; + int num_reorder_frames; + int max_dec_frame_buffering; +} VUIParameters; + +#endif + diff --git a/lcommon/inc/win32.h b/lcommon/inc/win32.h new file mode 100644 index 0000000..9fc71ab --- /dev/null +++ b/lcommon/inc/win32.h @@ -0,0 +1,122 @@ + +/*! + ************************************************************************ + * \file + * win32.h + * + * \brief + * win32 definitions for H.264 codec. + * + * \author + * + ************************************************************************ + */ +#ifndef _WIN32_H_ +#define _WIN32_H_ + +# include +# include +# include +# include +# include +#include + +#if (_MSC_VER >= 1400) || defined(__INTEL_COMPILER) || (__GNUC__ >= 5) // Check OPENMP compatibility +//# define OPENMP +# define NUM_THREADS 8 +#endif + +#if defined(WIN32) || defined (WIN64) +# include +# include +# include +# include +#if (_MSC_VER < 1400) +typedef int intptr_t; +#else +# include +#endif +#if defined(OPENMP) +# include +#endif + +# define strcasecmp _strcmpi +# define strncasecmp _strnicmp + +# define snprintf _snprintf +# define open _open +# define close _close +# define read _read +# define write _write +# define lseek _lseeki64 +# define fsync _commit +# define tell _telli64 +# define TIMEB _timeb +# define TIME_T LARGE_INTEGER +# define OPENFLAGS_WRITE _O_WRONLY|_O_CREAT|_O_BINARY|_O_TRUNC +# define OPEN_PERMISSIONS _S_IREAD | _S_IWRITE +# define OPENFLAGS_READ _O_RDONLY|_O_BINARY +# define inline _inline +# define forceinline __forceinline +#else +# include +# include +# include +# include +# include +#if defined(OPENMP) +# include +#endif + +#include + +# define TIMEB timeb +# define TIME_T struct timeval +# define tell(fd) lseek(fd, 0, SEEK_CUR) +# define OPENFLAGS_WRITE O_WRONLY|O_CREAT|O_TRUNC +# define OPENFLAGS_READ O_RDONLY +# define OPEN_PERMISSIONS S_IRUSR | S_IWUSR + +# if __STDC_VERSION__ >= 199901L + /* "inline" is a keyword */ +# else +# define inline /* nothing */ +# endif +# define forceinline inline +#endif + +#if (defined(WIN32) || defined(WIN64)) && !defined(__GNUC__) +typedef __int64 int64; +typedef unsigned __int64 uint64; +# define FORMAT_OFF_T "I64d" +# ifndef INT64_MIN +# define INT64_MIN (-9223372036854775807i64 - 1i64) +# endif +#else + +#ifndef __OPENCV_CORE_TYPES_H__ +typedef int64_t int64; +//typedef long long int64; +//typedef unsigned long long uint64; +typedef uint64_t uint64; + +#endif + + +# define FORMAT_OFF_T "lld" +# ifndef INT64_MIN +# define INT64_MIN (-9223372036854775807LL - 1LL) +# endif +#endif + +//! Edited by Joao Carreira +#ifndef NULL +#define NULL 0L +#endif + +extern void gettime(TIME_T* time); +extern void init_time(void); +extern int64 timediff(TIME_T* start, TIME_T* end); +extern int64 timenorm(int64 cur_time); + +#endif diff --git a/lcommon/src/blk_prediction.c b/lcommon/src/blk_prediction.c new file mode 100644 index 0000000..340ab40 --- /dev/null +++ b/lcommon/src/blk_prediction.c @@ -0,0 +1,63 @@ +/*! + ************************************************************************************* + * \file blk_prediction.c + * + * \brief + * Block Prediction related functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include +#include +#include + +#include "block.h" +#include "global.h" + +#include "macroblock.h" +#include "mc_prediction.h" +#include "image.h" +#include "mb_access.h" + +void compute_residue (imgpel **curImg, imgpel **mpr, int **mb_rres, int mb_x, int opix_x, int width, int height) +{ + imgpel *imgOrg, *imgPred; + int *m7; + int i, j; + + for (j = 0; j < height; j++) + { + imgOrg = &curImg[j][opix_x]; + imgPred = &mpr[j][mb_x]; + m7 = &mb_rres[j][mb_x]; + for (i = 0; i < width; i++) + { + *m7++ = *imgOrg++ - *imgPred++; + } + } +} + +void sample_reconstruct (imgpel **curImg, imgpel **mpr, int **mb_rres, int mb_x, int opix_x, int width, int height, int max_imgpel_value, int dq_bits) +{ + imgpel *imgOrg, *imgPred; + int *m7; + int i, j; + + for (j = 0; j < height; j++) + { + imgOrg = &curImg[j][opix_x]; + imgPred = &mpr[j][mb_x]; + m7 = &mb_rres[j][mb_x]; + for (i=0;i + * \note + * In the future this module should hide the Parameters and offer only + * Functions for their access. Modules which make frequent use of some parameters + * (e.g. picture size in macroblocks) are free to buffer them on local variables. + * This will not only avoid global variable and make the code more readable, but also + * speed it up. It will also greatly facilitate future enhancements such as the + * handling of different picture sizes in the same sequence. \n + * \n + * For now, everything is just copied to the inp_par structure (gulp) + * + ************************************************************************************** + * \par Configuration File Format + ************************************************************************************** + * Format is line oriented, maximum of one parameter per line \n + * \n + * Lines have the following format: \n + * \ = \ # Comments \\n \n + * Whitespace is space and \\t + * \par + * \ are the predefined names for Parameters and are case sensitive. + * See configfile.h for the definition of those names and their mapping to + * cfgparams->values. + * \par + * \ are either integers [0..9]* or strings. + * Integers must fit into the wordlengths, signed values are generally assumed. + * Strings containing no whitespace characters can be used directly. Strings containing + * whitespace characters are to be inclosed in double quotes ("string with whitespace") + * The double quote character is forbidden (may want to implement something smarter here). + * \par + * Any Parameters whose ParameterName is undefined lead to the termination of the program + * with an error message. + * + * \par Known bug/Shortcoming: + * zero-length strings (i.e. to signal an non-existing file + * have to be coded as "". + * + * \par Rules for using command files + * \n + * All Parameters are initially taken from DEFAULTCONFIGFILENAME, defined in configfile.h. + * If an -f \ parameter is present in the command line then this file is used to + * update the defaults of DEFAULTCONFIGFILENAME. There can be more than one -f parameters + * present. If -p parameters are present then these + * override the default and the additional config file's settings, and are themselves + * overridden by future -p parameters. There must be whitespace between -f and -p commands + * and their respective parameters + *********************************************************************** + */ + +#include + +#include "global.h" +#include "configfile.h" +#include "memalloc.h" + +static int ParameterNameToMapIndex (Mapping *Map, char *s); + + +#define MAX_ITEMS_TO_PARSE 10000 + +/*! + *********************************************************************** + * \brief + * allocates memory buf, opens file Filename in f, reads contents into + * buf and returns buf + * \param Filename + * name of config file + * \return + * if successfull, content of config file + * NULL in case of error. Error message will be set in errortext + *********************************************************************** + */ +char *GetConfigFileContent (char *Filename) +{ + long FileSize; + FILE *f; + char *buf; + + if (NULL == (f = fopen (Filename, "r"))) + { + snprintf (errortext, ET_SIZE, "Cannot open configuration file %s.", Filename); + return NULL; + } + + if (0 != fseek (f, 0, SEEK_END)) + { + snprintf (errortext, ET_SIZE, "Cannot fseek in configuration file %s.", Filename); + return NULL; + } + + FileSize = ftell (f); + + if (FileSize < 0 || FileSize > 150000) + { + snprintf (errortext, ET_SIZE, "\nUnreasonable Filesize %ld reported by ftell for configuration file %s.", FileSize, Filename); + return NULL; + } + if (0 != fseek (f, 0, SEEK_SET)) + { + snprintf (errortext, ET_SIZE, "Cannot fseek in configuration file %s.", Filename); + return NULL; + } + + if ((buf = malloc (FileSize + 1))==NULL) no_mem_exit("GetConfigFileContent: buf"); + + // Note that ftell() gives us the file size as the file system sees it. The actual file size, + // as reported by fread() below will be often smaller due to CR/LF to CR conversion and/or + // control characters after the dos EOF marker in the file. + + FileSize = (long) fread (buf, 1, FileSize, f); + buf[FileSize] = '\0'; + + + fclose (f); + return buf; +} + + +/*! + *********************************************************************** + * \brief + * Parses the character array buf and writes global variable input, which is defined in + * configfile.h. This hack will continue to be necessary to facilitate the addition of + * new parameters through the Map[] mechanism (Need compiler-generated addresses in map[]). + * \param p_Inp + * InputParameters of configuration + * \param Map + * Mapping structure to specify the name and value mapping relation + * \param buf + * buffer to be parsed + * \param bufsize + * buffer size of buffer + *********************************************************************** + */ +void ParseContent (InputParameters *p_Inp, Mapping *Map, char *buf, int bufsize) +{ + char *items[MAX_ITEMS_TO_PARSE] = {NULL}; + int MapIdx; + int item = 0; + int InString = 0, InItem = 0; + char *p = buf; + char *bufend = &buf[bufsize]; + int IntContent; + double DoubleContent; + int i; + + // Stage one: Generate an argc/argv-type list in items[], without comments and whitespace. + // This is context insensitive and could be done most easily with lex(1). + + while (p < bufend) + { + switch (*p) + { + case 13: + ++p; + break; + case '#': // Found comment + *p = '\0'; // Replace '#' with '\0' in case of comment immediately following integer or string + while (*p != '\n' && p < bufend) // Skip till EOL or EOF, whichever comes first + ++p; + InString = 0; + InItem = 0; + break; + case '\n': + InItem = 0; + InString = 0; + *p++='\0'; + break; + case ' ': + case '\t': // Skip whitespace, leave state unchanged + if (InString) + p++; + else + { // Terminate non-strings once whitespace is found + *p++ = '\0'; + InItem = 0; + } + break; + + case '"': // Begin/End of String + *p++ = '\0'; + if (!InString) + { + items[item++] = p; + InItem = ~InItem; + } + else + InItem = 0; + InString = ~InString; // Toggle + break; + + default: + if (!InItem) + { + items[item++] = p; + InItem = ~InItem; + } + p++; + } + } + + item--; + + for (i=0; i (MapIdx = ParameterNameToMapIndex (Map, items[i]))) + { + //snprintf (errortext, ET_SIZE, " Parsing error in config file: Parameter Name '%s' not recognized.", items[i]); + //error (errortext, 300); + printf ("\n\tParsing error in config file: Parameter Name '%s' not recognized.", items[i]); + i -= 2 ; + continue; + } + if (strcasecmp ("=", items[i+1])) + { + snprintf (errortext, ET_SIZE, " Parsing error in config file: '=' expected as the second token in each line."); + error (errortext, 300); + } + + // Now interpret the Value, context sensitive... + + switch (Map[MapIdx].Type) + { + case 0: // Numerical + if (1 != sscanf (items[i+2], "%d", &IntContent)) + { + snprintf (errortext, ET_SIZE, " Parsing error: Expected numerical value for Parameter of %s, found '%s'.", items[i], items[i+2]); + error (errortext, 300); + } + * (int *) (Map[MapIdx].Place) = IntContent; + printf ("."); + break; + case 1: + if (items[i + 2] == NULL) + memset((char *) Map[MapIdx].Place, 0, Map[MapIdx].char_size); + else + strncpy ((char *) Map[MapIdx].Place, items [i+2], Map[MapIdx].char_size); + printf ("."); + break; + case 2: // Numerical double + if (1 != sscanf (items[i+2], "%lf", &DoubleContent)) + { + snprintf (errortext, ET_SIZE, " Parsing error: Expected numerical value for Parameter of %s, found '%s'.", items[i], items[i+2]); + error (errortext, 300); + } + * (double *) (Map[MapIdx].Place) = DoubleContent; + printf ("."); + break; + default: + error ("Unknown value type in the map definition of configfile.h",-1); + } + } + *p_Inp = cfgparams; +} + +/*! + *********************************************************************** + * \brief + * Returns the index number from Map[] for a given parameter name. + * \param Map + * Mapping structure + * \param s + * parameter name string + * \return + * the index number if the string is a valid parameter name, \n + * -1 for error + *********************************************************************** + */ +static int ParameterNameToMapIndex (Mapping *Map, char *s) +{ + int i = 0; + + while (Map[i].TokenName != NULL) + if (0==strcasecmp (Map[i].TokenName, s)) + return i; + else + i++; + return -1; +} + +/*! + *********************************************************************** + * \brief + * Sets initial values for encoding parameters. + * \return + * -1 for error + *********************************************************************** + */ +int InitParams(Mapping *Map) +{ + int i = 0; + + while (Map[i].TokenName != NULL) + { + if (Map[i].Type == 0) + * (int *) (Map[i].Place) = (int) Map[i].Default; + else if (Map[i].Type == 2) + * (double *) (Map[i].Place) = Map[i].Default; + i++; + } + return -1; +} + +/*! + *********************************************************************** + * \brief + * Validates encoding parameters. + * \return + * -1 for error + *********************************************************************** + */ +int TestParams(Mapping *Map, int bitdepth_qp_scale[3]) +{ + int i = 0; + + while (Map[i].TokenName != NULL) + { + if (Map[i].param_limits == 1) + { + if (Map[i].Type == 0) + { + if ( * (int *) (Map[i].Place) < (int) Map[i].min_limit || * (int *) (Map[i].Place) > (int) Map[i].max_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should be in [%d, %d] range.", Map[i].TokenName, (int) Map[i].min_limit,(int)Map[i].max_limit ); + error (errortext, 400); + } + + } + else if (Map[i].Type == 2) + { + if ( * (double *) (Map[i].Place) < Map[i].min_limit || * (double *) (Map[i].Place) > Map[i].max_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should be in [%.2f, %.2f] range.", Map[i].TokenName,Map[i].min_limit ,Map[i].max_limit ); + error (errortext, 400); + } + } + } + else if (Map[i].param_limits == 2) + { + if (Map[i].Type == 0) + { + if ( * (int *) (Map[i].Place) < (int) Map[i].min_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should not be smaller than %d.", Map[i].TokenName, (int) Map[i].min_limit); + error (errortext, 400); + } + } + else if (Map[i].Type == 2) + { + if ( * (double *) (Map[i].Place) < Map[i].min_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should not be smaller than %2.f.", Map[i].TokenName,Map[i].min_limit); + error (errortext, 400); + } + } + } + else if (Map[i].param_limits == 3) // Only used for QPs + { + + if (Map[i].Type == 0) + { + int cur_qp = * (int *) (Map[i].Place); + int min_qp = (int) (Map[i].min_limit - (bitdepth_qp_scale? bitdepth_qp_scale[0]: 0)); + int max_qp = (int) Map[i].max_limit; + + if (( cur_qp < min_qp ) || ( cur_qp > max_qp )) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should be in [%d, %d] range.", Map[i].TokenName, min_qp, max_qp ); + error (errortext, 400); + } + } + } + + i++; + } + return -1; +} + + + +/*! + *********************************************************************** + * \brief + * Outputs encoding parameters. + * \return + * -1 for error + *********************************************************************** + */ +int DisplayParams(Mapping *Map, char *message) +{ + int i = 0; + + printf("******************************************************\n"); + printf("* %s *\n", message); + printf("******************************************************\n"); + while (Map[i].TokenName != NULL) + { + if (Map[i].Type == 0) + printf("Parameter %s = %d\n",Map[i].TokenName,* (int *) (Map[i].Place)); + else if (Map[i].Type == 1) + printf("Parameter %s = ""%s""\n",Map[i].TokenName,(char *) (Map[i].Place)); + else if (Map[i].Type == 2) + printf("Parameter %s = %.2f\n",Map[i].TokenName,* (double *) (Map[i].Place)); + i++; + } + printf("******************************************************\n"); + return i; +} + diff --git a/lcommon/src/img_io.c b/lcommon/src/img_io.c new file mode 100644 index 0000000..e021910 --- /dev/null +++ b/lcommon/src/img_io.c @@ -0,0 +1,327 @@ + +/*! + ************************************************************************************* + * \file img_io.c + * + * \brief + * image I/O related functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ +#include "contributors.h" +#include "global.h" +#include "img_io.h" +#include "report.h" + +static const VIDEO_SIZE VideoRes[] = { + { "qcif" , 176, 144}, + { "qqvga" , 160, 128}, + { "qvga" , 320, 240}, + { "sif" , 352, 240}, + { "cif" , 352, 288}, + { "vga" , 640, 480}, + { "sd1" , 720, 480}, + { "sd2" , 704, 576}, + { "sd3" , 720, 576}, + { "720p" , 1280, 720}, + { "1080p" , 1920, 1080}, + { NULL, 0, 0} +}; + +/*! + ************************************************************************ + * \brief + * Parse Size from from file name + * + ************************************************************************ + */ +int ParseSizeFromString (VideoDataFile *input_file, int *x_size, int *y_size, double *fps) +{ + char *p1, *p2, *tail; + char *fn = input_file->fname; + char c; + int i = 0; + + *x_size = *y_size = -1; + p1 = p2 = fn; + while (p1 != NULL && p2 != NULL) + { + // Search for first '_' + p1 = strstr( p1, "_"); + if (p1 == NULL) + break; + + // Search for end character of x_size (first 'x' after last '_') + p2 = strstr( p1, "x"); + + // If no 'x' is found, exit + if (p2 == NULL) + break; + + // Try conversion of number + *p2 = 0; + *x_size = strtol( p1 + 1, &tail, 10); + + // If there are characters left in the string, or the string is null, discard conversion + if (*tail != '\0' || *(p1 + 1) == '\0') + { + *p2 = 'x'; + p1 = tail; + continue; + } + + // Conversion was correct. Restore string + *p2 = 'x'; + + // Search for end character of y_size (first '_' or '.' after last 'x') + p1 = strpbrk( p2 + 1, "_."); + // If no '_' or '.' is found, try again from current position + if (p1 == NULL) + { + p1 = p2 + 1; + continue; + } + + // Try conversion of number + c = *p1; + *p1 = 0; + *y_size = strtol( p2 + 1, &tail, 10); + + // If there are characters left in the string, or the string is null, discard conversion + if (*tail != '\0' || *(p2 + 1) == '\0') + { + *p1 = c; + p1 = tail; + continue; + } + + // Conversion was correct. Restore string + *p1 = c; + + // Search for end character of y_size (first 'i' or 'p' after last '_') + p2 = strstr( p1 + 1, "ip"); + + // If no 'i' or 'p' is found, exit + if (p2 == NULL) + break; + + // Try conversion of number + c = *p2; + *p2 = 0; + *fps = strtod( p1 + 1, &tail); + + // If there are characters left in the string, or the string is null, discard conversion + if (*tail != '\0' || *(p1 + 1) == '\0') + { + *p2 = c; + p1 = tail; + continue; + } + + // Conversion was correct. Restore string + *p2 = c; + break; + } + + // Now lets test some common video file formats + if (p1 == NULL || p2 == NULL) + { + for (i = 0; VideoRes[i].name != NULL; i++) + { + if (strcasecmp (fn, VideoRes[i].name)) + { + *x_size = VideoRes[i].x_size; + *y_size = VideoRes[i].y_size; + // Should add frame rate support as well + break; + } + } + } + + return (*x_size == -1 || *y_size == -1) ? 0 : 1; +} + +/*! + ************************************************************************ + * \brief + * Parse Size from from file name + * + ************************************************************************ + */ +void ParseFrameNoFormatFromString (VideoDataFile *input_file) +{ + char *p1, *p2, *tail; + char *fn = input_file->fname; + char *fhead = input_file->fhead; + char *ftail = input_file->ftail; + int *zero_pad = &input_file->zero_pad; + int *num_digits = &input_file->num_digits; + + *zero_pad = 0; + *num_digits = -1; + p1 = p2 = fn; + while (p1 != NULL && p2 != NULL) + { + // Search for first '_' + p1 = strstr( p1, "%"); + if (p1 == NULL) + break; + + strncpy(fhead, fn, p1 - fn); + + // Search for end character of x_size (first 'x' after last '_') + p2 = strstr( p1, "d"); + + // If no 'x' is found, exit + if (p2 == NULL) + break; + + // Try conversion of number + *p2 = 0; + + if (*(p1 + 1) == '0') + *zero_pad = 1; + + *num_digits = strtol( p1 + 1, &tail, 10); + + // If there are characters left in the string, or the string is null, discard conversion + if (*tail != '\0' || *(p1 + 1) == '\0') + { + *p2 = 'd'; + p1 = tail; + continue; + } + + // Conversion was correct. Restore string + *p2 = 'd'; + + tail++; + strncpy(ftail, tail, (int) strlen(tail)); + break; + } + + if (input_file->vdtype == VIDEO_TIFF) + { + input_file->is_concatenated = 0; + } + else + input_file->is_concatenated = (*num_digits == -1) ? 1 : 0; +} + +/*! + ************************************************************************ + * \brief + * Open file containing a single frame + ************************************************************************ + */ +void OpenFrameFile( VideoDataFile *input_file, int FrameNumberInFile) +{ + char infile [FILE_NAME_SIZE], in_number[16]; + int length = 0; + in_number[length]='\0'; + length = (int) strlen(input_file->fhead); + strncpy(infile, input_file->fhead, length); + infile[length]='\0'; + if (input_file->zero_pad) + snprintf(in_number, 16, "%0*d", input_file->num_digits, FrameNumberInFile); + else + snprintf(in_number, 16, "%*d", input_file->num_digits, FrameNumberInFile); + + strncat(infile, in_number, sizeof(in_number)); + length += sizeof(in_number); + infile[length]='\0'; + strncat(infile, input_file->ftail, strlen(input_file->ftail)); + length += (int) strlen(input_file->ftail); + infile[length]='\0'; + + if ((input_file->f_num = open(infile, OPENFLAGS_READ)) == -1) + { + printf ("OpenFrameFile: cannot open file %s\n", infile); + report_stats_on_error(); + } +} + +/*! + ************************************************************************ + * \brief + * Open file(s) containing the entire frame sequence + ************************************************************************ + */ +void OpenFiles( VideoDataFile *input_file) +{ + if (input_file->is_concatenated == 1) + { + if ((int) strlen(input_file->fname) == 0) + { + snprintf(errortext, ET_SIZE, "No input sequence name was provided. Please check settings."); + error (errortext, 500); + } + + if ((input_file->f_num = open(input_file->fname, OPENFLAGS_READ)) == -1) + { + snprintf(errortext, ET_SIZE, "Input file %s does not exist",input_file->fname); + error (errortext, 500); + } + } +} + +/*! + ************************************************************************ + * \brief + * Close input file + ************************************************************************ + */ +void CloseFiles(VideoDataFile *input_file) +{ + if (input_file->f_num != -1) + close(input_file->f_num); + input_file->f_num = -1; +} + +/* ========================================================================== + * + * ParseVideoType + * + * ========================================================================== +*/ +VideoFileType ParseVideoType (VideoDataFile *input_file) +{ + char *format; + + format = input_file->fname + (int) strlen(input_file->fname) - 3; + + if (strcasecmp (format, "yuv") == 0) + { + input_file->vdtype = VIDEO_YUV; + input_file->format.yuv_format = YUV420; + input_file->avi = NULL; + } + else if (strcasecmp (format, "rgb") == 0) + { + input_file->vdtype = VIDEO_RGB; + input_file->format.yuv_format = YUV444; + input_file->avi = NULL; + } + else if (strcasecmp (format, "tif") == 0) + { + input_file->vdtype = VIDEO_TIFF; + input_file->avi = NULL; + } + else if (strcasecmp (format, "avi") == 0) + { + input_file->vdtype = VIDEO_AVI; + } + else + { + //snprintf(errortext, ET_SIZE, "ERROR: video file format not supported"); + //error (errortext, 500); + input_file->vdtype = VIDEO_YUV; + input_file->format.yuv_format = YUV420; + input_file->avi = NULL; + } + + return input_file->vdtype; +} diff --git a/lcommon/src/img_process.c b/lcommon/src/img_process.c new file mode 100644 index 0000000..1e7cad1 --- /dev/null +++ b/lcommon/src/img_process.c @@ -0,0 +1,272 @@ +/*! +************************************************************************************* +* \file img_process.c +* +* \brief +* Input data Image Processing functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* +************************************************************************************* +*/ + +#include "contributors.h" +#include "global.h" +#include "img_process.h" +#include "io_image.h" +#include "memalloc.h" +#include "fast_memory.h" + +static inline void ResetImage(ImageData *imgOut) +{ + fast_memset(imgOut->frm_data[0][0], 0, imgOut->format.height[0] * imgOut->format.width[0] * sizeof (imgpel)); + + if (imgOut->format.yuv_format != YUV400) + { + if (sizeof(imgpel) == sizeof(char)) + { + fast_memset(imgOut->frm_data[1][0], 128, imgOut->format.height[1] * imgOut->format.width[1] * sizeof (imgpel)); + fast_memset(imgOut->frm_data[2][0], 128, imgOut->format.height[2] * imgOut->format.width[2] * sizeof (imgpel)); + } + else + { + int i, j, k; + imgpel med_value; + for (k = 1; k <=2; k++) + { + med_value = (imgpel) (imgOut->format.max_value[k] + 1) >> 1; + for (j = 0; j < imgOut->format.height[k]; j++) + { + for (i = 0; i < imgOut->format.width[k]; i++) + { + imgOut->frm_data[k][j][i] = med_value; + } + } + } + } + } +} + + +static inline void CPImage(ImageData *imgOut, ImageData *imgIn) +{ + memcpy(imgOut->frm_data[0][0], imgIn->frm_data[0][0], imgIn->format.height[0] * imgIn->format.width[0] * sizeof (imgpel)); + + if (imgIn->format.yuv_format != YUV400) + { + memcpy(imgOut->frm_data[1][0], imgIn->frm_data[1][0], imgIn->format.height[1] * imgIn->format.width[1] * sizeof (imgpel)); + memcpy(imgOut->frm_data[2][0], imgIn->frm_data[2][0], imgIn->format.height[2] * imgIn->format.width[2] * sizeof (imgpel)); + } +} + +// to be modified +static inline void FilterImage(ImageData *imgOut, ImageData *imgIn) +{ + memcpy(imgOut->frm_data[0][0], imgIn->frm_data[0][0], imgIn->format.height[0] * imgIn->format.width[0] * sizeof (imgpel)); + + if (imgIn->format.yuv_format != YUV400) + { + memcpy(imgOut->frm_data[1][0], imgIn->frm_data[1][0], imgIn->format.height[1] * imgIn->format.width[1] * sizeof (imgpel)); + memcpy(imgOut->frm_data[2][0], imgIn->frm_data[2][0], imgIn->format.height[2] * imgIn->format.width[2] * sizeof (imgpel)); + } +} + +// Line interleaving for 3:2 pulldown +static inline void BlendImageLines(ImageData *imgIn0, ImageData *imgIn1) +{ + int j; + for (j = 1; j < imgIn1->format.height[0]; j += 2) + memcpy(imgIn0->frm_data[0][j], imgIn1->frm_data[0][j], imgIn1->format.width[0] * sizeof (imgpel)); + + if (imgIn1->format.yuv_format != YUV400) + { + for (j = 1; j < imgIn1->format.height[1]; j += 2) + { + memcpy(imgIn0->frm_data[1][j], imgIn1->frm_data[1][j], imgIn1->format.width[1] * sizeof (imgpel)); + } + for (j = 1; j < imgIn1->format.height[2]; j += 2) + { + memcpy(imgIn0->frm_data[2][j], imgIn1->frm_data[2][j], imgIn1->format.width[2] * sizeof (imgpel)); + } + } +} + +// to be modified +static inline void FilterImageSep(ImageData *imgOut, ImageData *imgIn) +{ + int i, j; + static const int SepFilter[6] = {1, -5, 20, 20, -5, 1}; + int max_width = imgOut->format.width[0] - 1; + int max_height = imgOut->format.height[0] - 1; + + int **temp_data = new_mem2Dint(imgIn->format.height[0], imgIn->format.width[0]); // temp memory for filtering. Could be allocated once to speed up code + imgpel *frm_data = NULL; + + // implementation was not optimized. only just implemented as proof of concept + // horizontal filtering + for (j = 0; j < imgOut->format.height[0]; j++) + { + frm_data = imgIn->frm_data[0][j]; + for (i = 0; i < imgOut->format.width[0]; i++) + { + temp_data[j][i] = + SepFilter[0] * frm_data[iClip3(0, max_width, i - 2)] + + SepFilter[1] * frm_data[iClip3(0, max_width, i - 1)] + + SepFilter[2] * frm_data[iClip3(0, max_width, i )] + + SepFilter[3] * frm_data[iClip3(0, max_width, i + 1)] + + SepFilter[4] * frm_data[iClip3(0, max_width, i + 2)] + + SepFilter[5] * frm_data[iClip3(0, max_width, i + 3)]; + } + } + + for (j = 0; j < imgOut->format.height[0]; j++) + { + frm_data = imgOut->frm_data[0][j]; + for (i = 0; i < imgOut->format.width[0]; i++) + { + frm_data[i] = (imgpel) iClip3(0, imgOut->format.max_value[0], rshift_rnd_sign( + SepFilter[0] * temp_data[iClip3(0, max_height, j - 2)][i] + + SepFilter[1] * temp_data[iClip3(0, max_height, j - 1)][i] + + SepFilter[2] * temp_data[iClip3(0, max_height, j )][i] + + SepFilter[3] * temp_data[iClip3(0, max_height, j + 1)][i] + + SepFilter[4] * temp_data[iClip3(0, max_height, j + 2)][i] + + SepFilter[5] * temp_data[iClip3(0, max_height, j + 3)][i], 10)); + } + } + + if (imgOut->format.yuv_format != YUV400) + { + int k; + + for (k = 1; k <=2; k++) + { + max_width = imgOut->format.width[k] - 1; + max_height = imgOut->format.height[k] - 1; + + // horizontal filtering + for (j = 0; j < imgOut->format.height[k]; j++) + { + frm_data = imgIn->frm_data[k][j]; + for (i = 0; i < imgOut->format.width[k]; i++) + { + temp_data[j][i] = + SepFilter[0] * frm_data[iClip3(0, max_width, i - 2)] + + SepFilter[1] * frm_data[iClip3(0, max_width, i - 1)] + + SepFilter[2] * frm_data[iClip3(0, max_width, i )] + + SepFilter[3] * frm_data[iClip3(0, max_width, i + 1)] + + SepFilter[4] * frm_data[iClip3(0, max_width, i + 2)] + + SepFilter[5] * frm_data[iClip3(0, max_width, i + 3)]; + } + } + + for (j = 0; j < imgOut->format.height[k]; j++) + { + frm_data = imgOut->frm_data[k][j]; + for (i = 0; i < imgOut->format.width[k]; i++) + { + frm_data[i] = (imgpel) iClip3(0, imgOut->format.max_value[k], rshift_rnd_sign( + SepFilter[0] * temp_data[iClip3(0, max_height, j - 2)][i] + + SepFilter[1] * temp_data[iClip3(0, max_height, j - 1)][i] + + SepFilter[2] * temp_data[iClip3(0, max_height, j )][i] + + SepFilter[3] * temp_data[iClip3(0, max_height, j + 1)][i] + + SepFilter[4] * temp_data[iClip3(0, max_height, j + 2)][i] + + SepFilter[5] * temp_data[iClip3(0, max_height, j + 3)][i], 10)); + } + } + } + } + + free_mem2Dint(temp_data); +} + + +// to be modified +static inline void MuxImages(ImageData *imgOut, ImageData *imgIn0, ImageData *imgIn1, ImageData *Map) +{ + int i, j; + for (j = 0; j < imgOut->format.height[0]; j++) + { + for (i = 0; i < imgOut->format.width[0]; i++) + { + imgOut->frm_data[0][j][i] = (imgpel) rshift_rnd_sf(imgIn0->frm_data[0][j][i] * (Map->format.max_value[0] - Map->frm_data[0][j][i]) + imgIn1->frm_data[0][j][i] * Map->frm_data[0][j][i], Map->format.bit_depth[0]); + } + } + + if (imgOut->format.yuv_format != YUV400) + { + int k; + for (k = 1; k <=2; k++) + { + for (j = 0; j < imgOut->format.height[k]; j++) + { + for (i = 0; i < imgOut->format.width[k]; i++) + { + imgOut->frm_data[k][j][i] = (imgpel) rshift_rnd_sf(imgIn0->frm_data[k][j][i] * (Map->format.max_value[k] - Map->frm_data[k][j][i]) + imgIn1->frm_data[k][j][i] * Map->frm_data[k][j][i], Map->format.bit_depth[k]); + } + } + } + } +} + +static inline void YV12toYUV(ImageData *imgOut, ImageData *imgIn) +{ + memcpy(imgOut->frm_data[0][0], imgIn->frm_data[0][0], imgIn->format.height[0] * imgIn->format.width[0] * sizeof (imgpel)); + + if (imgIn->format.yuv_format != YUV400) + { + memcpy(imgOut->frm_data[1][0], imgIn->frm_data[2][0], imgIn->format.height[1] * imgIn->format.width[1] * sizeof (imgpel)); + memcpy(imgOut->frm_data[2][0], imgIn->frm_data[1][0], imgIn->format.height[2] * imgIn->format.width[2] * sizeof (imgpel)); + } +} + +void process_image( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + switch( p_Inp->ProcessInput ) + { + default: + case 0: + CPImage(&p_Vid->imgData, &p_Vid->imgData0); + if (p_Inp->enable_32_pulldown) + BlendImageLines(&p_Vid->imgData, &p_Vid->imgData4); + break; + case 1: + FilterImage(&p_Vid->imgData, &p_Vid->imgData0); + if (p_Inp->enable_32_pulldown) + { + FilterImage(&p_Vid->imgData32, &p_Vid->imgData4); + BlendImageLines(&p_Vid->imgData, &p_Vid->imgData32); + } + break; + case 2: + YV12toYUV(&p_Vid->imgData, &p_Vid->imgData0); + if (p_Inp->enable_32_pulldown) + { + YV12toYUV(&p_Vid->imgData32, &p_Vid->imgData4); + BlendImageLines(&p_Vid->imgData, &p_Vid->imgData32); + } + break; + case 3: + MuxImages(&p_Vid->imgData, &p_Vid->imgData0, &p_Vid->imgData1, &p_Vid->imgData2); + if (p_Inp->enable_32_pulldown) + { + MuxImages(&p_Vid->imgData32, &p_Vid->imgData4, &p_Vid->imgData5, &p_Vid->imgData6); + BlendImageLines(&p_Vid->imgData, &p_Vid->imgData32); + } + + break; + case 4: + FilterImageSep(&p_Vid->imgData, &p_Vid->imgData0); + if (p_Inp->enable_32_pulldown) + { + FilterImageSep(&p_Vid->imgData, &p_Vid->imgData4); + BlendImageLines(&p_Vid->imgData, &p_Vid->imgData32); + } + + break; + } +} + + + diff --git a/lcommon/src/input.c b/lcommon/src/input.c new file mode 100644 index 0000000..b805589 --- /dev/null +++ b/lcommon/src/input.c @@ -0,0 +1,924 @@ + +/*! + ************************************************************************************* + * \file input.c + * + * \brief + * Input related functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "defines.h" +#include "input.h" +#include "img_io.h" +#include "memalloc.h" +#include "fast_memory.h" + +void buf2img_basic ( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift); +void buf2img_endian ( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift); +void buf2img_bitshift ( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift); +void fillPlane ( imgpel** imgX, int nVal, int size_x, int size_y); + +/*! + ************************************************************************ + * \brief + * checks if the System is big- or little-endian + * \return + * 0, little-endian (e.g. Intel architectures) + * 1, big-endian (e.g. SPARC, MIPS, PowerPC) + ************************************************************************ + */ +void initInput(VideoParameters *p_Vid, FrameFormat *source, FrameFormat *output) +{ + if (source->bit_depth[0] == output->bit_depth[0] && source->bit_depth[1] == output->bit_depth[1]) + { + if (( sizeof(char) != sizeof (imgpel)) && testEndian()) + p_Vid->buf2img = buf2img_endian; + else + p_Vid->buf2img = buf2img_basic; + } + else + p_Vid->buf2img = buf2img_bitshift; +} + + +/*! + ************************************************************************ + * \brief + * checks if the System is big- or little-endian + * \return + * 0, little-endian (e.g. Intel architectures) + * 1, big-endian (e.g. SPARC, MIPS, PowerPC) + ************************************************************************ + */ +int testEndian(void) +{ + short s; + byte *p; + + p=(byte*)&s; + + s=1; + + return (*p==0); +} + +#if (DEBUG_BITDEPTH) +/*! + ************************************************************************ + * \brief + * Masking to ensure data within appropriate range + ************************************************************************ + */ +static void MaskMSBs (imgpel** imgX, int mask, int width, int height) +{ + int i,j; + + for (j=0; j < height; j++) + { + for (i=0; i < width; i++) + { + imgX[j][i]=(imgpel) (imgX[j][i] & mask); + } + } +} +#endif + +/*! + ************************************************************************ + * \brief + * Fill plane with constant value + ************************************************************************ + */ +void fillPlane ( imgpel** imgX, //!< Pointer to image plane + int nVal, //!< Fill value (currently 0 <= nVal < 256) + int size_x, //!< horizontal size of picture + int size_y //!< vertical size of picture + ) +{ + int j, i; + + if (sizeof(imgpel) == sizeof(char)) + { + fast_memset(imgX[0], nVal, size_y * size_x); + } + else + { + for (j = 0; j < size_y; j++) + { + for (i = 0; i < size_x; i++) + { + imgX[j][i] = (imgpel) nVal; + } + } + } +} + +static void deinterleave_yuv420( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + int i; + // original buffer + unsigned char *icmp = *input; + // final buffer + unsigned char *ocmp0 = *output; + + unsigned char *ocmp1 = ocmp0 + symbol_size_in_bytes * source->size_cmp[Y_COMP]; + unsigned char *ocmp2 = ocmp1 + symbol_size_in_bytes * source->size_cmp[U_COMP]; + + for (i = 0; i < source->size_cmp[U_COMP]; i++) + { + memcpy(ocmp1, icmp, symbol_size_in_bytes); + ocmp1 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + memcpy(ocmp0, icmp, 2 * symbol_size_in_bytes); + ocmp0 += 2 * symbol_size_in_bytes; + icmp += 2 * symbol_size_in_bytes; + memcpy(ocmp2, icmp, symbol_size_in_bytes); + ocmp2 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + memcpy(ocmp0, icmp, 2 * symbol_size_in_bytes); + ocmp0 += 2 * symbol_size_in_bytes; + icmp += 2 * symbol_size_in_bytes; + } + + // flip buffers + icmp = *input; + *input = *output; + *output = icmp; +} + +static void deinterleave_yuv444( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + int i; + // original buffer + unsigned char *icmp = *input; + // final buffer + unsigned char *ocmp0 = *output; + + unsigned char *ocmp1 = ocmp0 + symbol_size_in_bytes * source->size_cmp[Y_COMP]; + unsigned char *ocmp2 = ocmp1 + symbol_size_in_bytes * source->size_cmp[U_COMP]; + + for (i = 0; i < source->size_cmp[Y_COMP]; i++) + { + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + memcpy(ocmp1, icmp, symbol_size_in_bytes); + ocmp1 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + memcpy(ocmp2, icmp, symbol_size_in_bytes); + ocmp2 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + } + // flip buffers + icmp = *input; + *input = *output; + *output = icmp; +} + +static void deinterleave_yuyv ( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + int i; + // original buffer + unsigned char *icmp = *input; + // final buffer + unsigned char *ocmp0 = *output; + + unsigned char *ocmp1 = ocmp0 + symbol_size_in_bytes * source->size_cmp[Y_COMP]; + unsigned char *ocmp2 = ocmp1 + symbol_size_in_bytes * source->size_cmp[U_COMP]; + + for (i = 0; i < source->size_cmp[U_COMP]; i++) + { + // Y + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // U + memcpy(ocmp1, icmp, symbol_size_in_bytes); + ocmp1 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // Y + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // V + memcpy(ocmp2, icmp, symbol_size_in_bytes); + ocmp2 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + } + // flip buffers + icmp = *input; + *input = *output; + *output = icmp; +} + +static void deinterleave_yvyu ( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + int i; + // original buffer + unsigned char *icmp = *input; + // final buffer + unsigned char *ocmp0 = *output; + + unsigned char *ocmp1 = ocmp0 + symbol_size_in_bytes * source->size_cmp[Y_COMP]; + unsigned char *ocmp2 = ocmp1 + symbol_size_in_bytes * source->size_cmp[U_COMP]; + + for (i = 0; i < source->size_cmp[U_COMP]; i++) + { + // Y + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // V + memcpy(ocmp2, icmp, symbol_size_in_bytes); + ocmp2 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // Y + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // U + memcpy(ocmp1, icmp, symbol_size_in_bytes); + ocmp1 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + } + // flip buffers + icmp = *input; + *input = *output; + *output = icmp; +} + +static void deinterleave_uyvy ( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + int i; + // original buffer + unsigned char *icmp = *input; + // final buffer + unsigned char *ocmp0 = *output; + + unsigned char *ocmp1 = ocmp0 + symbol_size_in_bytes * source->size_cmp[Y_COMP]; + unsigned char *ocmp2 = ocmp1 + symbol_size_in_bytes * source->size_cmp[U_COMP]; + + for (i = 0; i < source->size_cmp[U_COMP]; i++) + { + // U + memcpy(ocmp1, icmp, symbol_size_in_bytes); + ocmp1 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // Y + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // V + memcpy(ocmp2, icmp, symbol_size_in_bytes); + ocmp2 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + // Y + memcpy(ocmp0, icmp, symbol_size_in_bytes); + ocmp0 += symbol_size_in_bytes; + icmp += symbol_size_in_bytes; + } + // flip buffers + icmp = *input; + *input = *output; + *output = icmp; +} + +static void deinterleave_v210 ( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + int i; + // original buffer + unsigned char *icmp = *input; + + unsigned int *ui32cmp = (unsigned int *) *input; + unsigned short *ui16cmp0 = (unsigned short *) *output; + unsigned short *ui16cmp1 = ui16cmp0 + source->size_cmp[0]; + unsigned short *ui16cmp2 = ui16cmp1 + source->size_cmp[1]; + + for (i = 0; i < source->size_cmp[U_COMP] / 3; i++) + { + // Byte 3 Byte 2 Byte 1 Byte 0 + // Cr 0 Y 0 Cb 0 + // X X 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + *ui16cmp2 = (*ui32cmp & 0x3FF00000)>>20; // Cr 0 + *ui16cmp0 = (*ui32cmp & 0xffc00)>>10; // Y 0 + *ui16cmp1 = (*(ui32cmp++) & 0x3FF); // Cb 0 + + // Byte 7 Byte 6 Byte 5 Byte 4 + // Y 2 Cb 1 Y 1 + // X X 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + *(ui16cmp0 + 2) = (*ui32cmp & 0x3FF00000)>>20; // Y 2 + *(ui16cmp1 + 1) = (*ui32cmp & 0xffc00)>>10; // Cb 1 + *(ui16cmp0 + 1) = (*(ui32cmp++) & 0x3FF); // Y 1 + + // Byte 11 Byte 10 Byte 9 Byte 8 + // Cb 2 Y 3 Cr 1 + // X X 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + *(ui16cmp1 + 2) = (*ui32cmp & 0x3FF00000)>>20; // Cb 2 + *(ui16cmp0 + 3) = (*ui32cmp & 0xffc00)>>10; // Y 3 + *(ui16cmp2 + 1) = (*(ui32cmp++) & 0x3FF); // Cr 1 + + // Byte 15 Byte 14 Byte 13 Byte 12 + // Y 5 Cr 2 Y 4 + // X X 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + *(ui16cmp0 + 5) = (*ui32cmp & 0x3FF00000)>>20; // Y 2 + *(ui16cmp2 + 2) = (*ui32cmp & 0xffc00)>>10; // Cb 1 + *(ui16cmp0 + 4) = (*(ui32cmp++) & 0x3FF); // Y 1 + + //printf("luma: %d %d %d %d %d %d\n", *(ui16cmp0 + 0), *(ui16cmp0 + 1), *(ui16cmp0 + 2), *(ui16cmp0 + 3), *(ui16cmp0 + 4), *(ui16cmp0 + 5)); + + ui16cmp0 += 6; + ui16cmp1 += 3; + ui16cmp2 += 3; + } + // flip buffers + icmp = *input; + *input = *output; + *output = icmp; +} + +/*! + ************************************************************************ + * \brief + * Deinterleave file read buffer to source picture structure + ************************************************************************ + */ +static void deinterleave ( unsigned char** input, //!< input buffer + unsigned char** output, //!< output buffer + FrameFormat *source, //!< format of source buffer + int symbol_size_in_bytes //!< number of bytes per symbol + ) +{ + if (source->yuv_format == YUV420) + { // UYYVYY + deinterleave_yuv420(input, output, source, symbol_size_in_bytes); + } + else if (source->yuv_format == YUV422) + { + if (source->pixel_format == YUYV || source->pixel_format == YUY2) + { + deinterleave_yuyv(input, output, source, symbol_size_in_bytes); + } + else if (source->pixel_format == YVYU) + { + deinterleave_yvyu(input, output, source, symbol_size_in_bytes); + } + else if (source->pixel_format == UYVY) + { + deinterleave_uyvy(input, output, source, symbol_size_in_bytes); + } + else if (source->pixel_format == V210) + { + deinterleave_v210(input, output, source, symbol_size_in_bytes); + } + else { + printf( "Unsupported pixel format.\n"); + exit(EXIT_FAILURE); + } + } + else if (source->yuv_format == YUV444) + deinterleave_yuv444(input, output, source, symbol_size_in_bytes); +} + +/*! + ************************************************************************ + * \brief + * Convert file read buffer to source picture structure + ************************************************************************ + */ +void buf2img_bitshift ( imgpel** imgX, //!< Pointer to image plane + unsigned char* buf, //!< Buffer for file output + int size_x, //!< horizontal size of picture + int size_y, //!< vertical size of picture + int o_size_x, //!< horizontal size of picture + int o_size_y, //!< vertical size of picture + int symbol_size_in_bytes, //!< number of bytes in file used for one pixel + int bitshift //!< variable for bitdepth expansion + ) +{ + int i,j; + + uint16 tmp16, ui16; + unsigned long tmp32, ui32; + + // This test should be done once. + if (((symbol_size_in_bytes << 3) - bitshift) > (sizeof(imgpel)<< 3)) + { + error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500); + } + + if (testEndian()) + { + if (size_x != o_size_x || size_y != o_size_y) + { + error ("Rescaling not supported in big endian architectures. ", 500); + } + + // big endian + switch (symbol_size_in_bytes) + { + case 1: + { + for(j = 0; j < o_size_y; j++) + for(i = 0; i < o_size_x; i++) + { + imgX[j][i]= (imgpel) rshift_rnd(buf[i + j*size_x], bitshift); + } + break; + } + case 2: + { + for(j = 0; j < o_size_y; j++) + for(i = 0; i < o_size_x; i++) + { + memcpy(&tmp16, buf + ((i + j * size_x) * 2), 2); + ui16 = (tmp16 >> 8) | ((tmp16 & 0xFF) << 8); + imgX[j][i] = (imgpel) rshift_rnd(ui16, bitshift); + } + break; + } + case 4: + { + for(j = 0; j < o_size_y; j++) + for(i = 0; i < o_size_x; i++) + { + memcpy(&tmp32, buf + ((i + j * size_x) * 4), 4); + ui32 = ((tmp32 & 0xFF00) << 8) | ((tmp32 & 0xFF)<<24) | ((tmp32 & 0xFF0000)>>8) | ((tmp32 & 0xFF000000)>>24); + imgX[j][i] = (imgpel) rshift_rnd(ui32, bitshift); + } + } + default: + { + error ("reading only from formats of 8, 16 or 32 bit allowed on big endian architecture", 500); + break; + } + } + } + else + { + // little endian + int j_pos; + if (size_x == o_size_x && size_y == o_size_y) + { + for (j = 0; j < o_size_y; j++) + { + j_pos = j*size_x; + for (i = 0; i < o_size_x; i++) + { + ui16=0; + memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes); + imgX[j][i] = (imgpel) rshift_rnd(ui16,bitshift); + } + } + } + else + { + int iminwidth = imin(size_x, o_size_x); + int iminheight = imin(size_y, o_size_y); + int dst_offset_x = 0, dst_offset_y = 0; + int offset_x = 0, offset_y = 0; // currently not used + + // determine whether we need to center the copied frame or crop it + if ( o_size_x >= size_x ) + dst_offset_x = ( o_size_x - size_x ) >> 1; + + if (o_size_y >= size_y) + dst_offset_y = ( o_size_y - size_y ) >> 1; + + // check copied area to avoid copying memory garbage + // source + iminwidth = ( (offset_x + iminwidth ) > size_x ) ? (size_x - offset_x) : iminwidth; + iminheight = ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight; + // destination + iminwidth = ( (dst_offset_x + iminwidth ) > o_size_x ) ? (o_size_x - dst_offset_x) : iminwidth; + iminheight = ( (dst_offset_y + iminheight) > o_size_y ) ? (o_size_y - dst_offset_y) : iminheight; + + for (j=0; j < iminheight; j++) + { + j_pos = (j + offset_y) * size_x + offset_x; + for (i=0; i < iminwidth; i++) + { + ui16=0; + memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes); + imgX[j + dst_offset_y][i + dst_offset_x] = (imgpel) rshift_rnd(ui16,bitshift); + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Convert file read buffer to source picture structure + ************************************************************************ + */ +void buf2img_basic (imgpel** imgX, //!< Pointer to image plane + unsigned char* buf, //!< Buffer for file output + int size_x, //!< horizontal size of picture + int size_y, //!< vertical size of picture + int o_size_x, //!< horizontal size of picture + int o_size_y, //!< vertical size of picture + int symbol_size_in_bytes, //!< number of bytes in file used for one pixel + int dummy //!< dummy variable used for allowing function pointer use + ) +{ + int i,j; + unsigned char* temp_buf = buf; + + if (symbol_size_in_bytes> sizeof(imgpel)) + { + error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500); + } + + if (( sizeof (imgpel) == symbol_size_in_bytes)) + { + // imgpel == pixel_in_file -> simple copy + if (size_x == o_size_x && size_y == o_size_y) + memcpy(&imgX[0][0], temp_buf, size_x * size_y * sizeof(imgpel)); + else + { + int iminwidth = imin(size_x, o_size_x); + int iminheight = imin(size_y, o_size_y); + int dst_offset_x = 0, dst_offset_y = 0; + int offset_x = 0, offset_y = 0; // currently not used + + // determine whether we need to center the copied frame or crop it + if ( o_size_x >= size_x ) + dst_offset_x = ( o_size_x - size_x ) >> 1; + + if (o_size_y >= size_y) + dst_offset_y = ( o_size_y - size_y ) >> 1; + + // check copied area to avoid copying memory garbage + // source + iminwidth = ( (offset_x + iminwidth ) > size_x ) ? (size_x - offset_x) : iminwidth; + iminheight = ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight; + // destination + iminwidth = ( (dst_offset_x + iminwidth ) > o_size_x ) ? (o_size_x - dst_offset_x) : iminwidth; + iminheight = ( (dst_offset_y + iminheight) > o_size_y ) ? (o_size_y - dst_offset_y) : iminheight; + + for (i=0; i= size_x ) + dst_offset_x = ( o_size_x - size_x ) >> 1; + + if (o_size_y >= size_y) + dst_offset_y = ( o_size_y - size_y ) >> 1; + + // check copied area to avoid copying memory garbage + // source + iminwidth = ( (offset_x + iminwidth ) > size_x ) ? (size_x - offset_x) : iminwidth; + iminheight = ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight; + // destination + iminwidth = ( (dst_offset_x + iminwidth ) > o_size_x ) ? (o_size_x - dst_offset_x) : iminwidth; + iminheight = ( (dst_offset_y + iminheight) > o_size_y ) ? (o_size_y - dst_offset_y) : iminheight; + + for (j = 0; j < iminheight; j++) + { + memcpy(&imgX[j + dst_offset_y][dst_offset_x], &(temp_buf[(j + offset_y) * size_x + offset_x]), iminwidth * symbol_size_in_bytes); + } + for (j=0; j < iminheight; j++) + { + j_pos = (j + offset_y) * size_x + offset_x; + for (i=0; i < iminwidth; i++) + { + ui16 = 0; + memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes); + imgX[j + dst_offset_y][i + dst_offset_x]= (imgpel) ui16; + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Convert file read buffer to source picture structure + ************************************************************************ + */ +void buf2img_endian (imgpel** imgX, //!< Pointer to image plane + unsigned char* buf, //!< Buffer for file output + int size_x, //!< horizontal size of picture + int size_y, //!< vertical size of picture + int o_size_x, //!< horizontal size of picture + int o_size_y, //!< vertical size of picture + int symbol_size_in_bytes, //!< number of bytes in file used for one pixel + int dummy //!< dummy variable used for allowing function pointer use + ) +{ + int i,j; + + uint16 tmp16, ui16; + unsigned long tmp32, ui32; + + if (symbol_size_in_bytes > sizeof(imgpel)) + { + error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500); + } + + if (size_x != o_size_x || size_y != o_size_y) + { + error ("Rescaling not supported in big endian architectures. ", 500); + } + + // big endian + switch (symbol_size_in_bytes) + { + case 1: + { + for(j=0;j> 8) | ((tmp16&0xFF)<<8); + imgX[j][i] = (imgpel) ui16; + } + } + break; + } + case 4: + { + for(j=0;j>8) | ((tmp32&0xFF000000)>>24); + imgX[j][i] = (imgpel) ui32; + } + } + break; + } + default: + { + error ("reading only from formats of 8, 16 or 32 bit allowed on big endian architecture", 500); + break; + } + } +} + +/*! + ************************************************************************ + * \brief + * Create Frame Memory buffer + * + ************************************************************************ + */ +void AllocateFrameMemory (VideoParameters *p_Vid, InputParameters *p_Inp, FrameFormat *source) +{ + // Note that size seems to be ok even for v210 formats (wasteful yes, but should not + // create any issues with how we manage that format. + if (NULL == (p_Vid->buf = malloc (source->size * source->pic_unit_size_shift3))) + no_mem_exit("AllocateFrameMemory: p_Vid->buf"); + if (p_Inp->input_file1.is_interleaved) + { + if (NULL == (p_Vid->ibuf = malloc (source->size * source->pic_unit_size_shift3))) + no_mem_exit("AllocateFrameMemory: p_Vid->ibuf"); + } +} + +/*! + ************************************************************************ + * \brief + * Delete Frame Memory buffer + * + ************************************************************************ + */ +void DeleteFrameMemory (VideoParameters *p_Vid) +{ + if (p_Vid->buf != NULL) + free (p_Vid->buf); + if (p_Vid->ibuf != NULL) + free (p_Vid->ibuf); +} + +/*! + ************************************************************************ + * \brief + * Reads one new frame from file + * + * \param input_file + * structure containing information (filename, format) about the source file + * \param FrameNoInFile + * Frame number in the source file + * \param HeaderSize + * Number of bytes in the source file to be skipped + * \param source + * source file (on disk) information + * \param output + * output file (for encoding) information + * \param pImage + * Image planes + ************************************************************************ + */ +int read_one_frame (VideoParameters *p_Vid, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, FrameFormat *output, imgpel **pImage[3]) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int file_read = 0; + unsigned int symbol_size_in_bytes = source->pic_unit_size_shift3; + + const int bytes_y = source->size_cmp[0] * symbol_size_in_bytes; + const int bytes_uv = source->size_cmp[1] * symbol_size_in_bytes; + int bit_scale; + + Boolean rgb_input = (Boolean) (source->color_model == CM_RGB && source->yuv_format == YUV444); + + if (input_file->is_concatenated == 0) + { + if (input_file->vdtype == VIDEO_TIFF) + { + file_read = ReadTIFFImage (p_Inp, input_file, FrameNoInFile, source, p_Vid->buf); + } + else + { + file_read = ReadFrameSeparate (p_Inp, input_file, FrameNoInFile, HeaderSize, source, p_Vid->buf); + } + } + else + { + file_read = ReadFrameConcatenated (p_Inp, input_file, FrameNoInFile, HeaderSize, source, p_Vid->buf); + } + + if ( !file_read ) + { + return 0; + } + + // De-interleave input source + if (input_file->is_interleaved) + { + deinterleave ( &p_Vid->buf, &p_Vid->ibuf, source, symbol_size_in_bytes); + } + + bit_scale = source->bit_depth[0] - output->bit_depth[0]; + + if(rgb_input) + p_Vid->buf2img(pImage[0], p_Vid->buf + bytes_y, source->width[0], source->height[0], output->width[0], output->height[0], symbol_size_in_bytes, bit_scale); + else + p_Vid->buf2img(pImage[0], p_Vid->buf, source->width[0], source->height[0], output->width[0], output->height[0], symbol_size_in_bytes, bit_scale); + +#if (DEBUG_BITDEPTH) + MaskMSBs(pImage[0], ((1 << output->bit_depth[0]) - 1), output->width[0], output->height[0]); +#endif + + if (p_Vid->yuv_format != YUV400) + { + bit_scale = source->bit_depth[1] - output->bit_depth[1]; +#if (ALLOW_GRAYSCALE) + if (!p_Inp->grayscale) +#endif + { + if(rgb_input) + p_Vid->buf2img(pImage[1], p_Vid->buf + bytes_y + bytes_uv, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale); + else + p_Vid->buf2img(pImage[1], p_Vid->buf + bytes_y, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale); + + bit_scale = source->bit_depth[2] - output->bit_depth[2]; + if(rgb_input) + p_Vid->buf2img(pImage[2], p_Vid->buf, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale); + else + p_Vid->buf2img(pImage[2], p_Vid->buf + bytes_y + bytes_uv, source->width[1], source->height[1], output->width[1], output->height[1], symbol_size_in_bytes, bit_scale); + } +#if (DEBUG_BITDEPTH) + MaskMSBs(pImage[1], ((1 << output->bit_depth[1]) - 1), output->width[1], output->height[1]); + MaskMSBs(pImage[2], ((1 << output->bit_depth[2]) - 1), output->width[1], output->height[1]); +#endif + } + + return file_read; +} + +/*! + ************************************************************************ + * \brief + * Padding of automatically added border for picture sizes that are not + * multiples of macroblock/macroblock pair size + * + * \param output + * Image dimensions + * \param img_size_x + * coded image horizontal size (luma) + * \param img_size_y + * code image vertical size (luma) + * \param img_size_x_cr + * coded image horizontal size (chroma) + * \param img_size_y_cr + * code image vertical size (chroma) + * \param pImage + * image planes + ************************************************************************ + */ +void pad_borders (FrameFormat output, int img_size_x, int img_size_y, int img_size_x_cr, int img_size_y_cr, imgpel **pImage[3]) +{ + int x, y; + + // Luma or 1st component + // padding right border + if (output.width[0] < img_size_x) + for (y = 0; y < output.height[0]; y++) + for (x = output.width[0]; x < img_size_x; x++) + pImage[0][y][x] = pImage[0][y][x-1]; + + // padding bottom border + if (output.height[0] < img_size_y) + for (y = output.height[0]; y + * + ************************************************************************************* + */ +#include "contributors.h" + +#include "global.h" +#include "img_io.h" + +#define FAST_READ 1 + +#if FAST_READ +static inline int ReadData (int vfile, FrameFormat *source, unsigned char *buf) +{ + unsigned char *cur_buf = buf; + int read_size = source->pic_unit_size_shift3 * source->width[0]; + int i, j; + for (i = 0; i < source->height[0]; i++) + { + if (read(vfile, cur_buf, read_size) != read_size) + { + printf ("read_one_frame: cannot read %d bytes from input file, unexpected EOF!\n", source->width[0]); + return 0; + } + cur_buf += read_size; + } + + if (source->yuv_format != YUV400) + { + read_size = source->pic_unit_size_shift3 * source->width[1]; + for (j = 0; j < 2; j++) + { + for (i = 0; i < source->height[1]; i++) + { + if (read(vfile, cur_buf, read_size) != read_size) + { + printf ("read_one_frame: cannot read %d bytes from input file, unexpected EOF!\n", source->width[1]); + return 0; + } + cur_buf += read_size; + } + } + } + return 1; +} +#else +static inline int ReadData (int vfile, int framesize_in_bytes, unsigned char *buf) +{ + if (read(vfile, buf, (int) framesize_in_bytes) != (int) framesize_in_bytes) + { + printf ("read_one_frame: cannot read %d bytes from input file, unexpected EOF!\n", (int) framesize_in_bytes); + return 0; + } + else + { + return 1; + } +} +#endif + +static inline int ReadDataV210 (int vfile, int framesize_in_bytes, unsigned char *buf) +{ + if (read(vfile, buf, (int) framesize_in_bytes) != (int) framesize_in_bytes) + { + printf ("read_one_frame: cannot read %d bytes from input file, unexpected EOF!\n", (int) framesize_in_bytes); + return 0; + } + else + { + return 1; + } +} + + +/*! + ************************************************************************ + * \brief + * Reads one new frame from concatenated raw file + * Code does not distinguish between planar and interleaved data + * + * \param input_file + * Input file to read from + * \param FrameNoInFile + * Frame number in the source file + * \param HeaderSize + * Number of bytes in the source file to be skipped + * \param source + * source file (on disk) information + * \param buf + * image buffer data + ************************************************************************ + */ +int ReadFrameConcatenated (InputParameters *p_Inp, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, unsigned char *buf) +{ + int file_read = 0; + int vfile = input_file->f_num; + Boolean is_v210 = (input_file->is_interleaved && source->pixel_format == V210); + unsigned int symbol_size_in_bytes = source->pic_unit_size_shift3; + + const int bytes_y = source->size_cmp[0] * symbol_size_in_bytes; + const int bytes_uv = source->size_cmp[1] * symbol_size_in_bytes; + + const int64 framesize_in_bytes = (is_v210 == TRUE) ? 16 * (source->size_cmp[0] / 6) : bytes_y + 2 * bytes_uv; + + // Let us seek directly to the current frame + if (lseek (vfile, HeaderSize + framesize_in_bytes * (FrameNoInFile + p_Inp->start_frame), SEEK_SET) == -1) + { + snprintf(errortext, ET_SIZE, "read_one_frame: cannot advance file pointer in input file beyond frame %d\n", p_Inp->start_frame + FrameNoInFile); + error (errortext,-1); + } + + // Here we are at the correct position for the source frame in the file. + // Now read it. + if ((source->pic_unit_size_on_disk & 0x07) == 0) + { + if (is_v210 == TRUE) + { + file_read = ReadDataV210(vfile, (int) framesize_in_bytes, buf); + } + else + { +#if FAST_READ + file_read = ReadData (vfile, source, buf); +#else + file_read = ReadData (vfile, (int) framesize_in_bytes, buf); +#endif + } + } + else + { + printf ("read_one_frame (NOT IMPLEMENTED): pic unit size on disk must be divisible by 8"); + exit (-1); + } + return file_read; +} + +/*! + ************************************************************************ + * \brief + * Reads one new frame from separate data files + * Code does not distinguish between planar and interleaved data + * + * \param input_file + * Input file to read from + * \param FrameNoInFile + * Frame number in the source file + * \param HeaderSize + * Number of bytes in the source file to be skipped + * \param source + * source file (on disk) information + * \param buf + * taget buffer + ************************************************************************ + */ +int ReadFrameSeparate (InputParameters *p_Inp, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, unsigned char *buf) +{ + int file_read = 0; + int vfile = input_file->f_num; + + OpenFrameFile( input_file, FrameNoInFile + p_Inp->start_frame); + + // skip Header + if (lseek (vfile, HeaderSize, SEEK_SET) != HeaderSize) + { + error ("read_one_frame: cannot fseek to (Header size) in input file", -1); + } + + // Read data + if ((source->pic_unit_size_on_disk & 0x07) == 0) + { +#if FAST_READ + file_read = ReadData (vfile, source, buf); +#else + unsigned int symbol_size_in_bytes = source->pic_unit_size_shift3; + + const int bytes_y = source->size_cmp[0] * symbol_size_in_bytes; + const int bytes_uv = source->size_cmp[1] * symbol_size_in_bytes; + const int64 framesize_in_bytes = bytes_y + 2*bytes_uv; + + file_read = ReadData (vfile, (int) framesize_in_bytes, buf); +#endif + } + else + { + printf ("read_one_frame (NOT IMPLEMENTED): pic unit size on disk must be divisible by 8"); + exit (-1); + } + + if (vfile != -1) + close(vfile); + + return file_read; +} diff --git a/lcommon/src/io_tiff.c b/lcommon/src/io_tiff.c new file mode 100644 index 0000000..72331e7 --- /dev/null +++ b/lcommon/src/io_tiff.c @@ -0,0 +1,1153 @@ +/*! + ************************************************************************************* + * \file io_tiff.c + * + * \brief + * I/O functions related to TIFF images + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Larry Luther + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "contributors.h" +#include "report.h" +#include "io_tiff.h" + + +// Maximum number of rows in image +#define YRES 1080 + +// Order of member variables is critical + +//! TIFF Field Type Code +typedef enum TiffType { + T_BYTE = 1, //!< 8-bit unsigned integer. + T_ASCII = 2, //!< 8-bit byte that contains a 7-bit ASCII code; the last byte must be NUL (binary zero). + T_SHORT = 3, //!< 16-bit (2-byte) unsigned integer. + T_LONG = 4, //!< 32-bit (4-byte) unsigned integer. + T_RATIONAL = 5, //!< Two LONGs: the first represents the numerator of a fraction; the second, the denominator. + T_SBYTE = 6, //!< An 8-bit signed (twos-complement) integer. + T_UNDEFINED = 7, //!< An 8-bit byte that may contain anything, depending on the definition of the field. + T_SSHORT = 8, //!< A 16-bit (2-byte) signed (twos-complement) integer. + T_SLONG = 9, //!< A 32-bit (4-byte) signed (twos-complement) integer. + T_SRATIONAL = 10, //!< Two SLONG’s: the first represents the numerator of a fraction, the second the denominator. + T_FLOAT = 11, //!< Single precision (4-byte) IEEE format. + T_DOUBLE = 12 //!< Double precision (8-byte) IEEE format. +} TiffType; + + +typedef struct TiffDirectoryEntry { + uint16 tag; //!< The tag that identifies the field. + uint16 type; //!< The field type. + uint32 count; //!< Number of values of the indicated type. + uint32 offset; //!< Value or offset. +} TiffDirectoryEntry; + + +//! TIFF Image File Directory +typedef struct TiffIFD { + uint16 nEntries; + TiffDirectoryEntry *directoryEntry; +} TiffIFD; + + +typedef struct TiffImageFileHeader { + uint16 byteOrder; //!< "II" (4949H) or "MM" (4D4DH) + uint16 arbitraryNumber; //!< 42 + uint32 offset; //!< Offset of the 0th IFD +} TiffImageFileHeader; + + +//! TIFF file data +typedef struct Tiff { + uint16 *img; //!< Image data + uint8 *fileInMemory; //!< The file will be read into memory in one gulp here. + uint8 *mp; //!< Memory pointer. + int le; //!< Little endian - 0 false, 1 - true + int nStrips; + TiffImageFileHeader ifh; + // Information from TAGs + uint16 Orientation; + uint32 + BitsPerSample[3], + RowsPerStrip, + ImageLength, + ImageWidth, + StripByteCounts[YRES], + StripOffsets[YRES], + XResolution[2], + YResolution[2]; + + uint32 (*getU16) (struct Tiff *); + uint32 (*getU32) (struct Tiff *); +} Tiff; + +//! Video codes for RGB ==> YUV conversions +typedef enum VideoCode { + VC_NULL = 0, + VC_ITU_REC709 = 1, + VC_CCIR_601 = 3, + VC_FCC = 4, + VC_ITU_REC624BG = 5, + VC_SMPTE_170M = 6, + VC_SMPTE_240M = 7, + VC_SMPTE_260M = 7, + VC_ITU_REC709_EXACT = 8, + VC_MAX = 8 +} VideoCode; + + +static const double Coef[VC_MAX+1][3] = { + {0.299 , 0.587 , 0.114}, // 0 unspecified + {0.2126 , 0.7152 , 0.0722}, // 1 SMPTE RP-177 & 274M, ITU-R Rec. 709 + {0.299 , 0.587 , 0.114}, // 2 unspecified + {0.299 , 0.587 , 0.114}, // 3 CCIR 601 ITU-R BT.601 / SMPTE 125M + {0.30 , 0.59 , 0.11}, // 4 FCC + {0.299 , 0.587 , 0.114}, // 5 ITU-R Rec. 624-4 System B, G + {0.299 , 0.587 , 0.114}, // 6 SMPTE 170M + {0.212 , 0.701 , 0.087}, // 7 SMPTE 240M (1987) 260M + {0.212639, 0.715169, 0.072192} // 8 SMPTE RP-177 & 274M, ITU-R Rec. 709 exact +}; + +#define CR Coef[videoCode][0] +#define CG Coef[videoCode][1] +#define CB Coef[videoCode][2] +#define CU (0.5/(CB-1.0)) +#define CV (0.5/(CR-1.0)) + + +#define stdScaleY 219.0 // nominal range: 16..235 +#define stdScaleUV 224.0 // nominal range: 16..240 + +#define INTEGER_SCALE 16384 +#define INTEGER_SHIFT 14 + + +//! Parameters for RGB ==> YUV conversions. +typedef struct RGB_YUV { + uint16 + pixMax; //!< Maximum pixel value. + int + stdRange, //!< 0 = full range, 1 = std range + y, u, v, + r, g, b, + yr, yg, yb, + ur, ug, ub, + vr, vg, vb, + offy, offuv; + double + sy, suv; +} RGB_YUV; + +/*! + ************************************************************************ + * \brief + * Initialize pointer variables, since they are maintained across multiple calls to ReadTIFFImage + * + ************************************************************************ + */ +void constructTiff (Tiff * t) +{ + t->fileInMemory = 0; + t->img = 0; + t->mp = 0; +} + + +/*! + ************************************************************************ + * \brief + * free allocated memory + * + ************************************************************************ + */ +void destructTiff (Tiff * t) +{ + free_pointer( t->fileInMemory); + free_pointer( t->img); +} + + +// No swap versions + +/*! + ************************************************************************ + * \brief + * Get an unsigned short without swapping. + * + ************************************************************************ + */ +static uint32 getU16 (Tiff * t) +{ + union { + uint8 in[2]; + uint16 out; + } u; + u.in[0] = *t->mp++; + u.in[1] = *t->mp++; + return u.out; +} + + +/*! + ************************************************************************ + * \brief + * Get an unsigned long without swapping. + * + ************************************************************************ + */ +static uint32 getU32 (Tiff * t) +{ + union { + uint8 in[4]; + uint32 out; + } u; + u.in[0] = *t->mp++; + u.in[1] = *t->mp++; + u.in[2] = *t->mp++; + u.in[3] = *t->mp++; + return u.out; +} + + +// Swap versions + +/*! + ************************************************************************ + * \brief + * Get an unsigned short and swap. + * + ************************************************************************ + */ +static uint32 getSwappedU16 (Tiff * t) +{ + union { + uint8 in[2]; + uint16 out; + } u; + u.in[1] = *t->mp++; + u.in[0] = *t->mp++; + return u.out; +} + + +/*! + ************************************************************************ + * \brief + * Get an unsigned long and swap. + * + ************************************************************************ + */ +static uint32 getSwappedU32 (Tiff * t) +{ + union { + uint8 in[4]; + uint32 out; + } u; + u.in[3] = *t->mp++; + u.in[2] = *t->mp++; + u.in[1] = *t->mp++; + u.in[0] = *t->mp++; + return u.out; +} + + +/*! + ************************************************************************ + * \brief + * Get an array of (uint16|uint32|rational). + * + ************************************************************************ + */ +static void getIntArray (Tiff * t, uint32 offset, TiffType type, uint32 a[], int n) +{ + int i; + uint8 *mp = t->mp; // save memory pointer + + t->mp = t->fileInMemory + offset; + switch (type) + { + case T_SHORT: + for (i=0; i < n; ++i) + { + a[i] = getU16( t); + } + break; + case T_LONG: + for (i=0; i < n; ++i) + { + a[i] = getU32( t); + } + break; + case T_RATIONAL: + for (i=0; i < 2*n; ++i) + { + a[i] = getU32( t); + } + break; + default: + assert( type == T_SHORT || type == T_LONG || type == T_RATIONAL); + } + t->mp = mp; // restore memory pointer +} + + +/*! + ************************************************************************ + * \brief + * Read DirectoryEntry and store important results in 't'. + * + ************************************************************************ + */ +static int readDirectoryEntry (Tiff * t) +{ + uint32 tag = t->getU16( t); + TiffType type = (TiffType) t->getU16( t); + uint32 count = t->getU32( t); + uint32 offset = t->getU32( t); + + switch (tag) + { + case 256: // ImageWidth SHORT or LONG + assert( count == 1); + //printf( "256: ImageWidth = %u\n", offset); + t->ImageWidth = offset; + break; + case 257: // ImageLength SHORT or LONG + assert( count == 1); + //printf( "257: ImageLength = %u\n", offset); + t->ImageLength = offset; + if (offset > YRES) + { + fprintf( stdout, "readDirectoryEntry: ImageLength (%d) exceeds builtin maximum of %d\n", offset, YRES); + return 1; + } + break; + case 258: // BitsPerSample SHORT 8,8,8 + if (count != 3) + { + fprintf( stdout, "BitsPerSample (only [3] supported)\n"); + return 1; + } + getIntArray( t, offset, type, t->BitsPerSample, 3); + //printf( "258: BitsPerSample[%d] = %u,%u,%u\n", count, t->BitsPerSample[0], t->BitsPerSample[1], t->BitsPerSample[2]); + if (t->BitsPerSample[0] != t->BitsPerSample[1] || t->BitsPerSample[0] != t->BitsPerSample[2]) + { + fprintf( stdout, "BitsPerSample must be the same for all samples\n"); + return 1; + } + if (t->BitsPerSample[0] != 8 && t->BitsPerSample[0] != 16) + { + fprintf( stdout, "Only 8 or 16 BitsPerSample is supported\n"); + return 1; + } + break; + case 259: // Compression SHORT 1 or 32773 + assert( count == 1); + //printf( "259: Compression = %u\n", offset); + if (offset != 1) + { + fprintf( stdout, "Only uncompressed TIFF files supported\n"); + return 1; + } + break; + case 262: // PhotometricInterpretation SHORT 2 + assert( count == 1); + //printf( "262: PhotometricInterpretation = %u\n", offset); + assert( offset == 2); + break; + case 273: // StripOffsets SHORT or LONG + //printf( "273: StripOffsets[%d] = %u\n", count, offset); + getIntArray( t, offset, type, t->StripOffsets, count); + t->nStrips = count; + break; + case 274: // Orientation SHORT + assert( count == 1); + //printf( "274: Orientation = %u\n", offset); + t->Orientation = (uint16) offset; + if (t->Orientation != 1) + { + fprintf( stdout, "Only Orientation 1 is supported\n"); + return 1; + } + break; + case 277: // SamplesPerPixel SHORT 3 or more + assert( count == 1); + //printf( "277: SamplesPerPixel = %u\n", offset); + assert( offset == 3); + break; + case 278: // RowsPerStrip SHORT or LONG + assert( count == 1); + //printf( "278: RowsPerStrip = %u\n", offset); + t->RowsPerStrip = offset; + break; + case 279: // StripByteCounts LONG or SHORT + //printf( "279: StripByteCounts[%u] = %u\n", count, offset); + getIntArray( t, offset, type, t->StripByteCounts, count); + break; + case 282: // XResolution RATIONAL + assert( count == 1); + getIntArray( t, offset, type, t->XResolution, 1); + //printf( "282: XResolution = %u/%u\n", offset, t->XResolution[0], t->XResolution[1]); + break; + case 283: // YResolution RATIONAL + assert( count == 1); + getIntArray( t, offset, type, t->YResolution, 1); + //printf( "283: YResolution = %u/%u\n", offset, t->YResolution[0], t->YResolution[1]); + break; + case 284: // PlanarConfiguration SHORT + assert( count == 1); + //printf( "284: PlanarConfiguration = %u\n", offset); + assert( offset == 1); + break; + case 296: // ResolutionUnit SHORT 1, 2 or 3 + //printf( "296: ResolutionUnit = %u\n", offset); + assert( count == 1); + break; + case 305: // Software ASCII + //printf( "305: Software = %s\n", t->fileInMemory + offset); + break; + case 339: // SampleFormat SHORT 1 + default: + //printf( "%3d: Unforseen = %u\n", tag, offset); + ; + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * Read file named 'path' into memory buffer 't->fileInMemory'. + * + * \return + * 0 if successful + ************************************************************************ + */ +static int readFileIntoMemory (Tiff * t, const char * path) +{ + long + cnt, result; + uint16 + byteOrder; + int + endian = 1, + machineLittleEndian = (*( (char *)(&endian) ) == 1) ? 1 : 0, + fd; + + assert( t); + assert( path); + + fd = open( path, OPENFLAGS_READ); + if (fd == -1) + { + fprintf( stdout, "Couldn't open to read: %s\n", path); + return 1; + } + + cnt = (long) lseek( fd, 0, SEEK_END); // TIFF files by definition cannot exceed 2^32 + if (cnt == -1L) + return 1; + + if (lseek( fd, 0, SEEK_SET) == -1L) // reposition file at beginning + return 1; + + t->fileInMemory = (uint8 *) realloc( t->fileInMemory, cnt); + if (t->fileInMemory == 0) + { + close( fd); + return 1; + } + + result = (long) read( fd, t->fileInMemory, cnt); + if (result != cnt) + { + close( fd); + return 1; + } + + close( fd); + + byteOrder = (t->fileInMemory[0] << 8) | t->fileInMemory[1]; + switch (byteOrder) + { + case 0x4949: // little endian file + t->le = 1; + //printf( "Little endian file\n"); + break; + case 0x4D4D: // big endian file + t->le = 0; + //printf( "Big endian file\n"); + break; + default: + fprintf( stdout, "First two bytes indicate: Not a TIFF file\n"); + free_pointer( t->fileInMemory); + return 1; + } + if (t->le == machineLittleEndian) // endianness of machine matches file + { + t->getU16 = getU16; + t->getU32 = getU32; + } + else // endianness of machine does not match file + { + t->getU16 = getSwappedU16; + t->getU32 = getSwappedU32; + } + t->mp = t->fileInMemory; + return 0; +} + +/*! + ************************************************************************ + * \brief + * Read image data into 't->img'. + * + ************************************************************************ + */ +static int readImageData (Tiff * t) +{ + int i, j, n; + uint8 *mp, *s; + uint16 *p; + uint32 size; + + assert( t); + + size = t->ImageWidth * t->ImageLength * 3 * sizeof(uint16); + t->img = (uint16 *) realloc( t->img, size); + if (t->img == 0) + return 1; + + switch (t->BitsPerSample[0]) + { + case 8: + p = t->img; + for (i=0; i < t->nStrips; ++i) + { + n = t->StripByteCounts[i]; + s = t->fileInMemory + t->StripOffsets[i]; + for (j=0; j < n; ++j) + { + *p++ = *s++; + } + } + break; + case 16: + mp = t->mp; // save memory pointer + p = t->img; + for (i=0; i < t->nStrips; ++i) + { + n = t->StripByteCounts[i] / 2; + t->mp = t->fileInMemory + t->StripOffsets[i]; + for (j=0; j < n; ++j) + { + *p++ = (uint16) getU16( t); + } + } + t->mp = mp; // restore memory pointer + break; + } + return 0; +} + + +/*! + ***************************************************************************** + * \brief + * Read the ImageFileDirectory. + * + ***************************************************************************** +*/ +static int readImageFileDirectory (Tiff * t) +{ + uint32 i; + uint32 nEntries = t->getU16( t); + + for (i=0; i < nEntries; ++i) + { + readDirectoryEntry( t); + } + return 0; +} + + +/*! + ***************************************************************************** + * \brief + * Read the ImageFileHeader. + * + ***************************************************************************** +*/ +static int readImageFileHeader (Tiff * t) +{ + t->ifh.byteOrder = (uint16) getU16( t); + t->ifh.arbitraryNumber = (uint16) getU16( t); + t->ifh.offset = getU32( t); + if (t->ifh.arbitraryNumber != 42) + { + fprintf( stdout, "ImageFileHeader.arbitrary != 42\n"); + return 1; + } + t->mp = t->fileInMemory + t->ifh.offset; + return 0; +} + +/*! + ***************************************************************************** + * \brief + * Read the TIFF file named 'path' into 't'. + * + ***************************************************************************** +*/ +static int readTiff (Tiff * t, char * path) { + assert( t); + assert( path); + + if (readFileIntoMemory( t, path)) + goto Error; + if (readImageFileHeader( t)) + goto Error; + if (readImageFileDirectory( t)) + goto Error; + if (readImageData( t)) + goto Error; + return 0; + +Error: + free_pointer( t->fileInMemory); + free_pointer( t->img); + return 1; +} + +/*! + ***************************************************************************** + * \brief + * Initialize RGB ==> YUV conversion factors + * + ***************************************************************************** +*/ +static int RGB_YUV_initialize (RGB_YUV * T, + VideoCode videoCode, //!< <-- Describes color space. + int stdRange, //!< <-- 1 = Standard range, 0 = Full range + uint16 pixMax //!< <-- Maximum component value. + ) +{ + int i, pixScale; + + switch (videoCode) + { + case VC_ITU_REC709: + case VC_CCIR_601: + break; + default: + fprintf( stdout, "RGB_YUV_initialize: Unsupported videoCode (%d)\n", videoCode); + return 1; + } + + T->stdRange = stdRange; + T->pixMax = pixMax; + + pixScale = (int)pixMax + ((int)pixMax & 1); + + if (stdRange) + { + T->offy = (int)(INTEGER_SCALE * (pixScale * 16 / 256.0 + 0.5)); // setup + rounding + T->sy = INTEGER_SCALE * stdScaleY / 255.0; + T->suv = INTEGER_SCALE * stdScaleUV / 255.0; + } + else // full range + { + T->offy = (int)(INTEGER_SCALE * 0.5); // rounding + T->sy = INTEGER_SCALE; + T->suv = INTEGER_SCALE; + } + T->offuv = (int)(INTEGER_SCALE * (0.5 * pixScale + 0.5)); // offset + rounding + + // IMPORTANT NOTE: sign of 0.5 for rounding must agree with sign of CU & CV + T->yr = (int)(T-> sy*CR +0.5); T->yg = (int)(T-> sy*CG +0.5); T->yb = (int)(T-> sy*CB +0.5); + T->ur = (int)(T->suv*CR*CU-0.5); T->ug = (int)(T->suv*CG*CU-0.5); T->ub = (int)(T->suv*0.5 +0.5); + T->vr = (int)(T->suv*0.5 +0.5); T->vg = (int)(T->suv*CG*CV-0.5); T->vb = (int)(T->suv*CB*CV-0.5); + + i = (unsigned int)(T->sy + 0.5); + if (T->yr+T->yg+T->yb != i) + { + fprintf( stdout, "ERROR: RGB_YUV_initialize: yr+yg+yb=%d sy=%u\n", T->yr+T->yg+T->yb, i); + return 1; + } + if (T->ur+T->ug+T->ub) + { + fprintf( stdout, "ERROR: RGB_YUV_initialize: ur+ug+ub=%d\n", T->ur+T->ug+T->ub); + return 1; + } + if (T->vr+T->vg+T->vb) + { + fprintf( stdout, "ERROR: RGB_YUV_initialize: vr+vg+vb=%d\n", T->vr+T->vg+T->vb); + return 1; + } + + return 0; +} + +/*! + ***************************************************************************** + * \brief + * Convert interleaved/planar RGB components to interleaved/planar YUV components + * + ***************************************************************************** +*/ +static void RGB_YUV_rgb_to_yuv (RGB_YUV * T, + uint16 *rp, //!< <-- red components + uint16 *gp, //!< <-- green components + uint16 *bp, //!< <-- blue components + int xres, //!< <-- number of pixels in a row + int yres, //!< <-- number of rows + int rgb_stride, //!< <-- stride to next R,G,B component + uint16 *yp, //!< --> Y components + uint16 *up, //!< --> U components + uint16 *vp, //!< --> V components + int yuv_stride //!< <-- stride to next Y,U,V component + ) +{ + int i; + int count = xres * yres; + + if (T->stdRange) // clipping not needed + { + for (i=0; i < count; ++i) + { + T->r = (int) *rp; rp += rgb_stride; + T->g = (int) *gp; gp += rgb_stride; + T->b = (int) *bp; bp += rgb_stride; + // convert to YUV + *yp = (uint16)((T->yr*T->r + T->yg*T->g + T->yb*T->b + T-> offy) >> INTEGER_SHIFT); yp += yuv_stride; + *up = (uint16)((T->ur*T->r + T->ug*T->g + T->ub*T->b + T->offuv) >> INTEGER_SHIFT); up += yuv_stride; + *vp = (uint16)((T->vr*T->r + T->vg*T->g + T->vb*T->b + T->offuv) >> INTEGER_SHIFT); vp += yuv_stride; + } + } + else // full range -- need to clip + { + for (i=0; i < count; ++i) + { + T->r = (int) *rp; rp += rgb_stride; + T->g = (int) *gp; gp += rgb_stride; + T->b = (int) *bp; bp += rgb_stride; + + // convert to YUV + // right shift of neg value is wrong, but will get clipped so o.k. + T->y = (T->yr*T->r + T->yg*T->g + T->yb*T->b + T-> offy) >> INTEGER_SHIFT; + if (T->y < 0) + T->y = 0; + else if (T->y > T->pixMax) + T->y = (int) T->pixMax; + *yp = (uint16) T->y; yp += yuv_stride; + + T->u = (T->ur*T->r + T->ug*T->g + T->ub*T->b + T->offuv) >> INTEGER_SHIFT; + if (T->u < 0) + T->u = 0; + else if (T->u > T->pixMax) + T->u = (int) T->pixMax; + *up = (uint16) T->u; up += yuv_stride; + + T->v = (T->vr*T->r + T->vg*T->g + T->vb*T->b + T->offuv) >> INTEGER_SHIFT; + if (T->v < 0) + T->v = 0; + else if (T->v > T->pixMax) + T->v = (int) T->pixMax; + *vp = (uint16) T->v; vp += yuv_stride; + } + } // clipping +} + + +/*! + ***************************************************************************** + * \brief FIR horizontal filter and 2:1 subsampling (with no phase shift) + * + * \note + * FILTER SPECIFICATION FILE\n + * FILTER TYPE:HALF BAND 10H\n + * STOPBAND RIPPLE IN -dB -.4000E+02\n + * PASSBAND CUTOFF FREQUENCY 0.170000E+03 HERTZ\n + * SAMPLING FREQUENCY 0.100000E+04 HERTZ\n + * number of taps in decimal 17 (normalized & rounded in kevin_filter.xls)\n + * Window Kaiser *4096 *8192\n + * 0.000000000000000000E+00 coefficient of tap 0\n + * 0.274349475697109923E-02 coefficient of tap 1 11 22\n + * 0.000000000000000000E+00 coefficient of tap 2\n + * 0.116164603817880207E-01 coefficient of tap 3 47 94\n + * 0.000000000000000000E+00 coefficient of tap 4\n + * -.645752746253402865E-01 coefficient of tap 5 -262 -524\n + * 0.000000000000000000E+00 coefficient of tap 6\n + * 0.302322754093924128E+00 coefficient of tap 7 1228 2456\n + * 0.500000000000000000E+00 coefficient of tap 8 2048\n + * 0.302322754093924128E+00 coefficient of tap 9\n + * 0.000000000000000000E+00 coefficient of tap 10\n + * -.645752746253402865E-01 coefficient of tap 11\n + * 0.000000000000000000E+00 coefficient of tap 12\n + * 0.116164603817880207E-01 coefficient of tap 13\n + * 0.000000000000000000E+00 coefficient of tap 14\n + * 0.274349475697109923E-02 coefficient of tap 15\n + * 0.000000000000000000E+00 coefficient of tap 16\n + ***************************************************************************** +*/ +void horizontal_half_1chan_cosite (uint16 *srcPtr, + int srcXres, + int yres, + int srcZres, + uint16 *dstPtr, + int dstZres, + int pixMax //!< needed for clipping + ) +{ + int x, y, limit, n7, n5, n3, n1; + int result; + uint16 *src = srcPtr; + uint16 *dst = dstPtr; + + for (y=0; y < yres; y++) + { + for (x=0; x < 8; x+=2) + { + n1 = (x >= 1) ? 1 : x; + n3 = (x >= 3) ? 3 : x; + n5 = (x >= 5) ? 5 : x; + n7 = (x >= 7) ? 7 : x; + result = ( 2048* *(src) + + 1228*( *(src-n1*srcZres) + *(src+ srcZres) ) + - 262*( *(src-n3*srcZres) + *(src+3*srcZres) ) + + 47*( *(src-n5*srcZres) + *(src+5*srcZres) ) + + 11*( *(src-n7*srcZres) + *(src+7*srcZres) )+2048) / 4096; + if (result < 0) + result = 0; + else if (result > pixMax) + result = pixMax; + *dst = (uint16) result; + dst += dstZres; + src += 2*srcZres; + } + + limit = srcXres - 8; + for (x=8; x < limit; x+=2) + { + result = ( 2048* *(src) + + 1228*( *(src- srcZres) + *(src+ srcZres) ) + - 262*( *(src-3*srcZres) + *(src+3*srcZres) ) + + 47*( *(src-5*srcZres) + *(src+5*srcZres) ) + + 11*( *(src-7*srcZres) + *(src+7*srcZres) )+2048) / 4096; + if (result < 0) + result = 0; + else if (result > pixMax) + result = pixMax; + *dst = (uint16) result; + dst += dstZres; + src += 2*srcZres; + } + + limit = srcXres - (srcXres & 1); // must round down to not exceed dst + for (x=x; x < limit; x+=2) + { + n1 = (x < srcXres-1) ? 1 : 0; + n3 = (x < srcXres-3) ? 3 : (srcXres-1-x); + n5 = (x < srcXres-5) ? 5 : (srcXres-1-x); + n7 = (x < srcXres-7) ? 7 : (srcXres-1-x); + result = ( 2048* *(src) + + 1228*( *(src- srcZres) + *(src+n1*srcZres) ) + - 262*( *(src-3*srcZres) + *(src+n3*srcZres) ) + + 47*( *(src-5*srcZres) + *(src+n5*srcZres) ) + + 11*( *(src-7*srcZres) + *(src+n7*srcZres) )+2048) / 4096; + if (result < 0) + result = 0; + else if (result > pixMax) + result = pixMax; + *dst = (uint16) result; + dst += dstZres; + src += 2*srcZres; + } + } +} // horizontal_half_1chan_cosite + + +/*! + ***************************************************************************** + * \brief + * FIR vertical filter and 2:1 subsampling with 0.5 sample interval phase shift + * see vertical_half_1chan.pdf for response + ***************************************************************************** +*/ +void vertical_half_1chan (uint16 *srcPtr, + int xres, + int srcYres, + int srcZres, + uint16 *dstPtr, + int dstZres, + int pixMax //!< needed for clipping + ) +{ + int x, y, limit, n6, n5, n4, n3, n2, n1; + int result; + + int srcRowCount = xres * srcZres; + uint16 *src = srcPtr; + uint16 *dst = dstPtr; + + for (y=0; y < 6; y+=2) + { + n1 = (y >= 1) ? 1 : y; + n2 = (y >= 2) ? 2 : y; + n3 = (y >= 3) ? 3 : y; + n4 = (y >= 4) ? 4 : y; + /*n5 = (y >= 5) ? 5 : y;*/ + for (x=0; x < xres; x++) + { + result = (225*( *(src ) + *(src+ srcRowCount) ) + +69*( *(src-n1*srcRowCount) + *(src+2*srcRowCount) ) + -30*( *(src-n2*srcRowCount) + *(src+3*srcRowCount) ) + -16*( *(src-n3*srcRowCount) + *(src+4*srcRowCount) ) + + 6*( *(src-n4*srcRowCount) + *(src+5*srcRowCount) ) + + 2*( *(src- y*srcRowCount) + *(src+6*srcRowCount) )+256) / 512; + if (result < 0) + result = 0; + else if (result > pixMax) + result = pixMax; + *dst = (uint16) result; + dst += dstZres; + src += srcZres; + } + src += srcRowCount; + } + + limit = srcYres - 6; + for (y=6; y < limit; y+=2) + { + for (x=0; x < xres; x++) + { + result = (225*( *(src ) + *(src+ srcRowCount) ) + +69*( *(src- srcRowCount) + *(src+2*srcRowCount) ) + -30*( *(src-2*srcRowCount) + *(src+3*srcRowCount) ) + -16*( *(src-3*srcRowCount) + *(src+4*srcRowCount) ) + + 6*( *(src-4*srcRowCount) + *(src+5*srcRowCount) ) + + 2*( *(src-5*srcRowCount) + *(src+6*srcRowCount) )+256) / 512; + if (result < 0) + result = 0; + else if (result > pixMax) + result = pixMax; + *dst = (uint16) result; + dst += dstZres; + src += srcZres; + } + src += srcRowCount; + } + + limit = srcYres - (srcYres & 1); // must round down to not exceed dst + for (y=y; y < limit; y+=2) + { + n1 = (y < srcYres-1) ? 1 : 0; + n2 = (y < srcYres-2) ? 2 : (srcYres-1-y); + n3 = (y < srcYres-3) ? 3 : (srcYres-1-y); + n4 = (y < srcYres-4) ? 4 : (srcYres-1-y); + n5 = (y < srcYres-5) ? 5 : (srcYres-1-y); + n6 = (y < srcYres-6) ? 6 : (srcYres-1-y); + for (x=0; x < xres; x++) + { + result = (225*( *(src ) + *(src+n1*srcRowCount) ) + +69*( *(src- srcRowCount) + *(src+n2*srcRowCount) ) + -30*( *(src-2*srcRowCount) + *(src+n3*srcRowCount) ) + -16*( *(src-3*srcRowCount) + *(src+n4*srcRowCount) ) + + 6*( *(src-4*srcRowCount) + *(src+n5*srcRowCount) ) + + 2*( *(src-5*srcRowCount) + *(src+n6*srcRowCount) )+256) / 512; + if (result < 0) + result = 0; + else if (result > pixMax) + result = pixMax; + *dst = (uint16) result; + dst += dstZres; + src += srcZres; + } + src += srcRowCount; + } +} // vertical_half_1chan + + +/*! + ***************************************************************************** + * \brief + * Reads entire tiff file from harddrive. Any processing is done + * in memory, reducing I/O overhead + * \param input_file + * [in] Input file name etc. to read from + * \param FrameNoInFile + * [in] Frame number in the source file + * \param source + * [in] source file (on disk) information + * \param buf + * [out] memory buffer where image will be stored + * \return + * 1, success + * 0, failure + ***************************************************************************** + */ +int ReadTIFFImage (InputParameters *p_Inp, VideoDataFile *input_file, int FrameNoInFile, FrameFormat *source, unsigned char *buf) +{ + static Tiff t; // Declaring it static allows it to "remember" memory allocations; ATOUR: Not a good idea since this affects reentrancy + char path[FILE_NAME_SIZE]; + int frameNumberInFile, n, nComponents, height, i, width, y; + RGB_YUV rgb_yuv; + uint16 + *img, *temp = NULL, *temp2 = NULL, + *p, *yp, *up, *vp; + + assert( p_Inp); + assert( input_file); + assert( source); + assert( buf); + + width = source->width[0]; + height = source->height[0]; + assert( (width & 1) == 0 && (height & 1) == 0); // width & height must be even. + + if (source->color_model == CM_RGB && !input_file->is_interleaved) + { + fprintf( stdout, "ReadTIFFImage: RGB input file has not been declared as interleaved but only interleaved is supported\n"); + goto Error; + } + + frameNumberInFile = FrameNoInFile + p_Inp->start_frame; + if (input_file->num_digits > 0) + { + if (input_file->zero_pad) + { + n = snprintf( path, sizeof(path), "%s%0*d%s", input_file->fhead, input_file->num_digits, frameNumberInFile, input_file->ftail); + } + else + { + n = snprintf( path, sizeof(path), "%s%*d%s", input_file->fhead, input_file->num_digits, frameNumberInFile, input_file->ftail); + } + if (n == FILE_NAME_SIZE || n == -1) + { + fprintf( stdout, "ReadTIFFImage: file name is too large\n"); + return 0; + } + } + else + { + strcpy( path, input_file->fname); + } + + if (readTiff( &t, path)) + { + goto Error; + } + + if ((int) t.ImageLength != height) + { + fprintf( stdout, "ReadTIFFImage: Tiff height (%u) different from encoder input height (%d) . Exiting...\n", t.ImageLength, height); + goto Error; + } + if ((int) t.ImageWidth != width) + { + fprintf( stdout, "ReadTIFFImage: Tiff width (%u) different from encoder input width (%d) . Exiting...\n", t.ImageWidth, width); + goto Error; + } + + if (source->pic_unit_size_on_disk != 8 && source->pic_unit_size_on_disk != 16) { + fprintf( stdout, "ReadTIFFImage only supports pic_unit_size_on_disk of 8 or 16 not %d\n", source->pic_unit_size_on_disk); + goto Error; + } + + // Transfer image to 'buf' + + img = t.img; // default setting points at TIFF image data. + nComponents = width * height * 3; // for RGB, which will be overridden by YUV420 etc. + + if (source->color_model == CM_YUV) + { + if (RGB_YUV_initialize( &rgb_yuv, (VideoCode) p_Inp->videoCode, p_Inp->stdRange, 65535)) + goto Error; + + RGB_YUV_rgb_to_yuv( &rgb_yuv, img, img+1, img+2, width, height, 3, img, img+1, img+2, 3); + switch (source->yuv_format) + { + case YUV420: + // allocate planar buffer + nComponents = width * height * 3 / 2; + yp = temp = (uint16 *) malloc( nComponents * sizeof(uint16)); + up = yp + width * height; + vp = up + width * height / 4; + // Y + p = img; + for (i=0; i < width*height; ++i) + { + yp[i] = *p; p += 3; + } + // subsample into planar buffer + temp2 = (uint16 *) malloc( height * width * sizeof(uint16) / 2); + // U + horizontal_half_1chan_cosite( img+1, width, height, 3, temp2, 1, 65535); + vertical_half_1chan( temp2, width/2, height, 1, up, 1, 65535); + // V + horizontal_half_1chan_cosite( img+2, width, height, 3, temp2, 1, 65535); + vertical_half_1chan( temp2, width/2, height, 1, vp, 1, 65535); + free_pointer(temp2); + img = yp; // img points at result + break; + case YUV422: + // allocate planar buffer + nComponents = width * height * 2; + yp = temp = (uint16 *) malloc( nComponents * sizeof(uint16)); + up = yp + width*height; + vp = yp + width*height/2; + // Y + p = img; + for (i=0; i < width*height; ++i) + { + yp[i] = *p; p += 3; + } + // U & V + for (y=0; y < height; ++y) { + horizontal_half_1chan_cosite( img + 1 + y*width*3, width, 1, 3, up + y * width/2, 1, 65535); + horizontal_half_1chan_cosite( img + 2 + y*width*3, width, 1, 3, vp + y * width/2, 1, 65535); + } + img = yp; // img points at result + break; + case YUV444: + break; + default: + fprintf( stdout, "ReadTIFFImage: Unsupported ColorFormat (%d)\n", source->yuv_format); + goto Error; + } + } + + switch (source->pic_unit_size_shift3) + { + case 1: + for (i=0; i < nComponents; ++i) + { + buf[i] = (uint8)(img[i] >> 8); + } + break; + case 2: + for (i=0; i < nComponents; ++i) + { + ((uint16 *) buf)[i] = img[i]; + } + break; + default: + fprintf( stdout, "ReadTIFFImage only supports pic_unit_size_shift3 of 1 or 2 not %d\n", source->pic_unit_size_shift3); + goto Error; + } + + free_pointer(temp); + return 1; + +Error: + + free_pointer(temp); + report_stats_on_error(); + + return 0; +} diff --git a/lcommon/src/mbuffer_common.c b/lcommon/src/mbuffer_common.c new file mode 100644 index 0000000..cd3c2e3 --- /dev/null +++ b/lcommon/src/mbuffer_common.c @@ -0,0 +1,863 @@ + +/*! + *********************************************************************** + * \file + * mbuffer_common.c + * + * \brief + * Common (Encoder/Decoder) Frame buffer functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Tourapis + * - Yuwen He + *********************************************************************** + */ + +#include + +#include "global.h" +#include "header.h" +#include "image.h" +#include "mbuffer_common.h" +#include "mbuffer.h" +#include "memalloc.h" +#include "output.h" +#include "fast_memory.h" +#include "input.h" + +static void unmark_long_term_field_for_reference_by_frame_idx(DecodedPictureBuffer *p_Dpb, PictureStructure structure, int long_term_frame_idx, int mark_current, unsigned curr_frame_num, int curr_pic_num); +/*! + ************************************************************************ + * \brief + * Check if one of the frames/fields in frame store is used for short-term reference + ************************************************************************ + */ +static int is_short_term_reference(FrameStore* fs) +{ + + if (fs->is_used==3) // frame + { + if ((fs->frame->used_for_reference)&&(!fs->frame->is_long_term)) + { + return 1; + } + } + + if (fs->is_used & 1) // top field + { + if (fs->top_field) + { + if ((fs->top_field->used_for_reference)&&(!fs->top_field->is_long_term)) + { + return 1; + } + } + } + + if (fs->is_used & 2) // bottom field + { + if (fs->bottom_field) + { + if ((fs->bottom_field->used_for_reference)&&(!fs->bottom_field->is_long_term)) + { + return 1; + } + } + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * Check if one of the frames/fields in frame store is used for short-term reference + ************************************************************************ + */ +static int is_long_term_reference(FrameStore* fs) +{ + + if (fs->is_used==3) // frame + { + if ((fs->frame->used_for_reference)&&(fs->frame->is_long_term)) + { + return 1; + } + } + + if (fs->is_used & 1) // top field + { + if (fs->top_field) + { + if ((fs->top_field->used_for_reference)&&(fs->top_field->is_long_term)) + { + return 1; + } + } + } + + if (fs->is_used & 2) // bottom field + { + if (fs->bottom_field) + { + if ((fs->bottom_field->used_for_reference)&&(fs->bottom_field->is_long_term)) + { + return 1; + } + } + } + return 0; +} + +/*! + ************************************************************************ + * \brief + * Generates a alternating field list from a given FrameStore list + * + ************************************************************************ + */ +void gen_pic_list_from_frame_list(PictureStructure currStructure, FrameStore **fs_list, int list_idx, StorablePicture **list, char *list_size, int long_term) +{ + int top_idx = 0; + int bot_idx = 0; + + int (*is_ref)(StorablePicture *s) = (long_term) ? is_long_ref : is_short_ref; + + + if (currStructure == TOP_FIELD) + { + while ((top_idxis_used & 1) + { + if(is_ref(fs_list[top_idx]->top_field)) + { + // short term ref pic + list[(short) *list_size] = fs_list[top_idx]->top_field; + (*list_size)++; + top_idx++; + break; + } + } + } + for ( ; bot_idxis_used & 2) + { + if(is_ref(fs_list[bot_idx]->bottom_field)) + { + // short term ref pic + list[(short) *list_size] = fs_list[bot_idx]->bottom_field; + (*list_size)++; + bot_idx++; + break; + } + } + } + } + } + if (currStructure == BOTTOM_FIELD) + { + while ((top_idxis_used & 2) + { + if(is_ref(fs_list[bot_idx]->bottom_field)) + { + // short term ref pic + list[(short) *list_size] = fs_list[bot_idx]->bottom_field; + (*list_size)++; + bot_idx++; + break; + } + } + } + for ( ; top_idxis_used & 1) + { + if(is_ref(fs_list[top_idx]->top_field)) + { + // short term ref pic + list[(short) *list_size] = fs_list[top_idx]->top_field; + (*list_size)++; + top_idx++; + break; + } + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Returns long term pic with given LongtermPicNum + * + ************************************************************************ + */ +StorablePicture* get_long_term_pic(Slice *currSlice, DecodedPictureBuffer *p_Dpb, int LongtermPicNum) +{ + uint32 i; + + for (i=0; iltref_frames_in_buffer; i++) + { + if (currSlice->structure==FRAME) + { + if (p_Dpb->fs_ltref[i]->is_reference == 3) + if ((p_Dpb->fs_ltref[i]->frame->is_long_term)&&(p_Dpb->fs_ltref[i]->frame->long_term_pic_num == LongtermPicNum)) + return p_Dpb->fs_ltref[i]->frame; + } + else + { + if (p_Dpb->fs_ltref[i]->is_reference & 1) + if ((p_Dpb->fs_ltref[i]->top_field->is_long_term)&&(p_Dpb->fs_ltref[i]->top_field->long_term_pic_num == LongtermPicNum)) + return p_Dpb->fs_ltref[i]->top_field; + if (p_Dpb->fs_ltref[i]->is_reference & 2) + if ((p_Dpb->fs_ltref[i]->bottom_field->is_long_term)&&(p_Dpb->fs_ltref[i]->bottom_field->long_term_pic_num == LongtermPicNum)) + return p_Dpb->fs_ltref[i]->bottom_field; + } + } + return NULL; +} + +/*! + ************************************************************************ + * \brief + * Update the list of frame stores that contain reference frames/fields + * + ************************************************************************ + */ +void update_ref_list(DecodedPictureBuffer *p_Dpb) +{ + unsigned i, j; + for (i=0, j=0; iused_size; i++) + { + if (is_short_term_reference(p_Dpb->fs[i])) + { + p_Dpb->fs_ref[j++]=p_Dpb->fs[i]; + } + } + + p_Dpb->ref_frames_in_buffer = j; + + while (jsize) + { + p_Dpb->fs_ref[j++]=NULL; + } +} + + + +/*! + ************************************************************************ + * \brief + * Update the list of frame stores that contain long-term reference + * frames/fields + * + ************************************************************************ + */ +void update_ltref_list(DecodedPictureBuffer *p_Dpb) +{ + unsigned i, j; + for (i=0, j=0; iused_size; i++) + { + if (is_long_term_reference(p_Dpb->fs[i])) + { + p_Dpb->fs_ltref[j++] = p_Dpb->fs[i]; + } + } + + p_Dpb->ltref_frames_in_buffer = j; + + while (jsize) + { + p_Dpb->fs_ltref[j++]=NULL; + } +} + +/*! + ************************************************************************ + * \brief + * Calculate picNumX + ************************************************************************ + */ +static int get_pic_num_x (StorablePicture *p, int difference_of_pic_nums_minus1) +{ + int currPicNum; + + if (p->structure == FRAME) + currPicNum = p->frame_num; + else + currPicNum = 2 * p->frame_num + 1; + + return currPicNum - (difference_of_pic_nums_minus1 + 1); +} + +/*! + ************************************************************************ + * \brief + * Adaptive Memory Management: Mark short term picture unused + ************************************************************************ + */ +void mm_unmark_short_term_for_reference(DecodedPictureBuffer *p_Dpb, StorablePicture *p, int difference_of_pic_nums_minus1) +{ + int picNumX; + + uint32 i; + + picNumX = get_pic_num_x(p, difference_of_pic_nums_minus1); + + for (i=0; iref_frames_in_buffer; i++) + { + if (p->structure == FRAME) + { + if ((p_Dpb->fs_ref[i]->is_reference==3) && (p_Dpb->fs_ref[i]->is_long_term==0)) + { + if (p_Dpb->fs_ref[i]->frame->pic_num == picNumX) + { + unmark_for_reference(p_Dpb->fs_ref[i]); + return; + } + } + } + else + { + if ((p_Dpb->fs_ref[i]->is_reference & 1) && (!(p_Dpb->fs_ref[i]->is_long_term & 1))) + { + if (p_Dpb->fs_ref[i]->top_field->pic_num == picNumX) + { + p_Dpb->fs_ref[i]->top_field->used_for_reference = 0; + p_Dpb->fs_ref[i]->is_reference &= 2; + if (p_Dpb->fs_ref[i]->is_used == 3) + { + p_Dpb->fs_ref[i]->frame->used_for_reference = 0; + } + return; + } + } + if ((p_Dpb->fs_ref[i]->is_reference & 2) && (!(p_Dpb->fs_ref[i]->is_long_term & 2))) + { + if (p_Dpb->fs_ref[i]->bottom_field->pic_num == picNumX) + { + p_Dpb->fs_ref[i]->bottom_field->used_for_reference = 0; + p_Dpb->fs_ref[i]->is_reference &= 1; + if (p_Dpb->fs_ref[i]->is_used == 3) + { + p_Dpb->fs_ref[i]->frame->used_for_reference = 0; + } + return; + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Adaptive Memory Management: Mark long term picture unused + ************************************************************************ + */ +void mm_unmark_long_term_for_reference(DecodedPictureBuffer *p_Dpb, StorablePicture *p, int long_term_pic_num) +{ + uint32 i; + for (i=0; iltref_frames_in_buffer; i++) + { + if (p->structure == FRAME) + { + if ((p_Dpb->fs_ltref[i]->is_reference==3) && (p_Dpb->fs_ltref[i]->is_long_term==3)) + { + if (p_Dpb->fs_ltref[i]->frame->long_term_pic_num == long_term_pic_num) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } + } + else + { + if ((p_Dpb->fs_ltref[i]->is_reference & 1) && ((p_Dpb->fs_ltref[i]->is_long_term & 1))) + { + if (p_Dpb->fs_ltref[i]->top_field->long_term_pic_num == long_term_pic_num) + { + p_Dpb->fs_ltref[i]->top_field->used_for_reference = 0; + p_Dpb->fs_ltref[i]->top_field->is_long_term = 0; + p_Dpb->fs_ltref[i]->is_reference &= 2; + p_Dpb->fs_ltref[i]->is_long_term &= 2; + if (p_Dpb->fs_ltref[i]->is_used == 3) + { + p_Dpb->fs_ltref[i]->frame->used_for_reference = 0; + p_Dpb->fs_ltref[i]->frame->is_long_term = 0; + } + return; + } + } + if ((p_Dpb->fs_ltref[i]->is_reference & 2) && ((p_Dpb->fs_ltref[i]->is_long_term & 2))) + { + if (p_Dpb->fs_ltref[i]->bottom_field->long_term_pic_num == long_term_pic_num) + { + p_Dpb->fs_ltref[i]->bottom_field->used_for_reference = 0; + p_Dpb->fs_ltref[i]->bottom_field->is_long_term = 0; + p_Dpb->fs_ltref[i]->is_reference &= 1; + p_Dpb->fs_ltref[i]->is_long_term &= 1; + if (p_Dpb->fs_ltref[i]->is_used == 3) + { + p_Dpb->fs_ltref[i]->frame->used_for_reference = 0; + p_Dpb->fs_ltref[i]->frame->is_long_term = 0; + } + return; + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Mark a long-term reference frame or complementary field pair unused for referemce + ************************************************************************ + */ +static void unmark_long_term_frame_for_reference_by_frame_idx(DecodedPictureBuffer *p_Dpb, int long_term_frame_idx) +{ + uint32 i; + for(i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->long_term_frame_idx == long_term_frame_idx) + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } +} + + + +/*! + ************************************************************************ + * \brief + * mark a picture as long-term reference + ************************************************************************ + */ +static void mark_pic_long_term(DecodedPictureBuffer *p_Dpb, StorablePicture* p, int long_term_frame_idx, int picNumX) +{ + uint32 i; + int add_top, add_bottom; + + if (p->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference == 3) + { + if ((!p_Dpb->fs_ref[i]->frame->is_long_term)&&(p_Dpb->fs_ref[i]->frame->pic_num == picNumX)) + { + p_Dpb->fs_ref[i]->long_term_frame_idx = p_Dpb->fs_ref[i]->frame->long_term_frame_idx + = long_term_frame_idx; + p_Dpb->fs_ref[i]->frame->long_term_pic_num = long_term_frame_idx; + p_Dpb->fs_ref[i]->frame->is_long_term = 1; + + if (p_Dpb->fs_ref[i]->top_field && p_Dpb->fs_ref[i]->bottom_field) + { + p_Dpb->fs_ref[i]->top_field->long_term_frame_idx = p_Dpb->fs_ref[i]->bottom_field->long_term_frame_idx + = long_term_frame_idx; + p_Dpb->fs_ref[i]->top_field->long_term_pic_num = long_term_frame_idx; + p_Dpb->fs_ref[i]->bottom_field->long_term_pic_num = long_term_frame_idx; + + p_Dpb->fs_ref[i]->top_field->is_long_term = p_Dpb->fs_ref[i]->bottom_field->is_long_term + = 1; + + } + p_Dpb->fs_ref[i]->is_long_term = 3; + return; + } + } + } + printf ("Warning: reference frame for long term marking not found\n"); + } + else + { + if (p->structure == TOP_FIELD) + { + add_top = 1; + add_bottom = 0; + } + else + { + add_top = 0; + add_bottom = 1; + } + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference & 1) + { + if ((!p_Dpb->fs_ref[i]->top_field->is_long_term)&&(p_Dpb->fs_ref[i]->top_field->pic_num == picNumX)) + { + if ((p_Dpb->fs_ref[i]->is_long_term) && (p_Dpb->fs_ref[i]->long_term_frame_idx != long_term_frame_idx)) + { + printf ("Warning: assigning long_term_frame_idx different from other field\n"); + } + + p_Dpb->fs_ref[i]->long_term_frame_idx = p_Dpb->fs_ref[i]->top_field->long_term_frame_idx + = long_term_frame_idx; + p_Dpb->fs_ref[i]->top_field->long_term_pic_num = 2 * long_term_frame_idx + add_top; + p_Dpb->fs_ref[i]->top_field->is_long_term = 1; + p_Dpb->fs_ref[i]->is_long_term |= 1; + if (p_Dpb->fs_ref[i]->is_long_term == 3) + { + p_Dpb->fs_ref[i]->frame->is_long_term = 1; + p_Dpb->fs_ref[i]->frame->long_term_frame_idx = p_Dpb->fs_ref[i]->frame->long_term_pic_num = long_term_frame_idx; + } + return; + } + } + if (p_Dpb->fs_ref[i]->is_reference & 2) + { + if ((!p_Dpb->fs_ref[i]->bottom_field->is_long_term)&&(p_Dpb->fs_ref[i]->bottom_field->pic_num == picNumX)) + { + if ((p_Dpb->fs_ref[i]->is_long_term) && (p_Dpb->fs_ref[i]->long_term_frame_idx != long_term_frame_idx)) + { + printf ("Warning: assigning long_term_frame_idx different from other field\n"); + } + + p_Dpb->fs_ref[i]->long_term_frame_idx = p_Dpb->fs_ref[i]->bottom_field->long_term_frame_idx + = long_term_frame_idx; + p_Dpb->fs_ref[i]->bottom_field->long_term_pic_num = 2 * long_term_frame_idx + add_bottom; + p_Dpb->fs_ref[i]->bottom_field->is_long_term = 1; + p_Dpb->fs_ref[i]->is_long_term |= 2; + if (p_Dpb->fs_ref[i]->is_long_term == 3) + { + p_Dpb->fs_ref[i]->frame->is_long_term = 1; + p_Dpb->fs_ref[i]->frame->long_term_frame_idx = p_Dpb->fs_ref[i]->frame->long_term_pic_num = long_term_frame_idx; + } + return; + } + } + } + printf ("Warning: reference field for long term marking not found\n"); + } +} + + +/*! + ************************************************************************ + * \brief + * Assign a long term frame index to a short term picture + ************************************************************************ + */ +void mm_assign_long_term_frame_idx(DecodedPictureBuffer *p_Dpb, StorablePicture* p, int difference_of_pic_nums_minus1, int long_term_frame_idx) +{ + int picNumX = get_pic_num_x(p, difference_of_pic_nums_minus1); + + // remove frames/fields with same long_term_frame_idx + if (p->structure == FRAME) + { + unmark_long_term_frame_for_reference_by_frame_idx(p_Dpb, long_term_frame_idx); + } + else + { + unsigned i; + PictureStructure structure = FRAME; + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference & 1) + { + if (p_Dpb->fs_ref[i]->top_field->pic_num == picNumX) + { + structure = TOP_FIELD; + break; + } + } + if (p_Dpb->fs_ref[i]->is_reference & 2) + { + if (p_Dpb->fs_ref[i]->bottom_field->pic_num == picNumX) + { + structure = BOTTOM_FIELD; + break; + } + } + } + if (structure==FRAME) + { + error ("field for long term marking not found",200); + } + + unmark_long_term_field_for_reference_by_frame_idx(p_Dpb, structure, long_term_frame_idx, 0, 0, picNumX); + } + + mark_pic_long_term(p_Dpb, p, long_term_frame_idx, picNumX); +} + +/*! + ************************************************************************ + * \brief + * Set new max long_term_frame_idx + ************************************************************************ + */ +void mm_update_max_long_term_frame_idx(DecodedPictureBuffer *p_Dpb, int max_long_term_frame_idx_plus1) +{ + uint32 i; + + p_Dpb->max_long_term_pic_idx = max_long_term_frame_idx_plus1 - 1; + + // check for invalid frames + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->long_term_frame_idx > p_Dpb->max_long_term_pic_idx) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } +} + + +/*! + ************************************************************************ + * \brief + * Mark all long term reference pictures unused for reference + ************************************************************************ + */ +void mm_unmark_all_long_term_for_reference (DecodedPictureBuffer *p_Dpb) +{ + mm_update_max_long_term_frame_idx(p_Dpb, 0); +} + +/*! + ************************************************************************ + * \brief + * Mark all short term reference pictures unused for reference + ************************************************************************ + */ +void mm_unmark_all_short_term_for_reference (DecodedPictureBuffer *p_Dpb) +{ + unsigned int i; + for (i=0; iref_frames_in_buffer; i++) + { + unmark_for_reference(p_Dpb->fs_ref[i]); + } + update_ref_list(p_Dpb); +} + + +/*! + ************************************************************************ + * \brief + * Mark the current picture used for long term reference + ************************************************************************ + */ +void mm_mark_current_picture_long_term(DecodedPictureBuffer *p_Dpb, StorablePicture *p, int long_term_frame_idx) +{ + // remove long term pictures with same long_term_frame_idx + if (p->structure == FRAME) + { + unmark_long_term_frame_for_reference_by_frame_idx(p_Dpb, long_term_frame_idx); + } + else + { + unmark_long_term_field_for_reference_by_frame_idx(p_Dpb, p->structure, long_term_frame_idx, 1, p->pic_num, 0); + } + + p->is_long_term = 1; + p->long_term_frame_idx = long_term_frame_idx; +} + + +/*! + ************************************************************************ + * \brief + * Check if one of the frames/fields in frame store is used for reference + ************************************************************************ + */ +int is_used_for_reference(FrameStore* fs) +{ + if (fs->is_reference) + { + return 1; + } + + if (fs->is_used == 3) // frame + { + if (fs->frame->used_for_reference) + { + return 1; + } + } + + if (fs->is_used & 1) // top field + { + if (fs->top_field) + { + if (fs->top_field->used_for_reference) + { + return 1; + } + } + } + + if (fs->is_used & 2) // bottom field + { + if (fs->bottom_field) + { + if (fs->bottom_field->used_for_reference) + { + return 1; + } + } + } + return 0; +} + +/*! + ************************************************************************ + * \brief + * find smallest POC in the DPB. + ************************************************************************ + */ +void get_smallest_poc(DecodedPictureBuffer *p_Dpb, int *poc,int * pos) +{ + uint32 i; + + if (p_Dpb->used_size<1) + { + error("Cannot determine smallest POC, DPB empty.",150); + } + + *pos=-1; + *poc = INT_MAX; + for (i = 0; i < p_Dpb->used_size; i++) + { + if ((*poc > p_Dpb->fs[i]->poc)&&(!p_Dpb->fs[i]->is_output)) + { + *poc = p_Dpb->fs[i]->poc; + *pos = i; + } + } +} + +/*! + ************************************************************************ + * \brief + * Remove a picture from DPB which is no longer needed. + ************************************************************************ + */ +int remove_unused_frame_from_dpb(DecodedPictureBuffer *p_Dpb) +{ + uint32 i; + + // check for frames that were already output and no longer used for reference + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_output && (!is_used_for_reference(p_Dpb->fs[i]))) + { + remove_frame_from_dpb(p_Dpb, i); + return 1; + } + } + return 0; +} + +/*! + ************************************************************************ + * \brief + * Mark a long-term reference field unused for reference only if it's not + * the complementary field of the picture indicated by picNumX + ************************************************************************ + */ +static void unmark_long_term_field_for_reference_by_frame_idx(DecodedPictureBuffer *p_Dpb, PictureStructure structure, int long_term_frame_idx, int mark_current, unsigned curr_frame_num, int curr_pic_num) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + + assert(structure!=FRAME); + if (curr_pic_num<0) + curr_pic_num += (2 * p_Vid->max_frame_num); + + for(i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->long_term_frame_idx == long_term_frame_idx) + { + if (structure == TOP_FIELD) + { + if ((p_Dpb->fs_ltref[i]->is_long_term == 3)) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + else + { + if ((p_Dpb->fs_ltref[i]->is_long_term == 1)) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + else + { + if (mark_current) + { + if (p_Dpb->last_picture) + { + if ( ( p_Dpb->last_picture != p_Dpb->fs_ltref[i] )|| p_Dpb->last_picture->frame_num != curr_frame_num) + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + else + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } + else + { + if ((p_Dpb->fs_ltref[i]->frame_num) != (unsigned)(curr_pic_num >> 1)) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } + } + } + } + if (structure == BOTTOM_FIELD) + { + if ((p_Dpb->fs_ltref[i]->is_long_term == 3)) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + else + { + if ((p_Dpb->fs_ltref[i]->is_long_term == 2)) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + else + { + if (mark_current) + { + if (p_Dpb->last_picture) + { + if ( ( p_Dpb->last_picture != p_Dpb->fs_ltref[i] )|| p_Dpb->last_picture->frame_num != curr_frame_num) + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + else + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } + else + { + if ((p_Dpb->fs_ltref[i]->frame_num) != (unsigned)(curr_pic_num >> 1)) + { + unmark_for_long_term_reference(p_Dpb->fs_ltref[i]); + } + } + } + } + } + } + } +} + + + diff --git a/lcommon/src/memalloc.c b/lcommon/src/memalloc.c new file mode 100644 index 0000000..6e28331 --- /dev/null +++ b/lcommon/src/memalloc.c @@ -0,0 +1,2726 @@ + +/*! + ************************************************************************ + * \file memalloc.c + * + * \brief + * Memory allocation and free helper functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Karsten Suehring + * - Yuwen He + * + ************************************************************************ + */ + +#include "global.h" +#include "memalloc.h" + +/*! + ************************************************************************ + * \brief + * Initialize 2-dimensional top and bottom field to point to the proper + * lines in frame + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int init_top_bot_planes(imgpel **imgFrame, int dim0, imgpel ***imgTopField, imgpel ***imgBotField) +{ + int i; + + if((*imgTopField = (imgpel**)mem_malloc((dim0>>1) * sizeof(imgpel*))) == NULL) + no_mem_exit("init_top_bot_planes: imgTopField"); + + if((*imgBotField = (imgpel**)mem_malloc((dim0>>1) * sizeof(imgpel*))) == NULL) + no_mem_exit("init_top_bot_planes: imgBotField"); + + for(i = 0; i < (dim0>>1); i++) + { + (*imgTopField)[i] = imgFrame[2 * i ]; + (*imgBotField)[i] = imgFrame[2 * i + 1]; + } + + return dim0 * sizeof(imgpel*); +} + + /*! + ************************************************************************ + * \brief + * free 2-dimensional top and bottom fields without freeing target memory + * + * \par Output: + * memory size in bytes + ************************************************************************/ +void free_top_bot_planes(imgpel **imgTopField, imgpel **imgBotField) +{ + mem_free (imgTopField); + mem_free (imgBotField); +} + + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> DistortionData array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Ddist(DistortionData ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (DistortionData**)mem_malloc(dim0 * sizeof(DistortionData*))) == NULL) + no_mem_exit("get_mem2Ddist: array2D"); + if((*(*array2D) = (DistortionData* )mem_calloc(dim0 * dim1,sizeof(DistortionData ))) == NULL) + no_mem_exit("get_mem2Ddist: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(DistortionData*) + dim1 * sizeof(DistortionData)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> LambdaParams array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Dlm(LambdaParams ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (LambdaParams**)mem_malloc(dim0 * sizeof(LambdaParams*))) == NULL) + no_mem_exit("get_mem2Dlm: array2D"); + if((*(*array2D) = (LambdaParams* )mem_calloc(dim0 * dim1,sizeof(LambdaParams ))) == NULL) + no_mem_exit("get_mem2Dlm: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(LambdaParams*) + dim1 * sizeof(LambdaParams)); +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Ddist() + ************************************************************************ + */ +void free_mem2Ddist(DistortionData **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Ddist: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Ddist: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dlm() + ************************************************************************ + */ +void free_mem2Dlm(LambdaParams **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dlm: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dlm: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> PicMotionParams array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Dmp(PicMotionParams ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (PicMotionParams**)mem_malloc(dim0 * sizeof(PicMotionParams*))) == NULL) + no_mem_exit("get_mem2Dmp: array2D"); + if((*(*array2D) = (PicMotionParams* )mem_calloc(dim0 * dim1, sizeof(PicMotionParams ))) == NULL) + no_mem_exit("get_mem2Dmp: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(PicMotionParams*) + dim1 * sizeof(PicMotionParams)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> PicMotionParams array3D[frames][dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dmp(PicMotionParams ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(PicMotionParams**); + + if(((*array3D) = (PicMotionParams***)mem_malloc(dim0 * sizeof(PicMotionParams**))) == NULL) + no_mem_exit("get_mem3Dmp: array3D"); + + mem_size += get_mem2Dmp(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dmp() + ************************************************************************ + */ +void free_mem2Dmp(PicMotionParams **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dmp: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dmp: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3Dmp() + ************************************************************************ + */ +void free_mem3Dmp(PicMotionParams ***array3D) +{ + if (array3D) + { + free_mem2Dmp(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dmp: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> LevelQuantParams array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Dquant(LevelQuantParams ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (LevelQuantParams**) mem_malloc(dim0 * sizeof(LevelQuantParams*))) == NULL) + no_mem_exit("get_mem2Dquant: array2D"); + if((*(*array2D) = (LevelQuantParams* ) mem_calloc(dim0 * dim1,sizeof(LevelQuantParams ))) == NULL) + no_mem_exit("get_mem2Dquant: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(LevelQuantParams*) + dim1 * sizeof(LevelQuantParams)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> LevelQuantParams array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dquant(LevelQuantParams ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(LevelQuantParams**); + + if(((*array3D) = (LevelQuantParams***)mem_malloc(dim0 * sizeof(LevelQuantParams**))) == NULL) + no_mem_exit("get_mem3Dquant: array3D"); + + mem_size += get_mem2Dquant(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 4D memory array -> LevelQuantParams array3D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4Dquant(LevelQuantParams *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(LevelQuantParams***); + + if(((*array4D) = (LevelQuantParams****)mem_malloc(dim0 * sizeof(LevelQuantParams***))) == NULL) + no_mem_exit("get_mem4Dquant: array4D"); + + mem_size += get_mem3Dquant(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 5D memory array -> LevelQuantParams array3D[dim0][dim1][dim2][dim3][dim4] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem5Dquant(LevelQuantParams ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4) +{ + int i, mem_size = dim0 * sizeof(LevelQuantParams***); + + if(((*array5D) = (LevelQuantParams*****)mem_malloc(dim0 * sizeof(LevelQuantParams****))) == NULL) + no_mem_exit("get_mem5Dquant: array5D"); + + mem_size += get_mem4Dquant(*array5D, dim0 * dim1, dim2, dim3, dim4); + + for(i = 1; i < dim0; i++) + (*array5D)[i] = (*array5D)[i - 1] + dim1; + + return mem_size; +} + + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> WPParams array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Dwp(WPParams ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (WPParams**)mem_malloc(dim0 * sizeof(WPParams*))) == NULL) + no_mem_exit("get_mem2Dwp: array2D"); + if((*(*array2D) = (WPParams* )mem_calloc(dim0 * dim1,sizeof(WPParams ))) == NULL) + no_mem_exit("get_mem2Dwp: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(WPParams*) + dim1 * sizeof(WPParams)); +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dwp() + ************************************************************************ + */ +void free_mem2Dwp(WPParams **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dwp: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dwp: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dquant() + ************************************************************************ + */ +void free_mem2Dquant(LevelQuantParams **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dquant: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dquant: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3Dquant() + ************************************************************************ + */ +void free_mem3Dquant(LevelQuantParams ***array3D) +{ + if (array3D) + { + free_mem2Dquant(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dquant: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 4D memory array + * which was allocated with get_mem4Dquant() + ************************************************************************ + */ +void free_mem4Dquant(LevelQuantParams ****array4D) +{ + if (array4D) + { + free_mem3Dquant(*array4D); + mem_free (array4D); + } + else + { + error ("free_mem4Dquant: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 5D memory array + * which was allocated with get_mem5Dquant() + ************************************************************************ + */ +void free_mem5Dquant(LevelQuantParams *****array5D) +{ + if (array5D) + { + free_mem4Dquant(*array5D); + mem_free (array5D); + } + else + { + error ("free_mem5Dquant: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> StorablePicturePtr array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2D_spp(StorablePicturePtr ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (StorablePicturePtr**)mem_malloc(dim0 * sizeof(StorablePicturePtr*))) == NULL) + no_mem_exit("get_mem2D_spp: array2D"); + if((*(*array2D) = (StorablePicturePtr* )mem_calloc(dim0 * dim1,sizeof(StorablePicturePtr ))) == NULL) + no_mem_exit("get_mem2D_spp: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(StorablePicturePtr*) + dim1 * sizeof(StorablePicturePtr)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> StorablePicturePtr array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3D_spp(StorablePicturePtr ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(StorablePicturePtr**); + + if(((*array3D) = (StorablePicturePtr***)mem_malloc(dim0 * sizeof(StorablePicturePtr**))) == NULL) + no_mem_exit("get_mem3D_spp: array3D"); + + mem_size += get_mem2D_spp(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> MotionVector array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Dmv(MotionVector ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (MotionVector**)mem_malloc(dim0 * sizeof(MotionVector*))) == NULL) + no_mem_exit("get_mem2Dmv: array2D"); + if((*(*array2D) = (MotionVector* )mem_calloc(dim0 * dim1,sizeof(MotionVector ))) == NULL) + no_mem_exit("get_mem2Dmv: array2D"); + + memset(*(*array2D),0,dim0 * dim1 * sizeof(MotionVector ) ); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(MotionVector*) + dim1 * sizeof(MotionVector)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> MotionVector array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dmv(MotionVector ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(MotionVector**); + + if(((*array3D) = (MotionVector***)mem_malloc(dim0 * sizeof(MotionVector**))) == NULL) + no_mem_exit("get_mem3Dmv: array3D"); + + mem_size += get_mem2Dmv(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 4D memory array -> MotionVector array3D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4Dmv(MotionVector *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(MotionVector***); + + if(((*array4D) = (MotionVector****)mem_malloc(dim0 * sizeof(MotionVector***))) == NULL) + no_mem_exit("get_mem4Dpel: array4D"); + + mem_size += get_mem3Dmv(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 5D memory array -> MotionVector array3D[dim0][dim1][dim2][dim3][dim4] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem5Dmv(MotionVector ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4) +{ + int i, mem_size = dim0 * sizeof(MotionVector***); + + if(((*array5D) = (MotionVector*****)mem_malloc(dim0 * sizeof(MotionVector****))) == NULL) + no_mem_exit("get_mem5Dmv: array5D"); + + mem_size += get_mem4Dmv(*array5D, dim0 * dim1, dim2, dim3, dim4); + + for(i = 1; i < dim0; i++) + (*array5D)[i] = (*array5D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 6D memory array -> MotionVector array6D[dim0][dim1][dim2][dim3][dim4][dim5] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem6Dmv(MotionVector *******array6D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5) +{ + int i, mem_size = dim0 * sizeof(MotionVector*****); + + if(((*array6D) = (MotionVector******)mem_malloc(dim0 * sizeof(MotionVector*****))) == NULL) + no_mem_exit("get_mem6Dmv: array6D"); + + mem_size += get_mem5Dmv(*array6D, dim0 * dim1, dim2, dim3, dim4, dim5); + + for(i = 1; i < dim0; i++) + (*array6D)[i] = (*array6D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 7D memory array -> MotionVector array6D[dim0][dim1][dim2][dim3][dim4][dim5][dim6] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem7Dmv(MotionVector ********array7D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5, int dim6) +{ + int i, mem_size = dim0 * sizeof(MotionVector*****); + + if(((*array7D) = (MotionVector*******)mem_malloc(dim0 * sizeof(MotionVector******))) == NULL) + no_mem_exit("get_mem7Dmv: array7D"); + + mem_size += get_mem6Dmv(*array7D, dim0 * dim1, dim2, dim3, dim4, dim5, dim6); + + for(i = 1; i < dim0; i++) + (*array7D)[i] = (*array7D)[i - 1] + dim1; + + return mem_size; +} + + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2D_spp() + ************************************************************************ + */ +void free_mem2D_spp(StorablePicturePtr **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2D_spp: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2D_spp: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3D_spp() + ************************************************************************ + */ +void free_mem3D_spp(StorablePicturePtr ***array3D) +{ + if (array3D) + { + free_mem2D_spp(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3D_spp: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dmv() + ************************************************************************ + */ +void free_mem2Dmv(MotionVector **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dmv: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dmv: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3Dmv() + ************************************************************************ + */ +void free_mem3Dmv(MotionVector ***array3D) +{ + if (array3D) + { + free_mem2Dmv(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dmv: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 4D memory array + * which was allocated with get_mem4Dmv() + ************************************************************************ + */ +void free_mem4Dmv(MotionVector ****array4D) +{ + if (array4D) + { + free_mem3Dmv(*array4D); + mem_free (array4D); + } + else + { + error ("free_mem4Dmv: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 5D memory array + * which was allocated with get_mem5Dmv() + ************************************************************************ + */ +void free_mem5Dmv(MotionVector *****array5D) +{ + if (array5D) + { + free_mem4Dmv(*array5D); + mem_free (array5D); + } + else + { + error ("free_mem5Dmv: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 6D memory array + * which was allocated with get_mem6Dmv() + ************************************************************************ + */ +void free_mem6Dmv(MotionVector ******array6D) +{ + if (array6D) + { + free_mem5Dmv(*array6D); + mem_free (array6D); + } + else + { + error ("free_mem6Dmv: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 7D memory array + * which was allocated with get_mem7Dmv() + ************************************************************************ + */ +void free_mem7Dmv(MotionVector *******array7D) +{ + if (array7D) + { + free_mem6Dmv(*array7D); + mem_free (array7D); + } + else + { + error ("free_mem7Dmv: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * Allocate 1D memory array -> imgpel array1D[dim0 + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem1Dpel(imgpel **array1D, int dim0) +{ + if((*array1D = (imgpel*)mem_calloc(dim0, sizeof(imgpel))) == NULL) + no_mem_exit("get_mem1Dpel: array1D"); + + return (sizeof(imgpel*) + dim0 * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> imgpel array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2Dpel(imgpel ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (imgpel**)mem_malloc(dim0 * sizeof(imgpel*))) == NULL) + no_mem_exit("get_mem2Dpel: array2D"); + if((*(*array2D) = (imgpel* )mem_malloc(dim0 * dim1 * sizeof(imgpel ))) == NULL) + no_mem_exit("get_mem2Dpel: array2D"); + + for(i = 1 ; i < dim0; i++) + { + (*array2D)[i] = (*array2D)[i-1] + dim1; + } + + return dim0 * (sizeof(imgpel*) + dim1 * sizeof(imgpel)); +} + +int get_mem2Dpel_pad(imgpel ***array2D, int dim0, int dim1, int iPadY, int iPadX) +{ + int i; + imgpel *curr = NULL; + int iHeight, iWidth; + + iHeight = dim0+2*iPadY; + iWidth = dim1+2*iPadX; + if((*array2D = (imgpel**)mem_malloc(iHeight*sizeof(imgpel*))) == NULL) + no_mem_exit("get_mem2Dpel_pad: array2D"); + if((*(*array2D) = (imgpel* )mem_calloc(iHeight * iWidth, sizeof(imgpel ))) == NULL) + no_mem_exit("get_mem2Dpel_pad: array2D"); + + (*array2D)[0] += iPadX; + curr = (*array2D)[0]; + for(i = 1 ; i < iHeight; i++) + { + curr += iWidth; + (*array2D)[i] = curr; + } + (*array2D) = &((*array2D)[iPadY]); + + return iHeight * (sizeof(imgpel*) + iWidth * sizeof(imgpel)); +} + + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> imgpel array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dpel(imgpel ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(imgpel**); + + if(((*array3D) = (imgpel***)malloc(dim0 * sizeof(imgpel**))) == NULL) + no_mem_exit("get_mem3Dpel: array3D"); + + mem_size += get_mem2Dpel(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i - 1] + dim1; + + return mem_size; +} + +int get_mem3Dpel_pad(imgpel ****array3D, int dim0, int dim1, int dim2, int iPadY, int iPadX) +{ + int i, mem_size = dim0 * sizeof(imgpel**); + + if(((*array3D) = (imgpel***)mem_malloc(dim0*sizeof(imgpel**))) == NULL) + no_mem_exit("get_mem3Dpel_pad: array3D"); + + for(i = 0; i < dim0; i++) + mem_size += get_mem2Dpel_pad((*array3D)+i, dim1, dim2, iPadY, iPadX); + + return mem_size; +} + + +/*! + ************************************************************************ + * \brief + * Allocate 4D memory array -> imgpel array4D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4Dpel(imgpel *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(imgpel***); + + if(((*array4D) = (imgpel****)mem_malloc(dim0 * sizeof(imgpel***))) == NULL) + no_mem_exit("get_mem4Dpel: array4D"); + + mem_size += get_mem3Dpel(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i - 1] + dim1; + + return mem_size; +} + + +int get_mem4Dpel_pad(imgpel *****array4D, int dim0, int dim1, int dim2, int dim3, int iPadY, int iPadX) +{ + int i, mem_size = dim0 * sizeof(imgpel***); + + if(((*array4D) = (imgpel****)mem_malloc(dim0 * sizeof(imgpel***))) == NULL) + no_mem_exit("get_mem4Dpel_pad: array4D"); + + mem_size += get_mem3Dpel_pad(*array4D, dim0 * dim1, dim2, dim3, iPadY, iPadX); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 5D memory array -> imgpel array5D[dim0][dim1][dim2][dim3][dim4] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem5Dpel(imgpel ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4) +{ + int i, mem_size = dim0 * sizeof(imgpel****); + + if(((*array5D) = (imgpel*****)mem_malloc(dim0 * sizeof(imgpel****))) == NULL) + no_mem_exit("get_mem5Dpel: array5D"); + + mem_size += get_mem4Dpel(*array5D, dim0 * dim1, dim2, dim3, dim4); + + for(i = 1; i < dim0; i++) + (*array5D)[i] = (*array5D)[i - 1] + dim1; + + return mem_size; +} + +int get_mem5Dpel_pad(imgpel ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4, int iPadY, int iPadX) +{ + int i, mem_size = dim0 * sizeof(imgpel****); + + if(((*array5D) = (imgpel*****)mem_malloc(dim0 * sizeof(imgpel****))) == NULL) + no_mem_exit("get_mem5Dpel_pad: array5D"); + + mem_size += get_mem4Dpel_pad(*array5D, dim0 * dim1, dim2, dim3, dim4, iPadY, iPadX); + + for(i = 1; i < dim0; i++) + (*array5D)[i] = (*array5D)[i - 1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * free 1D memory array + * which was allocated with get_mem1Dpel() + ************************************************************************ + */ +void free_mem1Dpel(imgpel *array1D) +{ + if (array1D) + { + mem_free (array1D); + } + else + { + error ("free_mem1Dpel: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dpel() + ************************************************************************ + */ +void free_mem2Dpel(imgpel **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dpel: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dpel: trying to free unused memory",100); + } +} + +void free_mem2Dpel_pad(imgpel **array2D, int iPadY, int iPadX) +{ + if (array2D) + { + if (*array2D) + { + mem_free (array2D[-iPadY]-iPadX); + } + else + error ("free_mem2Dpel_pad: trying to free unused memory",100); + + mem_free (&array2D[-iPadY]); + } + else + { + error ("free_mem2Dpel_pad: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3Dpel() + ************************************************************************ + */ +void free_mem3Dpel(imgpel ***array3D) +{ + if (array3D) + { + free_mem2Dpel(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dpel: trying to free unused memory",100); + } +} + +void free_mem3Dpel_pad(imgpel ***array3D, int iDim12, int iPadY, int iPadX) +{ + if (array3D) + { + int i; + for(i=0; i byte array2D[dim0][dim1] + * + * \par Output: + * byte type array of size dim0 * dim1 + ************************************************************************ + */ +byte** new_mem2D(int dim0, int dim1) +{ + int i; + byte **array2D; + + if(( array2D = (byte**)mem_malloc(dim0 * sizeof(byte*))) == NULL) + no_mem_exit("get_mem2D: array2D"); + if((*(array2D) = (byte* )mem_calloc(dim0 * dim1,sizeof(byte ))) == NULL) + no_mem_exit("get_mem2D: array2D"); + + for(i = 1; i < dim0; i++) + array2D[i] = array2D[i-1] + dim1; + + return (array2D); +} + + + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> unsigned char array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************/ +int get_mem2D(byte ***array2D, int dim0, int dim1) +{ + int i; + + if(( *array2D = (byte**)mem_malloc(dim0 * sizeof(byte*))) == NULL) + no_mem_exit("get_mem2D: array2D"); + if((*(*array2D) = (byte* )mem_calloc(dim0 * dim1,sizeof(byte ))) == NULL) + no_mem_exit("get_mem2D: array2D"); + + for(i = 1; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(byte*) + dim1 * sizeof(byte)); +} + + +/*! + ************************************************************************ + * \brief + * Create 2D memory array -> int array2D[dim0][dim1] + * + * \par Output: + * int type array of size dim0 * dim1 + ************************************************************************ + */ +int** new_mem2Dint(int dim0, int dim1) +{ + int i; + int **array2D; + + if((array2D = (int**)mem_malloc(dim0 * sizeof(int*))) == NULL) + no_mem_exit("get_mem2Dint: array2D"); + if((*(array2D) = (int* )mem_calloc(dim0 * dim1, sizeof(int ))) == NULL) + no_mem_exit("get_mem2Dint: array2D"); + + for(i = 1 ; i < dim0; i++) + (array2D)[i] = (array2D)[i-1] + dim1; + + return (array2D); +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> int array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Dint(int ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (int**)mem_malloc(dim0 * sizeof(int*))) == NULL) + no_mem_exit("get_mem2Dint: array2D"); + if((*(*array2D) = (int* )mem_calloc(dim0 * dim1, sizeof(int ))) == NULL) + no_mem_exit("get_mem2Dint: array2D"); + + for(i = 1 ; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(int*) + dim1 * sizeof(int)); +} + +int get_mem2Dint_pad(int ***array2D, int dim0, int dim1, int iPadY, int iPadX) +{ + int i; + int *curr = NULL; + int iHeight, iWidth; + + iHeight = dim0+2*iPadY; + iWidth = dim1+2*iPadX; + if((*array2D = (int**)mem_malloc(iHeight*sizeof(int*))) == NULL) + no_mem_exit("get_mem2Dint_pad: array2D"); + if((*(*array2D) = (int* )mem_calloc(iHeight * iWidth, sizeof(int ))) == NULL) + no_mem_exit("get_mem2Dint_pad: array2D"); + + (*array2D)[0] += iPadX; + curr = (*array2D)[0]; + for(i = 1 ; i < iHeight; i++) + { + curr += iWidth; + (*array2D)[i] = curr; + } + (*array2D) = &((*array2D)[iPadY]); + + return iHeight * (sizeof(int*) + iWidth * sizeof(int)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> int64 array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Dint64(int64 ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (int64**)mem_malloc(dim0 * sizeof(int64*))) == NULL) + no_mem_exit("get_mem2Dint64: array2D"); + if((*(*array2D) = (int64* )mem_calloc(dim0 * dim1,sizeof(int64 ))) == NULL) + no_mem_exit("get_mem2Dint64: array2D"); + + for(i = 1; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(int64*) + dim1 * sizeof(int64)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> unsigned char array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3D(byte ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(byte**); + + if(((*array3D) = (byte***)mem_malloc(dim0 * sizeof(byte**))) == NULL) + no_mem_exit("get_mem3D: array3D"); + + mem_size += get_mem2D(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 4D memory array -> unsigned char array4D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4D(byte *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(byte***); + + if(((*array4D) = (byte****)mem_malloc(dim0 * sizeof(byte***))) == NULL) + no_mem_exit("get_mem4D: array4D"); + + mem_size += get_mem3D(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> int array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dint(int ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(int**); + + if(((*array3D) = (int***)mem_malloc(dim0 * sizeof(int**))) == NULL) + no_mem_exit("get_mem3Dint: array3D"); + + mem_size += get_mem2Dint(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory array -> int64 array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dint64(int64 ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(int64**); + + if(((*array3D) = (int64***)mem_malloc(dim0 * sizeof(int64**))) == NULL) + no_mem_exit("get_mem3Dint64: array3D"); + + mem_size += get_mem2Dint64(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i-1] + dim1; + + return mem_size; +} + +int get_mem2Ddistblk(distblk ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (distblk**)mem_malloc(dim0 * sizeof(distblk*))) == NULL) + no_mem_exit("get_mem2Ddistblk: array2D"); + if((*(*array2D) = (distblk* )mem_calloc(dim0 * dim1,sizeof(distblk ))) == NULL) + no_mem_exit("get_mem2Ddistblk: array2D"); + + for(i = 1; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(distblk*) + dim1 * sizeof(distblk)); +} + +int get_mem3Ddistblk(distblk ****array3D, int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(distblk**); + + if(((*array3D) = (distblk***)mem_malloc(dim0 * sizeof(distblk**))) == NULL) + no_mem_exit("get_mem3Ddistblk: array3D"); + + mem_size += get_mem2Ddistblk(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i-1] + dim1; + + return mem_size; +} + +int get_mem4Ddistblk(distblk *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(distblk***); + + if(((*array4D) = (distblk****)mem_malloc(dim0 * sizeof(distblk***))) == NULL) + no_mem_exit("get_mem4Ddistblk: array4D"); + + mem_size += get_mem3Ddistblk(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i-1] + dim1; + + return mem_size; +} +/*! + ************************************************************************ + * \brief + * Allocate 4D memory array -> int array4D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4Dint(int *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(int***); + + if(((*array4D) = (int****)mem_malloc(dim0 * sizeof(int***))) == NULL) + no_mem_exit("get_mem4Dint: array4D"); + + mem_size += get_mem3Dint(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i-1] + dim1; + + return mem_size; +} + +int get_mem4Dint64(int64 *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(int64***); + + if(((*array4D) = (int64****)mem_malloc(dim0 * sizeof(int64***))) == NULL) + no_mem_exit("get_mem4Dint64: array4D"); + + mem_size += get_mem3Dint64(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 5D memory array -> int array5D[dim0][dim1][dim2][dim3][dim4] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem5Dint(int ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4) +{ + int i, mem_size = dim0 * sizeof(int****); + + if(((*array5D) = (int*****)mem_malloc(dim0 * sizeof(int****))) == NULL) + no_mem_exit("get_mem5Dint: array5D"); + + mem_size += get_mem4Dint(*array5D, dim0 * dim1, dim2, dim3, dim4); + + for(i = 1; i < dim0; i++) + (*array5D)[i] = (*array5D)[i-1] + dim1; + + return mem_size; +} + + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2D() + ************************************************************************ + */ +void free_mem2D(byte **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2D: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2D: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dint() + ************************************************************************ + */ +void free_mem2Dint(int **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dint: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dint: trying to free unused memory",100); + } +} + +void free_mem2Dint_pad(int **array2D, int iPadY, int iPadX) +{ + if (array2D) + { + if (*array2D) + mem_free (array2D[-iPadY]-iPadX); + else + error ("free_mem2Dint_pad: trying to free unused memory",100); + + mem_free (&array2D[-iPadY]); + } + else + { + error ("free_mem2Dint_pad: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 2D memory array + * which was allocated with get_mem2Dint64() + ************************************************************************ + */ +void free_mem2Dint64(int64 **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else + error ("free_mem2Dint64: trying to free unused memory",100); + mem_free (array2D); + } + else + { + error ("free_mem2Dint64: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3D() + ************************************************************************ + */ +void free_mem3D(byte ***array3D) +{ + if (array3D) + { + free_mem2D(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3D: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 4D memory array + * which was allocated with get_mem3D() + ************************************************************************ + */ +void free_mem4D(byte ****array4D) +{ + if (array4D) + { + free_mem3D(*array4D); + mem_free (array4D); + } + else + { + error ("free_mem4D: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3Dint() + ************************************************************************ + */ +void free_mem3Dint(int ***array3D) +{ + if (array3D) + { + free_mem2Dint(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dint: trying to free unused memory",100); + } +} + + +/*! + ************************************************************************ + * \brief + * free 3D memory array + * which was allocated with get_mem3Dint64() + ************************************************************************ + */ +void free_mem3Dint64(int64 ***array3D) +{ + if (array3D) + { + free_mem2Dint64(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dint64: trying to free unused memory",100); + } +} + +void free_mem3Ddistblk(distblk ***array3D) +{ + if (array3D) + { + free_mem2Ddistblk(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Ddistblk: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 4D memory array + * which was allocated with get_mem4Dint() + ************************************************************************ + */ +void free_mem4Dint(int ****array4D) +{ + if (array4D) + { + free_mem3Dint( *array4D); + mem_free (array4D); + } else + { + error ("free_mem4Dint: trying to free unused memory",100); + } +} + +void free_mem4Dint64(int64 ****array4D) +{ + if (array4D) + { + free_mem3Dint64( *array4D); + mem_free (array4D); + } else + { + error ("free_mem4Dint64: trying to free unused memory",100); + } +} + +void free_mem4Ddistblk(distblk ****array4D) +{ + if (array4D) + { + free_mem3Ddistblk( *array4D); + mem_free (array4D); + } else + { + error ("free_mem4Ddistblk: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 5D int memory array + * which was allocated with get_mem5Dint() + ************************************************************************ + */ +void free_mem5Dint(int *****array5D) +{ + if (array5D) + { + free_mem4Dint( *array5D); + mem_free (array5D); + } else + { + error ("free_mem5Dint: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * Exit program if memory allocation failed (using error()) + * \param where + * string indicating which memory allocation failed + ************************************************************************ + */ +void no_mem_exit(char *where) +{ + snprintf(errortext, ET_SIZE, "Could not allocate memory: %s",where); + error (errortext, 100); +} + + +/*! + ************************************************************************ + * \brief + * Create 2D memory array -> uint16 array2D[dim0][dim1] + * + * \par Output: + * uint16 type array of size dim0 * dim1 + ************************************************************************ + */ +uint16** new_mem2Duint16(int dim0, int dim1) +{ + int i; + uint16 **array2D; + + if(( array2D = (uint16**)mem_malloc(dim0 * sizeof(uint16*))) == NULL) + no_mem_exit("get_mem2Duint16: array2D"); + if((*array2D = (uint16* )mem_calloc(dim0 * dim1,sizeof(uint16 ))) == NULL) + no_mem_exit("get_mem2Duint16: array2D"); + + for(i = 1; i < dim0; i++) + array2D[i] = array2D[i-1] + dim1; + + return (array2D); +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D uint16 memory array -> uint16 array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Duint16(uint16 ***array2D, int dim0, int dim1) +{ + int i; + + if(( *array2D = (uint16**)mem_malloc(dim0 * sizeof(uint16*))) == NULL) + no_mem_exit("get_mem2Duint16: array2D"); + + if((*(*array2D) = (uint16* )mem_calloc(dim0 * dim1,sizeof(uint16 ))) == NULL) + no_mem_exit("get_mem2Duint16: array2D"); + + for(i = 1; i < dim0; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(uint16*) + dim1 * sizeof(uint16)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory uint16 array -> uint16 array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Duint16(uint16 ****array3D,int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(uint16**); + + if(((*array3D) = (uint16***)mem_malloc(dim0 * sizeof(uint16**))) == NULL) + no_mem_exit("get_mem3Duint16: array3D"); + + mem_size += get_mem2Duint16(*array3D, dim0 * dim1, dim2); + + for(i = 1; i < dim0; i++) + (*array3D)[i] = (*array3D)[i-1] + dim1; + + return mem_size; +} + + +/*! + ************************************************************************ + * \brief + * Allocate 4D memory uint16 array -> uint16 array3D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4Duint16(uint16 *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(uint16***); + + if(((*array4D) = (uint16****)mem_malloc(dim0 * sizeof(uint16***))) == NULL) + no_mem_exit("get_mem4Duint16: array4D"); + + mem_size += get_mem3Duint16(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D short memory array -> short array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Dshort(short ***array2D, int dim0, int dim1) +{ + int i; + short *curr = NULL; + + if(( *array2D = (short**)mem_malloc(dim0 * sizeof(short*))) == NULL) + no_mem_exit("get_mem2Dshort: array2D"); + if((*(*array2D) = (short* )mem_calloc(dim0 * dim1,sizeof(short ))) == NULL) + no_mem_exit("get_mem2Dshort: array2D"); + + curr = (*array2D)[0]; + for(i = 1; i < dim0; i++) + { + curr += dim1; + (*array2D)[i] = curr; + } + + return dim0 * (sizeof(short*) + dim1 * sizeof(short)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory short array -> short array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dshort(short ****array3D,int dim0, int dim1, int dim2) +{ + int i, mem_size = dim0 * sizeof(short**); + short **curr = NULL; + + if(((*array3D) = (short***)mem_malloc(dim0 * sizeof(short**))) == NULL) + no_mem_exit("get_mem3Dshort: array3D"); + + mem_size += get_mem2Dshort(*array3D, dim0 * dim1, dim2); + + curr = (*array3D)[0]; + for(i = 1; i < dim0; i++) + { + curr += dim1; + (*array3D)[i] = curr; + } + + return mem_size; +} + + +/*! + ************************************************************************ + * \brief + * Allocate 4D memory short array -> short array3D[dim0][dim1][dim2][dim3] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem4Dshort(short *****array4D, int dim0, int dim1, int dim2, int dim3) +{ + int i, mem_size = dim0 * sizeof(short***); + + if(((*array4D) = (short****)mem_malloc(dim0 * sizeof(short***))) == NULL) + no_mem_exit("get_mem4Dshort: array4D"); + + mem_size += get_mem3Dshort(*array4D, dim0 * dim1, dim2, dim3); + + for(i = 1; i < dim0; i++) + (*array4D)[i] = (*array4D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 5D memory array -> short array5D[dim0][dim1][dim2][dim3][dim4] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem5Dshort(short ******array5D, int dim0, int dim1, int dim2, int dim3, int dim4) +{ + int i, mem_size = dim0 * sizeof(short****); + + if(((*array5D) = (short*****)mem_malloc(dim0 * sizeof(short****))) == NULL) + no_mem_exit("get_mem5Dshort: array5D"); + + mem_size += get_mem4Dshort(*array5D, dim0 * dim1, dim2, dim3, dim4); + + for(i = 1; i < dim0; i++) + (*array5D)[i] = (*array5D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 6D memory array -> short array6D[dim0][dim1][dim2][dim3][dim4][dim5] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem6Dshort(short *******array6D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5) +{ + int i, mem_size = dim0 * sizeof(short*****); + + if(((*array6D) = (short******)mem_malloc(dim0 * sizeof(short*****))) == NULL) + no_mem_exit("get_mem6Dshort: array6D"); + + mem_size += get_mem5Dshort(*array6D, dim0 * dim1, dim2, dim3, dim4, dim5); + + for(i = 1; i < dim0; i++) + (*array6D)[i] = (*array6D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * Allocate 7D memory array -> short array7D[dim0][dim1][dim2][dim3][dim4][dim5][dim6] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem7Dshort(short ********array7D, int dim0, int dim1, int dim2, int dim3, int dim4, int dim5, int dim6) +{ + int i, mem_size = dim0 * sizeof(short******); + + if(((*array7D) = (short*******)mem_malloc(dim0 * sizeof(short******))) == NULL) + no_mem_exit("get_mem7Dshort: array7D"); + + mem_size += get_mem6Dshort(*array7D, dim0 * dim1, dim2, dim3, dim4, dim5, dim6); + + for(i = 1; i < dim0; i++) + (*array7D)[i] = (*array7D)[i-1] + dim1; + + return mem_size; +} + +/*! + ************************************************************************ + * \brief + * free 2D uint16 memory array + * which was allocated with get_mem2Duint16() + ************************************************************************ + */ +void free_mem2Duint16(uint16 **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else error ("free_mem2Duint16: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Duint16: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 3D uint16 memory array + * which was allocated with get_mem3Duint16() + ************************************************************************ + */ +void free_mem3Duint16(uint16 ***array3D) +{ + if (array3D) + { + free_mem2Duint16(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Duint16: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 4D uint16 memory array + * which was allocated with get_mem4Duint16() + ************************************************************************ + */ +void free_mem4Duint16(uint16 ****array4D) +{ + if (array4D) + { + free_mem3Duint16( *array4D); + mem_free (array4D); + } + else + { + error ("free_mem4Duint16: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 2D short memory array + * which was allocated with get_mem2Dshort() + ************************************************************************ + */ +void free_mem2Dshort(short **array2D) +{ + if (array2D) + { + if (*array2D) + mem_free (*array2D); + else error ("free_mem2Dshort: trying to free unused memory",100); + + mem_free (array2D); + } + else + { + error ("free_mem2Dshort: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 3D short memory array + * which was allocated with get_mem3Dshort() + ************************************************************************ + */ +void free_mem3Dshort(short ***array3D) +{ + if (array3D) + { + free_mem2Dshort(*array3D); + mem_free (array3D); + } + else + { + error ("free_mem3Dshort: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 4D short memory array + * which was allocated with get_mem4Dshort() + ************************************************************************ + */ +void free_mem4Dshort(short ****array4D) +{ + if (array4D) + { + free_mem3Dshort( *array4D); + mem_free (array4D); + } + else + { + error ("free_mem4Dshort: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 5D short memory array + * which was allocated with get_mem5Dshort() + ************************************************************************ + */ +void free_mem5Dshort(short *****array5D) +{ + if (array5D) + { + free_mem4Dshort( *array5D) ; + mem_free (array5D); + } + else + { + error ("free_mem5Dshort: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 6D short memory array + * which was allocated with get_mem6Dshort() + ************************************************************************ + */ +void free_mem6Dshort(short ******array6D) +{ + if (array6D) + { + free_mem5Dshort( *array6D); + mem_free (array6D); + } + else + { + error ("free_mem6Dshort: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * free 7D short memory array + * which was allocated with get_mem7Dshort() + ************************************************************************ + */ +void free_mem7Dshort(short *******array7D) +{ + if (array7D) + { + free_mem6Dshort( *array7D); + mem_free (array7D); + } + else + { + error ("free_mem7Dshort: trying to free unused memory",100); + } +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> double array2D[dim0][dim1] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Ddouble(double ***array2D, int dim0, int dim1) +{ + int i; + + if((*array2D = (double**)mem_malloc(dim0 * sizeof(double*))) == NULL) + no_mem_exit("get_mem2Ddouble: array2D"); + + if(((*array2D)[0] = (double* )mem_calloc(dim0 * dim1, sizeof(double ))) == NULL) + no_mem_exit("get_mem2Ddouble: array2D"); + + for(i=1 ; i double array1D[dim0] + * Note that array is shifted towards offset allowing negative values + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem1Dodouble(double **array1D, int dim0, int offset) +{ + if((*array1D = (double*)mem_calloc(dim0, sizeof(double))) == NULL) + no_mem_exit("get_mem1Dodouble: array2D"); + + *array1D += offset; + + return dim0 * sizeof(double); +} + +/*! + ************************************************************************ + * \brief + * Allocate 2D memory array -> double array2D[dim0][dim1] + * Note that array is shifted towards offset allowing negative values + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Dodouble(double ***array2D, int dim0, int dim1, int offset) +{ + int i; + + if((*array2D = (double**)mem_malloc(dim0 * sizeof(double*))) == NULL) + no_mem_exit("get_mem2Dodouble: array2D"); + if(((*array2D)[0] = (double* )mem_calloc(dim0 * dim1,sizeof(double ))) == NULL) + no_mem_exit("get_mem2Dodouble: array2D"); + + (*array2D)[0] += offset; + + for(i=1 ; i double array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Dodouble(double ****array3D, int dim0, int dim1, int dim2, int offset) +{ + int i,j; + + if(((*array3D) = (double***)mem_malloc(dim0 * sizeof(double**))) == NULL) + no_mem_exit("get_mem3Dodouble: array3D"); + + if(((*array3D)[0] = (double** )mem_calloc(dim0 * dim1,sizeof(double*))) == NULL) + no_mem_exit("get_mem3Dodouble: array3D"); + + (*array3D) [0] += offset; + + for(i=1 ; i int array2D[dim0][dim1] + * Note that array is shifted towards offset allowing negative values + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_offset_mem2Dshort(short ***array2D, int dim0, int dim1, int offset_y, int offset_x) +{ + int i; + + if((*array2D = (short**)mem_malloc(dim0 * sizeof(short*))) == NULL) + no_mem_exit("get_offset_mem2Dshort: array2D"); + + if(((*array2D)[0] = (short* )mem_calloc(dim0 * dim1,sizeof(short))) == NULL) + no_mem_exit("get_offset_mem2Dshort: array2D"); + (*array2D)[0] += offset_x + offset_y * dim1; + + for(i=-1 ; i > -offset_y - 1; i--) + { + (*array2D)[i] = (*array2D)[i+1] - dim1; + } + + for(i=1 ; i < dim1 - offset_y; i++) + (*array2D)[i] = (*array2D)[i-1] + dim1; + + return dim0 * (sizeof(short*) + dim1 * sizeof(short)); +} + +/*! + ************************************************************************ + * \brief + * Allocate 3D memory int array -> int array3D[dim0][dim1][dim2] + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem3Doint(int ****array3D, int dim0, int dim1, int dim2, int offset) +{ + int i,j; + + if(((*array3D) = (int***)mem_malloc(dim0 * sizeof(int**))) == NULL) + no_mem_exit("get_mem3Doint: array3D"); + + if(((*array3D)[0] = (int** )mem_calloc(dim0 * dim1,sizeof(int*))) == NULL) + no_mem_exit("get_mem3Doint: array3D"); + + (*array3D) [0] += offset; + + for(i=1 ; i int array2D[dim0][dim1] + * Note that array is shifted towards offset allowing negative values + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Doint(int ***array2D, int dim0, int dim1, int offset) +{ + int i; + + if((*array2D = (int**)mem_malloc(dim0 * sizeof(int*))) == NULL) + no_mem_exit("get_mem2Dint: array2D"); + if(((*array2D)[0] = (int* )mem_calloc(dim0 * dim1,sizeof(int))) == NULL) + no_mem_exit("get_mem2Dint: array2D"); + + (*array2D)[0] += offset; + + for(i=1 ; i LambdaParams array2D[dim0][dim1] + * Note that array is shifted towards offset allowing negative values + * + * \par Output: + * memory size in bytes + ************************************************************************ + */ +int get_mem2Dolm(LambdaParams ***array2D, int dim0, int dim1, int offset) +{ + int i; + + if((*array2D = (LambdaParams**)mem_malloc(dim0 * sizeof(LambdaParams*))) == NULL) + no_mem_exit("get_mem2Dolm: array2D"); + if(((*array2D)[0] = (LambdaParams* )mem_calloc(dim0 * dim1, sizeof(LambdaParams))) == NULL) + no_mem_exit("get_mem2Dolm: array2D"); + + (*array2D)[0] += offset; + + for(i=1 ; i + * - Karsten Suehring + ************************************************************************************* + */ + +#include "global.h" +#include "mbuffer.h" + +/*! + ************************************************************************ + * \brief + * Get motion vector predictor + ************************************************************************ + */ +static void GetMotionVectorPredictorMBAFF (Macroblock *currMB, + PixelPos *block, // <--> block neighbors + MotionVector *pmv, + short ref_frame, + PicMotionParams **mv_info, + int list, + int mb_x, + int mb_y, + int blockshape_x, + int blockshape_y) +{ + int mv_a, mv_b, mv_c, pred_vec=0; + int mvPredType, rFrameL, rFrameU, rFrameUR; + int hv; + VideoParameters *p_Vid = currMB->p_Vid; + + mvPredType = MVPRED_MEDIAN; + + + if (currMB->mb_field) + { + rFrameL = block[0].available + ? (p_Vid->mb_data[block[0].mb_addr].mb_field + ? mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] + : mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] * 2) : -1; + rFrameU = block[1].available + ? (p_Vid->mb_data[block[1].mb_addr].mb_field + ? mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] + : mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] * 2) : -1; + rFrameUR = block[2].available + ? (p_Vid->mb_data[block[2].mb_addr].mb_field + ? mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] + : mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] * 2) : -1; + } + else + { + rFrameL = block[0].available + ? (p_Vid->mb_data[block[0].mb_addr].mb_field + ? mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] >>1 + : mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list]) : -1; + rFrameU = block[1].available + ? (p_Vid->mb_data[block[1].mb_addr].mb_field + ? mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] >>1 + : mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list]) : -1; + rFrameUR = block[2].available + ? (p_Vid->mb_data[block[2].mb_addr].mb_field + ? mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] >>1 + : mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list]) : -1; + } + + + /* Prediction if only one of the neighbors uses the reference frame + * we are checking + */ + if(rFrameL == ref_frame && rFrameU != ref_frame && rFrameUR != ref_frame) + mvPredType = MVPRED_L; + else if(rFrameL != ref_frame && rFrameU == ref_frame && rFrameUR != ref_frame) + mvPredType = MVPRED_U; + else if(rFrameL != ref_frame && rFrameU != ref_frame && rFrameUR == ref_frame) + mvPredType = MVPRED_UR; + // Directional predictions + if(blockshape_x == 8 && blockshape_y == 16) + { + if(mb_x == 0) + { + if(rFrameL == ref_frame) + mvPredType = MVPRED_L; + } + else + { + if( rFrameUR == ref_frame) + mvPredType = MVPRED_UR; + } + } + else if(blockshape_x == 16 && blockshape_y == 8) + { + if(mb_y == 0) + { + if(rFrameU == ref_frame) + mvPredType = MVPRED_U; + } + else + { + if(rFrameL == ref_frame) + mvPredType = MVPRED_L; + } + } + + for (hv=0; hv < 2; hv++) + { + if (hv == 0) + { + mv_a = block[0].available ? mv_info[block[0].pos_y][block[0].pos_x].mv[list].mv_x : 0; + mv_b = block[1].available ? mv_info[block[1].pos_y][block[1].pos_x].mv[list].mv_x : 0; + mv_c = block[2].available ? mv_info[block[2].pos_y][block[2].pos_x].mv[list].mv_x : 0; + } + else + { + if (currMB->mb_field) + { + mv_a = block[0].available ? p_Vid->mb_data[block[0].mb_addr].mb_field + ? mv_info[block[0].pos_y][block[0].pos_x].mv[list].mv_y + : mv_info[block[0].pos_y][block[0].pos_x].mv[list].mv_y / 2 + : 0; + mv_b = block[1].available ? p_Vid->mb_data[block[1].mb_addr].mb_field + ? mv_info[block[1].pos_y][block[1].pos_x].mv[list].mv_y + : mv_info[block[1].pos_y][block[1].pos_x].mv[list].mv_y / 2 + : 0; + mv_c = block[2].available ? p_Vid->mb_data[block[2].mb_addr].mb_field + ? mv_info[block[2].pos_y][block[2].pos_x].mv[list].mv_y + : mv_info[block[2].pos_y][block[2].pos_x].mv[list].mv_y / 2 + : 0; + } + else + { + mv_a = block[0].available ? p_Vid->mb_data[block[0].mb_addr].mb_field + ? mv_info[block[0].pos_y][block[0].pos_x].mv[list].mv_y * 2 + : mv_info[block[0].pos_y][block[0].pos_x].mv[list].mv_y + : 0; + mv_b = block[1].available ? p_Vid->mb_data[block[1].mb_addr].mb_field + ? mv_info[block[1].pos_y][block[1].pos_x].mv[list].mv_y * 2 + : mv_info[block[1].pos_y][block[1].pos_x].mv[list].mv_y + : 0; + mv_c = block[2].available ? p_Vid->mb_data[block[2].mb_addr].mb_field + ? mv_info[block[2].pos_y][block[2].pos_x].mv[list].mv_y * 2 + : mv_info[block[2].pos_y][block[2].pos_x].mv[list].mv_y + : 0; + } + } + + switch (mvPredType) + { + case MVPRED_MEDIAN: + if(!(block[1].available || block[2].available)) + { + pred_vec = mv_a; + } + else + { + pred_vec = imedian(mv_a, mv_b, mv_c); + } + break; + case MVPRED_L: + pred_vec = mv_a; + break; + case MVPRED_U: + pred_vec = mv_b; + break; + case MVPRED_UR: + pred_vec = mv_c; + break; + default: + break; + } + + if (hv == 0) + pmv->mv_x = (short) pred_vec; + else + pmv->mv_y = (short) pred_vec; + } +} + +/*! + ************************************************************************ + * \brief + * Get motion vector predictor + ************************************************************************ + */ +static void GetMotionVectorPredictorNormal (Macroblock *currMB, + PixelPos *block, // <--> block neighbors + MotionVector *pmv, + short ref_frame, + PicMotionParams **mv_info, + int list, + int mb_x, + int mb_y, + int blockshape_x, + int blockshape_y) +{ + int mvPredType = MVPRED_MEDIAN; + + int rFrameL = block[0].available ? mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] : -1; + int rFrameU = block[1].available ? mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] : -1; + int rFrameUR = block[2].available ? mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] : -1; + + /* Prediction if only one of the neighbors uses the reference frame + * we are checking + */ + if(rFrameL == ref_frame && rFrameU != ref_frame && rFrameUR != ref_frame) + mvPredType = MVPRED_L; + else if(rFrameL != ref_frame && rFrameU == ref_frame && rFrameUR != ref_frame) + mvPredType = MVPRED_U; + else if(rFrameL != ref_frame && rFrameU != ref_frame && rFrameUR == ref_frame) + mvPredType = MVPRED_UR; + + // Directional predictions + if(blockshape_x == 8 && blockshape_y == 16) + { + if(mb_x == 0) + { + if(rFrameL == ref_frame) + mvPredType = MVPRED_L; + } + else + { + if(rFrameUR == ref_frame) + mvPredType = MVPRED_UR; + } + } + else if(blockshape_x == 16 && blockshape_y == 8) + { + if(mb_y == 0) + { + if(rFrameU == ref_frame) + mvPredType = MVPRED_U; + } + else + { + if(rFrameL == ref_frame) + mvPredType = MVPRED_L; + } + } + + switch (mvPredType) + { + case MVPRED_MEDIAN: + if(!(block[1].available || block[2].available)) + { + if (block[0].available) + { + *pmv = mv_info[block[0].pos_y][block[0].pos_x].mv[list]; + } + else + { + *pmv = zero_mv; + } + } + else + { + MotionVector *mv_a = block[0].available ? &mv_info[block[0].pos_y][block[0].pos_x].mv[list] : (MotionVector *) &zero_mv; + MotionVector *mv_b = block[1].available ? &mv_info[block[1].pos_y][block[1].pos_x].mv[list] : (MotionVector *) &zero_mv; + MotionVector *mv_c = block[2].available ? &mv_info[block[2].pos_y][block[2].pos_x].mv[list] : (MotionVector *) &zero_mv; + + pmv->mv_x = (short) imedian(mv_a->mv_x, mv_b->mv_x, mv_c->mv_x); + pmv->mv_y = (short) imedian(mv_a->mv_y, mv_b->mv_y, mv_c->mv_y); + } + break; + case MVPRED_L: + if (block[0].available) + { + *pmv = mv_info[block[0].pos_y][block[0].pos_x].mv[list]; + } + else + { + *pmv = zero_mv; + } + break; + case MVPRED_U: + if (block[1].available) + { + *pmv = mv_info[block[1].pos_y][block[1].pos_x].mv[list]; + } + else + { + *pmv = zero_mv; + } + break; + case MVPRED_UR: + if (block[2].available) + { + *pmv = mv_info[block[2].pos_y][block[2].pos_x].mv[list]; + } + else + { + *pmv = zero_mv; + } + break; + default: + break; + } +} + +void init_motion_vector_prediction(Macroblock *currMB, int mb_aff_frame_flag) +{ + if (mb_aff_frame_flag) + currMB->GetMVPredictor = GetMotionVectorPredictorMBAFF; + else + currMB->GetMVPredictor = GetMotionVectorPredictorNormal; +} diff --git a/lcommon/src/nalucommon.c b/lcommon/src/nalucommon.c new file mode 100644 index 0000000..57074a5 --- /dev/null +++ b/lcommon/src/nalucommon.c @@ -0,0 +1,71 @@ + +/*! + ************************************************************************ + * \file nalucommon.c + * + * \brief + * Common NALU support functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + ************************************************************************ + */ + +#include "global.h" +#include "nalucommon.h" +#include "memalloc.h" + +/*! + ************************************************************************************* + * \brief + * Allocates memory for a NALU + * + * \param buffersize + * size of NALU buffer + * + * \return + * pointer to a NALU + ************************************************************************************* + */ +NALU_t *AllocNALU(int buffersize) +{ + NALU_t *n; + + if ((n = (NALU_t*)calloc (1, sizeof (NALU_t))) == NULL) + no_mem_exit ("AllocNALU: n"); + + n->max_size=buffersize; + + if ((n->buf = (byte*)calloc (buffersize, sizeof (byte))) == NULL) + { + free (n); + no_mem_exit ("AllocNALU: n->buf"); + } + + return n; +} + + +/*! + ************************************************************************************* + * \brief + * Frees a NALU + * + * \param n + * NALU to be freed + * + ************************************************************************************* + */ +void FreeNALU(NALU_t *n) +{ + if (n != NULL) + { + if (n->buf != NULL) + { + free(n->buf); + n->buf=NULL; + } + free (n); + } +} diff --git a/lcommon/src/parsetcommon.c b/lcommon/src/parsetcommon.c new file mode 100644 index 0000000..2256e3d --- /dev/null +++ b/lcommon/src/parsetcommon.c @@ -0,0 +1,244 @@ + +/*! + ************************************************************************************** + * \file + * parsetcommon.c + * \brief + * Picture and Sequence Parameter set generation and handling + * \date 25 November 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * + ************************************************************************************** + */ + +#include "global.h" +#include "parsetcommon.h" +#include "memalloc.h" +/*! + ************************************************************************************* + * \brief + * Allocates memory for a picture paramater set + * + * \return + * pointer to a pps + ************************************************************************************* + */ + +pic_parameter_set_rbsp_t *AllocPPS () + { + pic_parameter_set_rbsp_t *p; + + if ((p=calloc (1, sizeof (pic_parameter_set_rbsp_t))) == NULL) + no_mem_exit ("AllocPPS: PPS"); + p->slice_group_id = NULL; + return p; + } + + +/*! + ************************************************************************************* + * \brief + * Allocates memory for am sequence paramater set + * + * \return + * pointer to a sps + ************************************************************************************* + */ + +seq_parameter_set_rbsp_t *AllocSPS () + { + seq_parameter_set_rbsp_t *p; + + if ((p=calloc (1, sizeof (seq_parameter_set_rbsp_t))) == NULL) + no_mem_exit ("AllocSPS: SPS"); + return p; + } + + +/*! + ************************************************************************************* + * \brief + * Frees a picture parameter set + * + * \param pps to be freed + * Picture parameter set to be freed + ************************************************************************************* + */ + + void FreePPS (pic_parameter_set_rbsp_t *pps) + { + assert (pps != NULL); + if (pps->slice_group_id != NULL) + free (pps->slice_group_id); + free (pps); + } + + + /*! + ************************************************************************************* + * \brief + * Frees a sps + * + * \param sps + * Sequence parameter set to be freed + ************************************************************************************* + */ + + void FreeSPS (seq_parameter_set_rbsp_t *sps) + { + assert (sps != NULL); + free (sps); + } + + +int sps_is_equal(seq_parameter_set_rbsp_t *sps1, seq_parameter_set_rbsp_t *sps2) +{ + unsigned i; + int equal = 1; + + if ((!sps1->Valid) || (!sps2->Valid)) + return 0; + + equal &= (sps1->profile_idc == sps2->profile_idc); + equal &= (sps1->constrained_set0_flag == sps2->constrained_set0_flag); + equal &= (sps1->constrained_set1_flag == sps2->constrained_set1_flag); + equal &= (sps1->constrained_set2_flag == sps2->constrained_set2_flag); + equal &= (sps1->level_idc == sps2->level_idc); + equal &= (sps1->seq_parameter_set_id == sps2->seq_parameter_set_id); + equal &= (sps1->log2_max_frame_num_minus4 == sps2->log2_max_frame_num_minus4); + equal &= (sps1->pic_order_cnt_type == sps2->pic_order_cnt_type); + + if (!equal) return equal; + + if( sps1->pic_order_cnt_type == 0 ) + { + equal &= (sps1->log2_max_pic_order_cnt_lsb_minus4 == sps2->log2_max_pic_order_cnt_lsb_minus4); + } + + else if( sps1->pic_order_cnt_type == 1 ) + { + equal &= (sps1->delta_pic_order_always_zero_flag == sps2->delta_pic_order_always_zero_flag); + equal &= (sps1->offset_for_non_ref_pic == sps2->offset_for_non_ref_pic); + equal &= (sps1->offset_for_top_to_bottom_field == sps2->offset_for_top_to_bottom_field); + equal &= (sps1->num_ref_frames_in_pic_order_cnt_cycle == sps2->num_ref_frames_in_pic_order_cnt_cycle); + if (!equal) return equal; + + for ( i = 0 ; i< sps1->num_ref_frames_in_pic_order_cnt_cycle ;i ++) + equal &= (sps1->offset_for_ref_frame[i] == sps2->offset_for_ref_frame[i]); + } + + equal &= (sps1->num_ref_frames == sps2->num_ref_frames); + equal &= (sps1->gaps_in_frame_num_value_allowed_flag == sps2->gaps_in_frame_num_value_allowed_flag); + equal &= (sps1->pic_width_in_mbs_minus1 == sps2->pic_width_in_mbs_minus1); + equal &= (sps1->pic_height_in_map_units_minus1 == sps2->pic_height_in_map_units_minus1); + equal &= (sps1->frame_mbs_only_flag == sps2->frame_mbs_only_flag); + + if (!equal) return equal; + if( !sps1->frame_mbs_only_flag ) + equal &= (sps1->mb_adaptive_frame_field_flag == sps2->mb_adaptive_frame_field_flag); + + equal &= (sps1->direct_8x8_inference_flag == sps2->direct_8x8_inference_flag); + equal &= (sps1->frame_cropping_flag == sps2->frame_cropping_flag); + if (!equal) return equal; + if (sps1->frame_cropping_flag) + { + equal &= (sps1->frame_crop_left_offset == sps2->frame_crop_left_offset); + equal &= (sps1->frame_crop_right_offset == sps2->frame_crop_right_offset); + equal &= (sps1->frame_crop_top_offset == sps2->frame_crop_top_offset); + equal &= (sps1->frame_crop_bottom_offset == sps2->frame_crop_bottom_offset); + } + equal &= (sps1->vui_parameters_present_flag == sps2->vui_parameters_present_flag); + + return equal; +} + +int pps_is_equal(pic_parameter_set_rbsp_t *pps1, pic_parameter_set_rbsp_t *pps2) +{ + unsigned i, j; + int equal = 1; + + if ((!pps1->Valid) || (!pps2->Valid)) + return 0; + + equal &= (pps1->pic_parameter_set_id == pps2->pic_parameter_set_id); + equal &= (pps1->seq_parameter_set_id == pps2->seq_parameter_set_id); + equal &= (pps1->entropy_coding_mode_flag == pps2->entropy_coding_mode_flag); + equal &= (pps1->bottom_field_pic_order_in_frame_present_flag == pps2->bottom_field_pic_order_in_frame_present_flag); + equal &= (pps1->num_slice_groups_minus1 == pps2->num_slice_groups_minus1); + + if (!equal) return equal; + + if (pps1->num_slice_groups_minus1>0) + { + equal &= (pps1->slice_group_map_type == pps2->slice_group_map_type); + if (!equal) return equal; + if (pps1->slice_group_map_type == 0) + { + for (i=0; i<=pps1->num_slice_groups_minus1; i++) + equal &= (pps1->run_length_minus1[i] == pps2->run_length_minus1[i]); + } + else if( pps1->slice_group_map_type == 2 ) + { + for (i=0; inum_slice_groups_minus1; i++) + { + equal &= (pps1->top_left[i] == pps2->top_left[i]); + equal &= (pps1->bottom_right[i] == pps2->bottom_right[i]); + } + } + else if( pps1->slice_group_map_type == 3 || pps1->slice_group_map_type==4 || pps1->slice_group_map_type==5 ) + { + equal &= (pps1->slice_group_change_direction_flag == pps2->slice_group_change_direction_flag); + equal &= (pps1->slice_group_change_rate_minus1 == pps2->slice_group_change_rate_minus1); + } + else if( pps1->slice_group_map_type == 6 ) + { + equal &= (pps1->pic_size_in_map_units_minus1 == pps2->pic_size_in_map_units_minus1); + if (!equal) return equal; + for (i=0; i<=pps1->pic_size_in_map_units_minus1; i++) + equal &= (pps1->slice_group_id[i] == pps2->slice_group_id[i]); + } + } + + equal &= (pps1->num_ref_idx_l0_default_active_minus1 == pps2->num_ref_idx_l0_default_active_minus1); + equal &= (pps1->num_ref_idx_l1_default_active_minus1 == pps2->num_ref_idx_l1_default_active_minus1); + equal &= (pps1->weighted_pred_flag == pps2->weighted_pred_flag); + equal &= (pps1->weighted_bipred_idc == pps2->weighted_bipred_idc); + equal &= (pps1->pic_init_qp_minus26 == pps2->pic_init_qp_minus26); + equal &= (pps1->pic_init_qs_minus26 == pps2->pic_init_qs_minus26); + equal &= (pps1->chroma_qp_index_offset == pps2->chroma_qp_index_offset); + equal &= (pps1->deblocking_filter_control_present_flag == pps2->deblocking_filter_control_present_flag); + equal &= (pps1->constrained_intra_pred_flag == pps2->constrained_intra_pred_flag); + equal &= (pps1->redundant_pic_cnt_present_flag == pps2->redundant_pic_cnt_present_flag); + + if (!equal) return equal; + + //Fidelity Range Extensions Stuff + //It is initialized to zero, so should be ok to check all the time. + equal &= (pps1->transform_8x8_mode_flag == pps2->transform_8x8_mode_flag); + equal &= (pps1->pic_scaling_matrix_present_flag == pps2->pic_scaling_matrix_present_flag); + if(pps1->pic_scaling_matrix_present_flag) + { + for(i = 0; i < (6 + ((unsigned)pps1->transform_8x8_mode_flag << 1)); i++) + { + equal &= (pps1->pic_scaling_list_present_flag[i] == pps2->pic_scaling_list_present_flag[i]); + if(pps1->pic_scaling_list_present_flag[i]) + { + if(i < 6) + { + for (j = 0; j < 16; j++) + equal &= (pps1->ScalingList4x4[i][j] == pps2->ScalingList4x4[i][j]); + } + else + { + for (j = 0; j < 64; j++) + equal &= (pps1->ScalingList8x8[i-6][j] == pps2->ScalingList8x8[i-6][j]); + } + } + } + } + equal &= (pps1->second_chroma_qp_index_offset == pps2->second_chroma_qp_index_offset); + + return equal; +} diff --git a/lcommon/src/transcode_common.c b/lcommon/src/transcode_common.c new file mode 100644 index 0000000..56b8d47 --- /dev/null +++ b/lcommon/src/transcode_common.c @@ -0,0 +1,39 @@ +/*! +************************************************************************ +* \file transcode_common.h +* +* \brief +* Common Functions to write and read a frame node +* +* \author +* - João Carreira +* +************************************************************************ +*/ + +#include "transcode_common.h" +#include "memalloc.h" +//! this is not safe + +int write_trans_node( int pfile, TRANS_FRAME_NODE_T node) +{ + int i=0; + write(pfile,&node,sizeof(TRANS_FRAME_NODE_T)); + write(pfile, (*(node.pp_mv_info)), (node.frame_height/BLOCK_SIZE)*(node.frame_width/BLOCK_SIZE)*sizeof(PicMotionParams)); + return 0; +} + +int read_trans_node( int pfile, TRANS_FRAME_NODE_T *node) +{ + if( read(pfile,node,sizeof(TRANS_FRAME_NODE_T)) != sizeof(TRANS_FRAME_NODE_T) ) + { + return -1; + } + get_mem2Dmp(&(node->pp_mv_info), (node->frame_height/BLOCK_SIZE), (node->frame_width/BLOCK_SIZE) ); + if( read(pfile, (*(node->pp_mv_info)), (node->frame_height/BLOCK_SIZE)*(node->frame_width/BLOCK_SIZE)*sizeof(PicMotionParams)) != + (node->frame_height/BLOCK_SIZE)*(node->frame_width/BLOCK_SIZE)*sizeof(PicMotionParams) ) + { + return -1; + } + return 0; +} \ No newline at end of file diff --git a/lcommon/src/transform.c b/lcommon/src/transform.c new file mode 100644 index 0000000..883f2eb --- /dev/null +++ b/lcommon/src/transform.c @@ -0,0 +1,548 @@ +/*! + *************************************************************************** + * \file transform.c + * + * \brief + * Transform functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * \date + * 01. July 2007 + ************************************************************************** + */ + +#include "global.h" +#include "transform.h" + + +void forward4x4(int **block, int **tblock, int pos_y, int pos_x) +{ + int i, ii; + int tmp[16]; + int *pTmp = tmp, *pblock; + int p0,p1,p2,p3; + int t0,t1,t2,t3; + + // Horizontal + for (i=pos_y; i < pos_y + BLOCK_SIZE; i++) + { + pblock = &block[i][pos_x]; + p0 = *(pblock++); + p1 = *(pblock++); + p2 = *(pblock++); + p3 = *(pblock ); + + t0 = p0 + p3; + t1 = p1 + p2; + t2 = p1 - p2; + t3 = p0 - p3; + + *(pTmp++) = t0 + t1; + *(pTmp++) = (t3 << 1) + t2; + *(pTmp++) = t0 - t1; + *(pTmp++) = t3 - (t2 << 1); + } + + // Vertical + for (i=0; i < BLOCK_SIZE; i++) + { + pTmp = tmp + i; + p0 = *pTmp; + p1 = *(pTmp += BLOCK_SIZE); + p2 = *(pTmp += BLOCK_SIZE); + p3 = *(pTmp += BLOCK_SIZE); + + t0 = p0 + p3; + t1 = p1 + p2; + t2 = p1 - p2; + t3 = p0 - p3; + + ii = pos_x + i; + tblock[pos_y ][ii] = t0 + t1; + tblock[pos_y + 1][ii] = t2 + (t3 << 1); + tblock[pos_y + 2][ii] = t0 - t1; + tblock[pos_y + 3][ii] = t3 - (t2 << 1); + } +} + +void inverse4x4(int **tblock, int **block, int pos_y, int pos_x) +{ + int i, ii; + int tmp[16]; + int *pTmp = tmp, *pblock; + int p0,p1,p2,p3; + int t0,t1,t2,t3; + + // Horizontal + for (i = pos_y; i < pos_y + BLOCK_SIZE; i++) + { + pblock = &tblock[i][pos_x]; + t0 = *(pblock++); + t1 = *(pblock++); + t2 = *(pblock++); + t3 = *(pblock ); + + p0 = t0 + t2; + p1 = t0 - t2; + p2 = (t1 >> 1) - t3; + p3 = t1 + (t3 >> 1); + + *(pTmp++) = p0 + p3; + *(pTmp++) = p1 + p2; + *(pTmp++) = p1 - p2; + *(pTmp++) = p0 - p3; + } + + // Vertical + for (i = 0; i < BLOCK_SIZE; i++) + { + pTmp = tmp + i; + t0 = *pTmp; + t1 = *(pTmp += BLOCK_SIZE); + t2 = *(pTmp += BLOCK_SIZE); + t3 = *(pTmp += BLOCK_SIZE); + + p0 = t0 + t2; + p1 = t0 - t2; + p2 =(t1 >> 1) - t3; + p3 = t1 + (t3 >> 1); + + ii = i + pos_x; + block[pos_y ][ii] = p0 + p3; + block[pos_y + 1][ii] = p1 + p2; + block[pos_y + 2][ii] = p1 - p2; + block[pos_y + 3][ii] = p0 - p3; + } +} + + +void hadamard4x4(int **block, int **tblock) +{ + int i; + int tmp[16]; + int *pTmp = tmp, *pblock; + int p0,p1,p2,p3; + int t0,t1,t2,t3; + + // Horizontal + for (i = 0; i < BLOCK_SIZE; i++) + { + pblock = block[i]; + p0 = *(pblock++); + p1 = *(pblock++); + p2 = *(pblock++); + p3 = *(pblock ); + + t0 = p0 + p3; + t1 = p1 + p2; + t2 = p1 - p2; + t3 = p0 - p3; + + *(pTmp++) = t0 + t1; + *(pTmp++) = t3 + t2; + *(pTmp++) = t0 - t1; + *(pTmp++) = t3 - t2; + } + + // Vertical + for (i = 0; i < BLOCK_SIZE; i++) + { + pTmp = tmp + i; + p0 = *pTmp; + p1 = *(pTmp += BLOCK_SIZE); + p2 = *(pTmp += BLOCK_SIZE); + p3 = *(pTmp += BLOCK_SIZE); + + t0 = p0 + p3; + t1 = p1 + p2; + t2 = p1 - p2; + t3 = p0 - p3; + + tblock[0][i] = (t0 + t1) >> 1; + tblock[1][i] = (t2 + t3) >> 1; + tblock[2][i] = (t0 - t1) >> 1; + tblock[3][i] = (t3 - t2) >> 1; + } +} + + +void ihadamard4x4(int **tblock, int **block) +{ + int i; + int tmp[16]; + int *pTmp = tmp, *pblock; + int p0,p1,p2,p3; + int t0,t1,t2,t3; + + // Horizontal + for (i = 0; i < BLOCK_SIZE; i++) + { + pblock = tblock[i]; + t0 = *(pblock++); + t1 = *(pblock++); + t2 = *(pblock++); + t3 = *(pblock ); + + p0 = t0 + t2; + p1 = t0 - t2; + p2 = t1 - t3; + p3 = t1 + t3; + + *(pTmp++) = p0 + p3; + *(pTmp++) = p1 + p2; + *(pTmp++) = p1 - p2; + *(pTmp++) = p0 - p3; + } + + // Vertical + for (i = 0; i < BLOCK_SIZE; i++) + { + pTmp = tmp + i; + t0 = *pTmp; + t1 = *(pTmp += BLOCK_SIZE); + t2 = *(pTmp += BLOCK_SIZE); + t3 = *(pTmp += BLOCK_SIZE); + + p0 = t0 + t2; + p1 = t0 - t2; + p2 = t1 - t3; + p3 = t1 + t3; + + block[0][i] = p0 + p3; + block[1][i] = p1 + p2; + block[2][i] = p1 - p2; + block[3][i] = p0 - p3; + } +} + +void hadamard4x2(int **block, int **tblock) +{ + int i; + int tmp[8]; + int *pTmp = tmp; + int p0,p1,p2,p3; + int t0,t1,t2,t3; + + // Horizontal + *(pTmp++) = block[0][0] + block[1][0]; + *(pTmp++) = block[0][1] + block[1][1]; + *(pTmp++) = block[0][2] + block[1][2]; + *(pTmp++) = block[0][3] + block[1][3]; + + *(pTmp++) = block[0][0] - block[1][0]; + *(pTmp++) = block[0][1] - block[1][1]; + *(pTmp++) = block[0][2] - block[1][2]; + *(pTmp ) = block[0][3] - block[1][3]; + + // Vertical + pTmp = tmp; + for (i=0;i<2;i++) + { + p0 = *(pTmp++); + p1 = *(pTmp++); + p2 = *(pTmp++); + p3 = *(pTmp++); + + t0 = p0 + p3; + t1 = p1 + p2; + t2 = p1 - p2; + t3 = p0 - p3; + + tblock[i][0] = (t0 + t1); + tblock[i][1] = (t3 + t2); + tblock[i][2] = (t0 - t1); + tblock[i][3] = (t3 - t2); + } +} + +void ihadamard4x2(int **tblock, int **block) +{ + int i; + int tmp[8]; + int *pTmp = tmp; + int p0,p1,p2,p3; + int t0,t1,t2,t3; + + // Horizontal + *(pTmp++) = tblock[0][0] + tblock[1][0]; + *(pTmp++) = tblock[0][1] + tblock[1][1]; + *(pTmp++) = tblock[0][2] + tblock[1][2]; + *(pTmp++) = tblock[0][3] + tblock[1][3]; + + *(pTmp++) = tblock[0][0] - tblock[1][0]; + *(pTmp++) = tblock[0][1] - tblock[1][1]; + *(pTmp++) = tblock[0][2] - tblock[1][2]; + *(pTmp ) = tblock[0][3] - tblock[1][3]; + + // Vertical + pTmp = tmp; + for (i = 0; i < 2; i++) + { + p0 = *(pTmp++); + p1 = *(pTmp++); + p2 = *(pTmp++); + p3 = *(pTmp++); + + t0 = p0 + p2; + t1 = p0 - p2; + t2 = p1 - p3; + t3 = p1 + p3; + + // coefficients (transposed) + block[0][i] = t0 + t3; + block[1][i] = t1 + t2; + block[2][i] = t1 - t2; + block[3][i] = t0 - t3; + } +} + +//following functions perform 8 additions, 8 assignments. Should be a bit faster +void hadamard2x2(int **block, int tblock[4]) +{ + int p0,p1,p2,p3; + + p0 = block[0][0] + block[0][4]; + p1 = block[0][0] - block[0][4]; + p2 = block[4][0] + block[4][4]; + p3 = block[4][0] - block[4][4]; + + tblock[0] = (p0 + p2); + tblock[1] = (p1 + p3); + tblock[2] = (p0 - p2); + tblock[3] = (p1 - p3); +} + +void ihadamard2x2(int tblock[4], int block[4]) +{ + int t0,t1,t2,t3; + + t0 = tblock[0] + tblock[1]; + t1 = tblock[0] - tblock[1]; + t2 = tblock[2] + tblock[3]; + t3 = tblock[2] - tblock[3]; + + block[0] = (t0 + t2); + block[1] = (t1 + t3); + block[2] = (t0 - t2); + block[3] = (t1 - t3); +} + +/* +void hadamard2x2(int **block, int tblock[4]) +{ + //12 additions, 4 assignments + tblock[0] = (block[0][0] + block[0][4] + block[4][0] + block[4][4]); + tblock[1] = (block[0][0] - block[0][4] + block[4][0] - block[4][4]); + tblock[2] = (block[0][0] + block[0][4] - block[4][0] - block[4][4]); + tblock[3] = (block[0][0] - block[0][4] - block[4][0] + block[4][4]); +} + +void ihadamard2x2(int tblock[4], int block[4]) +{ + block[0] = (tblock[0] + tblock[1] + tblock[2] + tblock[3]); + block[1] = (tblock[0] - tblock[1] + tblock[2] - tblock[3]); + block[2] = (tblock[0] + tblock[1] - tblock[2] - tblock[3]); + block[3] = (tblock[0] - tblock[1] - tblock[2] + tblock[3]); +} + +*/ + + +void forward8x8(int **block, int **tblock, int pos_y, int pos_x) +{ + int i, ii; + int tmp[64]; + int *pTmp = tmp, *pblock; + int a0, a1, a2, a3; + int p0, p1, p2, p3, p4, p5 ,p6, p7; + int b0, b1, b2, b3, b4, b5, b6, b7; + + // Horizontal + for (i=pos_y; i < pos_y + BLOCK_SIZE_8x8; i++) + { + pblock = &block[i][pos_x]; + p0 = *(pblock++); + p1 = *(pblock++); + p2 = *(pblock++); + p3 = *(pblock++); + p4 = *(pblock++); + p5 = *(pblock++); + p6 = *(pblock++); + p7 = *(pblock ); + + a0 = p0 + p7; + a1 = p1 + p6; + a2 = p2 + p5; + a3 = p3 + p4; + + b0 = a0 + a3; + b1 = a1 + a2; + b2 = a0 - a3; + b3 = a1 - a2; + + a0 = p0 - p7; + a1 = p1 - p6; + a2 = p2 - p5; + a3 = p3 - p4; + + b4 = a1 + a2 + ((a0 >> 1) + a0); + b5 = a0 - a3 - ((a2 >> 1) + a2); + b6 = a0 + a3 - ((a1 >> 1) + a1); + b7 = a1 - a2 + ((a3 >> 1) + a3); + + *(pTmp++) = b0 + b1; + *(pTmp++) = b4 + (b7 >> 2); + *(pTmp++) = b2 + (b3 >> 1); + *(pTmp++) = b5 + (b6 >> 2); + *(pTmp++) = b0 - b1; + *(pTmp++) = b6 - (b5 >> 2); + *(pTmp++) = (b2 >> 1) - b3; + *(pTmp++) = (b4 >> 2) - b7; + } + + // Vertical + for (i=0; i < BLOCK_SIZE_8x8; i++) + { + pTmp = tmp + i; + p0 = *pTmp; + p1 = *(pTmp += BLOCK_SIZE_8x8); + p2 = *(pTmp += BLOCK_SIZE_8x8); + p3 = *(pTmp += BLOCK_SIZE_8x8); + p4 = *(pTmp += BLOCK_SIZE_8x8); + p5 = *(pTmp += BLOCK_SIZE_8x8); + p6 = *(pTmp += BLOCK_SIZE_8x8); + p7 = *(pTmp += BLOCK_SIZE_8x8); + + a0 = p0 + p7; + a1 = p1 + p6; + a2 = p2 + p5; + a3 = p3 + p4; + + b0 = a0 + a3; + b1 = a1 + a2; + b2 = a0 - a3; + b3 = a1 - a2; + + a0 = p0 - p7; + a1 = p1 - p6; + a2 = p2 - p5; + a3 = p3 - p4; + + b4 = a1 + a2 + ((a0 >> 1) + a0); + b5 = a0 - a3 - ((a2 >> 1) + a2); + b6 = a0 + a3 - ((a1 >> 1) + a1); + b7 = a1 - a2 + ((a3 >> 1) + a3); + + ii = pos_x + i; + tblock[pos_y ][ii] = b0 + b1; + tblock[pos_y + 1][ii] = b4 + (b7 >> 2); + tblock[pos_y + 2][ii] = b2 + (b3 >> 1); + tblock[pos_y + 3][ii] = b5 + (b6 >> 2); + tblock[pos_y + 4][ii] = b0 - b1; + tblock[pos_y + 5][ii] = b6 - (b5 >> 2); + tblock[pos_y + 6][ii] = (b2 >> 1) - b3; + tblock[pos_y + 7][ii] = (b4 >> 2) - b7; + } +} + +void inverse8x8(int **tblock, int **block, int pos_x) +{ + int i, ii; + int tmp[64]; + int *pTmp = tmp, *pblock; + int a0, a1, a2, a3; + int p0, p1, p2, p3, p4, p5 ,p6, p7; + int b0, b1, b2, b3, b4, b5, b6, b7; + + // Horizontal + for (i=0; i < BLOCK_SIZE_8x8; i++) + { + pblock = &tblock[i][pos_x]; + p0 = *(pblock++); + p1 = *(pblock++); + p2 = *(pblock++); + p3 = *(pblock++); + p4 = *(pblock++); + p5 = *(pblock++); + p6 = *(pblock++); + p7 = *(pblock ); + + a0 = p0 + p4; + a1 = p0 - p4; + a2 = p6 - (p2 >> 1); + a3 = p2 + (p6 >> 1); + + b0 = a0 + a3; + b2 = a1 - a2; + b4 = a1 + a2; + b6 = a0 - a3; + + a0 = -p3 + p5 - p7 - (p7 >> 1); + a1 = p1 + p7 - p3 - (p3 >> 1); + a2 = -p1 + p7 + p5 + (p5 >> 1); + a3 = p3 + p5 + p1 + (p1 >> 1); + + + b1 = a0 + (a3>>2); + b3 = a1 + (a2>>2); + b5 = a2 - (a1>>2); + b7 = a3 - (a0>>2); + + *(pTmp++) = b0 + b7; + *(pTmp++) = b2 - b5; + *(pTmp++) = b4 + b3; + *(pTmp++) = b6 + b1; + *(pTmp++) = b6 - b1; + *(pTmp++) = b4 - b3; + *(pTmp++) = b2 + b5; + *(pTmp++) = b0 - b7; + } + + // Vertical + for (i=0; i < BLOCK_SIZE_8x8; i++) + { + pTmp = tmp + i; + p0 = *pTmp; + p1 = *(pTmp += BLOCK_SIZE_8x8); + p2 = *(pTmp += BLOCK_SIZE_8x8); + p3 = *(pTmp += BLOCK_SIZE_8x8); + p4 = *(pTmp += BLOCK_SIZE_8x8); + p5 = *(pTmp += BLOCK_SIZE_8x8); + p6 = *(pTmp += BLOCK_SIZE_8x8); + p7 = *(pTmp += BLOCK_SIZE_8x8); + + a0 = p0 + p4; + a1 = p0 - p4; + a2 = p6 - (p2>>1); + a3 = p2 + (p6>>1); + + b0 = a0 + a3; + b2 = a1 - a2; + b4 = a1 + a2; + b6 = a0 - a3; + + a0 = -p3 + p5 - p7 - (p7 >> 1); + a1 = p1 + p7 - p3 - (p3 >> 1); + a2 = -p1 + p7 + p5 + (p5 >> 1); + a3 = p3 + p5 + p1 + (p1 >> 1); + + + b1 = a0 + (a3 >> 2); + b7 = a3 - (a0 >> 2); + b3 = a1 + (a2 >> 2); + b5 = a2 - (a1 >> 2); + + ii = i + pos_x; + block[0][ii] = b0 + b7; + block[1][ii] = b2 - b5; + block[2][ii] = b4 + b3; + block[3][ii] = b6 + b1; + block[4][ii] = b6 - b1; + block[5][ii] = b4 - b3; + block[6][ii] = b2 + b5; + block[7][ii] = b0 - b7; + } +} + diff --git a/lcommon/src/win32.c b/lcommon/src/win32.c new file mode 100644 index 0000000..ac7343d --- /dev/null +++ b/lcommon/src/win32.c @@ -0,0 +1,78 @@ + +/*! + ************************************************************************************* + * \file win32.c + * + * \brief + * Platform dependent code + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + ************************************************************************************* + */ + +#include "global.h" + + +#ifdef _WIN32 + +static LARGE_INTEGER freq; + +void gettime(TIME_T* time) +{ +#ifndef TIMING_DISABLE + QueryPerformanceCounter(time); +#endif +} + +int64 timediff(TIME_T* start, TIME_T* end) +{ +#ifndef TIMING_DISABLE + return (int64)((end->QuadPart - start->QuadPart)); +#else + return 0; +#endif +} + +void init_time(void) +{ + QueryPerformanceFrequency(&freq); +} + +int64 timenorm(int64 cur_time) +{ +#ifndef TIMING_DISABLE + return (int64)(cur_time * 1000 /(freq.QuadPart)); +#else + return 1; +#endif +} + +#else + +static struct timezone tz; + +void gettime(TIME_T* time) +{ + gettimeofday(time, &tz); +} + +void init_time(void) +{ +} + +int64 timediff(TIME_T* start, TIME_T* end) +{ + int t1, t2; + + t1 = end->tv_sec - start->tv_sec; + t2 = end->tv_usec - start->tv_usec; + return (int64) t2 + (int64) t1 * (int64) 1000000; +} + +int64 timenorm(int64 cur_time) +{ + return (int64)(cur_time / (int64) 1000); +} +#endif diff --git a/ldecod/Makefile b/ldecod/Makefile new file mode 100644 index 0000000..96f2a65 --- /dev/null +++ b/ldecod/Makefile @@ -0,0 +1,152 @@ +### +### Makefile for H.264/AVC decoder +### +### generated for UNIX/LINUX environments +### by H. Schwarz, Limin Wang +### + + + +NAME=ldecod + +### include debug information: 1=yes, 0=no +DBG?= 0 +### Generate 32 bit executable : 1=yes, 0=no +M32?= 0 +### include O level optimization : 0-3 +OPT?= 3 +### Static Compilation +STC?= 0 +### OPENMP support : 1=yes, 0=no +OPENMP?= 1 +### OPENCV support : 1=yes, 0=no +OPENCV?= 0 + + +DEPEND= dependencies + +BINDIR= ../bin +INCDIR= inc +SRCDIR= src +OBJDIR= obj + +ADDSRCDIR= ../lcommon/src +ADDINCDIR= ../lcommon/inc + +FERCSRCDIR= src/ferc +FERCINCDIR= inc/ferc + +ifeq ($(STC),1) +ifeq ($(DBG),1) ### Do not use static compilation for Debug mode +STC=0 +STATIC= +else +STATIC= -static +endif +else +STATIC= +endif + +LIBS= -lm $(STATIC) +CFLAGS= -std=gnu99 -pedantic -ffloat-store -fno-strict-aliasing -fsigned-char $(STATIC) +FLAGS= $(CFLAGS) -Wall -I$(INCDIR) -I$(ADDINCDIR) -I$(FERCINCDIR) -D __USE_LARGEFILE64 -D _FILE_OFFSET_BITS=64 +ifeq ($(M32),1) +FLAGS+=-m32 +endif + +ifeq ($(OPENMP),1) +FLAGS+=-fopenmp +endif + +ifeq ($(OPENCV),1) +LIBS+= `pkg-config --libs opencv` +CFLAGS+= -D HAVE_OPENCV=1 `pkg-config --cflags opencv` +else +CFLAGS+= -D HAVE_OPENCV=0 +endif + +# + +OPT_FLAG = -O$(OPT) +ifeq ($(DBG),1) +SUFFIX= .dbg +FLAGS+= -g +CFLAGS+= -D _DEBUG=1 +else +SUFFIX= +FLAGS+= $(OPT_FLAG) +endif + +OBJSUF= .o$(SUFFIX) + +SRC= $(wildcard $(SRCDIR)/*.c) +ADDSRC= $(wildcard $(ADDSRCDIR)/*.c) +FERCSRC= $(wildcard $(FERCSRCDIR)/*.c) +OBJ= $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o$(SUFFIX)) $(ADDSRC:$(ADDSRCDIR)/%.c=$(OBJDIR)/%.o$(SUFFIX)) $(FERCSRC:$(FERCSRCDIR)/%.c=$(OBJDIR)/%.o$(SUFFIX)) +BIN= $(BINDIR)/$(NAME)$(SUFFIX).exe + + +.PHONY: default distclean clean tags depend + +default: messages objdir_mk depend bin + +messages: +ifeq ($(M32),1) + @echo 'Compiling with M32 support...' +endif +ifeq ($(DBG),1) + @echo 'Compiling with Debug support...' + @echo 'Note static compilation not supported in this mode.' +endif +ifeq ($(STC),1) + @echo 'Compiling with -static support...' +endif +ifeq ($(OPENMP),1) + @echo 'Compiling with -fopenmp support...' +endif + +clean: + @echo remove all objects + @rm -rf $(OBJDIR) + +distclean: clean + @rm -f $(DEPEND) tags + @rm -f $(BIN) + +tags: + @echo update tag table + @ctags inc/*.h src/*.c + +bin: $(OBJ) + @echo + @echo 'creating binary "$(BIN)"' + @$(CC) $(FLAGS) -o $(BIN) $(OBJ) $(LIBS) + @echo '... done' + @echo + +depend: + @echo + @echo 'checking dependencies' + @$(SHELL) -ec '$(CC) $(FLAGS) -MM $(CFLAGS) -I$(INCDIR) -I$(ADDINCDIR) $(SRC) $(ADDSRC) \ + | sed '\''s@\(.*\)\.o[ :]@$(OBJDIR)/\1.o$(SUFFIX):@g'\'' \ + >$(DEPEND)' + @echo + +$(OBJDIR)/%.o$(SUFFIX): $(SRCDIR)/%.c + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +$(OBJDIR)/%.o$(SUFFIX): $(ADDSRCDIR)/%.c + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +$(OBJDIR)/%.o$(SUFFIX): $(FERCSRCDIR)/%.c + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +objdir_mk: + @echo 'Creating $(OBJDIR) ...' + @mkdir -p $(OBJDIR) + +-include $(DEPEND) + diff --git a/ldecod/decoder_default_config.cfg b/ldecod/decoder_default_config.cfg new file mode 100644 index 0000000..9a6d328 --- /dev/null +++ b/ldecod/decoder_default_config.cfg @@ -0,0 +1,86 @@ +# This is a file containing input parameters to the JVT H.264/AVC decoder. +# The text line following each parameter is discarded by the decoder. +# +# For bug reporting and known issues see: +# https://ipbt.hhi.fraunhofer.de +# +# New Input File Format is as follows +# = # Comment +# +########################################################################################## +# Files +########################################################################################## +InputFile = "BookArrival_V2_QP28.264" # H.264/AVC coded bitstream +OutputFile = "BookArrival.yuv" # Output file, YUV/RGB +RefFile = "..\_References_Inv\BookArrival.yuv" # Ref sequence (for SNR) + +FrameSkip = 0 +#StatsFile = "ola.csv" +WriteUV = 1 # Write 4:2:0 chroma components for monochrome streams +FileFormat = 0 # NAL mode (0=Annex B, 1: RTP packets) +RefOffset = 0 # SNR computation offset +POCScale = 2 # Poc Scale (1 or 2) +########################################################################################## +# HRD parameters +########################################################################################## +#R_decoder = 500000 # Rate_Decoder +#B_decoder = 104000 # B_decoder +#F_decoder = 73000 # F_decoder +#LeakyBucketParamFile = "leakybucketparam.cfg" # LeakyBucket Params +########################################################################################## +# decoder control parameters +########################################################################################## +DisplayDecParams = 1 # 1: Display parameters; +POCGap = 2 # POC gap (2: IPP /IbP/IpP (Default), 4: IPP with frame skip = 1 etc.) +IDRPeriod = 20 # IDR Period +Silent = 0 # Silent decode +IntraProfileDeblocking = 1 # Enable Deblocking filter in intra only profiles (0=disable, 1=filter according to SPS parameters) +DecFrmNum = 41 # Number of frames to be decoded (-n) +########################################################################################## +# Frame Loss Concealment Parameters +########################################################################################## +# None - 0 +# Frame Copy - FF: 1, BC: 2 +# Motion Copy - Temporal: 3, Spatial: 4, Both motion vectors: 5 +# SMART - MVE: 11, BASE_MC: 12, COMB/BASE_MC first: 13, INTERCOPY: 14, SAD_BASED: 15 +# DFDP - 21 +# ISMID - 22 +ConcealMode = 15 # Err Concealment +RefPOCGap = 4 # Reference POC gap (2: IPP (Default), 4: IbP / IpP) +MotionVectorCandidates = 2 +DisparityMethod = 0 # 0:Load, 1:VAR, 2:BM +DisparityWindow = 3 # Disparity search window corresponds to a 256/DisparityWindow +DispLoadFileName = "DisparityBookArrival.bmp" +DisparityProjection = 1 +Disparity4x4BlockSize = 4 +MVConcealmentMode = 3 # Conceal motion vector in the proposed mode + # 0: ZeroMV + # 1: Previous Vector + # 2: Average + # 3: Median +# Modification in frame next to a concealed frame +ErrorPropagation = 0 +# SearchMode Brief +# SearchMode = 0: Uses the previous reference pic for concealment of reference frames +# within the same view +# SearchMode = 1: Uses the closest frame to conceal (inc concealed frames) +# SearchMode = 2: Uses the closest frame to conceal (not concealed frames) +SearchModeRef = 2 +SearchModeNonRef = 1 +########################################################################################## +# MVC decoding parameters +########################################################################################## +DecodeAllLayers = 1 # Decode all views (-mpr) +########################################################################################## +# Multi Layer Decoder Parameters +########################################################################################## +DPBPLUS0 = 4 +DPBPLUS1 = 2 +########################################################################################## +# NAL Loss and stream parser Parameters +########################################################################################## +NALUParser = 1 +PredictionParser = 0 +# NAL Loss Patern. Indicate the losted NALU -- EX: 1,4,50 +DropNALU = 22 +#DropNALU = 31,49,64,140,149,176,182,223,291,303 \ No newline at end of file diff --git a/ldecod/inc/annexb.h b/ldecod/inc/annexb.h new file mode 100644 index 0000000..4ab78ce --- /dev/null +++ b/ldecod/inc/annexb.h @@ -0,0 +1,40 @@ + +/*! + ************************************************************************************* + * \file annexb.h + * + * \brief + * Annex B byte stream buffer handling. + * + ************************************************************************************* + */ + +#ifndef _ANNEXB_H_ +#define _ANNEXB_H_ + +#include "nalucommon.h" + +typedef struct annex_b_struct +{ + int BitStreamFile; //!< the bit stream file + byte *iobuffer; + byte *iobufferread; + int bytesinbuffer; + int is_eof; + int iIOBufferSize; + + int IsFirstByteStreamNALU; + int nextstartcodebytes; + byte *Buf; +} ANNEXB_t; + +extern int get_annex_b_NALU (VideoParameters *p_Vid, NALU_t *nalu, ANNEXB_t *annex_b); + +extern void open_annex_b (char *fn, ANNEXB_t *annex_b); +extern void close_annex_b (ANNEXB_t *annex_b); +extern void malloc_annex_b (VideoParameters *p_Vid, ANNEXB_t **p_annex_b); +extern void free_annex_b (ANNEXB_t **p_annex_b); +extern void init_annex_b (ANNEXB_t *annex_b); +extern void reset_annex_b (ANNEXB_t *annex_b); +#endif + diff --git a/ldecod/inc/biaridecod.h b/ldecod/inc/biaridecod.h new file mode 100644 index 0000000..062621b --- /dev/null +++ b/ldecod/inc/biaridecod.h @@ -0,0 +1,133 @@ + +/*! + *************************************************************************** + * \file + * biaridecod.h + * + * \brief + * Headerfile for binary arithmetic decoder routines + * + * \author + * Detlev Marpe, + * Gabi Blättermann + * Copyright (C) 2000 HEINRICH HERTZ INSTITUTE All Rights Reserved. + * + * \date + * 21. Oct 2000 + ************************************************************************** + */ + +#ifndef _BIARIDECOD_H_ +#define _BIARIDECOD_H_ + + +/************************************************************************ + * D e f i n i t i o n s + *********************************************************************** + */ + +/* Range table for LPS */ +static const byte rLPS_table_64x4[64][4]= +{ + { 128, 176, 208, 240}, + { 128, 167, 197, 227}, + { 128, 158, 187, 216}, + { 123, 150, 178, 205}, + { 116, 142, 169, 195}, + { 111, 135, 160, 185}, + { 105, 128, 152, 175}, + { 100, 122, 144, 166}, + { 95, 116, 137, 158}, + { 90, 110, 130, 150}, + { 85, 104, 123, 142}, + { 81, 99, 117, 135}, + { 77, 94, 111, 128}, + { 73, 89, 105, 122}, + { 69, 85, 100, 116}, + { 66, 80, 95, 110}, + { 62, 76, 90, 104}, + { 59, 72, 86, 99}, + { 56, 69, 81, 94}, + { 53, 65, 77, 89}, + { 51, 62, 73, 85}, + { 48, 59, 69, 80}, + { 46, 56, 66, 76}, + { 43, 53, 63, 72}, + { 41, 50, 59, 69}, + { 39, 48, 56, 65}, + { 37, 45, 54, 62}, + { 35, 43, 51, 59}, + { 33, 41, 48, 56}, + { 32, 39, 46, 53}, + { 30, 37, 43, 50}, + { 29, 35, 41, 48}, + { 27, 33, 39, 45}, + { 26, 31, 37, 43}, + { 24, 30, 35, 41}, + { 23, 28, 33, 39}, + { 22, 27, 32, 37}, + { 21, 26, 30, 35}, + { 20, 24, 29, 33}, + { 19, 23, 27, 31}, + { 18, 22, 26, 30}, + { 17, 21, 25, 28}, + { 16, 20, 23, 27}, + { 15, 19, 22, 25}, + { 14, 18, 21, 24}, + { 14, 17, 20, 23}, + { 13, 16, 19, 22}, + { 12, 15, 18, 21}, + { 12, 14, 17, 20}, + { 11, 14, 16, 19}, + { 11, 13, 15, 18}, + { 10, 12, 15, 17}, + { 10, 12, 14, 16}, + { 9, 11, 13, 15}, + { 9, 11, 12, 14}, + { 8, 10, 12, 14}, + { 8, 9, 11, 13}, + { 7, 9, 11, 12}, + { 7, 9, 10, 12}, + { 7, 8, 10, 11}, + { 6, 8, 9, 11}, + { 6, 7, 9, 10}, + { 6, 7, 8, 9}, + { 2, 2, 2, 2} +}; + + +static const byte AC_next_state_MPS_64[64] = +{ + 1,2,3,4,5,6,7,8,9,10, + 11,12,13,14,15,16,17,18,19,20, + 21,22,23,24,25,26,27,28,29,30, + 31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50, + 51,52,53,54,55,56,57,58,59,60, + 61,62,62,63 +}; + + +static const byte AC_next_state_LPS_64[64] = +{ + 0, 0, 1, 2, 2, 4, 4, 5, 6, 7, + 8, 9, 9,11,11,12,13,13,15,15, + 16,16,18,18,19,19,21,21,22,22, + 23,24,24,25,26,26,27,27,28,29, + 29,30,30,30,31,32,32,33,33,33, + 34,34,35,35,35,36,36,36,37,37, + 37,38,38,63 +}; + +static const byte renorm_table_32[32]={6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + + +extern void arideco_start_decoding(DecodingEnvironmentPtr eep, unsigned char *code_buffer, int firstbyte, int *code_len); +extern int arideco_bits_read(DecodingEnvironmentPtr dep); +extern void arideco_done_decoding(DecodingEnvironmentPtr dep); +extern void biari_init_context (int qp, BiContextTypePtr ctx, const char* ini); +extern unsigned int biari_decode_symbol(DecodingEnvironment *dep, BiContextType *bi_ct ); +extern unsigned int biari_decode_symbol_eq_prob(DecodingEnvironmentPtr dep); +extern unsigned int biari_decode_final(DecodingEnvironmentPtr dep); +#endif // BIARIDECOD_H_ + diff --git a/ldecod/inc/block.h b/ldecod/inc/block.h new file mode 100644 index 0000000..3ca0865 --- /dev/null +++ b/ldecod/inc/block.h @@ -0,0 +1,127 @@ + +/*! + ************************************************************************ + * \file block.h + * + * \brief + * definitions for block decoding functions + * + * \author + * Inge Lille-Langoy \n + * Telenor Satellite Services \n + * P.O.Box 6914 St.Olavs plass \n + * N-0130 Oslo, Norway + * + ************************************************************************ + */ + +#ifndef _BLOCK_H_ +#define _BLOCK_H_ + +#include "global.h" +#include "transform8x8.h" + +static const byte QP_SCALE_CR[52]= +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, + 12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, + 28,29,29,30,31,32,32,33,34,34,35,35,36,36,37,37, + 37,38,38,38,39,39,39,39 + +}; + +//! look up tables for FRExt_chroma support +static const unsigned char subblk_offset_x[3][8][4] = +{ + { + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12} + } +}; + + +static const unsigned char subblk_offset_y[3][8][4] = +{ + { + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {8, 8,12,12}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {8, 8,12,12}, + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {8, 8,12,12} + } +}; + +static const byte decode_block_scan[16] = {0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15}; + +extern void iMBtrans4x4(Macroblock *currMB, ColorPlane pl, int smb); +extern void iMBtrans8x8(Macroblock *currMB, ColorPlane pl); + +extern void itrans_sp_cr(Macroblock *currMB, int uv); + +extern void Inv_Residual_trans_4x4(Macroblock *currMB, ColorPlane pl, int ioff, int joff); +extern void Inv_Residual_trans_8x8(Macroblock *currMB, ColorPlane pl, int ioff,int joff); +extern void Inv_Residual_trans_16x16 (Macroblock *currMB, ColorPlane pl); +extern void Inv_Residual_trans_Chroma(Macroblock *currMB, int uv); + +extern void itrans4x4 (Macroblock *currMB, ColorPlane pl, int ioff, int joff); +extern void itrans4x4_ls(Macroblock *currMB, ColorPlane pl, int ioff, int joff); +extern void itrans_sp (Macroblock *currMB, ColorPlane pl, int ioff, int joff); +extern void itrans_2 (Macroblock *currMB, ColorPlane pl); +extern void iTransform (Macroblock *currMB, ColorPlane pl, int smb); + +extern void copy_image_data (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2, int width, int height); +extern void copy_image_data_16x16 (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2); +extern void copy_image_data_8x8 (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2); +extern void copy_image_data_4x4 (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2); +extern int CheckVertMV(Macroblock *currMB, int vec1_y, int block_size_y); +#endif + diff --git a/ldecod/inc/cabac.h b/ldecod/inc/cabac.h new file mode 100644 index 0000000..c83f391 --- /dev/null +++ b/ldecod/inc/cabac.h @@ -0,0 +1,63 @@ + +/*! + *************************************************************************** + * \file + * cabac.h + * + * \brief + * Header file for entropy coding routines + * + * \author + * Detlev Marpe \n + * Copyright (C) 2000 HEINRICH HERTZ INSTITUTE All Rights Reserved. + * + * \date + * 21. Oct 2000 (Changes by Tobias Oelbaum 28.08.2001) + *************************************************************************** + */ + +#ifndef _CABAC_H_ +#define _CABAC_H_ + +#include "global.h" + +extern MotionInfoContexts* create_contexts_MotionInfo(void); +extern TextureInfoContexts* create_contexts_TextureInfo(void); +extern void delete_contexts_MotionInfo(MotionInfoContexts *enco_ctx); +extern void delete_contexts_TextureInfo(TextureInfoContexts *enco_ctx); + +extern void cabac_new_slice(Slice *currSlice); + +extern void readMB_typeInfo_CABAC_i_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readMB_typeInfo_CABAC_p_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readMB_typeInfo_CABAC_b_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readB8_typeInfo_CABAC_p_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readB8_typeInfo_CABAC_b_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readIntraPredMode_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readRefFrame_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void read_MVD_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void read_mvd_CABAC_mbaff (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void read_CBP_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readRunLevel_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void read_dQuant_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readCIPredMode_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void read_skip_flag_CABAC_p_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void read_skip_flag_CABAC_b_slice (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readFieldModeInfo_CABAC (Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); +extern void readMB_transform_size_flag_CABAC(Macroblock *currMB, SyntaxElement *se, DecodingEnvironmentPtr dep_dp); + +extern void readIPCM_CABAC(Slice *currSlice, struct datapartition_dec *dP); + +extern int cabac_startcode_follows(Slice *currSlice, int eos_bit); + +extern int readSyntaxElement_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *this_dataPart); + +extern int check_next_mb_and_get_field_mode_CABAC_p_slice( Slice *currSlice, SyntaxElement *se, DataPartition *act_dp); +extern int check_next_mb_and_get_field_mode_CABAC_b_slice( Slice *currSlice, SyntaxElement *se, DataPartition *act_dp); + +extern void CheckAvailabilityOfNeighborsCABAC(Macroblock *currMB); + +extern void set_read_and_store_CBP(Macroblock **currMB, int chroma_format_idc); + +#endif // _CABAC_H_ + diff --git a/ldecod/inc/configfile.h b/ldecod/inc/configfile.h new file mode 100644 index 0000000..a0604f9 --- /dev/null +++ b/ldecod/inc/configfile.h @@ -0,0 +1,107 @@ + +/*! + *********************************************************************** + * \file + * configfile.h + * \brief + * Prototypes for configfile.c and definitions of used structures. + *********************************************************************** + */ + +#ifndef _CONFIGFILE_H_ +#define _CONFIGFILE_H_ + +#define DEFAULTCONFIGFILENAME "decoder.cfg" + +#include "config_common.h" +//#define PROFILE_IDC 88 +//#define LEVEL_IDC 21 + + +InputParameters cfgparams; + +#ifdef INCLUDED_BY_CONFIGFILE_C +// Mapping_Map Syntax: +// {NAMEinConfigFile, &cfgparams.VariableName, Type, InitialValue, LimitType, MinLimit, MaxLimit, CharSize} +// Types : {0:int, 1:text, 2: double} +// LimitType: {0:none, 1:both, 2:minimum, 3: QP based} +// We could separate this based on types to make it more flexible and allow also defaults for text types. +Mapping Map[] = { + {"InputFile", &cfgparams.infile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"OutputFile", &cfgparams.outfile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"RefFile", &cfgparams.reffile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"WriteUV", &cfgparams.write_uv, 0, 1.0, 1, 0.0, 1.0, }, + {"FileFormat", &cfgparams.FileFormat, 0, 0.0, 1, 0.0, 1.0, }, + {"RefOffset", &cfgparams.ref_offset, 0, 0.0, 1, 0.0, 256.0, }, + {"POCScale", &cfgparams.poc_scale, 0, 2.0, 1, 1.0, 10.0, }, +#ifdef _LEAKYBUCKET_ + {"R_decoder", &cfgparams.R_decoder, 0, 500000.0, 2, 0.0, 0.0, }, + {"B_decoder", &cfgparams.B_decoder, 0, 104000.0, 2, 0.0, 0.0, }, + {"F_decoder", &cfgparams.F_decoder, 0, 73000.0, 2, 0.0, 0.0, }, + {"LeakyBucketParamFile", &cfgparams.LeakyBucketParamFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, +#endif + {"DisplayDecParams", &cfgparams.bDisplayDecParams, 0, 1.0, 1, 0.0, 1.0, }, + + + {"RefPOCGap", &cfgparams.ref_poc_gap, 0, 2.0, 1, 0.0, 4.0, }, + {"POCGap", &cfgparams.poc_gap, 0, 2.0, 1, 0.0, 4.0, }, + {"Silent", &cfgparams.silent, 0, 0.0, 1, 0.0, 1.0, }, + {"IntraProfileDeblocking", &cfgparams.intra_profile_deblocking, 0, 1.0, 1, 0.0, 1.0, }, + {"DecFrmNum", &cfgparams.iDecFrmNum, 0, 0.0, 2, 0.0, 0.0, }, +#if (MVC_EXTENSION_ENABLE) + {"DecodeAllLayers", &cfgparams.DecodeAllLayers, 0, 0.0, 1, 0.0, 1.0, }, +#endif + {"DPBPLUS0", &cfgparams.dpb_plus[0], 0, 2.0, 1, -16.0, 16.0, }, + {"DPBPLUS1", &cfgparams.dpb_plus[1], 0, 0.0, 1, -16.0, 16.0, }, + + //Error Concealment + {"ConcealMode", &cfgparams.conceal_mode, 0, 0.0, 1, 0.0, 22.0, }, + + + + // {NAMEinConfigFile, &cfgparams.VariableName, Type, InitialValue, LimitType, MinLimit, MaxLimit, CharSize} + + //! Following parameters were edited by Joao Carreira + //! Parser + {"FrameSkip", &cfgparams.FrameSkip, 0, 0.0, 0, 0.0, 0.0, }, + {"IDRPeriod", &cfgparams.IDR_Period, 0, 0.0, 0, 0.0, 0.0, }, + {"GOPSize", &cfgparams.GOP_Size, 0, 0.0, 0, 0.0, 0.0, }, + {"SearchModeRef", &cfgparams.search_mode_ref, 0, 1.0, 1, 0.0, 4.0, }, + {"SearchModeNonRef", &cfgparams.search_mode_nonref, 0, 1.0, 1, 0.0, 4.0, }, + {"ErrorPropagation", &cfgparams.error_prop, 0, 0.0, 1, 0.0, 1.0, }, + {"DropNALU", &cfgparams.drop_nalu, 1, 0.0, 0, 0.0, 0.0, MAX_LOST_NALU, }, + //! Stats + {"StatsFile", &cfgparams.statsfile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + + {"DisparityMethod", &cfgparams.DisparityMethod, 0, 0.0, 1, 0.0, 4.0, }, + {"DisparityDirection", &cfgparams.DisparityDirection, 0, 0.0, 1, -1.0, 1.0, }, + {"DisparityReference", &cfgparams.DisparityReference, 0, 0.0, 1, 0.0, 1.0, }, + {"DisparityWindow", &cfgparams.DisparityWindow, 0, 1.0, 1, 1.0, 16.0, }, + {"DisparityProjection", &cfgparams.DisparityProjection, 0, 0.0, 1, 0.0, 2.0, }, + {"DispLoadFileName", &cfgparams.DispLoadFileName, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"Disparity4x4BlockSize", &cfgparams.Disparity4x4BlockSize, 0, 4.0, 1, 4.0, 256.0, }, + {"MotionVectorCandidates", &cfgparams.MotionVectorCandidates, 0, 0.0, 1, 0.0, 5, }, + {"MVConcealmentMode", &cfgparams.MVConcealmentMode, 0, 0.0, 1, 0.0, 4, }, + {"TemporalThreshold", &cfgparams.TemporalThreshold, 0, 0.0, 1, 0.0, 100, }, + {"SpatialThreshold", &cfgparams.SpatialThreshold, 0, 0.0, 1, 0.0, 100, }, + + //! NAL unit Parser parameters + {"NALUParser", &cfgparams.dump_nalu, 0, 0.0, 1, 0.0, 1.0, }, + {"PredictionParser", &cfgparams.PredictionParser, 0, 0.0, 1, 0.0, 1.0, }, + + //! Transcode parameters + {"TranscodeFile", &cfgparams.TranscodeFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + + {NULL, NULL, -1, 0.0, 0, 0.0, 0.0, }, + +}; +#endif + +#ifndef INCLUDED_BY_CONFIGFILE_C +extern Mapping Map[]; +#endif +extern void JMDecHelpExit (); +extern void ParseCommand(InputParameters *p_Inp, int ac, char *av[]); + +#endif + diff --git a/ldecod/inc/context_ini.h b/ldecod/inc/context_ini.h new file mode 100644 index 0000000..d56be25 --- /dev/null +++ b/ldecod/inc/context_ini.h @@ -0,0 +1,23 @@ + +/*! + ************************************************************************************* + * \file context_ini.h + * + * \brief + * CABAC context initializations + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Heiko Schwarz + ************************************************************************************** + */ + + +#ifndef _CONTEXT_INI_ +#define _CONTEXT_INI_ + +extern void init_contexts (Slice *currslice); + +#endif + diff --git a/ldecod/inc/contributors.h b/ldecod/inc/contributors.h new file mode 100644 index 0000000..3822e34 --- /dev/null +++ b/ldecod/inc/contributors.h @@ -0,0 +1,232 @@ + +/*! \file + * contributors.h + * \brief + * List of contributors and copyright information. + * + * \par Copyright statements + \verbatim + H.264 JM coder/decoder + + Copyright (C) 2000 by + Telenor Satellite Services, Norway + Ericsson Radio Systems, Sweden + TELES AG, Germany + Nokia Inc., USA + Nokia Corporation, Finland + Siemens AG, Germany + Fraunhofer-Institute for Telecommunications Heinrich-Hertz-Institut (HHI), Germany + University of Hannover, Institut of Communication Theory and Signal Processing, Germany + TICSP, Tampere University of Technology, Finland + Munich University of Technology, Institute for Communications Engineering, Germany + Videolocus, Canada + Motorola Inc., USA + Microsoft Corp., USA + Apple Computer, Inc. + RealNetworks, Inc., USA + Thomson, Inc., USA + Sejong Univ., Digital Media System Lab., Korea + \endverbatim + \par Full Contact Information + \verbatim + + Lowell Winger + Guy Côté + Michael Gallant + VideoLocus Inc. + 97 Randall Dr. + Waterloo, ON, Canada N2V1C5 + + Inge Lille-Langøy + Telenor Satellite Services + P.O.Box 6914 St.Olavs plass + N-0130 Oslo, Norway + + Rickard Sjoberg + Ericsson Radio Systems + KI/ERA/T/VV + 164 80 Stockholm, Sweden + + Stephan Wenger + TU Berlin / TELES AG + Sekr. FR 6-3 + Franklinstr. 28-29 + D-10587 Berlin, Germany + + Jani Lainema + Nokia Inc. / Nokia Research Center + 6000 Connection Drive + Irving, TX 75039, USA + + Sebastian Purreiter + Siemens AG + ICM MD MP RD MCH 83 + P.O.Box 80 17 07 + D-81617 Munich, Germany + + Thomas Wedi + University of Hannover + Institut of Communication Theory and Signal Processing + Appelstr. 9a + 30167 Hannover, Germany + + Guido Heising + Fraunhofer-Institute for Telecommunications + Heinrich-Hertz-Institut (HHI) + Einsteinufer 37 + 10587 Berlin + Germany + + Gabi Blaettermann + Fraunhofer-Institute for Telecommunications + Heinrich-Hertz-Institut (HHI) + Einsteinufer 37 + 10587 Berlin + Germany + + Detlev Marpe + Fraunhofer-Institute for Telecommunications + Heinrich-Hertz-Institut (HHI) + Einsteinufer 37 + 10587 Berlin + Germany + + Ragip Kurceren + Nokia Inc. / Nokia Research Center + 6000 Connection Drive + Irving, TX 75039, USA + + Viktor Varsa + Nokia Inc. / Nokia Research Center + 6000 Connection Drive + Irving, TX 75039, USA + + Ye-Kui Wang + Tampere University of Technology + Tampere International Center for Signal Processing + 33720 Tampere, Finland + + Ari Hourunranta + Nokia Corporation / Nokia Mobile Phones + P.O. Box 88 + 33721 Tampere, Finland + + Yann Le Maguet + Philips Research France + + Dong Tian + Tampere University of Technology + Tampere International Center for Signal Processing + 33720 Tampere, Finland + + Miska M. Hannuksela + Nokia Corporation / Nokia Mobile Phones + P.O. Box 88 + 33721 Tampere, Finland + + Karsten Suehring + Fraunhofer-Institute for Telecommunications + Heinrich-Hertz-Institut (HHI) + Einsteinufer 37 + 10587 Berlin + Germany + + Heiko Schwarz + Fraunhofer-Institute for Telecommunications + Heinrich-Hertz-Institut (HHI) + Einsteinufer 37 + 10587 Berlin + Germany + + Tobias Oelbaum + Institute for Communications Engineering + Munich University of Technology + Germany + + Limin Wang + Krit Panusopone + Rajeev Gandhi + Yue Yu + Motorola Inc. + 6450 Sequence Drive + San Diego, CA 92121 USA + + Feng Wu + Xiaoyan Sun + Microsoft Research Asia + 3/F, Beijing Sigma Center + No.49, Zhichun Road, Hai Dian District, + Beijing China 100080 + + Yoshihiro Kikuchi + Takeshi Chujoh + Toshiba Corporation + Research and Development Center + Kawasaki 212-8582, Japan + + Shinya Kadono + Matsushita Electric Industrial Co., Ltd. + 1006 Kadoma, Kadoma + Osaka 663-8113, Japan + + Dzung Hoang + 10533 Roy Butler Dr. + Austin, TX 78717 + + Eric Viscito + eV Consulting + 52 Tracy Ln + Shelburne, VT 05482 USA + + Barry Haskell + Apple Computer, Inc. + 2 Infinite Loop + Cupertino, California 95014 + + Greg Conklin + RealNetworks, Inc. + 2601 Elliott Ave + Seattle, WA 98101 + + Jill Boyce + Cristina Gomila + Thomson + 2 Independence Way + Princeton, NJ 08540 + + Alexis Michael Tourapis + Athanasios Leontaris + Chris Vogt + Peshala Pahalawatta + Yan Ye + Yuwen He + Dolby Laboratories Inc. + 3601 West Alameda Ave. + Burbank, CA 91505 + + Saurav K Bandyopadhyay + Purvin Pandit + Zhenyu Wu + Thomson Inc. + 2 Independence Way + Princeton, NJ 08540 + + Shun-ichi Sekiguchi + Information Technology R&D Center, + Mitsubishi Electric Corporation + 5-1-1, Ofuna, Kamakura, Japan + + Yung-Lyul Lee + Ki-Hun Han + Department of Computer Engineering, + Sejong University + 98 Kunja-Dong, Kwangjin-Gu, Seoul 143-747, Korea + + Jianhua Wu + Panasonic Singapore Laboratories Pte Ltd + Blk 1022 Tai Seng Ave #06-3530 Tai Seng Ind Est + Singapore 534415 + + \endverbatim +*/ + diff --git a/ldecod/inc/dec_statistics.h b/ldecod/inc/dec_statistics.h new file mode 100644 index 0000000..08ed871 --- /dev/null +++ b/ldecod/inc/dec_statistics.h @@ -0,0 +1,33 @@ +/*! + ************************************************************************** + * \file dec_statistics.h + * + * \brief + * Various decoding statistics + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Tourapis + * + ************************************************************************** + */ + +#ifndef _DEC_STATISTICS_H_ +#define _DEC_STATISTICS_H_ +#include "global.h" + +typedef struct dec_stat_parameters +{ + int frame_ctr [NUM_SLICE_TYPES]; //!< Counter for different frame coding types (assumes one slice type per frame) + int64 mode_use [NUM_SLICE_TYPES][MAXMODE]; //!< Macroblock mode usage per slice + int64 mode_use_transform [NUM_SLICE_TYPES][MAXMODE][2]; + + int64 *histogram_mv [2][2]; //!< mv histogram (per list and per direction) + int64 *histogram_refs[2]; //!< reference histogram (per list) +} DecStatParameters; + +extern void init_dec_stats (DecStatParameters *stats); +extern void delete_dec_stats(DecStatParameters *stats); + + +#endif diff --git a/ldecod/inc/defines.h b/ldecod/inc/defines.h new file mode 100644 index 0000000..f1cfb96 --- /dev/null +++ b/ldecod/inc/defines.h @@ -0,0 +1,310 @@ + +/*! + ************************************************************************** + * \file defines.h + * + * \brief + * Header file containing some useful global definitions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Karsten Suehring + * - Alexis Michael Tourapis + * + * + * \date + * 21. March 2001 + ************************************************************************** + */ + +#ifndef _DEFINES_H_ +#define _DEFINES_H_ +#ifdef TRACE +#undef TRACE +#endif +#if defined _DEBUG +# define TRACE 0 //!< 0:Trace off 1:Trace on 2:detailed CABAC context information +#else +# define TRACE 0 //!< 0:Trace off 1:Trace on 2:detailed CABAC context information +#endif + +#define JM "18 JC (FRExt)" +#define VERSION "18.2" +#define EXT_VERSION "(FRExt)" + +//! Edited by Joao Carreira +#define PRINTREFLIST_JC 0 //!< Print ref list info for debug purposes +#define FOUND_NALU 0 //!< printf Founded NAL Unit +#define PRINT_OUTPUT_DPB_POC 0 //!< Print outputed frames for debug purposes +#define DISPLAY_OUTPUTED_FRAMES 0 +#define ENABLE_PARSER 0 //!< Use Parser functions +//#define HAVE_OPENCV 0 + +//#ifndef _DEBUG +//#define _DEBUG 1 +//#endif + +//! Edited by Joao Carreira +#if( ENABLE_PARSER == 1 ) +#define PRINTREFLIST_JC 1 //!< Print ref list info for debug purposes +#define FOUND_NALU 1 //!< printf Founded NAL Unit +#define PRINT_OUTPUT_DPB_POC 1 //!< Print outputed frames for debug purposes +#define DUMP_DPB 1 //!< Dump DPB info for debug purposes +#endif + +//#define DISABLE_MB_DECODING //! disable MB deconding. Software work as a stream parser + +#if ( _RELEASE ) +#define LOG_LEVEL 0 //!< Status report only +#else +#define LOG_LEVEL 2 //!< Debug porpose +#endif + +//#define USE_STDOUT_STDERR 1 + +//#define printf printf + +#define DUMP_DPB 0 //!< Dump DPB info for debug purposes +#define PRINTREFLIST 0 //!< Print ref list info for debug purposes +#define PAIR_FIELDS_IN_OUTPUT 0 //!< Pair field pictures for output purposes +#define IMGTYPE 0 //!< Define imgpel size type. 0 implies byte (cannot handle >8 bit depths) and 1 implies unsigned short +#define ENABLE_FIELD_CTX 1 //!< Enables Field mode related context types for CABAC +#define ENABLE_HIGH444_CTX 1 //!< Enables High 444 profile context types for CABAC. +#define ZEROSNR 0 //!< PSNR computation method +#define ENABLE_OUTPUT_TONEMAPPING 1 //!< enable tone map the output if tone mapping SEI present +#define JCOST_CALC_SCALEUP 1 //!< 1: J = (D<>LAMBDA_ACCURACY_BITS) +#define DISABLE_ERC 1 //!< Disable any error concealment processes +#define JM_PARALLEL_DEBLOCK 0 //!< Enables Parallel Deblocking +#define SIMULCAST_ENABLE 0 //!< to test the decoder + +#define MVC_EXTENSION_ENABLE 1 //!< enable support for the Multiview High Profile +#define ENABLE_DEC_STATS 0 //!< enable decoder statistics collection + +#define MVC_INIT_VIEW_ID -1 +#define MAX_VIEW_NUM 5 +#define BASE_VIEW_IDX 0 + +#include "typedefs.h" + +#define SSE_MEMORY_ALIGNMENT 16 + +#define MAX_NUM_SLICES 500 +#define MAX_REFERENCE_PICTURES 32 //!< H.264 allows 32 fields +#define MAX_CODED_FRAME_SIZE 8000000 //!< bytes for one frame +#define MAX_NUM_DECSLICES 150 +#define MAX_DEC_THREADS 16 //16 core deocoding; +#define MCBUF_LUMA_PAD_X 32 +#define MCBUF_LUMA_PAD_Y 12 +#define MCBUF_CHROMA_PAD_X 16 +#define MCBUF_CHROMA_PAD_Y 8 +#define MAX_NUM_DPB_LAYERS MAX_VIEW_NUM + +//AVC Profile IDC definitions +typedef enum { + FREXT_CAVLC444 = 44, //!< YUV 4:4:4/14 "CAVLC 4:4:4" + BASELINE = 66, //!< YUV 4:2:0/8 "Baseline" + MAIN = 77, //!< YUV 4:2:0/8 "Main" + EXTENDED = 88, //!< YUV 4:2:0/8 "Extended" + FREXT_HP = 100, //!< YUV 4:2:0/8 "High" + FREXT_Hi10P = 110, //!< YUV 4:2:0/10 "High 10" + FREXT_Hi422 = 122, //!< YUV 4:2:2/10 "High 4:2:2" + FREXT_Hi444 = 244, //!< YUV 4:4:4/14 "High 4:4:4" + MVC_HIGH = 118, //!< YUV 4:2:0/8 "Multiview High" + STEREO_HIGH = 128 //!< YUV 4:2:0/8 "Stereo High" +} ProfileIDC; + +/* Edited by Joao Carreira */ +#define MAX_LOST_NALU 200 + +#define FILE_NAME_SIZE 255 +#define INPUT_TEXT_SIZE 1024 + + +#if (ENABLE_HIGH444_CTX == 1) +# define NUM_BLOCK_TYPES 22 +#else +# define NUM_BLOCK_TYPES 10 +#endif + + +//#define _LEAKYBUCKET_ + +#define BLOCK_SHIFT 2 +#define BLOCK_SIZE 4 +#define BLOCK_SIZE_8x8 8 +#define SMB_BLOCK_SIZE 8 +#define BLOCK_PIXELS 16 +#define MB_BLOCK_SIZE 16 +#define MB_PIXELS 256 // MB_BLOCK_SIZE * MB_BLOCK_SIZE +#define MB_PIXELS_SHIFT 8 // log2(MB_BLOCK_SIZE * MB_BLOCK_SIZE) +#define MB_BLOCK_SHIFT 4 +#define BLOCK_MULTIPLE 4 // (MB_BLOCK_SIZE/BLOCK_SIZE) +#define MB_BLOCK_PARTITIONS 16 // (BLOCK_MULTIPLE * BLOCK_MULTIPLE) +#define BLOCK_CONTEXT 64 // (4 * MB_BLOCK_PARTITIONS) + +// These variables relate to the subpel accuracy supported by the software (1/4) +#define BLOCK_SIZE_SP 16 // BLOCK_SIZE << 2 +#define BLOCK_SIZE_8x8_SP 32 // BLOCK_SIZE8x8 << 2 + +// Available MB modes +typedef enum { + PSKIP = 0, + BSKIP_DIRECT = 0, + P16x16 = 1, + P16x8 = 2, + P8x16 = 3, + SMB8x8 = 4, + SMB8x4 = 5, + SMB4x8 = 6, + SMB4x4 = 7, + P8x8 = 8, + I4MB = 9, + I16MB = 10, + IBLOCK = 11, + SI4MB = 12, + I8MB = 13, + IPCM = 14, + MAXMODE = 15 +} MBModeTypes; + +// number of intra prediction modes +#define NO_INTRA_PMODE 9 + +// Direct Mode types +typedef enum { + DIR_TEMPORAL = 0, //!< Temporal Direct Mode + DIR_SPATIAL = 1 //!< Spatial Direct Mode +} DirectModes; + +// CAVLC block types +typedef enum { + LUMA = 0, + LUMA_INTRA16x16DC = 1, + LUMA_INTRA16x16AC = 2, + CB = 3, + CB_INTRA16x16DC = 4, + CB_INTRA16x16AC = 5, + CR = 8, + CR_INTRA16x16DC = 9, + CR_INTRA16x16AC = 10 +} CAVLCBlockTypes; + +// CABAC block types +typedef enum { + LUMA_16DC = 0, + LUMA_16AC = 1, + LUMA_8x8 = 2, + LUMA_8x4 = 3, + LUMA_4x8 = 4, + LUMA_4x4 = 5, + CHROMA_DC = 6, + CHROMA_AC = 7, + CHROMA_DC_2x4 = 8, + CHROMA_DC_4x4 = 9, + CB_16DC = 10, + CB_16AC = 11, + CB_8x8 = 12, + CB_8x4 = 13, + CB_4x8 = 14, + CB_4x4 = 15, + CR_16DC = 16, + CR_16AC = 17, + CR_8x8 = 18, + CR_8x4 = 19, + CR_4x8 = 20, + CR_4x4 = 21 +} CABACBlockTypes; + +// Macro defines +#define Q_BITS 15 +#define DQ_BITS 6 +#define Q_BITS_8 16 +#define DQ_BITS_8 6 + + +#define IS_I16MB(MB) ((MB)->mb_type==I16MB || (MB)->mb_type==IPCM) +#define IS_DIRECT(MB) ((MB)->mb_type==0 && (currSlice->slice_type == B_SLICE )) + +#define TOTRUN_NUM 15 +#define RUNBEFORE_NUM 7 +#define RUNBEFORE_NUM_M1 6 + +// Quantization parameter range +#define MIN_QP 0 +#define MAX_QP 51 +// 4x4 intra prediction modes +typedef enum { + VERT_PRED = 0, + HOR_PRED = 1, + DC_PRED = 2, + DIAG_DOWN_LEFT_PRED = 3, + DIAG_DOWN_RIGHT_PRED = 4, + VERT_RIGHT_PRED = 5, + HOR_DOWN_PRED = 6, + VERT_LEFT_PRED = 7, + HOR_UP_PRED = 8 +} I4x4PredModes; + +// 16x16 intra prediction modes +typedef enum { + VERT_PRED_16 = 0, + HOR_PRED_16 = 1, + DC_PRED_16 = 2, + PLANE_16 = 3 +} I16x16PredModes; + +// 8x8 chroma intra prediction modes +typedef enum { + DC_PRED_8 = 0, + HOR_PRED_8 = 1, + VERT_PRED_8 = 2, + PLANE_8 = 3 +} I8x8PredModes; + +// Color components +enum { + Y_COMP = 0, // Y Component + U_COMP = 1, // U Component + V_COMP = 2, // V Component + R_COMP = 3, // R Component + G_COMP = 4, // G Component + B_COMP = 5, // B Component + T_COMP = 6 +} ColorComponent; + +enum { + EOS = 1, //!< End Of Sequence + SOP = 2, //!< Start Of Picture + SOS = 3, //!< Start Of Slice + SOS_CONT = 4 +}; + +// MV Prediction types +typedef enum { + MVPRED_MEDIAN = 0, + MVPRED_L = 1, + MVPRED_U = 2, + MVPRED_UR = 3 +} MVPredTypes; + +enum { + DECODING_OK = 0, + SEARCH_SYNC = 1, + PICTURE_DECODED = 2 +}; + +#define LAMBDA_ACCURACY_BITS 16 +#define INVALIDINDEX (-135792468) + +#define RC_MAX_TEMPORAL_LEVELS 5 + +//Start code and Emulation Prevention need this to be defined in identical manner at encoder and decoder +#define ZEROBYTES_SHORTSTARTCODE 2 //indicates the number of zero bytes in the short start-code prefix + +#define MAX_PLANE 3 +#define IS_FREXT_PROFILE(profile_idc) ( profile_idc>=FREXT_HP || profile_idc == FREXT_CAVLC444 ) +#define HI_INTRA_ONLY_PROFILE (((p_Vid->active_sps->profile_idc>=FREXT_Hi10P)&&(p_Vid->active_sps->constrained_set3_flag))||(p_Vid->active_sps->profile_idc==FREXT_CAVLC444)) + +#endif + diff --git a/ldecod/inc/elements.h b/ldecod/inc/elements.h new file mode 100644 index 0000000..f115bff --- /dev/null +++ b/ldecod/inc/elements.h @@ -0,0 +1,112 @@ + +/*! + ************************************************************************************* + * \file elements.h + * + * \brief + * Header file for elements in H.264 streams + * + * \date + * 6.10.2000 + * + * \version + * 1.0 + * + * \author + * Sebastian Purreiter \n + * Siemens AG, Information and Communication Mobile \n + * P.O.Box 80 17 07 \n + * D-81617 Munich, Germany \n + ************************************************************************************* + */ + +#ifndef _ELEMENTS_H_ +#define _ELEMENTS_H_ + +/*! + * definition of H.264 syntax elements + * order of elements follow dependencies for picture reconstruction + */ +/*! + * \brief Assignment of old TYPE partition elements to new + * elements + * + * old element | new elements + * ----------------+------------------------------------------------------------------- + * TYPE_HEADER | SE_HEADER, SE_PTYPE + * TYPE_MBHEADER | SE_MBTYPE, SE_REFFRAME, SE_INTRAPREDMODE + * TYPE_MVD | SE_MVD + * TYPE_CBP | SE_CBP_INTRA, SE_CBP_INTER + * SE_DELTA_QUANT_INTER + * SE_DELTA_QUANT_INTRA + * TYPE_COEFF_Y | SE_LUM_DC_INTRA, SE_LUM_AC_INTRA, SE_LUM_DC_INTER, SE_LUM_AC_INTER + * TYPE_2x2DC | SE_CHR_DC_INTRA, SE_CHR_DC_INTER + * TYPE_COEFF_C | SE_CHR_AC_INTRA, SE_CHR_AC_INTER + * TYPE_EOS | SE_EOS +*/ + +#define SE_HEADER 0 +#define SE_PTYPE 1 +#define SE_MBTYPE 2 +#define SE_REFFRAME 3 +#define SE_INTRAPREDMODE 4 +#define SE_MVD 5 +#define SE_CBP_INTRA 6 +#define SE_LUM_DC_INTRA 7 +#define SE_CHR_DC_INTRA 8 +#define SE_LUM_AC_INTRA 9 +#define SE_CHR_AC_INTRA 10 +#define SE_CBP_INTER 11 +#define SE_LUM_DC_INTER 12 +#define SE_CHR_DC_INTER 13 +#define SE_LUM_AC_INTER 14 +#define SE_CHR_AC_INTER 15 +#define SE_DELTA_QUANT_INTER 16 +#define SE_DELTA_QUANT_INTRA 17 +#define SE_BFRAME 18 +#define SE_EOS 19 +#define SE_MAX_ELEMENTS 20 + + +#define NO_EC 0 //!< no error concealment necessary +#define EC_REQ 1 //!< error concealment required +#define EC_SYNC 2 //!< search and sync on next header element + +#define MAXPARTITIONMODES 2 //!< maximum possible partition modes as defined in assignSE2partition[][] + +/*! + * \brief lookup-table to assign different elements to partition + * + * \note here we defined up to 6 different partitions similar to + * document Q15-k-18 described in the PROGFRAMEMODE. + * The Sliceheader contains the PSYNC information. \par + * + * Elements inside a partition are not ordered. They are + * ordered by occurence in the stream. + * Assumption: Only partitionlosses are considered. \par + * + * The texture elements luminance and chrominance are + * not ordered in the progressive form + * This may be changed in image.c \par + * + * We also defined the proposed internet partition mode + * of Stephan Wenger here. To select the desired mode + * uncomment one of the two following lines. \par + * + * -IMPORTANT: + * Picture- or Sliceheaders must be assigned to partition 0. \par + * Furthermore partitions must follow syntax dependencies as + * outlined in document Q15-J-23. + */ + + +static const byte assignSE2partition[][SE_MAX_ELEMENTS] = +{ + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // element number (do not uncomment) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, //!< all elements in one partition no data partitioning + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 2, 2, 2, 2, 0, 0, 0, 0 } //!< three partitions per slice +}; + + +#endif + diff --git a/ldecod/inc/erc_api.h b/ldecod/inc/erc_api.h new file mode 100644 index 0000000..af91513 --- /dev/null +++ b/ldecod/inc/erc_api.h @@ -0,0 +1,164 @@ + +/*! + ************************************************************************ + * \file erc_api.h + * + * \brief + * External (still inside video decoder) interface for error concealment module + * + * \author + * - Ari Hourunranta + * - Ye-Kui Wang + * - Jill Boyce + * - Saurav K Bandyopadhyay + * - Zhenyu Wu + * + * ************************************************************************ + */ + + +#ifndef _ERC_API_H_ +#define _ERC_API_H_ + +#include "erc_globals.h" + +/* +* Defines +*/ + +/* If the average motion vector of the correctly received macroblocks is less than the +threshold, concealByCopy is used, otherwise concealByTrial is used. */ +#define MVPERMB_THR 8 + +/* used to determine the size of the allocated memory for a temporal Region (MB) */ +#define DEF_REGION_SIZE 384 /* 8*8*6 */ + +#define ERC_BLOCK_OK 3 +#define ERC_BLOCK_CONCEALED 2 +#define ERC_BLOCK_CORRUPTED 1 +#define ERC_BLOCK_EMPTY 0 + + +/* +* Functions to convert MBNum representation to blockNum +*/ + +#define xPosYBlock(currYBlockNum,picSizeX) \ +((currYBlockNum)%((picSizeX)>>3)) + +#define yPosYBlock(currYBlockNum,picSizeX) \ +((currYBlockNum)/((picSizeX)>>3)) + +#define xPosMB(currMBNum,picSizeX) \ +((currMBNum)%((picSizeX)>>4)) + +#define yPosMB(currMBNum,picSizeX) \ +((currMBNum)/((picSizeX)>>4)) + +#define MBxy2YBlock(currXPos,currYPos,comp,picSizeX) \ +((((currYPos)<<1)+((comp)>>1))*((picSizeX)>>3)+((currXPos)<<1)+((comp)&1)) + +#define MBNum2YBlock(currMBNum,comp,picSizeX) \ +MBxy2YBlock(xPosMB((currMBNum),(picSizeX)),yPosMB((currMBNum),(picSizeX)),(comp),(picSizeX)) + + +/* +* typedefs +*/ + +/* segment data structure */ +typedef struct ercSegment_s +{ + short startMBPos; + short endMBPos; + char fCorrupted; +} ercSegment_t; + +/* Error detector & concealment instance data structure */ +typedef struct ercVariables_s +{ + /* Number of macroblocks (size or size/4 of the arrays) */ + int nOfMBs; + /* Number of segments (slices) in frame */ + int nOfSegments; + + /* Array for conditions of Y blocks */ + char *yCondition; + /* Array for conditions of U blocks */ + char *uCondition; + /* Array for conditions of V blocks */ + char *vCondition; + + /* Array for Slice level information */ + ercSegment_t *segments; + int currSegment; + + /* Conditions of the MBs of the previous frame */ + char *prevFrameYCondition; + + /* Flag telling if the current segment was found to be corrupted */ + int currSegmentCorrupted; + /* Counter for corrupted segments per picture */ + int nOfCorruptedSegments; + + /* State variables for error detector and concealer */ + int concealment; + +} ercVariables_t; + +/* +* External function interface +*/ + +void ercWriteMBMODEandMV(Macroblock *currMB); + +void ercInit (VideoParameters *p_Vid, int pic_sizex, int pic_sizey, int flag); +ercVariables_t *ercOpen( void ); +void ercReset( ercVariables_t *errorVar, int nOfMBs, int numOfSegments, int picSizeX ); +void ercClose( VideoParameters *p_Vid, ercVariables_t *errorVar ); +void ercSetErrorConcealment( ercVariables_t *errorVar, int value ); + +void ercStartSegment( int currMBNum, int segment, unsigned int bitPos, ercVariables_t *errorVar ); +void ercStopSegment( int currMBNum, int segment, unsigned int bitPos, ercVariables_t *errorVar ); +void ercMarkCurrSegmentLost(int picSizeX, ercVariables_t *errorVar ); +void ercMarkCurrSegmentOK(int picSizeX, ercVariables_t *errorVar ); +void ercMarkCurrMBConcealed( int currMBNum, int comp, int picSizeX, ercVariables_t *errorVar ); + +int ercConcealIntraFrame( VideoParameters *p_Vid, frame *recfr, int picSizeX, int picSizeY, ercVariables_t *errorVar ); +int ercConcealInterFrame( frame *recfr, objectBuffer_t *object_list, + int picSizeX, int picSizeY, ercVariables_t *errorVar, int chroma_format_idc ); + + + +/* Thomson APIs for concealing entire frame loss */ + +#include "mbuffer.h" +#include "output.h" + +struct concealment_node { + StorablePicture* picture; + int missingpocs; + struct concealment_node *next; +}; + +/** Edited by João Carreira + * Exclued Previous Frame concealment functions +extern struct concealment_node * init_node(StorablePicture* , int ); +extern void print_node( struct concealment_node * ); +extern void print_list( struct concealment_node * ); +extern void init_lists_for_non_reference_loss(DecodedPictureBuffer *p_Dpb, int , PictureStructure ); + +extern void conceal_non_ref_pics(DecodedPictureBuffer *p_Dpb, int diff); +extern void conceal_lost_frames (DecodedPictureBuffer *p_Dpb, Slice *pSlice); + +extern void sliding_window_poc_management(DecodedPictureBuffer *p_Dpb, StorablePicture *p); +extern void write_lost_non_ref_pic (DecodedPictureBuffer *p_Dpb, int poc, int p_out); +extern void write_lost_ref_after_idr (DecodedPictureBuffer *p_Dpb, int pos); +**/ + +extern int comp(const void *, const void *); + + +#endif + diff --git a/ldecod/inc/erc_do.h b/ldecod/inc/erc_do.h new file mode 100644 index 0000000..9b7012f --- /dev/null +++ b/ldecod/inc/erc_do.h @@ -0,0 +1,44 @@ + +/*! + ************************************************************************ + * \file erc_do.h + * + * \brief + * Header for the I & P frame error concealment common functions + * + * \author + * - Viktor Varsa + * - Ye-Kui Wang + * + ************************************************************************ + */ + +#ifndef _ERC_DO_H_ +#define _ERC_DO_H_ + + +#include "erc_api.h" + +void ercPixConcealIMB (VideoParameters *p_Vid, imgpel *currFrame, int row, int column, int predBlocks[], int frameWidth, int mbWidthInBlocks); + +int ercCollect8PredBlocks( int predBlocks[], int currRow, int currColumn, char *condition, + int maxRow, int maxColumn, int step, byte fNoCornerNeigh ); +int ercCollectColumnBlocks( int predBlocks[], int currRow, int currColumn, char *condition, int maxRow, int maxColumn, int step ); + +#define isSplitted(object_list,currMBNum) \ + ((object_list+((currMBNum)<<2))->regionMode >= REGMODE_SPLITTED) + +/* this can be used as isBlock(...,INTRA) or isBlock(...,INTER_COPY) */ +#define isBlock(object_list,currMBNum,comp,regMode) \ + (isSplitted(object_list,currMBNum) ? \ + ((object_list+((currMBNum)<<2)+(comp))->regionMode == REGMODE_##regMode##_8x8) : \ + ((object_list+((currMBNum)<<2))->regionMode == REGMODE_##regMode)) + +/* this can be used as getParam(...,mv) or getParam(...,xMin) or getParam(...,yMin) */ +#define getParam(object_list,currMBNum,comp,param) \ + (isSplitted(object_list,currMBNum) ? \ + ((object_list+((currMBNum)<<2)+(comp))->param) : \ + ((object_list+((currMBNum)<<2))->param)) + +#endif + diff --git a/ldecod/inc/erc_globals.h b/ldecod/inc/erc_globals.h new file mode 100644 index 0000000..2722cd5 --- /dev/null +++ b/ldecod/inc/erc_globals.h @@ -0,0 +1,52 @@ + +/*! + ************************************************************************ + * \file erc_globals.h + * + * \brief + * global header file for error concealment module + * + * \author + * - Viktor Varsa + * - Ye-Kui Wang + ************************************************************************ + */ + +#ifndef _ERC_GLOBALS_H_ +#define _ERC_GLOBALS_H_ + +#include "defines.h" + +/* "block" means an 8x8 pixel area */ + +/* Region modes */ +#define REGMODE_INTER_COPY 0 //!< Copy region +#define REGMODE_INTER_PRED 1 //!< Inter region with motion vectors +#define REGMODE_INTRA 2 //!< Intra region +#define REGMODE_SPLITTED 3 //!< Any region mode higher than this indicates that the region + //!< is splitted which means 8x8 block +#define REGMODE_INTER_COPY_8x8 4 +#define REGMODE_INTER_PRED_8x8 5 +#define REGMODE_INTRA_8x8 6 + +//! YUV pixel domain image arrays for a video frame +typedef struct frame_s +{ + VideoParameters *p_Vid; + imgpel *yptr; + imgpel *uptr; + imgpel *vptr; +} frame; + +//! region structure stores information about a region that is needed for concealment +typedef struct object_buffer +{ + byte regionMode; //!< region mode as above + int xMin; //!< X coordinate of the pixel position of the top-left corner of the region + int yMin; //!< Y coordinate of the pixel position of the top-left corner of the region + int mv[3]; //!< motion vectors in 1/4 pixel units: mvx = mv[0], mvy = mv[1], + //!< and ref_frame = mv[2] +} objectBuffer_t; + +#endif + diff --git a/ldecod/inc/errorconcealment.h b/ldecod/inc/errorconcealment.h new file mode 100644 index 0000000..4d5620c --- /dev/null +++ b/ldecod/inc/errorconcealment.h @@ -0,0 +1,21 @@ + + +/*! + **************************************************************************** + * \file errorconcealment.h + * + * \brief + * Header file for errorconcealment.c + * + **************************************************************************** + */ + +#ifndef _ERRORCONCEALMENT_H_ +#define _ERRORCONCEALMENT_H_ + +extern int get_concealed_element(VideoParameters *p_Vid, SyntaxElement *sym); +extern int set_ec_flag (VideoParameters *p_Vid, int se); +extern void reset_ec_flags (VideoParameters *p_Vid); + +#endif + diff --git a/ldecod/inc/ferc/ferc_api.h b/ldecod/inc/ferc/ferc_api.h new file mode 100644 index 0000000..38fcaa1 --- /dev/null +++ b/ldecod/inc/ferc/ferc_api.h @@ -0,0 +1,106 @@ + +/*! +************************************************************************ +* \file ferc_api.h.h +* +* \brief +* Definitions for frame lost error concealment. +* +* Based on Thomson APIs for concealing entire frame loss. +* Modification to be compatible with frame loss in auxiliary view, +* and some improvements in error concealment strategies +* +* \author +* Previous work +* - Jill Boyce +* - Saurav K Bandyopadhyay +* - Zhenyu Wu +* - Purvin Pandit +* Actual Work +* - Jo���o Carreira +* +************************************************************************ +*/ + +#ifndef _FERC_API_H +#define _FERC_API_H + +#define CONCEAL_REMAINING_FRAMES 1 + + +#include "global.h" +#include "mbuffer.h" + +/* Concealment Modes */ +enum { + + NONE_CONCEAL = 0, + // References + FRAME_COPY_FF = 1, + FRAME_COPY_BC = 2, + MOTION_COPY_TEMPORAL = 3, + MOTION_COPY_SPATIAL = 4, + MOTION_COPY_TEMPORAL_SPATIAL = 5, + MOTION_COPY_ENHANCED = 6, + // Concealment strategies implemented + INTERVIEW_COPY = 10, + MOTION_INTRAVIEW = 11, + MOTION_INTERVIEW = 12, + MOTION_INTERVIEW_FIRST = 13, + MOTION_INTERVIEW_MVE_INTERCOPY = 14, + MOTION_SMART_MOTION_BASED = 15, + MOTION_ITERATIONS = 16, + + MOTION_INTERACTIVE_INTRA_INTER = 17, + MOTION_INTRA_INTER_SAD = 18, + ENHANCED_MVE = 19, + + // Auxiliary methods + CONCEALMV = 50, + MOTION_INTRAVIEW_DISP = 51, + ZERO_MV_CONC = 52, + + MSE_BASED = 60, + SPAT_TEMP_DIFF = 61, + MOTION_DISP_FRAME = 62, + NONE = 63, + + //Previous proposed + REF_DFDP = 21, + REF_ISMID = 22, +}; + + +extern void fercOpenFrameConcealment ( VideoParameters *p_Vid ); +extern void fercCloseFrameConcealment ( VideoParameters *p_Vid ); + +extern void fercFillCurrPicture(VideoParameters *p_Vid, StorablePicture *currPicture); + +extern void fercConcealLostRefFrames(DecodedPictureBuffer *p_Dpb, Slice *currSlice, int is_IDR); + +extern void fercSlindingWindowsOnceFrameRemoved( DecodedPictureBuffer *p_Dpb , int pos ); +extern void fercAddPOC2Dpb( DecodedPictureBuffer *p_Dpb , int poc ); +extern void fercResetPOCInDpb( DecodedPictureBuffer *p_Dpb ); +extern void fercConcealLostNonRefFrames(DecodedPictureBuffer *p_Dpb, unsigned int diff); + +extern void fercConcealLostInterviewRefFrames(DecodedPictureBuffer *p_Dpb, StorablePicture **LostPicture, Slice *currSlice, int MissingView); + +extern void fercConcealRemainingLostFrames(DecodedPictureBuffer *p_Dpb, FrameStore *fs); + +extern void fercWriteConcealedLostNonRefFrames(DecodedPictureBuffer *p_Dpb, int iPoc, int iView); + +extern StorablePicture *fercGetPictureForConcealFromDpb(DecodedPictureBuffer *p_Dpb, int poc, int search_view_id, int search_mode, int search_concealed, unsigned int *position); + +extern void fercSaveListsInfo( VideoParameters *p_Vid, Slice *currSlice ); + +/* Error Propagation Concealment Functions */ +extern void GetDisparityForCurrentSlice(Slice *currSlice); + +extern void fercCopyImg( VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest ); +extern void fercModLostRefFrames( VideoParameters *p_Vid, StorablePicture *DecPicture ); + +extern void ProjectMotionToCurrSlice (VideoParameters *p_Vid, StorablePicture *currPicture, Slice *currSlice); +extern void ChangeInterViewPrediction(Macroblock *currMB, StorablePicture *dec_picture, int pred_dir, int i, int j, int block_size_x, int block_size_y ); +extern void fercFreeMotionPropInfo( StorablePicture *p ); + +#endif diff --git a/ldecod/inc/ferc/ferc_internals.h b/ldecod/inc/ferc/ferc_internals.h new file mode 100644 index 0000000..b2c24fc --- /dev/null +++ b/ldecod/inc/ferc/ferc_internals.h @@ -0,0 +1,148 @@ +/*! +************************************************************************ +* \file ferc_internals.h +* +* \brief +* Internal function for ferc API +* +* +* \author +* - Jo���o Carreira +* +************************************************************************ +*/ + +#ifndef _FERC_INTERNALS_H_ +#define _FERC_INTERNALS_H_ + +#include "defines.h" +#include "global.h" +#include "mbuffer.h" + +#define MAX_PEL_VALUE 255 +#define THRESHOLD_DISP 62 + + +/*! Definition of search modes */ +static enum search_frame { + CLOSEST_ALL = 0, + CLOSEST_RECEIVED = 1, + CLOSEST_FUTURE = 2, + EXACT = 3, + WELL_RECEIVED_STEREO = 4, +}; + +/*! Motion vector concealment modes implemented */ +enum { + ZERO_MV = 0, + PREVIOUS = 1, + AVERAGE = 2, + MEDIAN = 3, +}; + +struct ConcealNode { + StorablePicture* picture; + int MissPoc; + // int MissView; + struct ConcealNode *next; +}; + + +typedef struct conceal_params +{ + + int use_DisparityProjection; + //int use_InterMotionCopy; + //int use_IntraMotionCopy; + + //! Concealment Mode + int ConcealmentMode; + //! Concealment Function + void (*ConcealFuction) (VideoParameters *p_Vid, + StorablePicture *Source, StorablePicture *Dest ); + + int conceal_slice_type; + int flag_bad_poc_calculation; + + // picture error concealment + // concealment_head points to first node in list, concealment_end points to + // last node in list. Initialize both to NULL, meaning no nodes in list yet +#if (MVC_EXTENSION_ENABLE) + struct ConcealNode *ConcealHead[MAX_VIEW_NUM]; + // struct concealment_node *concealment_end[MAX_VIEW_NUM]; +#else + struct ConcealNode *ConcealHead[1]; + // struct concealment_node *concealment_end; +#endif + + int last_out_frame_no[MAX_VIEW_NUM]; + struct frame_store *last_out_fs[MAX_VIEW_NUM]; + + int fercPOCinDpb[MAX_VIEW_NUM][100]; + +}ConcealParameters; + + +struct partial_mv_double +{ + double mv_x; + double mv_y; +}; +struct partial_mv +{ + struct partial_mv_double mv; + char ref_idx; +}; + + +typedef struct motion_prop_info +{ + PicMotionParams ***mv_info; + int **mv_info_count; + int ***mv_info_count_lists; + int Temporal_Ref_Idx; + int Spatial_Ref_Idx; +}MotionPropInfo; + +extern int sort_by_frame_num_up( const void *arg1, const void *arg2 ); +extern int sort_by_poc_up( const void *arg1, const void *arg2 ); +extern int sort_mv_abs_up( const void *arg1, const void *arg2 ); + +extern void MeanFilter( imgpel **initial_matrix, imgpel **filtrated_matrix, int size_x, int size_y, int kernel_size ); +extern void MedianFilter( imgpel **initial_matrix, imgpel **filtrated_matrix, int size_x, int size_y, int kernel_size ); +extern void ConcealMotionVector(VideoParameters *p_Vid, StorablePicture *Dest, Slice *Slice, int y_block4x4, int x_block4x4,int method, int list, int conc_mv[3], int temporal_idx); + +extern void buildPredblockRegionYUV(VideoParameters *p_Vid, StorablePicture *ref_picture, Macroblock *currMB, int *mv,int x, int y, imgpel *pMB, int Block_Size, imgpel **tmp_block, int have_temp); +extern void EnhancedbuildPredblock4x4YUV(VideoParameters *p_Vid, int *mv, int x, int y, imgpel *predMB, int list, int current_mb_nr, imgpel **tmp_block); +extern void EnhancedbuildPredblockRegionYUV(VideoParameters *p_Vid, int *mv, int x, int y, imgpel *predMB, int list, int current_mb_nr, int BlockSize, imgpel **tmp_block); +extern void ferc_bi_prediction(imgpel *mb_pred, imgpel *block_l0, uint8 value_l0, imgpel *block_l1, uint8 value_l1, int ver_block_size, int hor_block_size, int have_uv); +extern void copyPredblockRegionYUVDestination(StorablePicture *Destination, imgpel *predBlock, int x, int y, int BLockSize); + + +extern StorablePicture *fercGetPictureForConcealFromDpb(DecodedPictureBuffer *p_Dpb, int poc, int search_view_id, int search_mode, int search_concealed, unsigned int *position); + + +//! Motion Estimation function +extern int blockMatch(const imgpel* refFrame, int stepBytesRF /*stride*/, const imgpel* curBlock, + int stepBytesCB /*stride*/, int* matchBlock /*results*/, int frameWidth, int frameHeight, int block_size); + +extern int blockMatch16x16SSE4(const imgpel* refFrame, int stepBytesRF, const imgpel* curBlock, + int stepBytesCB, int* matchBlock, int frameWidth, int frameHeight, int block_size); + +extern int blockMatch4x4SSE2(const imgpel* refFrame, int stepBytesRF, const imgpel* curBlock, + int stepBytesCB, int* matchBlock, int frameWidth, int frameHeight, int BlockSize); + + +//External Concelament Functions +extern void Conceal_by_FrameCopy (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest); +extern void Conceal_by_MotionCopy_Ref (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest); +//extern void Conceal_by_MotionCopyEnhanced (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest); +extern void Conceal_by_IntraInterMotionCopy (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest); +extern void Conceal_by_IntraInterMotionCopyBaseViewBased (VideoParameters *p_Vid, StorablePicture *Source/*Ignored*/, StorablePicture *Dest); +extern void Conceal_by_InteractiveIntraInterMotionCopy (VideoParameters *p_Vid, StorablePicture *Source/*Ignored*/, StorablePicture *Dest); +extern void Conceal_by_IntraInterMotionCopy_V2 (VideoParameters *p_Vid, StorablePicture *Source/*Ignored*/, StorablePicture *Dest); + +extern void Conceal_by_DisparityBasedFrameDifferenceProjection (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest); +extern void Conceal_by_InterViewSimilarityMotion (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest); + +#endif diff --git a/ldecod/inc/ferc/ferc_opencv_api.h b/ldecod/inc/ferc/ferc_opencv_api.h new file mode 100644 index 0000000..a7f7966 --- /dev/null +++ b/ldecod/inc/ferc/ferc_opencv_api.h @@ -0,0 +1,68 @@ +/*! +************************************************************************************* +* \file fercOpenCVApi.h +* +* \brief +* Functions to use OpenCV library in JM Software +* +* \date +* 29.11.2011 +* +* \author +* Jo�o Carreira +* +************************************************************************************* +*/ + + +#ifndef _FERC_OPENCV_API_H +#define _FERC_OPENCV_API_H + + +#include "mbuffer.h" +#include +#include + +#include "global.h" +#include "mbuffer.h" +#include "memalloc.h" + + + + +typedef struct{ + unsigned char *memory; + unsigned char **pY; + unsigned char **pU; + unsigned char **pV; + + unsigned int width; + unsigned int heigh; +}T_FRAME; + +enum Disparity{ + LOAD = 0, + VAR = 1, + BM = 2, + SGBM = 3, +}; + +typedef enum filters{ + NONE_FILTER = 0, + MEAN_FILTER = 1, + MEDIAN_FILTER = 2, +}CVFILTERTYPES; + +extern int CheckOpenCVUsage(void); + +extern void showStorablePicture(VideoParameters *p_Vid ,StorablePicture *Picture, int SymbolSize, int show_uv, char * WindowName, int wait); +extern void saveStorablePicture( VideoParameters *p_Vid, char *filename , StorablePicture *Picture , int SymbolSize, int save_uv ); + +extern void OpenCVCloseWindows (char *WindowName); + +extern void cvResizeStorablePicture( VideoParameters *p_Vid , StorablePicture *p_Input, StorablePicture *p_Output ); +extern void cvDisparity( VideoParameters *p_Vid , StorablePicture *Ref, StorablePicture *NonRef, StorablePicture *Disparity, int Method, int WindowRatio, int Direction ); +extern void cvFindImageContours( VideoParameters *p_Vid , StorablePicture *InputImage, StorablePicture *OutputContours ); +extern void cvImageFilter( VideoParameters *p_Vid , StorablePicture *InputImage, StorablePicture *OutputImage, CVFILTERTYPES Filter, int KernelSize ); +extern void cvLoadStorablePicture( VideoParameters *p_Vid, char *filename , StorablePicture *Picture , int SymbolSize, int load_uv ); +#endif diff --git a/ldecod/inc/ferc/ferc_proposed.h b/ldecod/inc/ferc/ferc_proposed.h new file mode 100644 index 0000000..d7c2478 --- /dev/null +++ b/ldecod/inc/ferc/ferc_proposed.h @@ -0,0 +1,22 @@ +/*! +************************************************************************ +* \file ferc_proposed.h +* +* \brief +* Function used in the proposed method +* +* \author +* - Joao Carreira +* +************************************************************************ +*/ + +#ifndef _FERC_PROPOSED_H_ +#define _FERC_PROPOSED_H_ + + +#include "defines.h" +#include "global.h" +#include "mbuffer.h" + +#endif diff --git a/ldecod/inc/filehandle.h b/ldecod/inc/filehandle.h new file mode 100644 index 0000000..360173f --- /dev/null +++ b/ldecod/inc/filehandle.h @@ -0,0 +1,23 @@ + +/*! + ************************************************************************************** + * \file + * filehandle.h + * \brief + * Trace file handling and standard error handling function headers. + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + *************************************************************************************** + */ + +#include "contributors.h" + +#if TRACE +extern void dectracebitcnt(int count); +extern void tracebits ( const char *trace_str, int len, int info, int value1); +extern void tracebits2 ( const char *trace_str, int len, int info); +extern void trace_info ( SyntaxElement *currSE, const char *description_str, int value1 ); +#endif + diff --git a/ldecod/inc/fmo.h b/ldecod/inc/fmo.h new file mode 100644 index 0000000..ba54f51 --- /dev/null +++ b/ldecod/inc/fmo.h @@ -0,0 +1,30 @@ + +/*! + *************************************************************************** + * + * \file fmo.h + * + * \brief + * Support for Flexilble Macroblock Ordering (FMO) + * + * \date + * 19 June, 2002 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + **************************************************************************/ + +#ifndef _FMO_H_ +#define _FMO_H_ + + +extern int fmo_init (VideoParameters *p_Vid, Slice *pSlice); +extern int FmoFinit (VideoParameters *p_Vid); + +extern int FmoGetNumberOfSliceGroup(VideoParameters *p_Vid); +extern int FmoGetLastMBOfPicture (VideoParameters *p_Vid); +extern int FmoGetLastMBInSliceGroup(VideoParameters *p_Vid, int SliceGroup); +extern int FmoGetSliceGroupId (VideoParameters *p_Vid, int mb); +extern int FmoGetNextMBNr (VideoParameters *p_Vid, int CurrentMbNr); + +#endif diff --git a/ldecod/inc/global.h b/ldecod/inc/global.h new file mode 100644 index 0000000..5abbf4e --- /dev/null +++ b/ldecod/inc/global.h @@ -0,0 +1,1242 @@ + +/*! +************************************************************************ +* \file +* global.h +* \brief +* global definitions for H.264 decoder. +* \author +* Copyright (C) 1999 Telenor Satellite Services,Norway +* Ericsson Radio Systems, Sweden +* +* Inge Lille-Langoy +* +* Telenor Satellite Services +* Keysers gt.13 tel.: +47 23 13 86 98 +* N-0130 Oslo,Norway fax.: +47 22 77 79 80 +* +* Rickard Sjoberg +* +* Ericsson Radio Systems +* KI/ERA/T/VV +* 164 80 Stockholm, Sweden +* +************************************************************************ +*/ +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ +#include +#include +#include +#include +#include +#include + +#include "win32.h" +#include "defines.h" +#include "ifunctions.h" +#include "parsetcommon.h" +#include "types.h" +#include "io_image.h" +#include "frame.h" +#include "distortion.h" +#include "io_video.h" + +typedef struct bit_stream_dec Bitstream; + +#define ET_SIZE 300 //!< size of error text buffer +extern char errortext[ET_SIZE]; //!< buffer for error message for exit with error() + +struct pic_motion_params_old; +struct pic_motion_params; + +/*********************************************************************** +* T y p e d e f i n i t i o n s f o r J M +*********************************************************************** +*/ +typedef enum +{ + DEC_OPENED = 0, + DEC_STOPPED, +}DecoderStatus_e; + +typedef enum +{ + LumaComp = 0, + CrComp = 1, + CbComp = 2 +} Color_Component; + +/*********************************************************************** +* D a t a t y p e s f o r C A B A C +*********************************************************************** +*/ + +typedef struct pix_pos +{ + int available; + int mb_addr; + short x; + short y; + short pos_x; + short pos_y; +} PixelPos; + +//! struct to characterize the state of the arithmetic coding engine +typedef struct +{ + unsigned int Drange; + unsigned int Dvalue; + int DbitsLeft; + byte *Dcodestrm; + int *Dcodestrm_len; +} DecodingEnvironment; + +typedef DecodingEnvironment *DecodingEnvironmentPtr; + +// Motion Vector structure +typedef struct +{ + short mv_x; + short mv_y; +} MotionVector; + +static const MotionVector zero_mv = {0, 0}; + +typedef struct +{ + short x; + short y; +} BlockPos; + +//! struct for context management +typedef struct +{ + uint16 state; // index into state-table CP + unsigned char MPS; // Least Probable Symbol 0/1 CP + unsigned char dummy; // for alignment +} BiContextType; + +typedef BiContextType *BiContextTypePtr; + + +/********************************************************************** +* C O N T E X T S F O R T M L S Y N T A X E L E M E N T S +********************************************************************** +*/ + +#define NUM_MB_TYPE_CTX 11 +#define NUM_B8_TYPE_CTX 9 +#define NUM_MV_RES_CTX 10 +#define NUM_REF_NO_CTX 6 +#define NUM_DELTA_QP_CTX 4 +#define NUM_MB_AFF_CTX 4 +#define NUM_TRANSFORM_SIZE_CTX 3 + +// structures that will be declared somewhere else +struct storable_picture; +struct datapartition_dec; +struct syntaxelement_dec; + +typedef struct +{ + BiContextType mb_type_contexts [3][NUM_MB_TYPE_CTX]; + BiContextType b8_type_contexts [2][NUM_B8_TYPE_CTX]; + BiContextType mv_res_contexts [2][NUM_MV_RES_CTX]; + BiContextType ref_no_contexts [2][NUM_REF_NO_CTX]; + BiContextType delta_qp_contexts[NUM_DELTA_QP_CTX]; + BiContextType mb_aff_contexts [NUM_MB_AFF_CTX]; +} MotionInfoContexts; + +#define NUM_IPR_CTX 2 +#define NUM_CIPR_CTX 4 +#define NUM_CBP_CTX 4 +#define NUM_BCBP_CTX 4 +#define NUM_MAP_CTX 15 +#define NUM_LAST_CTX 15 +#define NUM_ONE_CTX 5 +#define NUM_ABS_CTX 5 + +typedef struct +{ + BiContextType transform_size_contexts [NUM_TRANSFORM_SIZE_CTX]; + BiContextType ipr_contexts [NUM_IPR_CTX]; + BiContextType cipr_contexts[NUM_CIPR_CTX]; + BiContextType cbp_contexts [3][NUM_CBP_CTX]; + BiContextType bcbp_contexts[NUM_BLOCK_TYPES][NUM_BCBP_CTX]; + BiContextType map_contexts [2][NUM_BLOCK_TYPES][NUM_MAP_CTX]; + BiContextType last_contexts[2][NUM_BLOCK_TYPES][NUM_LAST_CTX]; + BiContextType one_contexts [NUM_BLOCK_TYPES][NUM_ONE_CTX]; + BiContextType abs_contexts [NUM_BLOCK_TYPES][NUM_ABS_CTX]; +} TextureInfoContexts; + + +//*********************** end of data type definition for CABAC ******************* + +/*********************************************************************** +* N e w D a t a t y p e s f o r T M L +*********************************************************************** +*/ + +/*! Buffer structure for decoded referenc picture marking commands */ +typedef struct DecRefPicMarking_s +{ + int memory_management_control_operation; + int difference_of_pic_nums_minus1; + int long_term_pic_num; + int long_term_frame_idx; + int max_long_term_frame_idx_plus1; + struct DecRefPicMarking_s *Next; +} DecRefPicMarking_t; + +//! cbp structure +typedef struct cbp_s +{ + int64 blk ; + int64 bits ; + int64 bits_8x8; +} CBPStructure; + +//! Macroblock +typedef struct macroblock_dec +{ + int is_decoded; + struct slice *p_Slice; //!< pointer to the current slice + struct video_par *p_Vid; //!< pointer to VideoParameters + struct inp_par *p_Inp; + int mbAddrX; //!< current MB address + int mbAddrA, mbAddrB, mbAddrC, mbAddrD; + Boolean mbAvailA, mbAvailB, mbAvailC, mbAvailD; + BlockPos mb; + int block_x; + int block_y; + int block_y_aff; + int pix_x; + int pix_y; + int pix_c_x; + int pix_c_y; + + int subblock_x; + int subblock_y; + + int qp; //!< QP luma + int qpc[2]; //!< QP chroma + int qp_scaled[MAX_PLANE]; //!< QP scaled for all comps. + Boolean is_lossless; + Boolean is_intra_block; + Boolean is_v_block; + Boolean DeblockCall; + + short slice_nr; + char ei_flag; //!< error indicator flag that enables concealment + char dpl_flag; //!< error indicator flag that signals a missing data partition + short delta_quant; //!< for rate control + short list_offset; + + struct macroblock_dec *mb_up; //!< pointer to neighboring MB (CABAC) + struct macroblock_dec *mb_left; //!< pointer to neighboring MB (CABAC) + + struct macroblock_dec *mbup; // neighbors for loopfilter + struct macroblock_dec *mbleft; // neighbors for loopfilter + + // some storage of macroblock syntax elements for global access + short mb_type; + short mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][2]; //!< indices correspond to [forw,backw][block_y][block_x][x,y] + //short ****mvd; //!< indices correspond to [forw,backw][block_y][block_x][x,y] + int cbp; + CBPStructure s_cbp[3]; + + int i16mode; + char b8mode[4]; + char b8pdir[4]; + char ipmode_DPCM; + char c_ipred_mode; //!< chroma intra prediction mode + char skip_flag; + short DFDisableIdc; + short DFAlphaC0Offset; + short DFBetaOffset; + + Boolean mb_field; + //Flag for MBAFF deblocking; + byte mixedModeEdgeFlag; + + // deblocking strength indices + byte strength_ver[4][4]; + byte strength_hor[4][16]; + + + Boolean luma_transform_size_8x8_flag; + Boolean NoMbPartLessThan8x8Flag; + + void (*itrans_4x4)(struct macroblock_dec *currMB, ColorPlane pl, int ioff, int joff); + void (*itrans_8x8)(struct macroblock_dec *currMB, ColorPlane pl, int ioff, int joff); + + void (*GetMVPredictor) (struct macroblock_dec *currMB, PixelPos *block, + MotionVector *pmv, short ref_frame, struct pic_motion_params **mv_info, int list, int mb_x, int mb_y, int blockshape_x, int blockshape_y); + + int (*read_and_store_CBP_block_bit) (struct macroblock_dec *currMB, DecodingEnvironmentPtr dep_dp, int type); + char (*readRefPictureIdx) (struct macroblock_dec *currMB, struct syntaxelement_dec *currSE, struct datapartition_dec *dP, char b8mode, int list); + + void (*read_comp_coeff_4x4_CABAC) (struct macroblock_dec *currMB, struct syntaxelement_dec *currSE, ColorPlane pl, int (*InvLevelScale4x4)[4], int qp_per, int cbp); + void (*read_comp_coeff_8x8_CABAC) (struct macroblock_dec *currMB, struct syntaxelement_dec *currSE, ColorPlane pl); + + void (*read_comp_coeff_4x4_CAVLC) (struct macroblock_dec *currMB, ColorPlane pl, int (*InvLevelScale4x4)[4], int qp_per, int cbp, byte **nzcoeff); + void (*read_comp_coeff_8x8_CAVLC) (struct macroblock_dec *currMB, ColorPlane pl, int (*InvLevelScale8x8)[8], int qp_per, int cbp, byte **nzcoeff); +} Macroblock; + +//! Syntaxelement +typedef struct syntaxelement_dec +{ + int type; //!< type of syntax element for data part. + int value1; //!< numerical value of syntax element + int value2; //!< for blocked symbols, e.g. run/level + int len; //!< length of code + int inf; //!< info part of CAVLC code + unsigned int bitpattern; //!< CAVLC bitpattern + int context; //!< CABAC context + int k; //!< CABAC context for coeff_count,uv + +#if TRACE +#define TRACESTRING_SIZE 100 //!< size of trace string + char tracestring[TRACESTRING_SIZE]; //!< trace string +#endif + + //! for mapping of CAVLC to syntaxElement + void (*mapping)(int len, int info, int *value1, int *value2); + //! used for CABAC: refers to actual coding method of each individual syntax element type + void (*reading)(struct macroblock_dec *currMB, struct syntaxelement_dec *, DecodingEnvironmentPtr); +} SyntaxElement; + + +//! Bitstream +struct bit_stream_dec +{ + // CABAC Decoding + int read_len; //!< actual position in the codebuffer, CABAC only + int code_len; //!< overall codebuffer length, CABAC only + // CAVLC Decoding + int frame_bitoffset; //!< actual position in the codebuffer, bit-oriented, CAVLC only + int bitstream_length; //!< over codebuffer lnegth, byte oriented, CAVLC only + // ErrorConcealment + byte *streamBuffer; //!< actual codebuffer for read bytes + int ei_flag; //!< error indication, 0: no error, else unspecified error +}; + +//! DataPartition +typedef struct datapartition_dec +{ + + Bitstream *bitstream; + DecodingEnvironment de_cabac; + + int (*readSyntaxElement)(struct macroblock_dec *currMB, struct syntaxelement_dec *, struct datapartition_dec *); + /*!< virtual function; + actual method depends on chosen data partition and + entropy coding method */ +} DataPartition; + +typedef struct wp_params +{ + short weight[3]; + short offset[3]; +} WPParams; + +#if (MVC_EXTENSION_ENABLE) +typedef struct nalunitheadermvcext_tag +{ + unsigned int non_idr_flag; + unsigned int priority_id; + unsigned int view_id; + unsigned int temporal_id; + unsigned int anchor_pic_flag; + unsigned int inter_view_flag; + unsigned int reserved_one_bit; + unsigned int iPrefixNALU; +} NALUnitHeaderMVCExt_t; +#endif + +//! Slice +typedef struct slice +{ + struct video_par *p_Vid; + struct inp_par *p_Inp; + pic_parameter_set_rbsp_t *active_pps; + seq_parameter_set_rbsp_t *active_sps; + int svc_extension_flag; + + // dpb pointer + struct decoded_picture_buffer *p_Dpb; + + //slice property; + int idr_flag; + int idr_pic_id; + int nal_reference_idc; //!< nal_reference_idc from NAL unit + int Transform8x8Mode; + Boolean chroma444_not_separate; //!< indicates chroma 4:4:4 coding with separate_colour_plane_flag equal to zero + + int toppoc; //poc for this top field + int bottompoc; //poc of bottom field of frame + int framepoc; //poc of this frame + + //the following is for slice header syntax elements of poc + // for poc mode 0. + unsigned int pic_order_cnt_lsb; + int delta_pic_order_cnt_bottom; + // for poc mode 1. + int delta_pic_order_cnt[2]; + + // //////////////////////// + // for POC mode 0: + signed int PicOrderCntMsb; + + //signed int PrevPicOrderCntMsb; + //unsigned int PrevPicOrderCntLsb; + + // for POC mode 1: + unsigned int AbsFrameNum; + int ThisPOC; + //signed int ExpectedPicOrderCnt, PicOrderCntCycleCnt, FrameNumInPicOrderCntCycle; + //unsigned int PreviousFrameNum, FrameNumOffset; + //int ExpectedDeltaPerPicOrderCntCycle; + //int PreviousFrameNumOffset; + // ///////////////////////// + + //information need to move to slice; + unsigned int current_mb_nr; // bitstream order + unsigned int num_dec_mb; + short current_slice_nr; + //int mb_x; + //int mb_y; + //int block_x; + //int block_y; + //int pix_c_x; + //int pix_c_y; + int cod_counter; //!< Current count of number of skipped macroblocks in a row + int allrefzero; + //end; + + int mb_aff_frame_flag; + int direct_spatial_mv_pred_flag; //!< Indicator for direct mode type (1 for Spatial, 0 for Temporal) + int num_ref_idx_active[2]; //!< number of available list references + //int num_ref_idx_l0_active; //!< number of available list 0 references + //int num_ref_idx_l1_active; //!< number of available list 1 references + + int ei_flag; //!< 0 if the partArr[0] contains valid information + int qp; + int slice_qp_delta; + int qs; + int slice_qs_delta; + int slice_type; //!< slice type + int model_number; //!< cabac model number + unsigned int frame_num; //frame_num for this frame + unsigned int field_pic_flag; + byte bottom_field_flag; + PictureStructure structure; //!< Identify picture structure type + int start_mb_nr; //!< MUST be set by NAL even in case of ei_flag == 1 + int end_mb_nr_plus1; + int max_part_nr; + int dp_mode; //!< data partitioning mode + int current_header; + int next_header; + int last_dquant; + + //slice header information; + int colour_plane_id; //!< colour_plane_id of the current coded slice + int redundant_pic_cnt; + int sp_switch; //!< 1 for switching sp, 0 for normal sp + int slice_group_change_cycle; + int redundant_slice_ref_idx; //!< reference index of redundant slice + int no_output_of_prior_pics_flag; + int long_term_reference_flag; + int adaptive_ref_pic_buffering_flag; + DecRefPicMarking_t *dec_ref_pic_marking_buffer; //!< stores the memory management control operations + + char listXsize[6]; + struct storable_picture **listX[6]; + + // int last_mb_nr; //!< only valid when entropy coding == CABAC + DataPartition *partArr; //!< array of partitions + MotionInfoContexts *mot_ctx; //!< pointer to struct of context models for use in CABAC + TextureInfoContexts *tex_ctx; //!< pointer to struct of context models for use in CABAC + + int mvscale[6][MAX_REFERENCE_PICTURES]; + + int ref_pic_list_reordering_flag[2]; + int *modification_of_pic_nums_idc[2]; + int *abs_diff_pic_num_minus1[2]; + int *long_term_pic_idx[2]; + +#if (MVC_EXTENSION_ENABLE) + int *abs_diff_view_idx_minus1[2]; + + int view_id; + int inter_view_flag; + int anchor_pic_flag; + + NALUnitHeaderMVCExt_t NaluHeaderMVCExt; +#endif + int layer_id; + short DFDisableIdc; //!< Disable deblocking filter on slice + short DFAlphaC0Offset; //!< Alpha and C0 offset for filtering slice + short DFBetaOffset; //!< Beta offset for filtering slice + + int pic_parameter_set_id; //!=0 multiview[VIEW1|VIEW0]; + int iPOC; + int iYUVFormat; //0: 4:0:0, 1: 4:2:0, 2: 4:2:2, 3: 4:4:4 + int iYUVStorageFormat; //0: YUV seperate; 1: YUV interleaved; 2: 3D output; + int iBitDepth; + byte *pY; //if iPictureFormat is 1, [0]: top; [1] bottom; + byte *pU; + byte *pV; + int iWidth; //frame width; + int iHeight; //frame height; + int iYBufStride; //stride of pY[0/1] buffer in bytes; + int iUVBufStride; //stride of pU[0/1] and pV[0/1] buffer in bytes; + int iSkipPicNum; + int iBufSize; + struct decodedpic_t *pNext; +} DecodedPicList; + +//****************************** ~DM *********************************** +typedef struct coding_par +{ + int layer_id; + int profile_idc; + int width; + int height; + int width_cr; //!< width chroma + int height_cr; //!< height chroma + + int pic_unit_bitsize_on_disk; + short bitdepth_luma; + short bitdepth_chroma; + int bitdepth_scale[2]; + int bitdepth_luma_qp_scale; + int bitdepth_chroma_qp_scale; + unsigned int dc_pred_value_comp[MAX_PLANE]; //!< component value for DC prediction (depends on component pel bit depth) + int max_pel_value_comp[MAX_PLANE]; //!< max value that one picture element (pixel) can take (depends on pic_unit_bitdepth) + + int yuv_format; + int lossless_qpprime_flag; + int num_blk8x8_uv; + int num_uv_blocks; + int num_cdc_coeff; + int mb_cr_size_x; + int mb_cr_size_y; + int mb_cr_size_x_blk; + int mb_cr_size_y_blk; + int mb_cr_size; + int mb_size[3][2]; //!< component macroblock dimensions + int mb_size_blk[3][2]; //!< component macroblock dimensions + int mb_size_shift[3][2]; + + int max_vmv_r; //!< maximum vertical motion vector range in luma quarter frame pixel units for the current level_idc + int separate_colour_plane_flag; + int ChromaArrayType; + int max_frame_num; + unsigned int PicWidthInMbs; + unsigned int PicHeightInMapUnits; + unsigned int FrameHeightInMbs; + unsigned int FrameSizeInMbs; + int iLumaPadX; + int iLumaPadY; + int iChromaPadX; + int iChromaPadY; + + int subpel_x; + int subpel_y; + int shiftpel_x; + int shiftpel_y; + int total_scale; + unsigned int oldFrameSizeInMbs; + + //padding info; + void (*img2buf) (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom, int iOutStride); + int rgb_output; + + imgpel **imgY_ref; //!< reference frame find snr + imgpel ***imgUV_ref; + Macroblock *mb_data; //!< array containing all MBs of a whole frame + Macroblock *mb_data_JV[MAX_PLANE]; //!< mb_data to be used for 4:4:4 independent mode + char *intra_block; + char *intra_block_JV[MAX_PLANE]; + BlockPos *PicPos; + byte **ipredmode; //!< prediction type [90][74] + byte **ipredmode_JV[MAX_PLANE]; + byte ****nz_coeff; + int **siblock; + int **siblock_JV[MAX_PLANE]; + int *qp_per_matrix; + int *qp_rem_matrix; +}CodingParameters; + +typedef struct layer_par +{ + int layer_id; + struct video_par *p_Vid; + CodingParameters *p_Cps; + seq_parameter_set_rbsp_t *p_SPS; + struct decoded_picture_buffer *p_Dpb; +}LayerParameters; + + +//! Edited by Joao Carreira +typedef struct vector_stats_t { + int total_frames; + float burst_average; + float burst_variance; +}VectorStats; + + + +// video parameters +typedef struct video_par +{ + struct inp_par *p_Inp; + pic_parameter_set_rbsp_t *active_pps; + seq_parameter_set_rbsp_t *active_sps; + seq_parameter_set_rbsp_t SeqParSet[MAXSPS]; + pic_parameter_set_rbsp_t PicParSet[MAXPPS]; + struct decoded_picture_buffer *p_Dpb_layer[MAX_NUM_DPB_LAYERS]; + CodingParameters *p_EncodePar[MAX_NUM_DPB_LAYERS]; + LayerParameters *p_LayerPar[MAX_NUM_DPB_LAYERS]; + +#if (MVC_EXTENSION_ENABLE) + subset_seq_parameter_set_rbsp_t *active_subset_sps; + //int svc_extension_flag; + subset_seq_parameter_set_rbsp_t SubsetSeqParSet[MAXSPS]; + int last_pic_width_in_mbs_minus1; + int last_pic_height_in_map_units_minus1; + int last_max_dec_frame_buffering; + int last_profile_idc; +#endif + + struct sei_params *p_SEI; + + struct old_slice_par *old_slice; +#if( MVC_EXTENSION_ENABLE ) + struct snr_par *snr[MAX_VIEW_NUM]; +#else + struct snr_par *snr; +#endif + int number; //!< frame number + + //current picture property; + unsigned int num_dec_mb; + int iSliceNumOfCurrPic; + int iNumOfSlicesAllocated; + int iNumOfSlicesDecoded; + Slice **ppSliceList; + char *intra_block; + char *intra_block_JV[MAX_PLANE]; + //int qp; //!< quant for the current frame + + //int sp_switch; //!< 1 for switching sp, 0 for normal sp + int type; //!< image type INTER/INTRA + + byte **ipredmode; //!< prediction type [90][74] + byte **ipredmode_JV[MAX_PLANE]; + byte ****nz_coeff; + int **siblock; + int **siblock_JV[MAX_PLANE]; + BlockPos *PicPos; + + int newframe; + int structure; //!< Identify picture structure type + + //Slice *currentSlice; //!< pointer to current Slice data struct + Slice *pNextSlice; //!< pointer to first Slice of next picture; + Macroblock *mb_data; //!< array containing all MBs of a whole frame + Macroblock *mb_data_JV[MAX_PLANE]; //!< mb_data to be used for 4:4:4 independent mode + //int colour_plane_id; //!< colour_plane_id of the current coded slice + int ChromaArrayType; + +#if (MVC_EXTENSION_ENABLE) + int pre_frame_num[MAX_VIEW_NUM]; //!< store the frame_num in the last decoded slice. For detecting gap in frame_num. +#else + int pre_frame_num; //!< store the frame_num in the last decoded slice. For detecting gap in frame_num. +#endif + int non_conforming_stream; + + // //////////////////////// + // for POC mode 0: + signed int PrevPicOrderCntMsb; + unsigned int PrevPicOrderCntLsb; + + // for POC mode 1: + signed int ExpectedPicOrderCnt, PicOrderCntCycleCnt, FrameNumInPicOrderCntCycle; + unsigned int PreviousFrameNum, FrameNumOffset; + int ExpectedDeltaPerPicOrderCntCycle; + int ThisPOC; + int PreviousFrameNumOffset; + // ///////////////////////// + + unsigned int PicHeightInMbs; + unsigned int PicSizeInMbs; + + int no_output_of_prior_pics_flag; + + int last_has_mmco_5; + int last_pic_bottom_field; + + int idr_psnr_number; + int psnr_number; + + // Timing related variables + TIME_T start_time; + TIME_T end_time; + + /* + * Edited by Joao Carreira + * Function Related to Frame error concealment + */ + // picture error concealment +#if (MVC_EXTENSION_ENABLE) + int last_ref_pic_poc[MAX_VIEW_NUM]; + int last_ref_hier0_poc[MAX_VIEW_NUM]; +#else + int last_ref_pic_poc; + int last_ref_hier0_poc; +#endif + + struct conceal_params *p_FrameConc; + + int ref_poc_gap; + int poc_gap; + int conceal_mode; + int earlier_missing_poc; + unsigned int frame_to_conceal; + double MotionAverage; + unsigned int NoZeroMVsCount; + unsigned int IntraBlocks; + + + Boolean first_sps; + // random access point decoding + int recovery_point; + int recovery_point_found; + int recovery_frame_cnt; + int recovery_frame_num; + int recovery_poc; + + byte *buf; + byte *ibuf; + + ImageData imgData; //!< Image data to be encoded (dummy variable for now) + ImageData imgData0; //!< base layer input + ImageData imgData1; //!< temp buffer for left de-muxed view + ImageData imgData2; //!< temp buffer for right de-muxed view + + // Data needed for 3:2 pulldown or temporal interleaving + ImageData imgData32; //!< Image data to be encoded + ImageData imgData4; + ImageData imgData5; + ImageData imgData6; + + + // Redundant slices. Should be moved to another structure and allocated only if extended profile + unsigned int previous_frame_num; //!< frame number of previous slice + //!< non-zero: i-th previous frame is correct + int Is_primary_correct; //!< if primary frame is correct, 0: incorrect + int Is_redundant_correct; //!< if redundant frame is correct, 0:incorrect + + // Time + int64 tot_time; + + // files + int p_out; //!< file descriptor to output YUV file +#if (MVC_EXTENSION_ENABLE) + int p_out_mvc[MAX_VIEW_NUM]; //!< file descriptor to output YUV file for MVC + int p_ref_mvc[MAX_VIEW_NUM]; //!< pointer to input original reference YUV file file +#else + int p_ref; //!< pointer to input original reference YUV file file +#endif + + + + //FILE *p_log; //!< SNR file + int LastAccessUnitExists; + int NALUCount; + + // B pictures + int Bframe_ctr; + int frame_no; + int frame_no_idr; + + int IDRframe_ctr; + + int g_nFrame; + Boolean global_init_done[MAX_VIEW_NUM]; + + // global picture format dependent buffers, memory allocation in decod.c + imgpel **imgY_ref; //!< reference frame find snr + imgpel ***imgUV_ref; + + int *qp_per_matrix; + int *qp_rem_matrix; + + /* Edited by Joao Carreira */ +#if ( MVC_EXTENSION_ENABLE ) + int last_output_frame_no[MAX_VIEW_NUM]; +#else + int last_output_frame_no; +#endif + struct storable_picture *dec_picture; + struct storable_picture *dec_picture_JV[MAX_PLANE]; //!< dec_picture to be used during 4:4:4 independent mode decoding + struct storable_picture *no_reference_picture; //!< dummy storable picture for recovery point + + // Error parameters + struct object_buffer *erc_object_list; + struct ercVariables_s *erc_errorVar; + + int erc_mvperMB; + struct video_par *erc_img; + int ec_flag[SE_MAX_ELEMENTS]; //!< array to set errorconcealment + + struct annex_b_struct *annex_b; + + struct frame_store *out_buffer; + + struct storable_picture *pending_output; + int pending_output_state; + int recovery_flag; + + int BitStreamFile; + + // report + char cslice_type[9]; + // FMO + int *MbToSliceGroupMap; + int *MapUnitToSliceGroupMap; + int NumberOfSliceGroups; // the number of slice groups -1 (0 == scan order, 7 == maximum) + +#if (ENABLE_OUTPUT_TONEMAPPING) + struct tone_mapping_struct_s *seiToneMapping; +#endif + + void (*buf2img) (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int o_size_x, int o_size_y, int symbol_size_in_bytes, int bitshift); + void (*getNeighbour) (Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix); + void (*get_mb_block_pos) (BlockPos *PicPos, int mb_addr, short *x, short *y); + void (*GetStrengthVer) (Macroblock *MbQ, int edge, int mvlimit, struct storable_picture *p); + void (*GetStrengthHor) (Macroblock *MbQ, int edge, int mvlimit, struct storable_picture *p); + void (*EdgeLoopLumaVer) (ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge); + void (*EdgeLoopLumaHor) (ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, struct storable_picture *p); + void (*EdgeLoopChromaVer)(imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, struct storable_picture *p); + void (*EdgeLoopChromaHor)(imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, struct storable_picture *p); + void (*img2buf) (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom, int iOutStride); + + ImageData tempData3; + DecodedPicList *pDecOuputPic; + int iDeblockMode; //0: deblock in picture, 1: deblock in slice; + struct nalu_t *nalu; + int iLumaPadX; + int iLumaPadY; + int iChromaPadX; + int iChromaPadY; + //control; + int bDeblockEnable; + int iPostProcess; + int bFrameInit; +#if _FLTDBG_ + FILE *fpDbg; +#endif + pic_parameter_set_rbsp_t *pNextPPS; + int last_dec_poc; + int last_dec_view_id; + int last_dec_layer_id; + int dpb_layer_id; + + /******************* deprecative variables; ***************************************/ + int width; + int height; + int width_cr; //!< width chroma + int height_cr; //!< height chroma + // Fidelity Range Extensions Stuff + int pic_unit_bitsize_on_disk; + short bitdepth_luma; + short bitdepth_chroma; + int bitdepth_scale[2]; + int bitdepth_luma_qp_scale; + int bitdepth_chroma_qp_scale; + unsigned int dc_pred_value_comp[MAX_PLANE]; //!< component value for DC prediction (depends on component pel bit depth) + int max_pel_value_comp[MAX_PLANE]; //!< max value that one picture element (pixel) can take (depends on pic_unit_bitdepth) + + int separate_colour_plane_flag; + int pic_unit_size_on_disk; + + int profile_idc; + int yuv_format; + int lossless_qpprime_flag; + int num_blk8x8_uv; + int num_uv_blocks; + int num_cdc_coeff; + int mb_cr_size_x; + int mb_cr_size_y; + int mb_cr_size_x_blk; + int mb_cr_size_y_blk; + int mb_cr_size; + int mb_size[3][2]; //!< component macroblock dimensions + int mb_size_blk[3][2]; //!< component macroblock dimensions + int mb_size_shift[3][2]; + int subpel_x; + int subpel_y; + int shiftpel_x; + int shiftpel_y; + int total_scale; + int max_frame_num; + + unsigned int PicWidthInMbs; + unsigned int PicHeightInMapUnits; + unsigned int FrameHeightInMbs; + unsigned int FrameSizeInMbs; + unsigned int oldFrameSizeInMbs; + int max_vmv_r; //!< maximum vertical motion vector range in luma quarter frame pixel units for the current level_idc + //int max_mb_vmv_r; //!< maximum vertical motion vector range in luma quarter pixel units for the current level_idc + /******************* end deprecative variables; ***************************************/ + + struct dec_stat_parameters *dec_stats; + + //! Control the number of views in stream + int n_views; + + /* + * Edited by Jo�o Carreira + * NAL Units parser + */ + void *p_ParserNAL; + void *p_PredictionParser; + /* + * Edited by Jo�o Carreira + * Transcode Module Struct pointer + */ + void *p_Transcode; + + /* + * Edited by Joao Carreira + * Report Variables + */ +#if ( MVC_EXTENSION_ENABLE ) + int nFramesConceal[MAX_VIEW_NUM]; + int nFramesDecoded[MAX_VIEW_NUM]; + int nFramesOut[MAX_VIEW_NUM]; +#else + int nFramesConceal; + int nFramesDecoded; + int nFramesOut; +#endif + /**** Stats ****/ +#define INITAL_PFRAMES_LENGTH 10000 + int *p_PFrames[MAX_VIEW_NUM]; + unsigned int n_PFrames[MAX_VIEW_NUM]; + VectorStats LostFrames[MAX_VIEW_NUM]; + VectorStats AfectedFrames[MAX_VIEW_NUM]; + int n_Loops; + int n_BiPred; + int n_SKIP; +} VideoParameters; + +// signal to noise ratio parameters +typedef struct snr_par +{ + int frame_ctr; + float snr[3]; //!< current SNR (component) + float snr1[3]; //!< SNR (dB) first frame (component) + float snra[3]; //!< Average component SNR (dB) remaining frames + float sse[3]; //!< component SSE + float msse[3]; //!< Average component SSE +} SNRParameters; + +// input parameters from configuration file +typedef struct inp_par +{ + char infile[FILE_NAME_SIZE]; //!< H.264 inputfile + char outfile[FILE_NAME_SIZE]; //!< Decoded YUV 4:2:0 output + char reffile[FILE_NAME_SIZE]; //!< Optional YUV 4:2:0 reference file for SNR measurement + //! Edited by Joao Carreira + char statsfile[FILE_NAME_SIZE]; //!< Optional YUV 4:2:0 reference file for SNR measurement + + int FileFormat; //!< File format of the Input file, PAR_OF_ANNEXB or PAR_OF_RTP + int ref_offset; + int poc_scale; + int write_uv; + int silent; + int intra_profile_deblocking; //!< Loop filter usage determined by flags and parameters in bitstream + + // Input/output sequence format related variables + FrameFormat source; //!< source related information + FrameFormat output; //!< output related information + + int ProcessInput; + int enable_32_pulldown; + VideoDataFile input_file1; //!< Input video file1 + VideoDataFile input_file2; //!< Input video file2 + VideoDataFile input_file3; //!< Input video file3 +#if (MVC_EXTENSION_ENABLE) + int DecodeAllLayers; +#endif + +#ifdef _LEAKYBUCKET_ + unsigned long R_decoder; //!< Decoder Rate in HRD Model + unsigned long B_decoder; //!< Decoder Buffer size in HRD model + unsigned long F_decoder; //!< Decoder Initial buffer fullness in HRD model + char LeakyBucketParamFile[FILE_NAME_SIZE]; //!< LeakyBucketParamFile +#endif + + // picture error concealment + int conceal_mode; + int DisparityMethod; + int DisparityDirection; + int DisparityReference; + int DisparityWindow; + char DispLoadFileName[FILE_NAME_SIZE]; + int DisparityProjection; + int Disparity4x4BlockSize; + int MotionVectorCandidates; + int MVConcealmentMode; + int TemporalThreshold; + int SpatialThreshold; + char TranscodeFile[FILE_NAME_SIZE]; + + int error_prop; + int ref_poc_gap; + int poc_gap; + int IDR_Period; + int GOP_Size; + int FrameSkip; + int search_mode_ref; + int search_mode_nonref; + + /* Edited by Jo�o Carreira */ +#define MAX_LOST_NALU 200 + char drop_nalu[MAX_LOST_NALU]; + + //! Edited by Joao Carreira + int dump_nalu; //!< if 1 write to a file the nal units found in bitstream + int PredictionParser; + + + // dummy for encoder + int start_frame; + + // Needed to allow compilation for decoder. May be used later for distortion computation operations + int stdRange; //!< 1 - standard range, 0 - full range + int videoCode; //!< 1 - 709, 3 - 601: See VideoCode in io_tiff. + int export_views; + + int iDecFrmNum; + + int bDisplayDecParams; + int dpb_plus[2]; +} InputParameters; + +typedef struct old_slice_par +{ + unsigned field_pic_flag; + unsigned frame_num; + int nal_ref_idc; + unsigned pic_oder_cnt_lsb; + int delta_pic_oder_cnt_bottom; + int delta_pic_order_cnt[2]; + byte bottom_field_flag; + byte idr_flag; + int idr_pic_id; + int pps_id; +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag; + int anchor_pic_flag; +#endif + int layer_id; +} OldSliceParams; + +typedef struct decoder_params +{ + InputParameters *p_Inp; //!< Input Parameters + VideoParameters *p_Vid; //!< Image Parameters + int64 bufferSize; //!< buffersize for tiff reads (not currently supported) + int UsedBits; // for internal statistics, is adjusted by read_se_v, read_ue_v, read_u_1 + FILE *p_trace; //!< Trace file + int bitcounter; +} DecoderParams; + +extern DecoderParams *p_Dec; + +// prototypes +extern void error(char *text, int code); + +// dynamic mem allocation +extern int init_global_buffers( VideoParameters *p_Vid, int layer_id ); +extern void free_global_buffers( VideoParameters *p_Vid); +extern void free_layer_buffers( VideoParameters *p_Vid, int layer_id ); + +extern int RBSPtoSODB(byte *streamBuffer, int last_byte_pos); +extern int EBSPtoRBSP(byte *streamBuffer, int end_bytepos, int begin_bytepos); + +extern void FreePartition (DataPartition *dp, int n); +extern DataPartition *AllocPartition(int n); + +extern void tracebits (const char *trace_str, int len, int info, int value1); +extern void tracebits2(const char *trace_str, int len, int info); + +extern unsigned CeilLog2 ( unsigned uiVal); +extern unsigned CeilLog2_sf( unsigned uiVal); + +// For 4:4:4 independent mode +extern void change_plane_JV ( VideoParameters *p_Vid, int nplane, Slice *pSlice); +extern void make_frame_picture_JV( VideoParameters *p_Vid ); + +#if (MVC_EXTENSION_ENABLE) +extern void nal_unit_header_mvc_extension(NALUnitHeaderMVCExt_t *NaluHeaderMVCExt, struct bit_stream_dec *bitstream); +#endif + +extern void FreeDecPicList ( DecodedPicList *pDecPicList ); +extern void ClearDecPicList( VideoParameters *p_Vid ); +extern DecodedPicList *get_one_avail_dec_pic_from_list(DecodedPicList *pDecPicList, int b3D, int view_id); +extern Slice *malloc_slice( InputParameters *p_Inp, VideoParameters *p_Vid ); +extern void free_slice (Slice *currSlice); +extern void copy_slice_info ( Slice *currSlice, OldSliceParams *p_old_slice ); +extern void OpenOutputFiles(VideoParameters *p_Vid, int view0_id, int view1_id); +extern void OpenRefFiles(VideoParameters *p_Vid, int view0_id, int view1_id); + +//! Edit by Joao Carreira +extern void OpenOutputFiles_per_layer(VideoParameters *p_Vid, int view_id); +extern void OpenRefFiles_per_layer(VideoParameters *p_Vid, int view_id); + +extern void set_global_coding_par(VideoParameters *p_Vid, CodingParameters *cps); + +static inline int is_FREXT_profile(unsigned int profile_idc) +{ + return ( profile_idc >= FREXT_HP || profile_idc == FREXT_CAVLC444 ); +} +static inline int HI_intra_only_profile(unsigned int profile_idc, Boolean constrained_set3_flag) +{ + return ( ((profile_idc >= FREXT_Hi10P) && constrained_set3_flag) || (profile_idc == FREXT_CAVLC444) ); +} +static inline int is_BL_profile(unsigned int profile_idc) +{ + return ( profile_idc == FREXT_CAVLC444 || profile_idc == BASELINE || profile_idc == MAIN || profile_idc == EXTENDED || + profile_idc == FREXT_HP || profile_idc == FREXT_Hi10P || profile_idc == FREXT_Hi422 || profile_idc == FREXT_Hi444); +} +static inline int is_EL_profile(unsigned int profile_idc) +{ + return ( (profile_idc == MVC_HIGH) || (profile_idc == STEREO_HIGH) + ); +} + +static inline int is_MVC_profile(unsigned int profile_idc) +{ + return ( (0) +#if (MVC_EXTENSION_ENABLE) + || (profile_idc == MVC_HIGH) || (profile_idc == STEREO_HIGH) +#endif + ); +} + + +//! Report Function +enum{ + STATUS = 0, + REPORT = 1, + DEBUG = 2, +}; +extern void av_log(int level, const char *fmt, ...); + + +#endif + diff --git a/ldecod/inc/h264decoder.h b/ldecod/inc/h264decoder.h new file mode 100644 index 0000000..7b8e068 --- /dev/null +++ b/ldecod/inc/h264decoder.h @@ -0,0 +1,54 @@ + +/*! + ************************************************************************ + * \file + * h264decoder.h + * \brief + * interface for H.264 decoder. + * \author + * Copyright (C) 2009 Dolby + * Yuwen He (yhe@dolby.com) + * + ************************************************************************ + */ +#ifndef _H264DECODER_H_ +#define _H264DECODER_H_ + +#include "global.h" + +typedef enum +{ + DEC_GEN_NOERR = 0, + DEC_OPEN_NOERR = 0, + DEC_CLOSE_NOERR = 0, + DEC_SUCCEED = 0, + DEC_EOS =1, + DEC_NEED_DATA = 2, + DEC_INVALID_PARAM = 3, + DEC_ERRMASK = 0x8000 +// DEC_ERRMASK = 0x80000000 +}DecErrCode; + +typedef struct dec_set_t +{ + int iPostprocLevel; // valid interval are [0..100] + int bDBEnable; + int bAllLayers; + int time_incr; + int bDecCompAdapt; +} DecSet_t; + +#ifdef __cplusplus +extern "C" { +#endif + +int OpenDecoder(InputParameters *p_Inp); +int DecodeOneFrame(DecodedPicList **ppDecPic); +int FinitDecoder(DecodedPicList **ppDecPicList); +int CloseDecoder(); +int SetOptsDecoder(DecSet_t *pDecOpts); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/ldecod/inc/header.h b/ldecod/inc/header.h new file mode 100644 index 0000000..d7269b1 --- /dev/null +++ b/ldecod/inc/header.h @@ -0,0 +1,22 @@ +/*! + ************************************************************************************* + * \file header.h + * + * \brief + * Prototypes for header.c + ************************************************************************************* + */ + +#ifndef _HEADER_H_ +#define _HEADER_H_ + +extern int FirstPartOfSliceHeader(Slice *currSlice); +extern int RestOfSliceHeader (Slice *currSlice); + +extern void dec_ref_pic_marking(VideoParameters *p_Vid, Bitstream *currStream, Slice *pSlice); + +extern void decode_poc(VideoParameters *p_Vid, Slice *pSlice); +extern int dumppoc (VideoParameters *p_Vid); + +#endif + diff --git a/ldecod/inc/image.h b/ldecod/inc/image.h new file mode 100644 index 0000000..aacfaeb --- /dev/null +++ b/ldecod/inc/image.h @@ -0,0 +1,47 @@ + +/*! + ************************************************************************ + * \file image.h + * + * \brief + * prototypes for image.c + * + ************************************************************************ + */ + +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + +#include "mbuffer.h" + + + +extern void calculate_frame_no(VideoParameters *p_Vid, StorablePicture *p); +extern void find_snr (VideoParameters *p_Vid, StorablePicture *p, int *p_ref); +extern int picture_order ( Slice *pSlice ); + +extern void decode_one_slice (Slice *currSlice); +extern int read_new_slice (Slice *currSlice); +extern void exit_picture (VideoParameters *p_Vid, StorablePicture **dec_picture); +extern int decode_one_frame (DecoderParams *pDecoder); + +extern int is_new_picture(StorablePicture *dec_picture, Slice *currSlice, OldSliceParams *p_old_slice); +extern void init_old_slice(OldSliceParams *p_old_slice); +// For 4:4:4 independent mode +extern void copy_dec_picture_JV (VideoParameters *p_Vid, StorablePicture *dst, StorablePicture *src ); + +extern void frame_postprocessing(VideoParameters *p_Vid); +extern void field_postprocessing(VideoParameters *p_Vid); + +#if (MVC_EXTENSION_ENABLE) +extern int GetViewIdx(VideoParameters *p_Vid, int iVOIdx); +extern int GetVOIdx(VideoParameters *p_Vid, int iViewId); +extern int get_maxViewIdx(VideoParameters *p_Vid, int view_id, int anchor_pic_flag, int listidx); +extern void init_mvc_picture(Slice *currSlice); +#endif + +extern void init_slice(VideoParameters *p_Vid, Slice *currSlice); +extern void decode_slice(Slice *currSlice, int current_header); + +#endif + diff --git a/ldecod/inc/intra16x16_pred.h b/ldecod/inc/intra16x16_pred.h new file mode 100644 index 0000000..86ee97a --- /dev/null +++ b/ldecod/inc/intra16x16_pred.h @@ -0,0 +1,26 @@ +/*! + ************************************************************************************* + * \file intra16x16_pred.h + * + * \brief + * definitions for intra 16x16 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#ifndef _INTRA16x16_PRED_H_ +#define _INTRA16x16_PRED_H_ + +#include "global.h" +#include "mbuffer.h" + +extern int intra_pred_16x16_mbaff (Macroblock *currMB, ColorPlane pl, int predmode); +extern int intra_pred_16x16_normal(Macroblock *currMB, ColorPlane pl, int predmode); + +#endif + diff --git a/ldecod/inc/intra4x4_pred.h b/ldecod/inc/intra4x4_pred.h new file mode 100644 index 0000000..67a5e14 --- /dev/null +++ b/ldecod/inc/intra4x4_pred.h @@ -0,0 +1,26 @@ +/*! + ************************************************************************************* + * \file intra4x4_pred.h + * + * \brief + * definitions for intra 4x4 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#ifndef _INTRA4x4_PRED_H_ +#define _INTRA4x4_PRED_H_ + +#include "global.h" +#include "mbuffer.h" + +extern int intra_pred_4x4_mbaff (Macroblock *currMB, ColorPlane pl, int ioff, int joff, int img_block_x, int img_block_y); +extern int intra_pred_4x4_normal(Macroblock *currMB, ColorPlane pl, int ioff, int joff, int img_block_x, int img_block_y); + +#endif + diff --git a/ldecod/inc/intra8x8_pred.h b/ldecod/inc/intra8x8_pred.h new file mode 100644 index 0000000..664ce7e --- /dev/null +++ b/ldecod/inc/intra8x8_pred.h @@ -0,0 +1,26 @@ +/*! + ************************************************************************************* + * \file intra8x8_pred.h + * + * \brief + * definitions for intra 8x8 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#ifndef _INTRA8x8_PRED_H_ +#define _INTRA8x8_PRED_H_ + +#include "global.h" +#include "mbuffer.h" + +extern int intra_pred_8x8_normal(Macroblock *currMB, ColorPlane pl, int ioff, int joff); +extern int intra_pred_8x8_mbaff(Macroblock *currMB, ColorPlane pl, int ioff, int joff); + +#endif + diff --git a/ldecod/inc/leaky_bucket.h b/ldecod/inc/leaky_bucket.h new file mode 100644 index 0000000..ad605a6 --- /dev/null +++ b/ldecod/inc/leaky_bucket.h @@ -0,0 +1,26 @@ + +/*! + ************************************************************************************* + * \file leaky_bucket.h + * + * \brief + * Header for Leaky Buffer parameters + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Shankar Regunathan + ************************************************************************************* + */ +#ifndef _LEAKY_BUCKET_H_ +#define _LEAKY_BUCKET_H_ + +#include "global.h" + +#ifdef _LEAKYBUCKET_ +// Leaky Bucket functions +unsigned long GetBigDoubleWord(FILE *fp); +void calc_buffer(InputParameters *p_Inp); +#endif + +#endif + diff --git a/ldecod/inc/loop_filter.h b/ldecod/inc/loop_filter.h new file mode 100644 index 0000000..c5dd912 --- /dev/null +++ b/ldecod/inc/loop_filter.h @@ -0,0 +1,68 @@ +/*! + *************************************************************************** + * \file + * loop_filter.h + * + * \date + * 25 April 2010 + * + * \brief + * Headerfile for loopfilter processing + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + + ************************************************************************** + */ + +#ifndef _LOOP_FILTER_H_ +#define _LOOP_FILTER_H_ + +#include "global.h" + + +#define GROUP_SIZE 1 + +/*********************************************************************************************************/ + +// NOTE: In principle, the alpha and beta tables are calculated with the formulas below +// Alpha( qp ) = 0.8 * (2^(qp/6) - 1) +// Beta ( qp ) = 0.5 * qp - 7 + +// The tables actually used have been "hand optimized" though (by Anthony Joch). So, the +// table values might be a little different to formula-generated values. Also, the first +// few values of both tables is set to zero to force the filter off at low qp’s + +static const byte ALPHA_TABLE[52] = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,4,4,5,6, 7,8,9,10,12,13,15,17, 20,22,25,28,32,36,40,45, 50,56,63,71,80,90,101,113, 127,144,162,182,203,226,255,255} ; +static const byte BETA_TABLE[52] = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,2,2,3, 3,3,3, 4, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 11,11,12,12,13,13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18} ; +static const byte CLIP_TAB[52][5] = +{ + { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 1, 1, 1, 1}, + { 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 2, 3, 3}, + { 0, 1, 2, 3, 3},{ 0, 2, 2, 3, 3},{ 0, 2, 2, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 3, 3, 5, 5},{ 0, 3, 4, 6, 6},{ 0, 3, 4, 6, 6}, + { 0, 4, 5, 7, 7},{ 0, 4, 5, 8, 8},{ 0, 4, 6, 9, 9},{ 0, 5, 7,10,10},{ 0, 6, 8,11,11},{ 0, 6, 8,13,13},{ 0, 7,10,14,14},{ 0, 8,11,16,16}, + { 0, 9,12,18,18},{ 0,10,13,20,20},{ 0,11,15,23,23},{ 0,13,17,25,25} +} ; + +static const char chroma_edge[2][4][4] = //[dir][edge][yuv_format] +{ { {-4, 0, 0, 0}, + {-4,-4,-4, 4}, + {-4, 4, 4, 8}, + {-4,-4,-4, 12}}, + + { {-4, 0, 0, 0}, + {-4,-4, 4, 4}, + {-4, 4, 8, 8}, + {-4,-4, 12, 12}}}; + +static const int pelnum_cr[2][4] = {{0,8,16,16}, {0,8, 8,16}}; //[dir:0=vert, 1=hor.][yuv_format] + + +static inline int compare_mvs(const MotionVector *mv0, const MotionVector *mv1, int mvlimit) +{ + return ((iabs( mv0->mv_x - mv1->mv_x) >= 4) | (iabs( mv0->mv_y - mv1->mv_y) >= mvlimit)); +} + +#endif diff --git a/ldecod/inc/loopfilter.h b/ldecod/inc/loopfilter.h new file mode 100644 index 0000000..781feb5 --- /dev/null +++ b/ldecod/inc/loopfilter.h @@ -0,0 +1,19 @@ +/*! + ************************************************************************ + * \file + * loopfilter.h + * \brief + * external deblocking filter interface + ************************************************************************ + */ + +#ifndef _LOOPFILTER_H_ +#define _LOOPFILTER_H_ + +#include "global.h" +#include "mbuffer.h" + +extern void DeblockPicture(VideoParameters *p_Vid, StorablePicture *p) ; + +void init_Deblock(VideoParameters *p_Vid, int mb_aff_frame_flag); +#endif //_LOOPFILTER_H_ diff --git a/ldecod/inc/macroblock.h b/ldecod/inc/macroblock.h new file mode 100644 index 0000000..b50901e --- /dev/null +++ b/ldecod/inc/macroblock.h @@ -0,0 +1,152 @@ +/*! + ************************************************************************ + * \file macroblock.h + * + * \brief + * Arrays for macroblock encoding + * + * \author + * Inge Lille-Langoy + * Copyright (C) 1999 Telenor Satellite Services, Norway + ************************************************************************ + */ + +#ifndef _MACROBLOCK_H_ +#define _MACROBLOCK_H_ + +#include "global.h" +#include "mbuffer.h" +#include "block.h" + +//! single scan pattern +static const byte SNGL_SCAN[16][2] = +{ + {0,0},{1,0},{0,1},{0,2}, + {1,1},{2,0},{3,0},{2,1}, + {1,2},{0,3},{1,3},{2,2}, + {3,1},{3,2},{2,3},{3,3} +}; + +//! field scan pattern +static const byte FIELD_SCAN[16][2] = +{ + {0,0},{0,1},{1,0},{0,2}, + {0,3},{1,1},{1,2},{1,3}, + {2,0},{2,1},{2,2},{2,3}, + {3,0},{3,1},{3,2},{3,3} +}; + +//! used to control block sizes : Not used/16x16/16x8/8x16/8x8/8x4/4x8/4x4 +static const int BLOCK_STEP[8][2]= +{ + {0,0},{4,4},{4,2},{2,4},{2,2},{2,1},{1,2},{1,1} +}; + +//! single scan pattern +static const byte SNGL_SCAN8x8[64][2] = { + {0,0}, {1,0}, {0,1}, {0,2}, {1,1}, {2,0}, {3,0}, {2,1}, {1,2}, {0,3}, {0,4}, {1,3}, {2,2}, {3,1}, {4,0}, {5,0}, + {4,1}, {3,2}, {2,3}, {1,4}, {0,5}, {0,6}, {1,5}, {2,4}, {3,3}, {4,2}, {5,1}, {6,0}, {7,0}, {6,1}, {5,2}, {4,3}, + {3,4}, {2,5}, {1,6}, {0,7}, {1,7}, {2,6}, {3,5}, {4,4}, {5,3}, {6,2}, {7,1}, {7,2}, {6,3}, {5,4}, {4,5}, {3,6}, + {2,7}, {3,7}, {4,6}, {5,5}, {6,4}, {7,3}, {7,4}, {6,5}, {5,6}, {4,7}, {5,7}, {6,6}, {7,5}, {7,6}, {6,7}, {7,7} +}; + + +//! field scan pattern +static const byte FIELD_SCAN8x8[64][2] = { // 8x8 + {0,0}, {0,1}, {0,2}, {1,0}, {1,1}, {0,3}, {0,4}, {1,2}, {2,0}, {1,3}, {0,5}, {0,6}, {0,7}, {1,4}, {2,1}, {3,0}, + {2,2}, {1,5}, {1,6}, {1,7}, {2,3}, {3,1}, {4,0}, {3,2}, {2,4}, {2,5}, {2,6}, {2,7}, {3,3}, {4,1}, {5,0}, {4,2}, + {3,4}, {3,5}, {3,6}, {3,7}, {4,3}, {5,1}, {6,0}, {5,2}, {4,4}, {4,5}, {4,6}, {4,7}, {5,3}, {6,1}, {6,2}, {5,4}, + {5,5}, {5,6}, {5,7}, {6,3}, {7,0}, {7,1}, {6,4}, {6,5}, {6,6}, {6,7}, {7,2}, {7,3}, {7,4}, {7,5}, {7,6}, {7,7} +}; + +//! single scan pattern +static const byte SCAN_YUV422[8][2] = +{ + {0,0},{0,1}, + {1,0},{0,2}, + {0,3},{1,1}, + {1,2},{1,3} +}; + +static const unsigned char cbp_blk_chroma[8][4] = +{ {16, 17, 18, 19}, + {20, 21, 22, 23}, + {24, 25, 26, 27}, + {28, 29, 30, 31}, + {32, 33, 34, 35}, + {36, 37, 38, 39}, + {40, 41, 42, 43}, + {44, 45, 46, 47} +}; + +static const unsigned char cofuv_blk_x[3][8][4] = +{ { {0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} }, + + { {0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 1, 0, 1}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} }, + + { {0, 1, 0, 1}, + {2, 3, 2, 3}, + {0, 1, 0, 1}, + {2, 3, 2, 3}, + {0, 1, 0, 1}, + {2, 3, 2, 3}, + {0, 1, 0, 1}, + {2, 3, 2, 3} } +}; + +static const unsigned char cofuv_blk_y[3][8][4] = +{ + { { 0, 0, 1, 1}, + { 0, 0, 1, 1}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0} }, + + { { 0, 0, 1, 1}, + { 2, 2, 3, 3}, + { 0, 0, 1, 1}, + { 2, 2, 3, 3}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0} }, + + { { 0, 0, 1, 1}, + { 0, 0, 1, 1}, + { 2, 2, 3, 3}, + { 2, 2, 3, 3}, + { 0, 0, 1, 1}, + { 0, 0, 1, 1}, + { 2, 2, 3, 3}, + { 2, 2, 3, 3}} +}; + +extern void setup_slice_methods_mbaff(Slice *currSlice); +extern void setup_slice_methods (Slice *currSlice); +extern void get_neighbors(Macroblock *currMB, PixelPos *block, int mb_x, int mb_y, int blockshape_x); + +extern void start_macroblock (Slice *currSlice, Macroblock **currMB); +extern int decode_one_macroblock(Macroblock *currMB, StorablePicture *dec_picture); +extern Boolean exit_macroblock (Slice *currSlice, int eos_bit); +extern void update_qp (Macroblock *currMB, int qp); + + +#endif + diff --git a/ldecod/inc/mb_prediction.h b/ldecod/inc/mb_prediction.h new file mode 100644 index 0000000..b77048c --- /dev/null +++ b/ldecod/inc/mb_prediction.h @@ -0,0 +1,35 @@ + +/*! + ************************************************************************************* + * \file mb_prediction.h + * + * \brief + * Functions for macroblock prediction + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#ifndef _MB_PREDICTION_H_ +#define _MB_PREDICTION_H_ + +extern int mb_pred_intra4x4 (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern int mb_pred_intra16x16 (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_intra8x8 (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); + +extern int mb_pred_skip (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern int mb_pred_sp_skip (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_p_inter8x8 (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_p_inter16x16 (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_p_inter16x8 (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_p_inter8x16 (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_b_d4x4spatial (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern int mb_pred_b_d8x8spatial (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern int mb_pred_b_d4x4temporal(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern int mb_pred_b_d8x8temporal(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern int mb_pred_b_inter8x8 (Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture); +extern int mb_pred_ipcm (Macroblock *currMB); + +#endif diff --git a/ldecod/inc/mbuffer.h b/ldecod/inc/mbuffer.h new file mode 100644 index 0000000..5c14b4d --- /dev/null +++ b/ldecod/inc/mbuffer.h @@ -0,0 +1,291 @@ +/*! +*********************************************************************** +* \file +* mbuffer.h +* +* \brief +* Frame buffer functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Karsten Suehring +* - Alexis Michael Tourapis + +* - Jill Boyce +* - Saurav K Bandyopadhyay +* - Zhenyu Wu +* +*********************************************************************** +*/ +#ifndef _MBUFFERDEC_H_ +#define _MBUFFERDEC_H_ + +#include "global.h" + +#define MAX_LIST_SIZE 33 +//! definition of pic motion parameters +typedef struct pic_motion_params_old +{ + byte * mb_field; //!< field macroblock indicator +} PicMotionParamsOld; + +//! definition of pic motion parameters +typedef struct pic_motion_params +{ + struct storable_picture *ref_pic[2]; //!< referrence picture pointer + MotionVector mv[2]; //!< motion vector + char ref_idx[2]; //!< reference picture [list][subblock_y][subblock_x] + //byte mb_field; //!< field macroblock indicator + byte slice_no; +} PicMotionParams; + +//! definition a picture (field or frame) +typedef struct storable_picture +{ + PictureStructure structure; + + int frame_no; + +#if (MVC_EXTENSION_ENABLE) + int view_id; +#endif + + int poc; + int top_poc; + int bottom_poc; + int frame_poc; + unsigned int frame_num; + unsigned int recovery_frame; + + int pic_num; + int long_term_pic_num; + int long_term_frame_idx; + + byte is_long_term; + + int used_for_reference; + int temp_used_for_reference; //!< Error concealment temp variable + + int is_output; + int non_existing; + int separate_colour_plane_flag; + + short max_slice_id; + + int size_x, size_y, size_x_cr, size_y_cr; + int size_x_m1, size_y_m1, size_x_cr_m1, size_y_cr_m1; + int coded_frame; + int mb_aff_frame_flag; + unsigned PicWidthInMbs; + unsigned PicSizeInMbs; + int iLumaPadY, iLumaPadX; + int iChromaPadY, iChromaPadX; + + + imgpel ** imgY; //!< Y picture component + imgpel *** imgUV; //!< U and V picture components + + struct pic_motion_params **mv_info; //!< Motion info + struct pic_motion_params **JVmv_info[MAX_PLANE]; //!< Motion info + + struct pic_motion_params_old motion; //!< Motion info + struct pic_motion_params_old JVmotion[MAX_PLANE]; //!< Motion info for 4:4:4 independent mode decoding + + struct storable_picture *top_field; // for mb aff, if frame for referencing the top field + struct storable_picture *bottom_field; // for mb aff, if frame for referencing the bottom field + struct storable_picture *frame; // for mb aff, if field for referencing the combined frame + + int slice_type; + int idr_flag; + int no_output_of_prior_pics_flag; + int long_term_reference_flag; + int adaptive_ref_pic_buffering_flag; + + int chroma_format_idc; + int frame_mbs_only_flag; + int frame_cropping_flag; + int frame_crop_left_offset; + int frame_crop_right_offset; + int frame_crop_top_offset; + int frame_crop_bottom_offset; + int qp; + int chroma_qp_offset[2]; + int slice_qp_delta; + DecRefPicMarking_t *dec_ref_pic_marking_buffer; //!< stores the memory management control operations + + //! Picture error concealment + int concealed_pic; //indicates if this is a concealed picture + char Conc_listXsize[2]; + int Conc_listXInterviewPos[2]; + struct storable_picture *Conc_listX[2][MAX_LIST_SIZE]; + struct storable_picture *disparity; + + // variables for tone mapping + int seiHasTone_mapping; + int tone_mapping_model_id; + int tonemapped_bit_depth; + imgpel* tone_mapping_lut; //!< tone mapping look up table + + int proc_flag; +#if (MVC_EXTENSION_ENABLE) + int inter_view_flag; + int anchor_pic_flag; +#endif + + int iLumaStride; + int iChromaStride; + int iLumaExpandedHeight; + int iChromaExpandedHeight; + imgpel **cur_imgY; // for more efficient get_block_luma + int no_ref; + int iCodingType; + // + char listXsize[MAX_NUM_SLICES][2]; + struct storable_picture **listX[MAX_NUM_SLICES][2]; + int layer_id; + + //! Edited by Joao Carreira + Slice *PicSlice; + struct motion_prop_info *Matrix_MV_Info; + int have_concealed_reference; //!< Control if a frame have concealed frames as references + int ref_pic_list_reordering_flag[2]; + int pixel_factor; //!< factor used to obtain the pixel values real = pixel / pixel_factor; + double mean_value; + + int have_pic; + +} StorablePicture; + +typedef StorablePicture *StorablePicturePtr; + +//! Frame Stores for Decoded Picture Buffer +typedef struct frame_store +{ + int is_used; //!< 0=empty; 1=top; 2=bottom; 3=both fields (or frame) + int is_reference; //!< 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used + int temp_is_reference; //!< temp variable of is_reference for motion copy erro concealment + + int is_long_term; //!< 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used + int is_orig_reference; //!< original marking by nal_ref_idc: 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used + + int is_non_existent; + + unsigned frame_num; + unsigned recovery_frame; + + int frame_num_wrap; + int long_term_frame_idx; + int is_output; + int poc; + + int frame_no; + + int unused_concealment; //!< picture error concealment + + StorablePicture *frame; + StorablePicture *top_field; + StorablePicture *bottom_field; + +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag[2]; + int anchor_pic_flag[2]; +#endif + int layer_id; +} FrameStore; + + +//! Decoded Picture Buffer +typedef struct decoded_picture_buffer +{ + VideoParameters *p_Vid; + InputParameters *p_Inp; + FrameStore **fs; + FrameStore **fs_ref; + FrameStore **fs_ltref; + FrameStore **fs_ilref; // inter-layer reference (for multi-layered codecs) + unsigned size_ilref; + unsigned size; + unsigned used_size; + unsigned used_size_concealment; //! Dpb used size for error concealment strategies + unsigned ref_frames_in_buffer; + unsigned ltref_frames_in_buffer; + int last_output_poc; +#if (MVC_EXTENSION_ENABLE) + int last_output_view_id; +#endif + int max_long_term_pic_idx; + + + int init_done; + int num_ref_frames; + + FrameStore *last_picture; + unsigned used_size_il; + int layer_id; + + //DPB related function; + +} DecodedPictureBuffer; + + +extern void init_dpb(VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb, int type); +extern void re_init_dpb(VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb, int type); +extern void free_dpb(DecodedPictureBuffer *p_Dpb); +extern FrameStore* alloc_frame_store(void); +extern void free_frame_store (FrameStore* f); +extern StorablePicture* alloc_storable_picture(VideoParameters *p_Vid, PictureStructure type, int size_x, int size_y, int size_x_cr, int size_y_cr, int is_output); +extern void free_storable_picture (StorablePicture* p); +extern void store_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p); +extern StorablePicture* get_short_term_pic (Slice *currSlice, DecodedPictureBuffer *p_Dpb, int picNum); + +#if (MVC_EXTENSION_ENABLE) +extern void idr_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p); +extern void flush_dpbs(DecodedPictureBuffer **p_Dpb, int nLayers); +extern int GetMaxDecFrameBuffering(VideoParameters *p_Vid); +extern void append_interview_list(DecodedPictureBuffer *p_Dpb, + PictureStructure currPicStructure, int list_idx, + FrameStore **list, int *listXsize, int currPOC, + int curr_view_id, int anchor_pic_flag); +#endif + +extern void unmark_for_reference(FrameStore* fs); +extern void unmark_for_long_term_reference(FrameStore* fs); +extern void remove_frame_from_dpb(DecodedPictureBuffer *p_Dpb, int pos); + +extern void flush_dpb(DecodedPictureBuffer *p_Dpb); +extern void init_lists_p_slice (Slice *currSlice); +extern void init_lists_b_slice (Slice *currSlice); +extern void init_lists_i_slice (Slice *currSlice); +extern void update_pic_num (Slice *currSlice); + +extern void dpb_split_field (VideoParameters *p_Vid, FrameStore *fs); +extern void dpb_combine_field (VideoParameters *p_Vid, FrameStore *fs); +extern void dpb_combine_field_yuv(VideoParameters *p_Vid, FrameStore *fs); + +extern void reorder_ref_pic_list(Slice *currSlice, int cur_list); + +extern void init_mbaff_lists (VideoParameters *p_Vid, Slice *currSlice); +extern void alloc_ref_pic_list_reordering_buffer(Slice *currSlice); +extern void free_ref_pic_list_reordering_buffer(Slice *currSlice); + +extern void fill_frame_num_gap(VideoParameters *p_Vid, Slice *pSlice); + +extern void compute_colocated (Slice *currSlice, StorablePicture **listX[6]); + + +extern int init_img_data(VideoParameters *p_Vid, ImageData *p_ImgData, seq_parameter_set_rbsp_t *sps); +extern void free_img_data(VideoParameters *p_Vid, ImageData *p_ImgData); +extern void pad_dec_picture(VideoParameters *p_Vid, StorablePicture *dec_picture); +extern void pad_buf(imgpel *pImgBuf, int iWidth, int iHeight, int iStride, int iPadX, int iPadY); +extern void process_picture_in_dpb_s(VideoParameters *p_Vid, StorablePicture *p_pic); +extern StorablePicture * clone_storable_picture( VideoParameters *p_Vid, StorablePicture *p_pic ); +extern void store_proc_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p); +extern void check_for_previous_interview_frames(DecodedPictureBuffer *p_Dpb, StorablePicture* p); + +//! Debug porpose +extern void dump_ref_lists(Slice *currSlice); +extern void dump_dpb(DecodedPictureBuffer *p_Dpb); +#endif + diff --git a/ldecod/inc/mbuffer_mvc.h b/ldecod/inc/mbuffer_mvc.h new file mode 100644 index 0000000..5cc17cb --- /dev/null +++ b/ldecod/inc/mbuffer_mvc.h @@ -0,0 +1,37 @@ + +/*! + *********************************************************************** + * \file + * mbuffer_mvc.h + * + * \brief + * MVC Frame buffer functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Athanasios Leontaris + * - Karsten Suehring + * - Alexis Michael Tourapis + * + *********************************************************************** + */ +#ifndef _MBUFFER_MVC_H_ +#define _MBUFFER_MVC_H_ + +#include "global.h" + +#if (MVC_EXTENSION_ENABLE) +extern void reorder_lists_mvc (Slice * currSlice, int currPOC); +extern void init_lists_p_slice_mvc(Slice *currSlice); +extern void init_lists_b_slice_mvc(Slice *currSlice); +extern void init_lists_i_slice_mvc(Slice *currSlice); + +extern void reorder_ref_pic_list_mvc(Slice *currSlice, int cur_list, int **anchor_ref, int **non_anchor_ref, + int view_id, int anchor_pic_flag, int currPOC, int listidx); + +extern void reorder_short_term(Slice *currSlice, int cur_list, int num_ref_idx_lX_active_minus1, int picNumLX, int *refIdxLX, int currViewID); +extern void reorder_long_term(Slice *currSlice, StorablePicture **RefPicListX, int num_ref_idx_lX_active_minus1, int LongTermPicNum, int *refIdxLX, int currViewID); +#endif + +#endif + diff --git a/ldecod/inc/mc_prediction.h b/ldecod/inc/mc_prediction.h new file mode 100644 index 0000000..f7d0f89 --- /dev/null +++ b/ldecod/inc/mc_prediction.h @@ -0,0 +1,33 @@ + +/*! + ************************************************************************************* + * \file mc_prediction.h + * + * \brief + * definitions for motion compensated prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#ifndef _MC_PREDICTION_H_ +#define _MC_PREDICTION_H_ + +#include "global.h" +#include "mbuffer.h" + +extern int allocate_pred_mem(Slice *currSlice); +extern void free_pred_mem (Slice *currSlice); + +extern void get_block_luma(StorablePicture *curr_ref, int x_pos, int y_pos, int block_size_x, int block_size_y, imgpel **block, + int shift_x,int maxold_x,int maxold_y,int **tmp_res,int max_imgpel_value,imgpel no_ref_value,Macroblock *currMB); + +extern void intra_cr_decoding (Macroblock *currMB, int yuv); +extern void prepare_direct_params(Macroblock *currMB, StorablePicture *dec_picture, MotionVector *pmvl0, MotionVector *pmvl1,char *l0_rFrame, char *l1_rFrame); +extern void perform_mc (Macroblock *currMB, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int i, int j, int block_size_x, int block_size_y); +#endif + diff --git a/ldecod/inc/nalu.h b/ldecod/inc/nalu.h new file mode 100644 index 0000000..545f592 --- /dev/null +++ b/ldecod/inc/nalu.h @@ -0,0 +1,27 @@ + +/*! + ************************************************************************************** + * \file + * nalu.h + * \brief + * Common NALU support functions + * + * \date 25 November 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + *************************************************************************************** + */ + + +#ifndef _NALU_H_ +#define _NALU_H_ + +#include "nalucommon.h" + +extern void CheckZeroByteNonVCL(VideoParameters *p_Vid, NALU_t *nalu); +extern void CheckZeroByteVCL (VideoParameters *p_Vid, NALU_t *nalu); + +extern int read_next_nalu(VideoParameters *p_Vid, NALU_t *nalu); + +#endif diff --git a/ldecod/inc/output.h b/ldecod/inc/output.h new file mode 100644 index 0000000..6439995 --- /dev/null +++ b/ldecod/inc/output.h @@ -0,0 +1,26 @@ + +/*! + ************************************************************************************** + * \file + * output.h + * \brief + * Picture writing routine headers + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + *************************************************************************************** + */ + +#ifndef _OUTPUT_H_ +#define _OUTPUT_H_ + + +extern void write_stored_frame(VideoParameters *p_Vid, FrameStore *fs, int p_out); +extern void direct_output (VideoParameters *p_Vid, StorablePicture *p, int p_out); +extern void init_out_buffer (VideoParameters *p_Vid); +extern void uninit_out_buffer (VideoParameters *p_Vid); +#if (PAIR_FIELDS_IN_OUTPUT) +extern void flush_pending_output(VideoParameters *p_Vid, int p_out); +#endif +extern void init_output(CodingParameters *p_CodingParams, int symbol_size_in_bytes); +#endif //_OUTPUT_H_ diff --git a/ldecod/inc/parset.h b/ldecod/inc/parset.h new file mode 100644 index 0000000..7dc3b8a --- /dev/null +++ b/ldecod/inc/parset.h @@ -0,0 +1,68 @@ + +/*! + ************************************************************************************** + * \file + * parset.h + * \brief + * Picture and Sequence Parameter Sets, decoder operations + * + * \date 25 November 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + *************************************************************************************** + */ + + +#ifndef _PARSET_H_ +#define _PARSET_H_ + +#include "parsetcommon.h" +#include "nalucommon.h" + +static const byte ZZ_SCAN[16] = +{ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +static const byte ZZ_SCAN8[64] = +{ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +extern void Scaling_List(int *scalingList, int sizeOfScalingList, Boolean *UseDefaultScalingMatrix, Bitstream *s); + +extern void InitVUI(seq_parameter_set_rbsp_t *sps); +extern int ReadVUI(DataPartition *p, seq_parameter_set_rbsp_t *sps); +extern int ReadHRDParameters(DataPartition *p, hrd_parameters_t *hrd); + +extern void PPSConsistencyCheck (pic_parameter_set_rbsp_t *pps); +extern void SPSConsistencyCheck (seq_parameter_set_rbsp_t *sps); + +extern void MakePPSavailable (VideoParameters *p_Vid, int id, pic_parameter_set_rbsp_t *pps); +extern void MakeSPSavailable (VideoParameters *p_Vid, int id, seq_parameter_set_rbsp_t *sps); + +extern void ProcessSPS (VideoParameters *p_Vid, NALU_t *nalu); +extern void ProcessPPS (VideoParameters *p_Vid, NALU_t *nalu); + +extern void CleanUpPPS(VideoParameters *p_Vid); + +extern void activate_sps (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps); +extern void activate_pps (VideoParameters *p_Vid, pic_parameter_set_rbsp_t *pps); + +extern void UseParameterSet (Slice *currSlice); + +#if (MVC_EXTENSION_ENABLE) +extern void SubsetSPSConsistencyCheck (subset_seq_parameter_set_rbsp_t *subset_sps); +extern void ProcessSubsetSPS (VideoParameters *p_Vid, NALU_t *nalu); + +extern void mvc_vui_parameters_extension(MVCVUI_t *pMVCVUI, Bitstream *s); +extern void seq_parameter_set_mvc_extension(subset_seq_parameter_set_rbsp_t *subset_sps, Bitstream *s); +extern void init_subset_sps_list(subset_seq_parameter_set_rbsp_t *subset_sps_list, int iSize); +extern void reset_subset_sps(subset_seq_parameter_set_rbsp_t *subset_sps); +extern int GetBaseViewId(VideoParameters *p_Vid, subset_seq_parameter_set_rbsp_t **subset_sps); +extern void get_max_dec_frame_buf_size(seq_parameter_set_rbsp_t *sps); +#endif + +#endif diff --git a/ldecod/inc/quant.h b/ldecod/inc/quant.h new file mode 100644 index 0000000..64dcc0c --- /dev/null +++ b/ldecod/inc/quant.h @@ -0,0 +1,169 @@ + +/*! + ************************************************************************ + * \file quant.h + * + * \brief + * definitions for quantization functions + * + * \author + * + ************************************************************************ + */ + +#ifndef _QUANT_H_ +#define _QUANT_H_ + +// exported variables +static const int dequant_coef8[6][8][8] = +{ + { + {20, 19, 25, 19, 20, 19, 25, 19}, + {19, 18, 24, 18, 19, 18, 24, 18}, + {25, 24, 32, 24, 25, 24, 32, 24}, + {19, 18, 24, 18, 19, 18, 24, 18}, + {20, 19, 25, 19, 20, 19, 25, 19}, + {19, 18, 24, 18, 19, 18, 24, 18}, + {25, 24, 32, 24, 25, 24, 32, 24}, + {19, 18, 24, 18, 19, 18, 24, 18} + }, + { + {22, 21, 28, 21, 22, 21, 28, 21}, + {21, 19, 26, 19, 21, 19, 26, 19}, + {28, 26, 35, 26, 28, 26, 35, 26}, + {21, 19, 26, 19, 21, 19, 26, 19}, + {22, 21, 28, 21, 22, 21, 28, 21}, + {21, 19, 26, 19, 21, 19, 26, 19}, + {28, 26, 35, 26, 28, 26, 35, 26}, + {21, 19, 26, 19, 21, 19, 26, 19} + }, + { + {26, 24, 33, 24, 26, 24, 33, 24}, + {24, 23, 31, 23, 24, 23, 31, 23}, + {33, 31, 42, 31, 33, 31, 42, 31}, + {24, 23, 31, 23, 24, 23, 31, 23}, + {26, 24, 33, 24, 26, 24, 33, 24}, + {24, 23, 31, 23, 24, 23, 31, 23}, + {33, 31, 42, 31, 33, 31, 42, 31}, + {24, 23, 31, 23, 24, 23, 31, 23} + }, + { + {28, 26, 35, 26, 28, 26, 35, 26}, + {26, 25, 33, 25, 26, 25, 33, 25}, + {35, 33, 45, 33, 35, 33, 45, 33}, + {26, 25, 33, 25, 26, 25, 33, 25}, + {28, 26, 35, 26, 28, 26, 35, 26}, + {26, 25, 33, 25, 26, 25, 33, 25}, + {35, 33, 45, 33, 35, 33, 45, 33}, + {26, 25, 33, 25, 26, 25, 33, 25} + }, + { + {32, 30, 40, 30, 32, 30, 40, 30}, + {30, 28, 38, 28, 30, 28, 38, 28}, + {40, 38, 51, 38, 40, 38, 51, 38}, + {30, 28, 38, 28, 30, 28, 38, 28}, + {32, 30, 40, 30, 32, 30, 40, 30}, + {30, 28, 38, 28, 30, 28, 38, 28}, + {40, 38, 51, 38, 40, 38, 51, 38}, + {30, 28, 38, 28, 30, 28, 38, 28} + }, + { + {36, 34, 46, 34, 36, 34, 46, 34}, + {34, 32, 43, 32, 34, 32, 43, 32}, + {46, 43, 58, 43, 46, 43, 58, 43}, + {34, 32, 43, 32, 34, 32, 43, 32}, + {36, 34, 46, 34, 36, 34, 46, 34}, + {34, 32, 43, 32, 34, 32, 43, 32}, + {46, 43, 58, 43, 46, 43, 58, 43}, + {34, 32, 43, 32, 34, 32, 43, 32} + } +}; + + +//! Dequantization coefficients +static const int dequant_coef[6][4][4] = { + { + { 10, 13, 10, 13}, + { 13, 16, 13, 16}, + { 10, 13, 10, 13}, + { 13, 16, 13, 16}}, + { + { 11, 14, 11, 14}, + { 14, 18, 14, 18}, + { 11, 14, 11, 14}, + { 14, 18, 14, 18}}, + { + { 13, 16, 13, 16}, + { 16, 20, 16, 20}, + { 13, 16, 13, 16}, + { 16, 20, 16, 20}}, + { + { 14, 18, 14, 18}, + { 18, 23, 18, 23}, + { 14, 18, 14, 18}, + { 18, 23, 18, 23}}, + { + { 16, 20, 16, 20}, + { 20, 25, 20, 25}, + { 16, 20, 16, 20}, + { 20, 25, 20, 25}}, + { + { 18, 23, 18, 23}, + { 23, 29, 23, 29}, + { 18, 23, 18, 23}, + { 23, 29, 23, 29}} +}; + +static const int quant_coef[6][4][4] = { + { + { 13107, 8066, 13107, 8066}, + { 8066, 5243, 8066, 5243}, + { 13107, 8066, 13107, 8066}, + { 8066, 5243, 8066, 5243}}, + { + { 11916, 7490, 11916, 7490}, + { 7490, 4660, 7490, 4660}, + { 11916, 7490, 11916, 7490}, + { 7490, 4660, 7490, 4660}}, + { + { 10082, 6554, 10082, 6554}, + { 6554, 4194, 6554, 4194}, + { 10082, 6554, 10082, 6554}, + { 6554, 4194, 6554, 4194}}, + { + { 9362, 5825, 9362, 5825}, + { 5825, 3647, 5825, 3647}, + { 9362, 5825, 9362, 5825}, + { 5825, 3647, 5825, 3647}}, + { + { 8192, 5243, 8192, 5243}, + { 5243, 3355, 5243, 3355}, + { 8192, 5243, 8192, 5243}, + { 5243, 3355, 5243, 3355}}, + { + { 7282, 4559, 7282, 4559}, + { 4559, 2893, 4559, 2893}, + { 7282, 4559, 7282, 4559}, + { 4559, 2893, 4559, 2893}} +}; + +// SP decoding parameter (EQ. 8-425) +static const int A[4][4] = { + { 16, 20, 16, 20}, + { 20, 25, 20, 25}, + { 16, 20, 16, 20}, + { 20, 25, 20, 25} +}; + +// exported functions +// quantization initialization +extern void init_qp_process (CodingParameters *cps); +extern void free_qp_matrices(CodingParameters *cps); + +// For Q-matrix +extern void assign_quant_params (Slice *currslice); +extern void CalculateQuant4x4Param(Slice *currslice); +extern void CalculateQuant8x8Param(Slice *currslice); + +#endif + diff --git a/ldecod/inc/report_dec.h b/ldecod/inc/report_dec.h new file mode 100644 index 0000000..ac027dc --- /dev/null +++ b/ldecod/inc/report_dec.h @@ -0,0 +1,23 @@ + +/*! + ************************************************************************ + * \file report_dec.h + * + * \brief + * headers for decoder reports + * + * \author + * João Carreira + ************************************************************************ + */ + +#ifndef _REPORT_DEC_H_ +#define _REPORT_DEC_H_ + + +extern void init_report (InputParameters *p_Inp); +extern void FinalReport(VideoParameters *p_Vid); +extern void report_to_logfile(VideoParameters *p_Vid); +extern void report_stats (VideoParameters *p_Vid); + +#endif \ No newline at end of file diff --git a/ldecod/inc/rtp.h b/ldecod/inc/rtp.h new file mode 100644 index 0000000..2171a95 --- /dev/null +++ b/ldecod/inc/rtp.h @@ -0,0 +1,46 @@ + +/*! + ************************************************************************************* + * \file rtp.h + * + * \brief + * Prototypes for rtp.c + ************************************************************************************* + */ + +#ifndef _RTP_H_ +#define _RTP_H_ + +#include "nalucommon.h" + +#define MAXRTPPAYLOADLEN (65536 - 40) //!< Maximum payload size of an RTP packet */ +#define MAXRTPPACKETSIZE (65536 - 28) //!< Maximum size of an RTP packet incl. header */ +#define H264PAYLOADTYPE 105 //!< RTP paylaod type fixed here for simplicity*/ +#define H264SSRC 0x12345678 //!< SSRC, chosen to simplify debugging */ +#define RTP_TR_TIMESTAMP_MULT 1000 //!< should be something like 27 Mhz / 29.97 Hz */ + +typedef struct +{ + unsigned int v; //!< Version, 2 bits, MUST be 0x2 + unsigned int p; //!< Padding bit, Padding MUST NOT be used + unsigned int x; //!< Extension, MUST be zero + unsigned int cc; /*!< CSRC count, normally 0 in the absence + of RTP mixers */ + unsigned int m; //!< Marker bit + unsigned int pt; //!< 7 bits, Payload Type, dynamically established + uint16 seq; /*!< RTP sequence number, incremented by one for + each sent packet */ + unsigned int timestamp; //!< timestamp, 27 MHz for H.264 + unsigned int ssrc; //!< Synchronization Source, chosen randomly + byte * payload; //!< the payload including payload headers + unsigned int paylen; //!< length of payload in bytes + byte * packet; //!< complete packet including header and payload + unsigned int packlen; //!< length of packet, typically paylen+12 +} RTPpacket_t; + +void DumpRTPHeader (RTPpacket_t *p); +int GetRTPNALU (VideoParameters *p_Vid, NALU_t *nalu, int BitStreamFile); +void OpenRTPFile (char *fn, int *p_BitStreamFile); +void CloseRTPFile(int *p_BitStreamFile); + +#endif diff --git a/ldecod/inc/sei.h b/ldecod/inc/sei.h new file mode 100644 index 0000000..9145c4f --- /dev/null +++ b/ldecod/inc/sei.h @@ -0,0 +1,144 @@ + +/*! + ************************************************************************************* + * \file sei.h + * + * \brief + * Prototypes for sei.c + ************************************************************************************* + */ + +#ifndef SEI_H +#define SEI_H + +typedef enum { + SEI_BUFFERING_PERIOD = 0, + SEI_PIC_TIMING, + SEI_PAN_SCAN_RECT, + SEI_FILLER_PAYLOAD, + SEI_USER_DATA_REGISTERED_ITU_T_T35, + SEI_USER_DATA_UNREGISTERED, + SEI_RECOVERY_POINT, + SEI_DEC_REF_PIC_MARKING_REPETITION, + SEI_SPARE_PIC, + SEI_SCENE_INFO, + SEI_SUB_SEQ_INFO, + SEI_SUB_SEQ_LAYER_CHARACTERISTICS, + SEI_SUB_SEQ_CHARACTERISTICS, + SEI_FULL_FRAME_FREEZE, + SEI_FULL_FRAME_FREEZE_RELEASE, + SEI_FULL_FRAME_SNAPSHOT, + SEI_PROGRESSIVE_REFINEMENT_SEGMENT_START, + SEI_PROGRESSIVE_REFINEMENT_SEGMENT_END, + SEI_MOTION_CONSTRAINED_SLICE_GROUP_SET, + SEI_FILM_GRAIN_CHARACTERISTICS, + SEI_DEBLOCKING_FILTER_DISPLAY_PREFERENCE, + SEI_STEREO_VIDEO_INFO, + SEI_POST_FILTER_HINTS, + SEI_TONE_MAPPING, + SEI_SCALABILITY_INFO, + SEI_SUB_PIC_SCALABLE_LAYER, + SEI_NON_REQUIRED_LAYER_REP, + SEI_PRIORITY_LAYER_INFO, + SEI_LAYERS_NOT_PRESENT, + SEI_LAYER_DEPENDENCY_CHANGE, + SEI_SCALABLE_NESTING, + SEI_BASE_LAYER_TEMPORAL_HRD, + SEI_QUALITY_LAYER_INTEGRITY_CHECK, + SEI_REDUNDANT_PIC_PROPERTY, + SEI_TL0_DEP_REP_INDEX, + SEI_TL_SWITCHING_POINT, + SEI_PARALLEL_DECODING_INFO, + SEI_MVC_SCALABLE_NESTING, + SEI_VIEW_SCALABILITY_INFO, + SEI_MULTIVIEW_SCENE_INFO, + SEI_MULTIVIEW_ACQUISITION_INFO, + SEI_NON_REQUIRED_VIEW_COMPONENT, + SEI_VIEW_DEPENDENCY_CHANGE, + SEI_OPERATION_POINTS_NOT_PRESENT, + SEI_BASE_VIEW_TEMPORAL_HRD, + SEI_FRAME_PACKING_ARRANGEMENT, + + SEI_MAX_ELEMENTS //!< number of maximum syntax elements +} SEI_type; + +#define MAX_FN 256 +// tone mapping information +#define MAX_CODED_BIT_DEPTH 12 +#define MAX_SEI_BIT_DEPTH 12 +#define MAX_NUM_PIVOTS (1<> %file% +) +pause \ No newline at end of file diff --git a/ldecod/ldecod.props b/ldecod/ldecod.props new file mode 100644 index 0000000..49f1286 --- /dev/null +++ b/ldecod/ldecod.props @@ -0,0 +1,17 @@ + + + + + + + + Ws2_32.lib;%(AdditionalDependencies) + + + + + ldecod\inc;lcommon\inc;ldecod\inc\ferc + + + + \ No newline at end of file diff --git a/ldecod/src/annexb.c b/ldecod/src/annexb.c new file mode 100644 index 0000000..628a0c5 --- /dev/null +++ b/ldecod/src/annexb.c @@ -0,0 +1,353 @@ + +/*! + ************************************************************************************* + * \file annexb.c + * + * \brief + * Annex B Byte Stream format + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + ************************************************************************************* + */ + +#include "global.h" +#include "annexb.h" +#include "memalloc.h" +#include "fast_memory.h" + +static const int IOBUFFERSIZE = 512*1024; //65536; + +void malloc_annex_b(VideoParameters *p_Vid, ANNEXB_t **p_annex_b) +{ + if ( ((*p_annex_b) = (ANNEXB_t *) calloc(1, sizeof(ANNEXB_t))) == NULL) + { + snprintf(errortext, ET_SIZE, "Memory allocation for Annex_B file failed"); + error(errortext,100); + } + if (((*p_annex_b)->Buf = (byte*) malloc(p_Vid->nalu->max_size)) == NULL) + { + error("malloc_annex_b: Buf", 101); + } +} + + +void init_annex_b(ANNEXB_t *annex_b) +{ + annex_b->BitStreamFile = -1; + annex_b->iobuffer = NULL; + annex_b->iobufferread = NULL; + annex_b->bytesinbuffer = 0; + annex_b->is_eof = FALSE; + annex_b->IsFirstByteStreamNALU = 1; + annex_b->nextstartcodebytes = 0; +} + +void free_annex_b(ANNEXB_t **p_annex_b) +{ + free((*p_annex_b)->Buf); + (*p_annex_b)->Buf = NULL; + free(*p_annex_b); + *p_annex_b = NULL; +} + +/*! +************************************************************************ +* \brief +* fill IO buffer +************************************************************************ +*/ +static inline int getChunk(ANNEXB_t *annex_b) +{ + unsigned int readbytes = read (annex_b->BitStreamFile, annex_b->iobuffer, annex_b->iIOBufferSize); + if (0==readbytes) + { + annex_b->is_eof = TRUE; + return 0; + } + + annex_b->bytesinbuffer = readbytes; + annex_b->iobufferread = annex_b->iobuffer; + return readbytes; +} + +/*! +************************************************************************ +* \brief +* returns a byte from IO buffer +************************************************************************ +*/ +static inline byte getfbyte(ANNEXB_t *annex_b) +{ + if (0 == annex_b->bytesinbuffer) + { + if (0 == getChunk(annex_b)) + return 0; + } + annex_b->bytesinbuffer--; + return (*annex_b->iobufferread++); +} + +/*! + ************************************************************************ + * \brief + * returns if new start code is found at byte aligned position buf. + * new-startcode is of form N 0x00 bytes, followed by a 0x01 byte. + * + * \return + * 1 if start-code is found or \n + * 0, indicating that there is no start code + * + * \param Buf + * pointer to byte-stream + * \param zeros_in_startcode + * indicates number of 0x00 bytes in start-code. + ************************************************************************ + */ +static inline int FindStartCode (unsigned char *Buf, int zeros_in_startcode) +{ + int i; + + for (i = 0; i < zeros_in_startcode; i++) + { + if(*(Buf++) != 0) + { + return 0; + } + } + + if(*Buf != 1) + return 0; + + return 1; +} + + +/*! + ************************************************************************ + * \brief + * Returns the size of the NALU (bits between start codes in case of + * Annex B. nalu->buf and nalu->len are filled. Other field in + * nalu-> remain uninitialized (will be taken care of by NALUtoRBSP. + * + * \return + * 0 if there is nothing any more to read (EOF) + * -1 in case of any error + * + * \note Side-effect: Returns length of start-code in bytes. + * + * \note + * get_annex_b_NALU expects start codes at byte aligned positions in the file + * + ************************************************************************ + */ + +int get_annex_b_NALU (VideoParameters *p_Vid, NALU_t *nalu, ANNEXB_t *annex_b) +{ + int i; + int info2 = 0, info3 = 0, pos = 0; + int StartCodeFound = 0; + int LeadingZero8BitsCount = 0; + byte *pBuf = annex_b->Buf; + + if (annex_b->nextstartcodebytes != 0) + { + for (i=0; inextstartcodebytes-1; i++) + { + (*pBuf++) = 0; + pos++; + } + (*pBuf++) = 1; + pos++; + } + else + { + while(!annex_b->is_eof) + { + pos++; + if ((*(pBuf++)= getfbyte(annex_b))!= 0) + break; + } + } + if(annex_b->is_eof == TRUE) + { + if(pos==0) + { + return 0; + } + else + { + printf( "get_annex_b_NALU can't read start code\n"); + return -1; + } + } + + if(*(pBuf - 1) != 1 || pos < 3) + { + printf ("get_annex_b_NALU: no Start Code at the beginning of the NALU, return -1\n"); + return -1; + } + + if (pos == 3) + { + nalu->startcodeprefix_len = 3; + } + else + { + LeadingZero8BitsCount = pos - 4; + nalu->startcodeprefix_len = 4; + } + + //the 1st byte stream NAL unit can has leading_zero_8bits, but subsequent ones are not + //allowed to contain it since these zeros(if any) are considered trailing_zero_8bits + //of the previous byte stream NAL unit. + if(!annex_b->IsFirstByteStreamNALU && LeadingZero8BitsCount > 0) + { + printf ("get_annex_b_NALU: The leading_zero_8bits syntax can only be present in the first byte stream NAL unit, return -1\n"); + return -1; + } + + LeadingZero8BitsCount = pos; + annex_b->IsFirstByteStreamNALU = 0; + + while (!StartCodeFound) + { + if (annex_b->is_eof == TRUE) + { + pBuf -= 2; + while(*(pBuf--)==0) + pos--; + + + nalu->len = (pos - 1) - LeadingZero8BitsCount; + memcpy (nalu->buf, annex_b->Buf + LeadingZero8BitsCount, nalu->len); + nalu->forbidden_bit = (*(nalu->buf) >> 7) & 1; + nalu->nal_reference_idc = (NalRefIdc) ((*(nalu->buf) >> 5) & 3); + nalu->nal_unit_type = (NaluType) ((*(nalu->buf)) & 0x1f); + annex_b->nextstartcodebytes = 0; + + // printf ("get_annex_b_NALU, eof case: pos %d nalu->len %d, nalu->reference_idc %d, nal_unit_type %d \n", pos, nalu->len, nalu->nal_reference_idc, nalu->nal_unit_type); + +#if TRACE + fprintf (p_Dec->p_trace, "\n\nLast NALU in File\n\n"); + fprintf (p_Dec->p_trace, "Annex B NALU w/ %s startcode, len %d, forbidden_bit %d, nal_reference_idc %d, nal_unit_type %d\n\n", + nalu->startcodeprefix_len == 4?"long":"short", nalu->len, nalu->forbidden_bit, nalu->nal_reference_idc, nalu->nal_unit_type); + fflush (p_Dec->p_trace); +#endif + return (pos - 1); + } + + pos++; + *(pBuf ++) = getfbyte(annex_b); + info3 = FindStartCode(pBuf - 4, 3); + if(info3 != 1) + { + info2 = FindStartCode(pBuf - 3, 2); + StartCodeFound = info2 & 0x01; + } + else + StartCodeFound = 1; + } + + // Here, we have found another start code (and read length of startcode bytes more than we should + // have. Hence, go back in the file + if(info3 == 1) //if the detected start code is 00 00 01, trailing_zero_8bits is sure not to be present + { + pBuf -= 5; + while(*(pBuf--) == 0) + pos--; + annex_b->nextstartcodebytes = 4; + } + else if (info2 == 1) + annex_b->nextstartcodebytes = 3; + else + { + printf(" Panic: Error in next start code search \n"); + return -1; + } + + pos -= annex_b->nextstartcodebytes; + + // Here the leading zeros(if any), Start code, the complete NALU, trailing zeros(if any) + // and the next start code is in the Buf. + // The size of Buf is pos - rewind, pos are the number of bytes excluding the next + // start code, and (pos) - LeadingZero8BitsCount + // is the size of the NALU. + + nalu->len = pos - LeadingZero8BitsCount; + fast_memcpy (nalu->buf, annex_b->Buf + LeadingZero8BitsCount, nalu->len); + nalu->forbidden_bit = (*(nalu->buf) >> 7) & 1; + nalu->nal_reference_idc = (NalRefIdc) ((*(nalu->buf) >> 5) & 3); + nalu->nal_unit_type = (NaluType) ((*(nalu->buf)) & 0x1f); + nalu->lost_packets = 0; + + + //printf ("get_annex_b_NALU, regular case: pos %d nalu->len %d, nalu->reference_idc %d, nal_unit_type %d \n", pos, nalu->len, nalu->nal_reference_idc, nalu->nal_unit_type); +#if TRACE + fprintf (p_Dec->p_trace, "\n\nAnnex B NALU w/ %s startcode, len %d, forbidden_bit %d, nal_reference_idc %d, nal_unit_type %d\n\n", + nalu->startcodeprefix_len == 4?"long":"short", nalu->len, nalu->forbidden_bit, nalu->nal_reference_idc, nalu->nal_unit_type); + fflush (p_Dec->p_trace); +#endif + + return (pos); + +} + + + +/*! + ************************************************************************ + * \brief + * Opens the bit stream file named fn + * \return + * none + ************************************************************************ + */ +void open_annex_b (char *fn, ANNEXB_t *annex_b) +{ + if (NULL != annex_b->iobuffer) + { + error ("open_annex_b: tried to open Annex B file twice",500); + } + if ((annex_b->BitStreamFile = open(fn, OPENFLAGS_READ)) == -1) + { + snprintf (errortext, ET_SIZE, "Cannot open Annex B ByteStream file '%s'", fn); + error(errortext,500); + } + + annex_b->iIOBufferSize = IOBUFFERSIZE * sizeof (byte); + annex_b->iobuffer = malloc (annex_b->iIOBufferSize); + if (NULL == annex_b->iobuffer) + { + error ("open_annex_b: cannot allocate IO buffer",500); + } + annex_b->is_eof = FALSE; + getChunk(annex_b); +} + + +/*! + ************************************************************************ + * \brief + * Closes the bit stream file + ************************************************************************ + */ +void close_annex_b(ANNEXB_t *annex_b) +{ + if (annex_b->BitStreamFile != -1) + { + close(annex_b->BitStreamFile); + annex_b->BitStreamFile = - 1; + } + free (annex_b->iobuffer); + annex_b->iobuffer = NULL; +} + + +void reset_annex_b(ANNEXB_t *annex_b) +{ + annex_b->is_eof = FALSE; + annex_b->bytesinbuffer = 0; + annex_b->iobufferread = annex_b->iobuffer; +} diff --git a/ldecod/src/biaridecod.c b/ldecod/src/biaridecod.c new file mode 100644 index 0000000..b900495 --- /dev/null +++ b/ldecod/src/biaridecod.c @@ -0,0 +1,314 @@ +/*! + ************************************************************************************* + * \file biaridecod.c + * + * \brief + * Binary arithmetic decoder routines. + * + * This modified implementation of the M Coder is based on JVT-U084 + * with the choice of M_BITS = 16. + * + * \date + * 21. Oct 2000 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Gabi Blaettermann + * - Gunnar Marten + ************************************************************************************* + */ + +#include "global.h" +#include "memalloc.h" +#include "biaridecod.h" + + +#define B_BITS 10 // Number of bits to represent the whole coding interval +#define HALF 0x01FE //(1 << (B_BITS-1)) - 2 +#define QUARTER 0x0100 //(1 << (B_BITS-2)) + +/*! + ************************************************************************ + * \brief + * Allocates memory for the DecodingEnvironment struct + * \return DecodingContextPtr + * allocates memory + ************************************************************************ + */ +DecodingEnvironmentPtr arideco_create_decoding_environment() +{ + DecodingEnvironmentPtr dep; + + if ((dep = calloc(1,sizeof(DecodingEnvironment))) == NULL) + no_mem_exit("arideco_create_decoding_environment: dep"); + return dep; +} + + +/*! + *********************************************************************** + * \brief + * Frees memory of the DecodingEnvironment struct + *********************************************************************** + */ +void arideco_delete_decoding_environment(DecodingEnvironmentPtr dep) +{ + if (dep == NULL) + { + snprintf(errortext, ET_SIZE, "Error freeing dep (NULL pointer)"); + error (errortext, 200); + } + else + free(dep); +} + +/*! + ************************************************************************ + * \brief + * finalize arithetic decoding(): + ************************************************************************ + */ +void arideco_done_decoding(DecodingEnvironmentPtr dep) +{ + (*dep->Dcodestrm_len)++; +#if(TRACE==2) + fprintf(p_trace, "done_decoding: %d\n", *dep->Dcodestrm_len); +#endif +} + +/*! + ************************************************************************ + * \brief + * read one byte from the bitstream + ************************************************************************ + */ +static inline unsigned int getbyte(DecodingEnvironmentPtr dep) +{ +#if(TRACE==2) + fprintf(p_trace, "get_byte: %d\n", (*dep->Dcodestrm_len)); +#endif + return dep->Dcodestrm[(*dep->Dcodestrm_len)++]; +} + +/*! + ************************************************************************ + * \brief + * read two bytes from the bitstream + ************************************************************************ + */ +static inline unsigned int getword(DecodingEnvironmentPtr dep) +{ + int *len = dep->Dcodestrm_len; + byte *p_code_strm = &dep->Dcodestrm[*len]; +#if(TRACE==2) + fprintf(p_trace, "get_byte: %d\n", *len); + fprintf(p_trace, "get_byte: %d\n", *len + 1); +#endif + *len += 2; + return ((*p_code_strm<<8) | *(p_code_strm + 1)); +} +/*! + ************************************************************************ + * \brief + * Initializes the DecodingEnvironment for the arithmetic coder + ************************************************************************ + */ +void arideco_start_decoding(DecodingEnvironmentPtr dep, unsigned char *code_buffer, + int firstbyte, int *code_len) +{ + + dep->Dcodestrm = code_buffer; + dep->Dcodestrm_len = code_len; + *dep->Dcodestrm_len = firstbyte; + + dep->Dvalue = getbyte(dep); + dep->Dvalue = (dep->Dvalue << 16) | getword(dep); // lookahead of 2 bytes: always make sure that bitstream buffer + // contains 2 more bytes than actual bitstream + dep->DbitsLeft = 15; + dep->Drange = HALF; + +#if (2==TRACE) + fprintf(p_trace, "value: %d firstbyte: %d code_len: %d\n", dep->Dvalue >> dep->DbitsLeft, firstbyte, *code_len); +#endif +} + + +/*! + ************************************************************************ + * \brief + * arideco_bits_read + ************************************************************************ + */ +int arideco_bits_read(DecodingEnvironmentPtr dep) +{ +#if (2==TRACE) + int tmp = ((*dep->Dcodestrm_len) << 3) - dep->DbitsLeft; + fprintf(p_trace, "tmp: %d\n", tmp); + return tmp; +#else + return (((*dep->Dcodestrm_len) << 3) - dep->DbitsLeft); +#endif +} + + +/*! +************************************************************************ +* \brief +* biari_decode_symbol(): +* \return +* the decoded symbol +************************************************************************ +*/ +unsigned int biari_decode_symbol(DecodingEnvironment *dep, BiContextType *bi_ct ) +{ + unsigned int bit = bi_ct->MPS; + unsigned int *value = &dep->Dvalue; + unsigned int *range = &dep->Drange; + uint16 *state = &bi_ct->state; + unsigned int rLPS = rLPS_table_64x4[*state][(*range>>6) & 0x03]; + int *DbitsLeft = &dep->DbitsLeft; + + *range -= rLPS; + + if(*value < (*range << *DbitsLeft)) //MPS + { + *state = AC_next_state_MPS_64[*state]; // next state + if( *range >= QUARTER ) + { + return (bit); + } + else + { + *range <<= 1; + (*DbitsLeft)--; + } + } + else // LPS + { + int renorm = renorm_table_32[(rLPS>>3) & 0x1F]; + *value -= (*range << *DbitsLeft); + + *range = (rLPS << renorm); + (*DbitsLeft) -= renorm; + + bit ^= 0x01; + if (!(*state)) // switch meaning of MPS if necessary + bi_ct->MPS ^= 0x01; + + *state = AC_next_state_LPS_64[*state]; // next state + } + + if( *DbitsLeft > 0 ) + { + return (bit); + } + else + { + *value <<= 16; + *value |= getword(dep); // lookahead of 2 bytes: always make sure that bitstream buffer + // contains 2 more bytes than actual bitstream + (*DbitsLeft) += 16; + + return (bit); + } +} + + +/*! + ************************************************************************ + * \brief + * biari_decode_symbol_eq_prob(): + * \return + * the decoded symbol + ************************************************************************ + */ +unsigned int biari_decode_symbol_eq_prob(DecodingEnvironmentPtr dep) +{ + int tmp_value; + unsigned int *value = &dep->Dvalue; + int *DbitsLeft = &dep->DbitsLeft; + + if(--(*DbitsLeft) == 0) + { + *value = (*value << 16) | getword( dep ); // lookahead of 2 bytes: always make sure that bitstream buffer + // contains 2 more bytes than actual bitstream + *DbitsLeft = 16; + } + tmp_value = *value - (dep->Drange << *DbitsLeft); + + if (tmp_value < 0) + { + return 0; + } + else + { + *value = tmp_value; + return 1; + } +} + +/*! + ************************************************************************ + * \brief + * biari_decode_symbol_final(): + * \return + * the decoded symbol + ************************************************************************ + */ +unsigned int biari_decode_final(DecodingEnvironmentPtr dep) +{ + unsigned int range = dep->Drange - 2; + int value = dep->Dvalue; + value -= (range << dep->DbitsLeft); + + if (value < 0) + { + if( range >= QUARTER ) + { + dep->Drange = range; + return 0; + } + else + { + dep->Drange = (range << 1); + if( --(dep->DbitsLeft) > 0 ) + return 0; + else + { + dep->Dvalue = (dep->Dvalue << 16) | getword( dep ); // lookahead of 2 bytes: always make sure that bitstream buffer + // contains 2 more bytes than actual bitstream + dep->DbitsLeft = 16; + return 0; + } + } + } + else + { + return 1; + } +} + +/*! + ************************************************************************ + * \brief + * Initializes a given context with some pre-defined probability state + ************************************************************************ + */ +void biari_init_context (int qp, BiContextTypePtr ctx, const char* ini) +{ + int pstate = ((ini[0]* qp )>>4) + ini[1]; + + if ( pstate >= 64 ) + { + pstate = imin(126, pstate); + ctx->state = (uint16) (pstate - 64); + ctx->MPS = 1; + } + else + { + pstate = imax(1, pstate); + ctx->state = (uint16) (63 - pstate); + ctx->MPS = 0; + } +} + diff --git a/ldecod/src/block.c b/ldecod/src/block.c new file mode 100644 index 0000000..64d16d8 --- /dev/null +++ b/ldecod/src/block.c @@ -0,0 +1,907 @@ + +/*! + *********************************************************************** + * \file + * block.c + * + * \brief + * Block functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langoy + * - Rickard Sjoberg + *********************************************************************** + */ + +#include "contributors.h" + +#include "global.h" +#include "block.h" +#include "blk_prediction.h" +#include "image.h" +#include "mb_access.h" +#include "transform.h" +#include "quant.h" +#include "memalloc.h" + +/*! + *********************************************************************** + * \brief + * Inverse 4x4 transformation, transforms cof to mb_rres + *********************************************************************** + */ +void itrans4x4(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< used color plane + int ioff, //!< index to 4x4 block + int joff) //!< index to 4x4 block +{ + Slice *currSlice = currMB->p_Slice; + int **mb_rres = currSlice->mb_rres[pl]; + + inverse4x4(currSlice->cof[pl],mb_rres,joff,ioff); + + sample_reconstruct (&currSlice->mb_rec[pl][joff], &currSlice->mb_pred[pl][joff], &mb_rres[joff], ioff, ioff, BLOCK_SIZE, BLOCK_SIZE, currMB->p_Vid->max_pel_value_comp[pl], DQ_BITS); +} + +/*! + **************************************************************************** + * \brief + * Inverse 4x4 lossless_qpprime transformation, transforms cof to mb_rres + **************************************************************************** + */ +void itrans4x4_ls(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< Color plane (for 4:4:4) + int ioff, //!< index to 4x4 block + int joff) //!< index to 4x4 block +{ + int i,j; + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel **mb_rec = currSlice->mb_rec[pl]; + int **mb_rres = currSlice->mb_rres [pl]; + + for (j = joff; j < joff + BLOCK_SIZE; ++j) + { + for (i = ioff; i < ioff + BLOCK_SIZE; ++i) + { + mb_rec[j][i] = (imgpel) iClip1(max_imgpel_value, mb_pred[j][i] + mb_rres[j][i]); + } + } +} + +/*! +************************************************************************ +* \brief +* Inverse residual DPCM for Intra lossless coding +* +************************************************************************ +*/ +void Inv_Residual_trans_4x4(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< used color plane + int ioff, //!< index to 4x4 block + int joff) //!< index to 4x4 block +{ + int i,j; + int temp[4][4]; + Slice *currSlice = currMB->p_Slice; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel **mb_rec = currSlice->mb_rec[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + int **cof = currSlice->cof[pl]; + + if(currMB->ipmode_DPCM == VERT_PRED) + { + for(i=0; i<4; ++i) + { + temp[0][i] = cof[joff + 0][ioff + i]; + temp[1][i] = cof[joff + 1][ioff + i] + temp[0][i]; + temp[2][i] = cof[joff + 2][ioff + i] + temp[1][i]; + temp[3][i] = cof[joff + 3][ioff + i] + temp[2][i]; + } + + for(i=0; i<4; ++i) + { + mb_rres[joff ][ioff + i]=temp[0][i]; + mb_rres[joff + 1][ioff + i]=temp[1][i]; + mb_rres[joff + 2][ioff + i]=temp[2][i]; + mb_rres[joff + 3][ioff + i]=temp[3][i]; + } + } + else if(currMB->ipmode_DPCM == HOR_PRED) + { + for(j=0; j<4; ++j) + { + temp[j][0] = cof[joff + j][ioff ]; + temp[j][1] = cof[joff + j][ioff + 1] + temp[j][0]; + temp[j][2] = cof[joff + j][ioff + 2] + temp[j][1]; + temp[j][3] = cof[joff + j][ioff + 3] + temp[j][2]; + } + + for(j=0; j<4; ++j) + { + mb_rres[joff + j][ioff ]=temp[j][0]; + mb_rres[joff + j][ioff + 1]=temp[j][1]; + mb_rres[joff + j][ioff + 2]=temp[j][2]; + mb_rres[joff + j][ioff + 3]=temp[j][3]; + } + } + else + { + for (j = joff; j < joff + BLOCK_SIZE; ++j) + for (i = ioff; i < ioff + BLOCK_SIZE; ++i) + mb_rres[j][i] = cof[j][i]; + } + + for (j = joff; j < joff + BLOCK_SIZE; ++j) + { + for (i = ioff; i < ioff + BLOCK_SIZE; ++i) + { + mb_rec[j][i] = (imgpel) (mb_rres[j][i] + mb_pred[j][i]); + } + } +} + +/*! +************************************************************************ +* \brief +* Inverse residual DPCM for Intra lossless coding +* +* \par Input: +* ioff_x,joff_y: Block position inside a macro block (0,8). +************************************************************************ +*/ +//For residual DPCM +void Inv_Residual_trans_8x8(Macroblock *currMB, ColorPlane pl, int ioff,int joff) +{ + Slice *currSlice = currMB->p_Slice; + int i, j; + int temp[8][8]; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel **mb_rec = currSlice->mb_rec[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + + if(currMB->ipmode_DPCM == VERT_PRED) + { + for(i=0; i<8; ++i) + { + temp[0][i] = mb_rres[joff + 0][ioff + i]; + temp[1][i] = mb_rres[joff + 1][ioff + i] + temp[0][i]; + temp[2][i] = mb_rres[joff + 2][ioff + i] + temp[1][i]; + temp[3][i] = mb_rres[joff + 3][ioff + i] + temp[2][i]; + temp[4][i] = mb_rres[joff + 4][ioff + i] + temp[3][i]; + temp[5][i] = mb_rres[joff + 5][ioff + i] + temp[4][i]; + temp[6][i] = mb_rres[joff + 6][ioff + i] + temp[5][i]; + temp[7][i] = mb_rres[joff + 7][ioff + i] + temp[6][i]; + } + for(i=0; i<8; ++i) + { + mb_rres[joff ][ioff+i]=temp[0][i]; + mb_rres[joff+1][ioff+i]=temp[1][i]; + mb_rres[joff+2][ioff+i]=temp[2][i]; + mb_rres[joff+3][ioff+i]=temp[3][i]; + mb_rres[joff+4][ioff+i]=temp[4][i]; + mb_rres[joff+5][ioff+i]=temp[5][i]; + mb_rres[joff+6][ioff+i]=temp[6][i]; + mb_rres[joff+7][ioff+i]=temp[7][i]; + } + } + else if(currMB->ipmode_DPCM == HOR_PRED)//HOR_PRED + { + for(i=0; i<8; ++i) + { + temp[i][0] = mb_rres[joff + i][ioff + 0]; + temp[i][1] = mb_rres[joff + i][ioff + 1] + temp[i][0]; + temp[i][2] = mb_rres[joff + i][ioff + 2] + temp[i][1]; + temp[i][3] = mb_rres[joff + i][ioff + 3] + temp[i][2]; + temp[i][4] = mb_rres[joff + i][ioff + 4] + temp[i][3]; + temp[i][5] = mb_rres[joff + i][ioff + 5] + temp[i][4]; + temp[i][6] = mb_rres[joff + i][ioff + 6] + temp[i][5]; + temp[i][7] = mb_rres[joff + i][ioff + 7] + temp[i][6]; + } + for(i=0; i<8; ++i) + { + mb_rres[joff+i][ioff+0]=temp[i][0]; + mb_rres[joff+i][ioff+1]=temp[i][1]; + mb_rres[joff+i][ioff+2]=temp[i][2]; + mb_rres[joff+i][ioff+3]=temp[i][3]; + mb_rres[joff+i][ioff+4]=temp[i][4]; + mb_rres[joff+i][ioff+5]=temp[i][5]; + mb_rres[joff+i][ioff+6]=temp[i][6]; + mb_rres[joff+i][ioff+7]=temp[i][7]; + } + } + + for (j = joff; j < joff + BLOCK_SIZE*2; ++j) + { + for (i = ioff; i < ioff + BLOCK_SIZE*2; ++i) + { + mb_rec [j][i] = (imgpel) (mb_rres[j][i] + mb_pred[j][i]); + } + } +} + + + +/*! +************************************************************************ +* \brief +* Inverse residual DPCM for Intra lossless coding +* +************************************************************************ +*/ +void Inv_Residual_trans_16x16(Macroblock *currMB, //!< current macroblock + ColorPlane pl) //!< used color plane +{ + int i,j; + int temp[16][16]; + Slice *currSlice = currMB->p_Slice; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel **mb_rec = currSlice->mb_rec[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + int **cof = currSlice->cof[pl]; + + if(currMB->ipmode_DPCM == VERT_PRED_16) + { + for(i=0; iipmode_DPCM == HOR_PRED_16) + { + for(j=0; jp_Slice; + //imgpel **mb_pred = currSlice->mb_pred[uv+1]; + //imgpel **mb_rec = currSlice->mb_rec[uv+1]; + int **mb_rres = currSlice->mb_rres[uv+1]; + int **cof = currSlice->cof[uv+1]; + int width, height; + + width = currMB->p_Vid->mb_cr_size_x; + height = currMB->p_Vid->mb_cr_size_y; + + if(currMB->c_ipred_mode == VERT_PRED_8) + { + for(i=0; ip_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int j; + + int transform_pl = (p_Vid->separate_colour_plane_flag != 0) ? PLANE_Y : pl; + int **cof = currSlice->cof[transform_pl]; + int qp_scaled = currMB->qp_scaled[transform_pl]; + + int qp_per = p_Vid->qp_per_matrix[ qp_scaled ]; + int qp_rem = p_Vid->qp_rem_matrix[ qp_scaled ]; + + int invLevelScale = currSlice->InvLevelScale4x4_Intra[pl][qp_rem][0][0]; + int **M4; + get_mem2Dint(&M4, BLOCK_SIZE, BLOCK_SIZE); + + // horizontal + for (j=0; j < 4;++j) + { + M4[j][0]=cof[j<<2][0]; + M4[j][1]=cof[j<<2][4]; + M4[j][2]=cof[j<<2][8]; + M4[j][3]=cof[j<<2][12]; + } + + ihadamard4x4(M4, M4); + + // vertical + for (j=0; j < 4;++j) + { + cof[j<<2][0] = rshift_rnd((( M4[j][0] * invLevelScale) << qp_per), 6); + cof[j<<2][4] = rshift_rnd((( M4[j][1] * invLevelScale) << qp_per), 6); + cof[j<<2][8] = rshift_rnd((( M4[j][2] * invLevelScale) << qp_per), 6); + cof[j<<2][12] = rshift_rnd((( M4[j][3] * invLevelScale) << qp_per), 6); + } + + free_mem2Dint(M4); +} + + +void itrans_sp(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< used color plane + int ioff, //!< index to 4x4 block + int joff) //!< index to 4x4 block +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int i,j; + int ilev, icof; + + int qp = (currSlice->slice_type == SI_SLICE) ? currSlice->qs : currSlice->qp; + int qp_per = p_Vid->qp_per_matrix[ qp ]; + int qp_rem = p_Vid->qp_rem_matrix[ qp ]; + + int qp_per_sp = p_Vid->qp_per_matrix[ currSlice->qs ]; + int qp_rem_sp = p_Vid->qp_rem_matrix[ currSlice->qs ]; + int q_bits_sp = Q_BITS + qp_per_sp; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel **mb_rec = currSlice->mb_rec[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + int **cof = currSlice->cof[pl]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + const int (*InvLevelScale4x4) [4] = dequant_coef[qp_rem]; + const int (*InvLevelScale4x4SP)[4] = dequant_coef[qp_rem_sp]; + int **PBlock; + + get_mem2Dint(&PBlock, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + for (j=0; j< BLOCK_SIZE; ++j) + { + PBlock[j][0] = mb_pred[j+joff][ioff ]; + PBlock[j][1] = mb_pred[j+joff][ioff + 1]; + PBlock[j][2] = mb_pred[j+joff][ioff + 2]; + PBlock[j][3] = mb_pred[j+joff][ioff + 3]; + } + + forward4x4(PBlock, PBlock, 0, 0); + + if(currSlice->sp_switch || currSlice->slice_type==SI_SLICE) + { + for (j=0;j> qp_per) / InvLevelScale4x4[j][i]; + //icof = ((cof[joff + j][ioff + i] * quant_coef[qp_rem][j][i])>> (qp_per + 15)) ; + // icof = rshift_rnd_sf(cof[joff + j][ioff + i] * quant_coef[qp_rem][j][i], qp_per + 15); + ilev = rshift_rnd_sf(iabs(PBlock[j][i]) * quant_coef[qp_rem_sp][j][i], q_bits_sp); + ilev = isignab(ilev, PBlock[j][i]) + icof; + cof[joff + j][ioff + i] = ilev * InvLevelScale4x4SP[j][i] << qp_per_sp; + } + } + } + else + { + for (j=0;j> qp_per) / InvLevelScale4x4[j][i]; + //icof = cof[joff + j][ioff + i]; + //icof = rshift_rnd_sf(cof[joff + j][ioff + i] * quant_coef[qp_rem][j][i], qp_per + 15); + ilev = PBlock[j][i] + ((icof * InvLevelScale4x4[j][i] * A[j][i] << qp_per) >> 6); + ilev = isign(ilev) * rshift_rnd_sf(iabs(ilev) * quant_coef[qp_rem_sp][j][i], q_bits_sp); + //cof[joff + j][ioff + i] = ilev * InvLevelScale4x4SP[j][i] << qp_per_sp; + cof[joff + j][ioff + i] = ilev * InvLevelScale4x4SP[j][i] << qp_per_sp; + } + } + } + + inverse4x4(cof, mb_rres, joff, ioff); + + for (j=joff; jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int i,j,ilev, icof, n2,n1; + int mp1[BLOCK_SIZE]; + int qp_per,qp_rem; + int qp_per_sp,qp_rem_sp,q_bits_sp; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + int **cof = currSlice->cof[uv + 1]; + int **PBlock = new_mem2Dint(MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + qp_per = p_Vid->qp_per_matrix[ ((currSlice->qp < 0 ? currSlice->qp : QP_SCALE_CR[currSlice->qp]))]; + qp_rem = p_Vid->qp_rem_matrix[ ((currSlice->qp < 0 ? currSlice->qp : QP_SCALE_CR[currSlice->qp]))]; + + qp_per_sp = p_Vid->qp_per_matrix[ ((currSlice->qs < 0 ? currSlice->qs : QP_SCALE_CR[currSlice->qs]))]; + qp_rem_sp = p_Vid->qp_rem_matrix[ ((currSlice->qs < 0 ? currSlice->qs : QP_SCALE_CR[currSlice->qs]))]; + q_bits_sp = Q_BITS + qp_per_sp; + + if (currSlice->slice_type == SI_SLICE) + { + qp_per = qp_per_sp; + qp_rem = qp_rem_sp; + } + + for (j=0; j < p_Vid->mb_cr_size_y; ++j) + { + for (i=0; i < p_Vid->mb_cr_size_x; ++i) + { + PBlock[j][i] = mb_pred[j][i]; + mb_pred[j][i] = 0; + } + } + + for (n2=0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE) + { + for (n1=0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE) + { + forward4x4(PBlock, PBlock, n2, n1); + } + } + + // 2X2 transform of DC coeffs. + mp1[0] = (PBlock[0][0] + PBlock[4][0] + PBlock[0][4] + PBlock[4][4]); + mp1[1] = (PBlock[0][0] - PBlock[4][0] + PBlock[0][4] - PBlock[4][4]); + mp1[2] = (PBlock[0][0] + PBlock[4][0] - PBlock[0][4] - PBlock[4][4]); + mp1[3] = (PBlock[0][0] - PBlock[4][0] - PBlock[0][4] + PBlock[4][4]); + + if (currSlice->sp_switch || currSlice->slice_type == SI_SLICE) + { + for (n2=0; n2 < 2; ++n2 ) + { + for (n1=0; n1 < 2; ++n1 ) + { + //quantization fo predicted block + ilev = rshift_rnd_sf(iabs (mp1[n1+n2*2]) * quant_coef[qp_rem_sp][0][0], q_bits_sp + 1); + //addition + ilev = isignab(ilev, mp1[n1+n2*2]) + cof[n2<<2][n1<<2]; + //dequantization + mp1[n1+n2*2] =ilev * dequant_coef[qp_rem_sp][0][0] << qp_per_sp; + } + } + + for (n2 = 0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE) + { + for (n1 = 0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE) + { + for (j = 0; j < BLOCK_SIZE; ++j) + { + for (i = 0; i < BLOCK_SIZE; ++i) + { + // recovering coefficient since they are already dequantized earlier + cof[n2 + j][n1 + i] = (cof[n2 + j][n1 + i] >> qp_per) / dequant_coef[qp_rem][j][i]; + + //quantization of the predicted block + ilev = rshift_rnd_sf(iabs(PBlock[n2 + j][n1 + i]) * quant_coef[qp_rem_sp][j][i], q_bits_sp); + //addition of the residual + ilev = isignab(ilev,PBlock[n2 + j][n1 + i]) + cof[n2 + j][n1 + i]; + // Inverse quantization + cof[n2 + j][n1 + i] = ilev * dequant_coef[qp_rem_sp][j][i] << qp_per_sp; + } + } + } + } + } + else + { + for (n2=0; n2 < 2; ++n2 ) + { + for (n1=0; n1 < 2; ++n1 ) + { + ilev = mp1[n1+n2*2] + (((cof[n2<<2][n1<<2] * dequant_coef[qp_rem][0][0] * A[0][0]) << qp_per) >> 5); + ilev = isign(ilev) * rshift_rnd_sf(iabs(ilev) * quant_coef[qp_rem_sp][0][0], q_bits_sp + 1); + //ilev = isignab(rshift_rnd_sf(iabs(ilev)* quant_coef[qp_rem_sp][0][0], q_bits_sp + 1), ilev); + mp1[n1+n2*2] = ilev * dequant_coef[qp_rem_sp][0][0] << qp_per_sp; + } + } + + for (n2 = 0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE) + { + for (n1 = 0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE) + { + for (j = 0; j< BLOCK_SIZE; ++j) + { + for (i = 0; i< BLOCK_SIZE; ++i) + { + // recovering coefficient since they are already dequantized earlier + //icof = ((((cof[n2 + j][n1 + i] << 4) + qp_per/2)>> qp_per) + dequant_coef[qp_rem][j][i]/2) / dequant_coef[qp_rem][j][i]; + icof = (cof[n2 + j][n1 + i] >> qp_per) / dequant_coef[qp_rem][j][i]; + //dequantization and addition of the predicted block + ilev = PBlock[n2 + j][n1 + i] + ((icof * dequant_coef[qp_rem][j][i] * A[j][i] << qp_per) >> 6); + //quantization and dequantization + ilev = isign(ilev) * rshift_rnd_sf(iabs(ilev) * quant_coef[qp_rem_sp][j][i], q_bits_sp); + cof[n2 + j][n1 + i] = ilev * dequant_coef[qp_rem_sp][j][i] << qp_per_sp; + //printf( " %d %d %d\n", j, i, quant_coef[qp_rem_sp][j][i]); + } + } + } + } + } + + cof[0][0] = (mp1[0] + mp1[1] + mp1[2] + mp1[3]) >> 1; + cof[0][4] = (mp1[0] + mp1[1] - mp1[2] - mp1[3]) >> 1; + cof[4][0] = (mp1[0] - mp1[1] + mp1[2] - mp1[3]) >> 1; + cof[4][4] = (mp1[0] - mp1[1] - mp1[2] + mp1[3]) >> 1; + + free_mem2Dint(PBlock); +} + +void iMBtrans4x4(Macroblock *currMB, ColorPlane pl, int smb) +{ + Slice *currSlice = currMB->p_Slice; + //VideoParameters *p_Vid = currMB->p_Vid; + + StorablePicture *dec_picture = currMB->p_Slice->dec_picture; + int jj, ii; + int block8x8; + int k; + + imgpel **curr_img = pl ? dec_picture->imgUV[pl - 1]: dec_picture->imgY; + + // =============== 4x4 itrans ================ + // ------------------------------------------- + if (currMB->is_lossless && currMB->mb_type == I16MB) + { + Inv_Residual_trans_16x16(currMB, pl) ; + } + else if (smb || currMB->is_lossless == TRUE) + { + currMB->itrans_4x4 = (smb) ? itrans_sp : ((currMB->is_lossless == FALSE) ? itrans4x4 : Inv_Residual_trans_4x4); + for (block8x8=0; block8x8 < MB_BLOCK_SIZE; block8x8 += 4) + { + for (k = block8x8; k < block8x8 + 4; ++k ) + { + jj = ((decode_block_scan[k] >> 2) & 3) << BLOCK_SHIFT; + ii = (decode_block_scan[k] & 3) << BLOCK_SHIFT; + + currMB->itrans_4x4(currMB, pl, ii, jj); // use integer transform and make 4x4 block mb_rres from prediction block mb_pred + } + } + } + else + { + int **cof = currSlice->cof[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + + if (currMB->is_intra_block == FALSE) + { + if (currMB->cbp & 0x01) + { + inverse4x4(cof, mb_rres, 0, 0); + inverse4x4(cof, mb_rres, 0, 4); + inverse4x4(cof, mb_rres, 4, 0); + inverse4x4(cof, mb_rres, 4, 4); + } + if (currMB->cbp & 0x02) + { + inverse4x4(cof, mb_rres, 0, 8); + inverse4x4(cof, mb_rres, 0, 12); + inverse4x4(cof, mb_rres, 4, 8); + inverse4x4(cof, mb_rres, 4, 12); + } + if (currMB->cbp & 0x04) + { + inverse4x4(cof, mb_rres, 8, 0); + inverse4x4(cof, mb_rres, 8, 4); + inverse4x4(cof, mb_rres, 12, 0); + inverse4x4(cof, mb_rres, 12, 4); + } + if (currMB->cbp & 0x08) + { + inverse4x4(cof, mb_rres, 8, 8); + inverse4x4(cof, mb_rres, 8, 12); + inverse4x4(cof, mb_rres, 12, 8); + inverse4x4(cof, mb_rres, 12, 12); + } + } + else + { + for (jj = 0; jj < MB_BLOCK_SIZE; jj += BLOCK_SIZE) + { + inverse4x4(cof, mb_rres, jj, 0); + inverse4x4(cof, mb_rres, jj, 4); + inverse4x4(cof, mb_rres, jj, 8); + inverse4x4(cof, mb_rres, jj, 12); + } + } + sample_reconstruct (currSlice->mb_rec[pl], currSlice->mb_pred[pl], mb_rres, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE, currMB->p_Vid->max_pel_value_comp[pl], DQ_BITS); + } + + // construct picture from 4x4 blocks + copy_image_data_16x16(&curr_img[currMB->pix_y], currSlice->mb_rec[pl], currMB->pix_x, 0); +} + +void iMBtrans8x8(Macroblock *currMB, ColorPlane pl) +{ + //VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currMB->p_Slice->dec_picture; + imgpel **curr_img = pl ? dec_picture->imgUV[pl - 1]: dec_picture->imgY; + + // Perform 8x8 idct + if (currMB->cbp & 0x01) + itrans8x8(currMB, pl, 0, 0); + else + icopy8x8(currMB, pl, 0, 0); + + if (currMB->cbp & 0x02) + itrans8x8(currMB, pl, 8, 0); + else + icopy8x8(currMB, pl, 8, 0); + + if (currMB->cbp & 0x04) + itrans8x8(currMB, pl, 0, 8); + else + icopy8x8(currMB, pl, 0, 8); + + if (currMB->cbp & 0x08) + itrans8x8(currMB, pl, 8, 8); + else + icopy8x8(currMB, pl, 8, 8); + + copy_image_data_16x16(&curr_img[currMB->pix_y], currMB->p_Slice->mb_rec[pl], currMB->pix_x, 0); +} + +void iTransform(Macroblock *currMB, ColorPlane pl, int smb) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + imgpel **curr_img; + int uv = pl-1; + + if ((currMB->cbp & 15) != 0 || smb) + { + if(currMB->luma_transform_size_8x8_flag == 0) // 4x4 inverse transform + { + iMBtrans4x4(currMB, pl, smb); + } + else // 8x8 inverse transform + { + iMBtrans8x8(currMB, pl); + } + } + else + { + curr_img = pl ? dec_picture->imgUV[uv] : dec_picture->imgY; + copy_image_data_16x16(&curr_img[currMB->pix_y], currSlice->mb_pred[pl], currMB->pix_x, 0); + } + if(smb) + currSlice->is_reset_coeff = FALSE; + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + imgpel **curUV; + int b8; + int ioff, joff; + imgpel **mb_rec; + + for(uv = PLANE_U; uv <= PLANE_V; ++uv) + { + // =============== 4x4 itrans ================ + // ------------------------------------------- + curUV = &dec_picture->imgUV[uv - 1][currMB->pix_c_y]; + mb_rec = currSlice->mb_rec[uv]; + + if (!smb && (currMB->cbp >> 4)) + { + if (currMB->is_lossless == FALSE) + { + const unsigned char *x_pos, *y_pos; + + for (b8 = 0; b8 < (p_Vid->num_uv_blocks); ++b8) + { + x_pos = subblk_offset_x[1][b8]; + y_pos = subblk_offset_y[1][b8]; + + itrans4x4(currMB, uv, *x_pos++, *y_pos++); + itrans4x4(currMB, uv, *x_pos++, *y_pos++); + itrans4x4(currMB, uv, *x_pos++, *y_pos++); + itrans4x4(currMB, uv, *x_pos , *y_pos ); + } + sample_reconstruct (mb_rec, currSlice->mb_pred[uv], currSlice->mb_rres[uv], 0, 0, + p_Vid->mb_size[1][0], p_Vid->mb_size[1][1], currMB->p_Vid->max_pel_value_comp[uv], DQ_BITS); + } + else + { + const unsigned char *x_pos, *y_pos; + for (b8 = 0; b8 < (p_Vid->num_uv_blocks); ++b8) + { + x_pos = subblk_offset_x[1][b8]; + y_pos = subblk_offset_y[1][b8]; + + itrans4x4_ls(currMB, uv, *x_pos++, *y_pos++); + itrans4x4_ls(currMB, uv, *x_pos++, *y_pos++); + itrans4x4_ls(currMB, uv, *x_pos++, *y_pos++); + itrans4x4_ls(currMB, uv, *x_pos , *y_pos ); + } + } + copy_image_data(curUV, mb_rec, currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + + currSlice->is_reset_coeff_cr = FALSE; + } + else if (smb) + { + currMB->itrans_4x4 = (currMB->is_lossless == FALSE) ? itrans4x4 : itrans4x4_ls; + itrans_sp_cr(currMB, uv - 1); + + for (joff = 0; joff < p_Vid->mb_cr_size_y; joff += BLOCK_SIZE) + { + for(ioff = 0; ioff < p_Vid->mb_cr_size_x ;ioff += BLOCK_SIZE) + { + currMB->itrans_4x4(currMB, uv, ioff, joff); + } + } + + copy_image_data(curUV, mb_rec, currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + currSlice->is_reset_coeff_cr = FALSE; + } + else + { + copy_image_data(curUV, currSlice->mb_pred[uv], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + } + } + } +} + +/*! + ************************************************************************************* + * \brief + * Copy ImgPel Data from one structure to another (16x16) + ************************************************************************************* + */ +void copy_image_data_16x16(imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2) +{ + int j; + for(j = 0; j < MB_BLOCK_SIZE; j += 4) + { + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), MB_BLOCK_SIZE * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), MB_BLOCK_SIZE * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), MB_BLOCK_SIZE * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), MB_BLOCK_SIZE * sizeof (imgpel)); + } +} + +/*! + ************************************************************************************* + * \brief + * Copy ImgPel Data from one structure to another (8x8) + ************************************************************************************* + */ +void copy_image_data_8x8(imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2) +{ + int j; + for(j = 0; j < BLOCK_SIZE_8x8; j+=4) + { + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE_8x8 * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE_8x8 * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE_8x8 * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE_8x8 * sizeof (imgpel)); + } +} + + +/*! + ************************************************************************************* + * \brief + * Copy ImgPel Data from one structure to another (4x4) + ************************************************************************************* + */ +void copy_image_data_4x4(imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2) +{ + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE * sizeof (imgpel)); + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), BLOCK_SIZE * sizeof (imgpel)); + memcpy((*imgBuf1 + off1), (*imgBuf2 + off2), BLOCK_SIZE * sizeof (imgpel)); +} + +int CheckVertMV(Macroblock *currMB, int vec1_y, int block_size_y) +{ + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currMB->p_Slice->dec_picture; + int y_pos = vec1_y>>2; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1; + + if(y_pos < (-p_Vid->iLumaPadY + 2) || y_pos > (maxold_y + p_Vid->iLumaPadY - block_size_y - 2)) + return 1; + else + return 0; +} + + +/*! + ************************************************************************************* + * \brief + * Copy ImgPel Data from one structure to another (8x8) + ************************************************************************************* + */ +void copy_image_data(imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2, int width, int height) +{ + int j; + for(j = 0; j < height; ++j) + { + memcpy((*imgBuf1++ + off1), (*imgBuf2++ + off2), width * sizeof (imgpel)); + } +} diff --git a/ldecod/src/cabac.c b/ldecod/src/cabac.c new file mode 100644 index 0000000..96b61b8 --- /dev/null +++ b/ldecod/src/cabac.c @@ -0,0 +1,2448 @@ +/*! + ************************************************************************************* + * \file cabac.c + * + * \brief + * CABAC entropy coding routines + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + ************************************************************************************** + */ + +#include "global.h" +#include "cabac.h" +#include "memalloc.h" +#include "elements.h" +#include "image.h" +#include "biaridecod.h" +#include "mb_access.h" +#include "vlc.h" + +#if TRACE +int symbolCount = 0; +#endif + +static const short maxpos [] = {15, 14, 63, 31, 31, 15, 3, 14, 7, 15, 15, 14, 63, 31, 31, 15, 15, 14, 63, 31, 31, 15}; +static const short c1isdc [] = { 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1}; +static const short type2ctx_bcbp[] = { 0, 1, 2, 3, 3, 4, 5, 6, 5, 5, 10, 11, 12, 13, 13, 14, 16, 17, 18, 19, 19, 20}; +static const short type2ctx_map [] = { 0, 1, 2, 3, 4, 5, 6, 7, 6, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}; // 8 +static const short type2ctx_last[] = { 0, 1, 2, 3, 4, 5, 6, 7, 6, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}; // 8 +static const short type2ctx_one [] = { 0, 1, 2, 3, 3, 4, 5, 6, 5, 5, 10, 11, 12, 13, 13, 14, 16, 17, 18, 19, 19, 20}; // 7 +static const short type2ctx_abs [] = { 0, 1, 2, 3, 3, 4, 5, 6, 5, 5, 10, 11, 12, 13, 13, 14, 16, 17, 18, 19, 19, 20}; // 7 +static const short max_c2 [] = { 4, 4, 4, 4, 4, 4, 3, 4, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; // 9 + +/*********************************************************************** + * L O C A L L Y D E F I N E D F U N C T I O N P R O T O T Y P E S + *********************************************************************** + */ +static unsigned int unary_bin_decode ( DecodingEnvironmentPtr dep_dp, BiContextTypePtr ctx, int ctx_offset); +static unsigned int unary_bin_max_decode ( DecodingEnvironmentPtr dep_dp, BiContextTypePtr ctx, int ctx_offset, unsigned int max_symbol); +static unsigned int unary_exp_golomb_level_decode( DecodingEnvironmentPtr dep_dp, BiContextTypePtr ctx); +static unsigned int unary_exp_golomb_mv_decode ( DecodingEnvironmentPtr dep_dp, BiContextTypePtr ctx, unsigned int max_bin); + +void CheckAvailabilityOfNeighborsCABAC(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos up, left; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + p_Vid->getNeighbour(currMB, -1, 0, mb_size, &left); + p_Vid->getNeighbour(currMB, 0, -1, mb_size, &up); + + if (up.available) + currMB->mb_up = &currMB->p_Slice->mb_data[up.mb_addr]; //&p_Vid->mb_data[up.mb_addr]; + else + currMB->mb_up = NULL; + + if (left.available) + currMB->mb_left = &currMB->p_Slice->mb_data[left.mb_addr]; //&p_Vid->mb_data[left.mb_addr]; + else + currMB->mb_left = NULL; +} + +void cabac_new_slice(Slice *currSlice) +{ + currSlice->last_dquant = 0; +} + +/*! + ************************************************************************ + * \brief + * Allocation of contexts models for the motion info + * used for arithmetic decoding + * + ************************************************************************ + */ +MotionInfoContexts* create_contexts_MotionInfo(void) +{ + MotionInfoContexts *deco_ctx; + + deco_ctx = (MotionInfoContexts*) calloc(1, sizeof(MotionInfoContexts) ); + if( deco_ctx == NULL ) + no_mem_exit("create_contexts_MotionInfo: deco_ctx"); + + return deco_ctx; +} + + +/*! + ************************************************************************ + * \brief + * Allocates of contexts models for the texture info + * used for arithmetic decoding + ************************************************************************ + */ +TextureInfoContexts* create_contexts_TextureInfo(void) +{ + TextureInfoContexts *deco_ctx; + + deco_ctx = (TextureInfoContexts*) calloc(1, sizeof(TextureInfoContexts) ); + if( deco_ctx == NULL ) + no_mem_exit("create_contexts_TextureInfo: deco_ctx"); + + return deco_ctx; +} + + +/*! + ************************************************************************ + * \brief + * Frees the memory of the contexts models + * used for arithmetic decoding of the motion info. + ************************************************************************ + */ +void delete_contexts_MotionInfo(MotionInfoContexts *deco_ctx) +{ + if( deco_ctx == NULL ) + return; + + free( deco_ctx ); +} + + +/*! + ************************************************************************ + * \brief + * Frees the memory of the contexts models + * used for arithmetic decoding of the texture info. + ************************************************************************ + */ +void delete_contexts_TextureInfo(TextureInfoContexts *deco_ctx) +{ + if( deco_ctx == NULL ) + return; + + free( deco_ctx ); +} + +void readFieldModeInfo_CABAC(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + //VideoParameters *p_Vid = currMB->p_Vid; + MotionInfoContexts *ctx = currSlice->mot_ctx; + int a = currMB->mbAvailA ? currSlice->mb_data[currMB->mbAddrA].mb_field : 0; + int b = currMB->mbAvailB ? currSlice->mb_data[currMB->mbAddrB].mb_field : 0; + int act_ctx = a + b; + + se->value1 = biari_decode_symbol (dep_dp, &ctx->mb_aff_contexts[act_ctx]); + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + + +int check_next_mb_and_get_field_mode_CABAC_p_slice( Slice *currSlice, + SyntaxElement *se, + DataPartition *act_dp) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + BiContextTypePtr mb_type_ctx_copy[3]; + BiContextTypePtr mb_aff_ctx_copy; + DecodingEnvironmentPtr dep_dp_copy; + MotionInfoContexts *mot_ctx = currSlice->mot_ctx; + + int length; + DecodingEnvironmentPtr dep_dp = &(act_dp->de_cabac); + + int skip = 0; + int field = 0; + int i; + + Macroblock *currMB; + + //get next MB + ++currSlice->current_mb_nr; // ++p_Vid->current_mb_nr; + + currMB = &currSlice->mb_data[currSlice->current_mb_nr]; + currMB->p_Vid = p_Vid; + currMB->p_Slice = currSlice; + currMB->slice_nr = currSlice->current_slice_nr; + currMB->mb_field = currSlice->mb_data[currSlice->current_mb_nr-1].mb_field; + currMB->mbAddrX = currSlice->current_mb_nr; + currMB->list_offset = ((currSlice->mb_aff_frame_flag)&&(currMB->mb_field))? (currMB->mbAddrX&0x01) ? 4 : 2 : 0; + + CheckAvailabilityOfNeighborsMBAFF(currMB); + CheckAvailabilityOfNeighborsCABAC(currMB); + + //create + dep_dp_copy = (DecodingEnvironmentPtr) calloc(1, sizeof(DecodingEnvironment) ); + for (i=0;i<3;++i) + mb_type_ctx_copy[i] = (BiContextTypePtr) calloc(NUM_MB_TYPE_CTX, sizeof(BiContextType) ); + mb_aff_ctx_copy = (BiContextTypePtr) calloc(NUM_MB_AFF_CTX, sizeof(BiContextType) ); + + //copy + memcpy(dep_dp_copy,dep_dp,sizeof(DecodingEnvironment)); + length = *(dep_dp_copy->Dcodestrm_len) = *(dep_dp->Dcodestrm_len); + for (i=0;i<3;++i) + memcpy(mb_type_ctx_copy[i], mot_ctx->mb_type_contexts[i],NUM_MB_TYPE_CTX*sizeof(BiContextType) ); + memcpy(mb_aff_ctx_copy, mot_ctx->mb_aff_contexts,NUM_MB_AFF_CTX*sizeof(BiContextType) ); + + //check_next_mb +#if TRACE + strncpy(se->tracestring, "mb_skip_flag (of following bottom MB)", TRACESTRING_SIZE); +#endif + currSlice->last_dquant = 0; + read_skip_flag_CABAC_p_slice(currMB, se, dep_dp); + + skip = (se->value1==0); + + if (!skip) + { +#if TRACE + strncpy(se->tracestring, "mb_field_decoding_flag (of following bottom MB)", TRACESTRING_SIZE); +#endif + readFieldModeInfo_CABAC( currMB, se,dep_dp); + field = se->value1; + currSlice->mb_data[currSlice->current_mb_nr-1].mb_field = field; + } + + //reset + currSlice->current_mb_nr--; + + memcpy(dep_dp,dep_dp_copy,sizeof(DecodingEnvironment)); + *(dep_dp->Dcodestrm_len) = length; + for (i=0;i<3;++i) + memcpy(mot_ctx->mb_type_contexts[i],mb_type_ctx_copy[i], NUM_MB_TYPE_CTX*sizeof(BiContextType) ); + memcpy( mot_ctx->mb_aff_contexts,mb_aff_ctx_copy,NUM_MB_AFF_CTX*sizeof(BiContextType) ); + + CheckAvailabilityOfNeighborsCABAC(currMB); + + //delete + free(dep_dp_copy); + for (i=0;i<3;++i) + free(mb_type_ctx_copy[i]); + free(mb_aff_ctx_copy); + + return skip; +} + +int check_next_mb_and_get_field_mode_CABAC_b_slice( Slice *currSlice, + SyntaxElement *se, + DataPartition *act_dp) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + BiContextTypePtr mb_type_ctx_copy[3]; + BiContextTypePtr mb_aff_ctx_copy; + DecodingEnvironmentPtr dep_dp_copy; + + int length; + DecodingEnvironmentPtr dep_dp = &(act_dp->de_cabac); + MotionInfoContexts *mot_ctx = currSlice->mot_ctx; + + int skip = 0; + int field = 0; + int i; + + Macroblock *currMB; + + //get next MB + ++currSlice->current_mb_nr; // ++p_Vid->current_mb_nr; + + currMB = &currSlice->mb_data[currSlice->current_mb_nr]; + currMB->p_Vid = p_Vid; + currMB->p_Slice = currSlice; + currMB->slice_nr = currSlice->current_slice_nr; + currMB->mb_field = currSlice->mb_data[currSlice->current_mb_nr-1].mb_field; + currMB->mbAddrX = currSlice->current_mb_nr; + currMB->list_offset = ((currSlice->mb_aff_frame_flag)&&(currMB->mb_field))? (currMB->mbAddrX & 0x01) ? 4 : 2 : 0; + + CheckAvailabilityOfNeighborsMBAFF(currMB); + CheckAvailabilityOfNeighborsCABAC(currMB); + + //create + dep_dp_copy = (DecodingEnvironmentPtr) calloc(1, sizeof(DecodingEnvironment) ); + for (i=0;i<3;++i) + mb_type_ctx_copy[i] = (BiContextTypePtr) calloc(NUM_MB_TYPE_CTX, sizeof(BiContextType) ); + mb_aff_ctx_copy = (BiContextTypePtr) calloc(NUM_MB_AFF_CTX, sizeof(BiContextType) ); + + //copy + memcpy(dep_dp_copy,dep_dp,sizeof(DecodingEnvironment)); + length = *(dep_dp_copy->Dcodestrm_len) = *(dep_dp->Dcodestrm_len); + + for (i=0;i<3;++i) + memcpy(mb_type_ctx_copy[i], mot_ctx->mb_type_contexts[i],NUM_MB_TYPE_CTX*sizeof(BiContextType) ); + + memcpy(mb_aff_ctx_copy, mot_ctx->mb_aff_contexts,NUM_MB_AFF_CTX*sizeof(BiContextType) ); + + //check_next_mb +#if TRACE + strncpy(se->tracestring, "mb_skip_flag (of following bottom MB)", TRACESTRING_SIZE); +#endif + currSlice->last_dquant = 0; + read_skip_flag_CABAC_b_slice(currMB, se, dep_dp); + + skip = (se->value1==0 && se->value2==0); + if (!skip) + { +#if TRACE + strncpy(se->tracestring, "mb_field_decoding_flag (of following bottom MB)", TRACESTRING_SIZE); +#endif + readFieldModeInfo_CABAC( currMB, se,dep_dp); + field = se->value1; + currSlice->mb_data[currSlice->current_mb_nr-1].mb_field = field; + } + + //reset + currSlice->current_mb_nr--; + + memcpy(dep_dp,dep_dp_copy,sizeof(DecodingEnvironment)); + *(dep_dp->Dcodestrm_len) = length; + + for (i=0;i<3;++i) + memcpy(mot_ctx->mb_type_contexts[i],mb_type_ctx_copy[i], NUM_MB_TYPE_CTX * sizeof(BiContextType) ); + + memcpy( mot_ctx->mb_aff_contexts, mb_aff_ctx_copy, NUM_MB_AFF_CTX * sizeof(BiContextType) ); + + CheckAvailabilityOfNeighborsCABAC(currMB); + + //delete + free(dep_dp_copy); + for (i=0;i<3;++i) + free(mb_type_ctx_copy[i]); + free(mb_aff_ctx_copy); + + return skip; +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the motion + * vector data of a B-frame MB. + ************************************************************************ + */ +void read_MVD_CABAC( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + int *mb_size = currMB->p_Vid->mb_size[IS_LUMA]; + Slice *currSlice = currMB->p_Slice; + MotionInfoContexts *ctx = currSlice->mot_ctx; + int i = currMB->subblock_x; + int j = currMB->subblock_y; + int a = 0; + //int act_ctx; + int act_sym; + int list_idx = se->value2 & 0x01; + int k = (se->value2 >> 1); // MVD component + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , mb_size, &block_a); + get4x4NeighbourBase(currMB, i , j - 1, mb_size, &block_b); + if (block_a.available) + { + a = iabs(currSlice->mb_data[block_a.mb_addr].mvd[list_idx][block_a.y][block_a.x][k]); + } + if (block_b.available) + { + a += iabs(currSlice->mb_data[block_b.mb_addr].mvd[list_idx][block_b.y][block_b.x][k]); + } + + //a += b; + + if (a < 3) + a = 5 * k; + else if (a > 32) + a = 5 * k + 3; + else + a = 5 * k + 2; + + se->context = a; + + act_sym = biari_decode_symbol(dep_dp, ctx->mv_res_contexts[0] + a ); + + if (act_sym != 0) + { + a = 5 * k; + act_sym = unary_exp_golomb_mv_decode(dep_dp, ctx->mv_res_contexts[1] + a, 3) + 1; + + if(biari_decode_symbol_eq_prob(dep_dp)) + act_sym = -act_sym; + } + se->value1 = act_sym; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the motion + * vector data of a B-frame MB. + ************************************************************************ + */ +void read_mvd_CABAC_mbaff( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + MotionInfoContexts *ctx = currSlice->mot_ctx; + int i = currMB->subblock_x; + int j = currMB->subblock_y; + int a = 0, b = 0; + int act_ctx; + int act_sym; + int list_idx = se->value2 & 0x01; + int k = (se->value2 >> 1); // MVD component + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + if (block_a.available) + { + a = iabs(currSlice->mb_data[block_a.mb_addr].mvd[list_idx][block_a.y][block_a.x][k]); + if (currSlice->mb_aff_frame_flag && (k==1)) + { + if ((currMB->mb_field==0) && (currSlice->mb_data[block_a.mb_addr].mb_field==1)) + a *= 2; + else if ((currMB->mb_field==1) && (currSlice->mb_data[block_a.mb_addr].mb_field==0)) + a /= 2; + } + } + + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + if (block_b.available) + { + b = iabs(currSlice->mb_data[block_b.mb_addr].mvd[list_idx][block_b.y][block_b.x][k]); + if (currSlice->mb_aff_frame_flag && (k==1)) + { + if ((currMB->mb_field==0) && (currSlice->mb_data[block_b.mb_addr].mb_field==1)) + b *= 2; + else if ((currMB->mb_field==1) && (currSlice->mb_data[block_b.mb_addr].mb_field==0)) + b /= 2; + } + } + a += b; + + if (a < 3) + act_ctx = 5 * k; + else if (a > 32) + act_ctx = 5 * k + 3; + else + act_ctx = 5 * k + 2; + + se->context = act_ctx; + + act_sym = biari_decode_symbol(dep_dp,&ctx->mv_res_contexts[0][act_ctx] ); + + if (act_sym != 0) + { + act_ctx = 5 * k; + act_sym = unary_exp_golomb_mv_decode(dep_dp, ctx->mv_res_contexts[1] + act_ctx, 3) + 1; + + if(biari_decode_symbol_eq_prob(dep_dp)) + act_sym = -act_sym; + } + se->value1 = act_sym; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the 8x8 block type. + ************************************************************************ + */ +void readB8_typeInfo_CABAC_p_slice (Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + int act_sym = 0; + + MotionInfoContexts *ctx = currSlice->mot_ctx; + BiContextType *b8_type_contexts = &ctx->b8_type_contexts[0][1]; + + if (biari_decode_symbol (dep_dp, b8_type_contexts++)) + act_sym = 0; + else + { + if (biari_decode_symbol (dep_dp, ++b8_type_contexts)) + { + act_sym = (biari_decode_symbol (dep_dp, ++b8_type_contexts))? 2: 3; + } + else + { + act_sym = 1; + } + } + + se->value1 = act_sym; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the 8x8 block type. + ************************************************************************ + */ +void readB8_typeInfo_CABAC_b_slice (Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + int act_sym = 0; + + MotionInfoContexts *ctx = currSlice->mot_ctx; + BiContextType *b8_type_contexts = ctx->b8_type_contexts[1]; + + if (biari_decode_symbol (dep_dp, b8_type_contexts++)) + { + if (biari_decode_symbol (dep_dp, b8_type_contexts++)) + { + if (biari_decode_symbol (dep_dp, b8_type_contexts++)) + { + if (biari_decode_symbol (dep_dp, b8_type_contexts)) + { + act_sym = 10; + if (biari_decode_symbol (dep_dp, b8_type_contexts)) + act_sym++; + } + else + { + act_sym = 6; + if (biari_decode_symbol (dep_dp, b8_type_contexts)) + act_sym += 2; + if (biari_decode_symbol (dep_dp, b8_type_contexts)) + act_sym++; + } + } + else + { + act_sym = 2; + if (biari_decode_symbol (dep_dp, b8_type_contexts)) + act_sym += 2; + if (biari_decode_symbol (dep_dp, b8_type_contexts)) + act_sym ++; + } + } + else + { + act_sym = (biari_decode_symbol (dep_dp, ++b8_type_contexts)) ? 1: 0; + } + ++act_sym; + } + else + { + act_sym = 0; + } + + se->value1 = act_sym; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the macroblock + * type info of a given MB. + ************************************************************************ + */ +void read_skip_flag_CABAC_p_slice( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + int a = (currMB->mb_left != NULL) ? (currMB->mb_left->skip_flag == 0) : 0; + int b = (currMB->mb_up != NULL) ? (currMB->mb_up ->skip_flag == 0) : 0; + BiContextType *mb_type_contexts = &currMB->p_Slice->mot_ctx->mb_type_contexts[1][a + b]; + + se->value1 = (biari_decode_symbol(dep_dp, mb_type_contexts) != 1); + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif + if (!se->value1) + { + currMB->p_Slice->last_dquant = 0; + } +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the macroblock + * type info of a given MB. + ************************************************************************ + */ +void read_skip_flag_CABAC_b_slice( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + int a = (currMB->mb_left != NULL) ? (currMB->mb_left->skip_flag == 0) : 0; + int b = (currMB->mb_up != NULL) ? (currMB->mb_up ->skip_flag == 0) : 0; + BiContextType *mb_type_contexts = &currMB->p_Slice->mot_ctx->mb_type_contexts[2][7 + a + b]; + + se->value1 = se->value2 = (biari_decode_symbol (dep_dp, mb_type_contexts) != 1); + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n", symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif + if (!se->value1) + { + currMB->p_Slice->last_dquant = 0; + } +} + +/*! +*************************************************************************** +* \brief +* This function is used to arithmetically decode the macroblock +* intra_pred_size flag info of a given MB. +*************************************************************************** +*/ + +void readMB_transform_size_flag_CABAC( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + TextureInfoContexts*ctx = currSlice->tex_ctx; + + int b = (currMB->mb_up == NULL) ? 0 : currMB->mb_up->luma_transform_size_8x8_flag; + int a = (currMB->mb_left == NULL) ? 0 : currMB->mb_left->luma_transform_size_8x8_flag; + + int act_sym = biari_decode_symbol(dep_dp, ctx->transform_size_contexts + a + b ); + + se->value1 = act_sym; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif + +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the macroblock + * type info of a given MB. + ************************************************************************ + */ +void readMB_typeInfo_CABAC_i_slice(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + MotionInfoContexts *ctx = currSlice->mot_ctx; + + int a = 0, b = 0; + int act_ctx; + int act_sym; + int mode_sym; + int curr_mb_type = 0; + + if(currSlice->slice_type == I_SLICE) // INTRA-frame + { + if (currMB->mb_up != NULL) + b = (((currMB->mb_up)->mb_type != I4MB && currMB->mb_up->mb_type != I8MB) ? 1 : 0 ); + + if (currMB->mb_left != NULL) + a = (((currMB->mb_left)->mb_type != I4MB && currMB->mb_left->mb_type != I8MB) ? 1 : 0 ); + + act_ctx = a + b; + act_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx); + se->context = act_ctx; // store context + + if (act_sym==0) // 4x4 Intra + { + curr_mb_type = act_sym; + } + else // 16x16 Intra + { + mode_sym = biari_decode_final(dep_dp); + if(mode_sym == 1) + { + curr_mb_type = 25; + } + else + { + act_sym = 1; + act_ctx = 4; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); // decoding of AC/no AC + act_sym += mode_sym*12; + act_ctx = 5; + // decoding of cbp: 0,1,2 + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + if (mode_sym!=0) + { + act_ctx=6; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + act_sym+=4; + if (mode_sym!=0) + act_sym+=4; + } + // decoding of I pred-mode: 0,1,2,3 + act_ctx = 7; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + act_sym += mode_sym*2; + act_ctx = 8; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + act_sym += mode_sym; + curr_mb_type = act_sym; + } + } + } + else if(currSlice->slice_type == SI_SLICE) // SI-frame + { + // special ctx's for SI4MB + if (currMB->mb_up != NULL) + b = (( (currMB->mb_up)->mb_type != SI4MB) ? 1 : 0 ); + + if (currMB->mb_left != NULL) + a = (( (currMB->mb_left)->mb_type != SI4MB) ? 1 : 0 ); + + act_ctx = a + b; + act_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[1] + act_ctx); + se->context = act_ctx; // store context + + if (act_sym==0) // SI 4x4 Intra + { + curr_mb_type = 0; + } + else // analog INTRA_IMG + { + if (currMB->mb_up != NULL) + b = (( (currMB->mb_up)->mb_type != I4MB) ? 1 : 0 ); + + if (currMB->mb_left != NULL) + a = (( (currMB->mb_left)->mb_type != I4MB) ? 1 : 0 ); + + act_ctx = a + b; + act_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx); + se->context = act_ctx; // store context + + if (act_sym==0) // 4x4 Intra + { + curr_mb_type = 1; + } + else // 16x16 Intra + { + mode_sym = biari_decode_final(dep_dp); + if( mode_sym==1 ) + { + curr_mb_type = 26; + } + else + { + act_sym = 2; + act_ctx = 4; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); // decoding of AC/no AC + act_sym += mode_sym*12; + act_ctx = 5; + // decoding of cbp: 0,1,2 + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + if (mode_sym!=0) + { + act_ctx=6; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + act_sym+=4; + if (mode_sym!=0) + act_sym+=4; + } + // decoding of I pred-mode: 0,1,2,3 + act_ctx = 7; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + act_sym += mode_sym*2; + act_ctx = 8; + mode_sym = biari_decode_symbol(dep_dp, ctx->mb_type_contexts[0] + act_ctx ); + act_sym += mode_sym; + curr_mb_type = act_sym; + } + } + } + } + + se->value1 = curr_mb_type; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the macroblock + * type info of a given MB. + ************************************************************************ + */ +void readMB_typeInfo_CABAC_p_slice(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + MotionInfoContexts *ctx = currSlice->mot_ctx; + + int act_ctx; + int act_sym; + int mode_sym; + int curr_mb_type; + BiContextType *mb_type_contexts = ctx->mb_type_contexts[1]; + + if (biari_decode_symbol(dep_dp, &mb_type_contexts[4] )) + { + if (biari_decode_symbol(dep_dp, &mb_type_contexts[7] )) + act_sym = 7; + else + act_sym = 6; + } + else + { + if (biari_decode_symbol(dep_dp, &mb_type_contexts[5] )) + { + if (biari_decode_symbol(dep_dp, &mb_type_contexts[7] )) + act_sym = 2; + else + act_sym = 3; + } + else + { + if (biari_decode_symbol(dep_dp, &mb_type_contexts[6] )) + act_sym = 4; + else + act_sym = 1; + } + } + + if (act_sym <= 6) + { + curr_mb_type = act_sym; + } + else // additional info for 16x16 Intra-mode + { + mode_sym = biari_decode_final(dep_dp); + if( mode_sym==1 ) + { + curr_mb_type = 31; + } + else + { + act_ctx = 8; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); // decoding of AC/no AC + act_sym += mode_sym*12; + + // decoding of cbp: 0,1,2 + act_ctx = 9; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + if (mode_sym != 0) + { + act_sym+=4; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + if (mode_sym != 0) + act_sym+=4; + } + + // decoding of I pred-mode: 0,1,2,3 + act_ctx = 10; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + act_sym += mode_sym*2; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + act_sym += mode_sym; + curr_mb_type = act_sym; + } + } + + se->value1 = curr_mb_type; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the macroblock + * type info of a given MB. + ************************************************************************ + */ +void readMB_typeInfo_CABAC_b_slice(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + MotionInfoContexts *ctx = currSlice->mot_ctx; + + int a = 0, b = 0; + int act_ctx; + int act_sym; + int mode_sym; + int curr_mb_type; + BiContextType *mb_type_contexts = ctx->mb_type_contexts[2]; + + if (currMB->mb_up != NULL) + b = (( (currMB->mb_up)->mb_type != 0) ? 1 : 0 ); + + if (currMB->mb_left != NULL) + a = (( (currMB->mb_left)->mb_type != 0) ? 1 : 0 ); + + act_ctx = a + b; + + if (biari_decode_symbol (dep_dp, &mb_type_contexts[act_ctx])) + { + if (biari_decode_symbol (dep_dp, &mb_type_contexts[4])) + { + if (biari_decode_symbol (dep_dp, &mb_type_contexts[5])) + { + act_sym = 12; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 8; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 4; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 2; + + if (act_sym == 24) + act_sym=11; + else if (act_sym == 26) + act_sym = 22; + else + { + if (act_sym == 22) + act_sym = 23; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 1; + } + } + else + { + act_sym = 3; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 4; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 2; + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym += 1; + } + } + else + { + if (biari_decode_symbol (dep_dp, &mb_type_contexts[6])) + act_sym=2; + else + act_sym=1; + } + } + else + { + act_sym = 0; + } + + + if (act_sym <= 23) + { + curr_mb_type = act_sym; + } + else // additional info for 16x16 Intra-mode + { + mode_sym = biari_decode_final(dep_dp); + if( mode_sym == 1 ) + { + curr_mb_type = 48; + } + else + { + mb_type_contexts = ctx->mb_type_contexts[1]; + act_ctx = 8; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); // decoding of AC/no AC + act_sym += mode_sym*12; + + // decoding of cbp: 0,1,2 + act_ctx = 9; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + if (mode_sym != 0) + { + act_sym+=4; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + if (mode_sym != 0) + act_sym+=4; + } + + // decoding of I pred-mode: 0,1,2,3 + act_ctx = 10; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + act_sym += mode_sym*2; + mode_sym = biari_decode_symbol(dep_dp, mb_type_contexts + act_ctx ); + act_sym += mode_sym; + curr_mb_type = act_sym; + } + } + + se->value1 = curr_mb_type; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode a pair of + * intra prediction modes of a given MB. + ************************************************************************ + */ +void readIntraPredMode_CABAC( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + TextureInfoContexts *ctx = currSlice->tex_ctx; + // use_most_probable_mode + int act_sym = biari_decode_symbol(dep_dp, ctx->ipr_contexts); + + // remaining_mode_selector + if (act_sym == 1) + se->value1 = -1; + else + { + se->value1 = (biari_decode_symbol(dep_dp, ctx->ipr_contexts + 1) ); + se->value1 |= (biari_decode_symbol(dep_dp, ctx->ipr_contexts + 1) << 1); + se->value1 |= (biari_decode_symbol(dep_dp, ctx->ipr_contexts + 1) << 2); + } + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the reference + * parameter of a given MB. + ************************************************************************ + */ +void readRefFrame_CABAC(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + MotionInfoContexts *ctx = currSlice->mot_ctx; + Macroblock *neighborMB = NULL; + + int addctx = 0; + int a = 0, b = 0; + int act_ctx; + int act_sym; + int list = se->value2; + + PixelPos block_a, block_b; + + get4x4Neighbour(currMB, currMB->subblock_x - 1, currMB->subblock_y , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4Neighbour(currMB, currMB->subblock_x, currMB->subblock_y - 1, p_Vid->mb_size[IS_LUMA], &block_b); + + if (block_b.available) + { + int b8b=((block_b.x >> 1) & 0x01)+(block_b.y & 0x02); + neighborMB = &currSlice->mb_data[block_b.mb_addr]; + if (!( (neighborMB->mb_type==IPCM) || IS_DIRECT(neighborMB) || (neighborMB->b8mode[b8b]==0 && neighborMB->b8pdir[b8b]==2))) + { + if (currSlice->mb_aff_frame_flag && (currMB->mb_field == FALSE) && (neighborMB->mb_field == TRUE)) + b = (dec_picture->mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] > 1 ? 2 : 0); + else + b = (dec_picture->mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] > 0 ? 2 : 0); + } + } + + if (block_a.available) + { + int b8a=((block_a.x >> 1) & 0x01)+(block_a.y & 0x02); + neighborMB = &currSlice->mb_data[block_a.mb_addr]; + if (!((neighborMB->mb_type==IPCM) || IS_DIRECT(neighborMB) || (neighborMB->b8mode[b8a]==0 && neighborMB->b8pdir[b8a]==2))) + { + if (currSlice->mb_aff_frame_flag && (currMB->mb_field == FALSE) && (neighborMB->mb_field == 1)) + a = (dec_picture->mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list] > 1 ? 1 : 0); + else + a = (dec_picture->mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list] > 0 ? 1 : 0); + } + } + + act_ctx = a + b; + se->context = act_ctx; // store context + + act_sym = biari_decode_symbol(dep_dp,ctx->ref_no_contexts[addctx] + act_ctx ); + + if (act_sym != 0) + { + act_ctx = 4; + act_sym = unary_bin_decode(dep_dp,ctx->ref_no_contexts[addctx] + act_ctx,1); + ++act_sym; + } + se->value1 = act_sym; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); +// fprintf(p_Dec->p_trace," c: %d :%d \n",ctx->ref_no_contexts[addctx][act_ctx].cum_freq[0],ctx->ref_no_contexts[addctx][act_ctx].cum_freq[1]); + fflush(p_Dec->p_trace); +#endif +} + + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the delta qp + * of a given MB. + ************************************************************************ + */ +void read_dQuant_CABAC( Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + MotionInfoContexts *ctx = currSlice->mot_ctx; + int *dquant = &se->value1; + int act_ctx = ((currSlice->last_dquant != 0) ? 1 : 0); + int act_sym = biari_decode_symbol(dep_dp,ctx->delta_qp_contexts + act_ctx ); + + if (act_sym != 0) + { + act_ctx = 2; + act_sym = unary_bin_decode(dep_dp,ctx->delta_qp_contexts + act_ctx,1); + ++act_sym; + *dquant = (act_sym + 1) >> 1; + if((act_sym & 0x01)==0) // lsb is signed bit + *dquant = -*dquant; + } + else + *dquant = 0; + + currSlice->last_dquant = *dquant; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the coded + * block pattern of a given MB. + ************************************************************************ + */ +void read_CBP_CABAC(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currMB->p_Slice->dec_picture; + Slice *currSlice = currMB->p_Slice; + TextureInfoContexts *ctx = currSlice->tex_ctx; + Macroblock *neighborMB = NULL; + + int mb_x, mb_y; + int a = 0, b = 0; + int curr_cbp_ctx; + int cbp = 0; + int cbp_bit; + int mask; + PixelPos block_a; + + // coding of luma part (bit by bit) + for (mb_y=0; mb_y < 4; mb_y += 2) + { + if (mb_y == 0) + { + neighborMB = currMB->mb_up; + b = 0; + } + + for (mb_x=0; mb_x < 4; mb_x += 2) + { + if (mb_y == 0) + { + if (neighborMB != NULL) + { + if(neighborMB->mb_type!=IPCM) + b = (( (neighborMB->cbp & (1<<(2 + (mb_x>>1)))) == 0) ? 2 : 0); + } + } + else + b = ( ((cbp & (1<<(mb_x/2))) == 0) ? 2: 0); + + if (mb_x == 0) + { + get4x4Neighbour(currMB, (mb_x<<2) - 1, (mb_y << 2), p_Vid->mb_size[IS_LUMA], &block_a); + if (block_a.available) + { + if(currSlice->mb_data[block_a.mb_addr].mb_type==IPCM) + a = 0; + else + a = (( (currSlice->mb_data[block_a.mb_addr].cbp & (1<<(2*(block_a.y/2)+1))) == 0) ? 1 : 0); + } + else + a=0; + } + else + a = ( ((cbp & (1<> 1))); + cbp_bit = biari_decode_symbol(dep_dp, ctx->cbp_contexts[0] + curr_cbp_ctx ); + if (cbp_bit) + cbp += mask; + } + } + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + // coding of chroma part + // CABAC decoding for BinIdx 0 + b = 0; + neighborMB = currMB->mb_up; + if (neighborMB != NULL) + { + if (neighborMB->mb_type==IPCM || (neighborMB->cbp > 15)) + b = 2; + } + + a = 0; + neighborMB = currMB->mb_left; + if (neighborMB != NULL) + { + if (neighborMB->mb_type==IPCM || (neighborMB->cbp > 15)) + a = 1; + } + + curr_cbp_ctx = a + b; + cbp_bit = biari_decode_symbol(dep_dp, ctx->cbp_contexts[1] + curr_cbp_ctx ); + + // CABAC decoding for BinIdx 1 + if (cbp_bit) // set the chroma bits + { + b = 0; + neighborMB = currMB->mb_up; + if (neighborMB != NULL) + { + //if ((neighborMB->mb_type == IPCM) || ((neighborMB->cbp > 15) && ((neighborMB->cbp >> 4) == 2))) + if ((neighborMB->mb_type == IPCM) || ((neighborMB->cbp >> 4) == 2)) + b = 2; + } + + + a = 0; + neighborMB = currMB->mb_left; + if (neighborMB != NULL) + { + if ((neighborMB->mb_type == IPCM) || ((neighborMB->cbp >> 4) == 2)) + a = 1; + } + + curr_cbp_ctx = a + b; + cbp_bit = biari_decode_symbol(dep_dp, ctx->cbp_contexts[2] + curr_cbp_ctx ); + cbp += (cbp_bit == 1) ? 32 : 16; + } + } + + se->value1 = cbp; + + if (!cbp) + { + currSlice->last_dquant = 0; + } + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif +} + +/*! + ************************************************************************ + * \brief + * This function is used to arithmetically decode the chroma + * intra prediction mode of a given MB. + ************************************************************************ + */ +void readCIPredMode_CABAC(Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + TextureInfoContexts *ctx = currSlice->tex_ctx; + int *act_sym = &se->value1; + + Macroblock *MbUp = currMB->mb_up; + Macroblock *MbLeft = currMB->mb_left; + + int b = (MbUp != NULL) ? (((MbUp->c_ipred_mode != 0) && (MbUp->mb_type != IPCM)) ? 1 : 0) : 0; + int a = (MbLeft != NULL) ? (((MbLeft->c_ipred_mode != 0) && (MbLeft->mb_type != IPCM)) ? 1 : 0) : 0; + int act_ctx = a + b; + + *act_sym = biari_decode_symbol(dep_dp, ctx->cipr_contexts + act_ctx ); + + if (*act_sym != 0) + *act_sym = unary_bin_max_decode(dep_dp, ctx->cipr_contexts + 3, 0, 1) + 1; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, se->tracestring, se->value1); + fflush(p_Dec->p_trace); +#endif + +} + + +/*! + ************************************************************************ + * \brief + * Read CBP4-BIT + ************************************************************************ +*/ +static int read_and_store_CBP_block_bit_444 (Macroblock *currMB, + DecodingEnvironmentPtr dep_dp, + int type) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + TextureInfoContexts *tex_ctx = currSlice->tex_ctx; + Macroblock *mb_data = currSlice->mb_data; + int y_ac = (type==LUMA_16AC || type==LUMA_8x8 || type==LUMA_8x4 || type==LUMA_4x8 || type==LUMA_4x4 + || type==CB_16AC || type==CB_8x8 || type==CB_8x4 || type==CB_4x8 || type==CB_4x4 + || type==CR_16AC || type==CR_8x8 || type==CR_8x4 || type==CR_4x8 || type==CR_4x4); + int y_dc = (type==LUMA_16DC || type==CB_16DC || type==CR_16DC); + int u_ac = (type==CHROMA_AC && !currMB->is_v_block); + int v_ac = (type==CHROMA_AC && currMB->is_v_block); + int chroma_dc = (type==CHROMA_DC || type==CHROMA_DC_2x4 || type==CHROMA_DC_4x4); + int u_dc = (chroma_dc && !currMB->is_v_block); + int v_dc = (chroma_dc && currMB->is_v_block); + int j = (y_ac || u_ac || v_ac ? currMB->subblock_y : 0); + int i = (y_ac || u_ac || v_ac ? currMB->subblock_x : 0); + int bit = (y_dc ? 0 : y_ac ? 1 : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 : 35); + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int cbp_bit = 1; // always one for 8x8 mode + int ctx; + int bit_pos_a = 0; + int bit_pos_b = 0; + + PixelPos block_a, block_b; + if (y_ac) + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4Neighbour(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + if (block_a.available) + bit_pos_a = 4*block_a.y + block_a.x; + if (block_b.available) + bit_pos_b = 4*block_b.y + block_b.x; + } + else if (y_dc) + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4Neighbour(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + } + else if (u_ac||v_ac) + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4Neighbour(currMB, i , j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + if (block_a.available) + bit_pos_a = 4*block_a.y + block_a.x; + if (block_b.available) + bit_pos_b = 4*block_b.y + block_b.x; + } + else + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4Neighbour(currMB, i , j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + } + + if (dec_picture->chroma_format_idc!=YUV444) + { + if (type!=LUMA_8x8) + { + //--- get bits from neighboring blocks --- + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit=1; + else + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[0].bits, bit + bit_pos_b); + } + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit=1; + else + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[0].bits, bit + bit_pos_a); + } + + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + } + } + else if( (p_Vid->separate_colour_plane_flag != 0) ) + { + if (type!=LUMA_8x8) + { + //--- get bits from neighbouring blocks --- + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit = 1; + else + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[0].bits,bit+bit_pos_b); + } + + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit = 1; + else + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[0].bits,bit+bit_pos_a); + } + + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + } + } + else + { + if (block_b.available) + { + if((type==LUMA_8x8 || type==CB_8x8 || type==CR_8x8) && + !mb_data[block_b.mb_addr].luma_transform_size_8x8_flag) + {} + else if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit=1; + else + { + if(type==LUMA_8x8) + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[0].bits_8x8, bit + bit_pos_b); + else if (type==CB_8x8) + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[1].bits_8x8, bit + bit_pos_b); + else if (type==CR_8x8) + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[2].bits_8x8, bit + bit_pos_b); + else if ((type==CB_4x4)||(type==CB_4x8)||(type==CB_8x4)||(type==CB_16AC)||(type==CB_16DC)) + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[1].bits,bit+bit_pos_b); + else if ((type==CR_4x4)||(type==CR_4x8)||(type==CR_8x4)||(type==CR_16AC)||(type==CR_16DC)) + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[2].bits,bit+bit_pos_b); + else + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[0].bits,bit+bit_pos_b); + } + } + + + if (block_a.available) + { + if((type==LUMA_8x8 || type==CB_8x8 || type==CR_8x8) && + !mb_data[block_a.mb_addr].luma_transform_size_8x8_flag) + {} + else if(mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit=1; + else + { + if(type==LUMA_8x8) + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[0].bits_8x8,bit+bit_pos_a); + else if (type==CB_8x8) + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[1].bits_8x8,bit+bit_pos_a); + else if (type==CR_8x8) + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[2].bits_8x8,bit+bit_pos_a); + else if ((type==CB_4x4)||(type==CB_4x8)||(type==CB_8x4)||(type==CB_16AC)||(type==CB_16DC)) + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[1].bits,bit+bit_pos_a); + else if ((type==CR_4x4)||(type==CR_4x8)||(type==CR_8x4)||(type==CR_16AC)||(type==CR_16DC)) + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[2].bits,bit+bit_pos_a); + else + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[0].bits,bit+bit_pos_a); + } + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + } + + //--- set bits for current block --- + bit = (y_dc ? 0 : y_ac ? 1 + j + (i >> 2) : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 + j + (i >> 2) : 35 + j + (i >> 2)); + + if (cbp_bit) + { + CBPStructure *s_cbp = currMB->s_cbp; + if (type==LUMA_8x8) + { + s_cbp[0].bits |= ((int64) 0x33 << bit ); + + if (dec_picture->chroma_format_idc==YUV444) + { + s_cbp[0].bits_8x8 |= ((int64) 0x33 << bit ); + } + } + else if (type==CB_8x8) + { + s_cbp[1].bits_8x8 |= ((int64) 0x33 << bit ); + s_cbp[1].bits |= ((int64) 0x33 << bit ); + } + else if (type==CR_8x8) + { + s_cbp[2].bits_8x8 |= ((int64) 0x33 << bit ); + s_cbp[2].bits |= ((int64) 0x33 << bit ); + } + else if (type==LUMA_8x4) + { + s_cbp[0].bits |= ((int64) 0x03 << bit ); + } + else if (type==CB_8x4) + { + s_cbp[1].bits |= ((int64) 0x03 << bit ); + } + else if (type==CR_8x4) + { + s_cbp[2].bits |= ((int64) 0x03 << bit ); + } + else if (type==LUMA_4x8) + { + s_cbp[0].bits |= ((int64) 0x11<< bit ); + } + else if (type==CB_4x8) + { + s_cbp[1].bits |= ((int64)0x11<< bit ); + } + else if (type==CR_4x8) + { + s_cbp[2].bits |= ((int64)0x11<< bit ); + } + else if ((type==CB_4x4)||(type==CB_16AC)||(type==CB_16DC)) + { + s_cbp[1].bits |= i64_power2(bit); + } + else if ((type==CR_4x4)||(type==CR_16AC)||(type==CR_16DC)) + { + s_cbp[2].bits |= i64_power2(bit); + } + else + { + s_cbp[0].bits |= i64_power2(bit); + } + } + return cbp_bit; +} + + +static inline int set_cbp_bit(Macroblock *neighbor_mb) +{ + if(neighbor_mb->mb_type == IPCM) + return 1; + else + return (int) (neighbor_mb->s_cbp[0].bits & 0x01); +} + +static inline int set_cbp_bit_ac(Macroblock *neighbor_mb, PixelPos *block) +{ + if (neighbor_mb->mb_type == IPCM) + return 1; + else + { + int bit_pos = 1 + (block->y << 2) + block->x; + return get_bit(neighbor_mb->s_cbp[0].bits, bit_pos); + } +} + +/*! + ************************************************************************ + * \brief + * Read CBP4-BIT + ************************************************************************ + */ +static int read_and_store_CBP_block_bit_normal (Macroblock *currMB, + DecodingEnvironmentPtr dep_dp, + int type) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + TextureInfoContexts *tex_ctx = currSlice->tex_ctx; + int cbp_bit = 1; // always one for 8x8 mode + Macroblock *mb_data = currSlice->mb_data; + + if (type==LUMA_16DC) + { + int upper_bit = 1; + int left_bit = 1; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &block_a); + get4x4NeighbourBase(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + upper_bit = set_cbp_bit(&mb_data[block_b.mb_addr]); + } + + if (block_a.available) + { + left_bit = set_cbp_bit(&mb_data[block_a.mb_addr]); + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + //--- set bits for current block --- + + if (cbp_bit) + { + currMB->s_cbp[0].bits |= 1; + } + } + else if (type==LUMA_16AC) + { + int j = currMB->subblock_y; + int i = currMB->subblock_x; + int bit = 1; + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + upper_bit = set_cbp_bit_ac(&mb_data[block_b.mb_addr], &block_b); + } + + if (block_a.available) + { + left_bit = set_cbp_bit_ac(&mb_data[block_a.mb_addr], &block_a); + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + if (cbp_bit) + { + //--- set bits for current block --- + bit = 1 + j + (i >> 2); + currMB->s_cbp[0].bits |= i64_power2(bit); + } + } + else if (type==LUMA_8x4) + { + int j = currMB->subblock_y; + int i = currMB->subblock_x; + int bit = 1; + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + upper_bit = set_cbp_bit_ac(&mb_data[block_b.mb_addr], &block_b); + } + + if (block_a.available) + { + left_bit = set_cbp_bit_ac(&mb_data[block_a.mb_addr], &block_a); + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + if (cbp_bit) + { + //--- set bits for current block --- + bit = 1 + j + (i >> 2); + currMB->s_cbp[0].bits |= ((int64) 0x03 << bit ); + } + } + else if (type==LUMA_4x8) + { + int j = currMB->subblock_y; + int i = currMB->subblock_x; + int bit = 1; + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + upper_bit = set_cbp_bit_ac(&mb_data[block_b.mb_addr], &block_b); + } + + if (block_a.available) + { + left_bit = set_cbp_bit_ac(&mb_data[block_a.mb_addr], &block_a); + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + if (cbp_bit) + { + //--- set bits for current block --- + bit = 1 + j + (i >> 2); + + currMB->s_cbp[0].bits |= ((int64) 0x11 << bit ); + } + } + else if (type==LUMA_4x4) + { + int j = currMB->subblock_y; + int i = currMB->subblock_x; + int bit = 1; + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_LUMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + upper_bit = set_cbp_bit_ac(&mb_data[block_b.mb_addr], &block_b); + } + + if (block_a.available) + { + left_bit = set_cbp_bit_ac(&mb_data[block_a.mb_addr], &block_a); + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + if (cbp_bit) + { + //--- set bits for current block --- + bit = 1 + j + (i >> 2); + + currMB->s_cbp[0].bits |= i64_power2(bit); + } + } + else if (type == LUMA_8x8) + { + int j = currMB->subblock_y; + int i = currMB->subblock_x; + //--- set bits for current block --- + int bit = 1 + j + (i >> 2); + + currMB->s_cbp[0].bits |= ((int64) 0x33 << bit ); + } + else if (type==CHROMA_DC || type==CHROMA_DC_2x4 || type==CHROMA_DC_4x4) + { + int u_dc = (!currMB->is_v_block); + int j = 0; + int i = 0; + int bit = (u_dc ? 17 : 18); + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit = 1; + else + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[0].bits, bit); + } + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit = 1; + else + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[0].bits, bit); + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + if (cbp_bit) + { + //--- set bits for current block --- + bit = (u_dc ? 17 : 18); + currMB->s_cbp[0].bits |= i64_power2(bit); + } + } + else + { + int u_ac = (!currMB->is_v_block); + int j = currMB->subblock_y; + int i = currMB->subblock_x; + int bit = (u_ac ? 19 : 35); + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + PixelPos block_a, block_b; + + get4x4NeighbourBase(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4NeighbourBase(currMB, i , j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + + //--- get bits from neighboring blocks --- + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit=1; + else + { + int bit_pos_b = 4*block_b.y + block_b.x; + upper_bit = get_bit(mb_data[block_b.mb_addr].s_cbp[0].bits, bit + bit_pos_b); + } + } + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit=1; + else + { + int bit_pos_a = 4*block_a.y + block_a.x; + left_bit = get_bit(mb_data[block_a.mb_addr].s_cbp[0].bits,bit + bit_pos_a); + } + } + + ctx = 2 * upper_bit + left_bit; + //===== encode symbol ===== + cbp_bit = biari_decode_symbol (dep_dp, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + + if (cbp_bit) + { + //--- set bits for current block --- + bit = (u_ac ? 19 + j + (i >> 2) : 35 + j + (i >> 2)); + currMB->s_cbp[0].bits |= i64_power2(bit); + } + } + return cbp_bit; +} + + +void set_read_and_store_CBP(Macroblock **currMB, int chroma_format_idc) +{ + if (chroma_format_idc == YUV444) + (*currMB)->read_and_store_CBP_block_bit = read_and_store_CBP_block_bit_444; + else + (*currMB)->read_and_store_CBP_block_bit = read_and_store_CBP_block_bit_normal; +} + + + + +//===== position -> ctx for MAP ===== +//--- zig-zag scan ---- +static const byte pos2ctx_map8x8 [] = { 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 3, 3, 6, 7, 7, 7, 8, 9, 10, 9, 8, 7, + 7, 6, 11, 12, 13, 11, 6, 7, 8, 9, 14, 10, 9, 8, 6, 11, + 12, 13, 11, 6, 9, 14, 10, 9, 11, 12, 13, 11 ,14, 10, 12, 14}; // 15 CTX +static const byte pos2ctx_map8x4 [] = { 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 9, 8, 6, 7, 8, + 9, 10, 11, 9, 8, 6, 12, 8, 9, 10, 11, 9, 13, 13, 14, 14}; // 15 CTX +static const byte pos2ctx_map4x4 [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14}; // 15 CTX +static const byte pos2ctx_map2x4c[] = { 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 15 CTX +static const byte pos2ctx_map4x4c[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2}; // 15 CTX +static const byte* pos2ctx_map [] = {pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8, pos2ctx_map8x4, + pos2ctx_map8x4, pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map4x4, + pos2ctx_map2x4c, pos2ctx_map4x4c, + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8,pos2ctx_map8x4, + pos2ctx_map8x4, pos2ctx_map4x4, + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8,pos2ctx_map8x4, + pos2ctx_map8x4,pos2ctx_map4x4}; +//--- interlace scan ---- +//taken from ABT +static const byte pos2ctx_map8x8i[] = { 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 8, 4, 5, + 6, 9, 10, 10, 8, 11, 12, 11, 9, 9, 10, 10, 8, 11, 12, 11, + 9, 9, 10, 10, 8, 11, 12, 11, 9, 9, 10, 10, 8, 13, 13, 9, + 9, 10, 10, 8, 13, 13, 9, 9, 10, 10, 14, 14, 14, 14, 14, 14}; // 15 CTX +static const byte pos2ctx_map8x4i[] = { 0, 1, 2, 3, 4, 5, 6, 3, 4, 5, 6, 3, 4, 7, 6, 8, + 9, 7, 6, 8, 9, 10, 11, 12, 12, 10, 11, 13, 13, 14, 14, 14}; // 15 CTX +static const byte pos2ctx_map4x8i[] = { 0, 1, 1, 1, 2, 3, 3, 4, 4, 4, 5, 6, 2, 7, 7, 8, + 8, 8, 5, 6, 9, 10, 10, 11, 11, 11, 12, 13, 13, 14, 14, 14}; // 15 CTX +static const byte* pos2ctx_map_int[] = {pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8i,pos2ctx_map8x4i, + pos2ctx_map4x8i,pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map4x4, + pos2ctx_map2x4c, pos2ctx_map4x4c, + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8i,pos2ctx_map8x4i, + pos2ctx_map8x4i,pos2ctx_map4x4, + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8i,pos2ctx_map8x4i, + pos2ctx_map8x4i,pos2ctx_map4x4}; + +//===== position -> ctx for LAST ===== +static const byte pos2ctx_last8x8 [] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8}; // 9 CTX +static const byte pos2ctx_last8x4 [] = { 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8}; // 9 CTX + +static const byte pos2ctx_last4x4 [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // 15 CTX +static const byte pos2ctx_last2x4c[] = { 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 15 CTX +static const byte pos2ctx_last4x4c[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2}; // 15 CTX +static const byte* pos2ctx_last [] = {pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last8x8, pos2ctx_last8x4, + pos2ctx_last8x4, pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last4x4, + pos2ctx_last2x4c, pos2ctx_last4x4c, + pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last8x8,pos2ctx_last8x4, + pos2ctx_last8x4, pos2ctx_last4x4, + pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last8x8,pos2ctx_last8x4, + pos2ctx_last8x4, pos2ctx_last4x4}; + + + +/*! + ************************************************************************ + * \brief + * Read Significance MAP + ************************************************************************ + */ +static int read_significance_map (Macroblock *currMB, + DecodingEnvironmentPtr dep_dp, + int type, + int coeff[]) +{ + Slice *currSlice = currMB->p_Slice; + int fld = ( currSlice->structure!=FRAME || currMB->mb_field ); + const byte *pos2ctx_Map = (fld) ? pos2ctx_map_int[type] : pos2ctx_map[type]; + const byte *pos2ctx_Last = pos2ctx_last[type]; + + BiContextTypePtr map_ctx = currSlice->tex_ctx->map_contexts [fld][type2ctx_map [type]]; + BiContextTypePtr last_ctx = currSlice->tex_ctx->last_contexts[fld][type2ctx_last[type]]; + + int i; + int coeff_ctr = 0; + int i0 = 0; + int i1 = maxpos[type]; + + + if (!c1isdc[type]) + { + ++i0; + ++i1; + } + + for (i=i0; i < i1; ++i) // if last coeff is reached, it has to be significant + { + //--- read significance symbol --- + if (biari_decode_symbol (dep_dp, map_ctx + pos2ctx_Map[i])) + { + *(coeff++) = 1; + ++coeff_ctr; + //--- read last coefficient symbol --- + if (biari_decode_symbol (dep_dp, last_ctx + pos2ctx_Last[i])) + { + memset(coeff, 0, (i1 - i) * sizeof(int)); + return coeff_ctr; + } + } + else + { + *(coeff++) = 0; + } + } + //--- last coefficient must be significant if no last symbol was received --- + if (i < i1 + 1) + { + *coeff = 1; + ++coeff_ctr; + } + + return coeff_ctr; +} + + + +/*! + ************************************************************************ + * \brief + * Read Levels + ************************************************************************ + */ +static void read_significant_coefficients (DecodingEnvironmentPtr dep_dp, + TextureInfoContexts *tex_ctx, + int type, + int *coeff) +{ + BiContextType *one_contexts = tex_ctx->one_contexts[type2ctx_one[type]]; + BiContextType *abs_contexts = tex_ctx->abs_contexts[type2ctx_abs[type]]; + const short max_type = max_c2[type]; + int i = maxpos[type]; + int *cof = coeff + i; + int c1 = 1; + int c2 = 0; + + for (; i>=0; i--) + { + if (*cof != 0) + { + *cof += biari_decode_symbol (dep_dp, one_contexts + c1); + + if (*cof == 2) + { + *cof += unary_exp_golomb_level_decode (dep_dp, abs_contexts + c2); + c2 = imin (++c2, max_type); + c1 = 0; + } + else if (c1) + { + c1 = imin (++c1, 4); + } + + if (biari_decode_symbol_eq_prob(dep_dp)) + { + *cof = - *cof; + } + } + cof--; + } +} + + +/*! + ************************************************************************ + * \brief + * Read Block-Transform Coefficients + ************************************************************************ + */ +void readRunLevel_CABAC (Macroblock *currMB, + SyntaxElement *se, + DecodingEnvironmentPtr dep_dp) +{ + Slice *currSlice = currMB->p_Slice; + int *coeff_ctr = &currSlice->coeff_ctr; + int *coeff = currSlice->coeff; + + //--- read coefficients for whole block --- + if (*coeff_ctr < 0) + { + //===== decode CBP-BIT ===== + if ((*coeff_ctr = currMB->read_and_store_CBP_block_bit (currMB, dep_dp, se->context) ) != 0) + { + //===== decode significance map ===== + *coeff_ctr = read_significance_map (currMB, dep_dp, se->context, coeff); + + //===== decode significant coefficients ===== + read_significant_coefficients (dep_dp, currSlice->tex_ctx, se->context, coeff); + } + } + + //--- set run and level --- + if (*coeff_ctr) + { + //--- set run and level (coefficient) --- + for (se->value2 = 0; coeff[currSlice->pos] == 0; ++currSlice->pos, ++se->value2); + se->value1 = coeff[currSlice->pos++]; + } + else + { + //--- set run and level (EOB) --- + se->value1 = se->value2 = 0; + } + //--- decrement coefficient counter and re-set position --- + if ((*coeff_ctr)-- == 0) + currSlice->pos = 0; + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-53s %3d %3d\n",symbolCount++, se->tracestring, se->value1,se->value2); + fflush(p_Dec->p_trace); +#endif +} + +/*! + ************************************************************************ + * \brief + * arithmetic decoding + ************************************************************************ + */ +int readSyntaxElement_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *this_dataPart) +{ + DecodingEnvironmentPtr dep_dp = &(this_dataPart->de_cabac); + int curr_len = arideco_bits_read(dep_dp); + + // perform the actual decoding by calling the appropriate method + se->reading(currMB, se, dep_dp); + //read again and minus curr_len = arideco_bits_read(dep_dp); from above + se->len = (arideco_bits_read(dep_dp) - curr_len); + +#if (TRACE==2) + fprintf(p_Dec->p_trace, "curr_len: %d\n",curr_len); + fprintf(p_Dec->p_trace, "se_len: %d\n",se->len); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * decoding of unary binarization using one or 2 distinct + * models for the first and all remaining bins; no terminating + * "0" for max_symbol + *********************************************************************** + */ +static unsigned int unary_bin_max_decode(DecodingEnvironmentPtr dep_dp, + BiContextTypePtr ctx, + int ctx_offset, + unsigned int max_symbol) +{ + unsigned int symbol = biari_decode_symbol(dep_dp, ctx ); + + if (symbol == 0 || (max_symbol == 0)) + return symbol; + else + { + unsigned int l; + ctx += ctx_offset; + symbol = 0; + do + { + l = biari_decode_symbol(dep_dp, ctx); + ++symbol; + } + while( (l != 0) && (symbol < max_symbol) ); + + if ((l != 0) && (symbol == max_symbol)) + ++symbol; + return symbol; + } +} + + +/*! + ************************************************************************ + * \brief + * decoding of unary binarization using one or 2 distinct + * models for the first and all remaining bins + *********************************************************************** + */ +static unsigned int unary_bin_decode(DecodingEnvironmentPtr dep_dp, + BiContextTypePtr ctx, + int ctx_offset) +{ + unsigned int symbol = biari_decode_symbol(dep_dp, ctx ); + + if (symbol == 0) + return 0; + else + { + unsigned int l; + ctx += ctx_offset;; + symbol = 0; + do + { + l = biari_decode_symbol(dep_dp, ctx); + ++symbol; + } + while( l != 0 ); + return symbol; + } +} + + +/*! + ************************************************************************ + * \brief + * finding end of a slice in case this is not the end of a frame + * + * Unsure whether the "correction" below actually solves an off-by-one + * problem or whether it introduces one in some cases :-( Anyway, + * with this change the bit stream format works with CABAC again. + * StW, 8.7.02 + ************************************************************************ + */ +int cabac_startcode_follows(Slice *currSlice, int eos_bit) +{ + unsigned int bit; + + if( eos_bit ) + { + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + DataPartition *dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + DecodingEnvironmentPtr dep_dp = &(dP->de_cabac); + + bit = biari_decode_final (dep_dp); //GB + +#if TRACE + fprintf(p_Dec->p_trace, "@%-6d %-63s (%3d)\n",symbolCount++, "end_of_slice_flag", bit); + fflush(p_Dec->p_trace); +#endif + } + else + { + bit = 0; + } + + return (bit == 1 ? 1 : 0); +} + +/*! + ************************************************************************ + * \brief + * Exp Golomb binarization and decoding of a symbol + * with prob. of 0.5 + ************************************************************************ + */ +static unsigned int exp_golomb_decode_eq_prob( DecodingEnvironmentPtr dep_dp, + int k) +{ + unsigned int l; + int symbol = 0; + int binary_symbol = 0; + + do + { + l = biari_decode_symbol_eq_prob(dep_dp); + if (l == 1) + { + symbol += (1<p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + Bitstream* currStream = dP->bitstream; + DecodingEnvironmentPtr dep = &(dP->de_cabac); + byte *buf = currStream->streamBuffer; + int BitstreamLengthInBits = (dP->bitstream->bitstream_length << 3) + 7; + + int val = 0; + + int bits_read = 0; + int bitoffset, bitdepth; + int uv, i, j; + + while (dep->DbitsLeft >= 8) + { + dep->Dvalue >>= 8; + dep->DbitsLeft -= 8; + (*dep->Dcodestrm_len)--; + } + + bitoffset = (*dep->Dcodestrm_len) << 3; + + // read luma values + bitdepth = p_Vid->bitdepth_luma; + for(i=0;icof[0][i][j] = val; + + bitoffset += bitdepth; + } + } + + // read chroma values + bitdepth = p_Vid->bitdepth_chroma; + if ((dec_picture->chroma_format_idc != YUV400) && (p_Vid->separate_colour_plane_flag == 0)) + { + for (uv = 1; uv < 3; ++uv) + { + for(i = 0; i < p_Vid->mb_cr_size_y; ++i) + { + for(j = 0; j < p_Vid->mb_cr_size_x; ++j) + { + bits_read += GetBits(buf, bitoffset, &val, BitstreamLengthInBits, bitdepth); +#if TRACE + tracebits2("pcm_byte chroma", bitdepth, val); +#endif + currSlice->cof[uv][i][j] = val; + + bitoffset += bitdepth; + } + } + } + } + + (*dep->Dcodestrm_len) += ( bits_read >> 3); + if (bits_read & 7) + { + ++(*dep->Dcodestrm_len); + } +} + diff --git a/ldecod/src/configfile.c b/ldecod/src/configfile.c new file mode 100644 index 0000000..09b1259 --- /dev/null +++ b/ldecod/src/configfile.c @@ -0,0 +1,312 @@ + +/*! + *********************************************************************** + * \file + * configfile.c + * \brief + * Configuration handling. + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * \note + * In the future this module should hide the Parameters and offer only + * Functions for their access. Modules which make frequent use of some parameters + * (e.g. picture size in macroblocks) are free to buffer them on local variables. + * This will not only avoid global variable and make the code more readable, but also + * speed it up. It will also greatly facilitate future enhancements such as the + * handling of different picture sizes in the same sequence. \n + * \n + * For now, everything is just copied to the inp_par structure (gulp) + * + ************************************************************************************** + * \par Configuration File Format + ************************************************************************************** + * Format is line oriented, maximum of one parameter per line \n + * \n + * Lines have the following format: \n + * \ = \ # Comments \\n \n + * Whitespace is space and \\t + * \par + * \ are the predefined names for Parameters and are case sensitive. + * See configfile.h for the definition of those names and their mapping to + * cfgparams->values. + * \par + * \ are either integers [0..9]* or strings. + * Integers must fit into the wordlengths, signed values are generally assumed. + * Strings containing no whitespace characters can be used directly. Strings containing + * whitespace characters are to be inclosed in double quotes ("string with whitespace") + * The double quote character is forbidden (may want to implement something smarter here). + * \par + * Any Parameters whose ParameterName is undefined lead to the termination of the program + * with an error message. + * + * \par Known bug/Shortcoming: + * zero-length strings (i.e. to signal an non-existing file + * have to be coded as "". + * + * \par Rules for using command files + * \n + * All Parameters are initially taken from DEFAULTCONFIGFILENAME, defined in configfile.h. + * If an -f \ parameter is present in the command line then this file is used to + * update the defaults of DEFAULTCONFIGFILENAME. There can be more than one -f parameters + * present. If -p parameters are present then these + * override the default and the additional config file's settings, and are themselves + * overridden by future -p parameters. There must be whitespace between -f and -p commands + * and their respective parameters + *********************************************************************** + */ + +#define INCLUDED_BY_CONFIGFILE_C + +#include + +#include "global.h" +#include "memalloc.h" +#include "config_common.h" +#include "configfile.h" +#define MAX_ITEMS_TO_PARSE 10000 + +static void PatchInp (InputParameters *p_Inp); + +/*! + *********************************************************************** + * \brief + * print help message and exit + *********************************************************************** + */ +void JMDecHelpExit (void) +{ + fprintf( stdout, "\n ldecod [-h] [-d defdec.cfg] {[-f curenc1.cfg]...[-f curencN.cfg]}" + " {[-p EncParam1=EncValue1]..[-p EncParamM=EncValueM]}\n\n" + "## Parameters\n\n" + + "## Options\n" + " -h : prints function usage\n" + " -d : use as default file for parameter initializations.\n" + " If not used then file defaults to encoder.cfg in local directory.\n" + " -f : read for reseting selected encoder parameters.\n" + " Multiple files could be used that set different parameters\n" + " -p : Set parameter to .\n" + " See default decoder.cfg file for description of all parameters.\n\n" + + "## Examples of usage:\n" + " ldecod\n" + " ldecod -h\n" + " ldecod -d default.cfg\n" + " ldecod -f curenc1.cfg\n" + " ldecod -f curenc1.cfg -p InputFile=\"e:\\data\\container_qcif_30.264\" -p OutputFile=\"dec.yuv\" -p RefFile=\"Rec.yuv\"\n"); + + exit(-1); +} + + +/*! +************************************************************************ +* \brief +* exit with error message if reading from config file failed +************************************************************************ +*/ +static inline void conf_read_check (int val, int expected) +{ + if (val != expected) + { + error ("init_conf: error reading from config file", 500); + } +} + +/*! + *********************************************************************** + * \brief + * Parse the command line parameters and read the config files. + * \param p_Vid + * VideoParameters structure for encoding + * \param p_Inp + * InputParameters structure as input configuration + * \param ac + * number of command line parameters + * \param av + * command line parameters + *********************************************************************** + */ +void ParseCommand(InputParameters *p_Inp, int ac, char *av[]) +{ + char *content = NULL; + int CLcount, ContentLen, NumberParams; + char *filename=DEFAULTCONFIGFILENAME; + + if (ac==2) + { + if (0 == strncmp (av[1], "-v", 2)) + { + printf("JM " JM ": compiled " __DATE__ " " __TIME__ "\n"); + exit(-1); + } + + if (0 == strncmp (av[1], "-h", 2)) + { + JMDecHelpExit(); + } + } + + memcpy (&cfgparams, p_Inp, sizeof (InputParameters)); + //Set default parameters. + printf ("Setting Default Parameters...\n"); + InitParams(Map); + + *p_Inp = cfgparams; + // Process default config file + CLcount = 1; + + if (ac>=3) + { + if ((strlen(av[1])==2) && (0 == strncmp (av[1], "-d", 2))) + { + if(0 == strncmp (av[2], "null", 4)) + filename=NULL; + else + filename=av[2]; + CLcount = 3; + } + if (0 == strncmp (av[1], "-h", 2)) + { + JMDecHelpExit(); + } + } + if(filename) + { + printf ("Parsing Configfile %s\n", filename); + content = GetConfigFileContent (filename); + if (NULL != content) + { + //error (errortext, 300); + ParseContent (p_Inp, Map, content, (int) strlen(content)); + printf ("\n"); + free (content); + } + } + // Parse the command line + + while (CLcount < ac) + { + if (0 == strncmp (av[CLcount], "-h", 2)) + { + JMDecHelpExit(); + } + + if (0 == strncmp (av[CLcount], "-f", 2) || 0 == strncmp (av[CLcount], "-F", 2)) // A file parameter? + { + content = GetConfigFileContent (av[CLcount+1]); + if (NULL==content) + error (errortext, 300); + printf ("Parsing Configfile %s", av[CLcount+1]); + ParseContent (p_Inp, Map, content, (int) strlen (content)); + printf ("\n"); + free (content); + CLcount += 2; + } + else if (0 == strncmp (av[CLcount], "-i", 2) || 0 == strncmp (av[CLcount], "-I", 2)) // A file parameter? + { + strncpy(p_Inp->infile, av[CLcount+1], FILE_NAME_SIZE); + CLcount += 2; + } + else if (0 == strncmp (av[CLcount], "-r", 2) || 0 == strncmp (av[CLcount], "-R", 2)) // A file parameter? + { + strncpy(p_Inp->reffile, av[CLcount+1], FILE_NAME_SIZE); + CLcount += 2; + } + else if (0 == strncmp (av[CLcount], "-o", 2) || 0 == strncmp (av[CLcount], "-O", 2)) // A file parameter? + { + strncpy(p_Inp->outfile, av[CLcount+1], FILE_NAME_SIZE); + CLcount += 2; + } + else if (0 == strncmp (av[CLcount], "-s", 2) || 0 == strncmp (av[CLcount], "-S", 2)) // A file parameter? + { + p_Inp->silent = 1; + CLcount += 1; + } + else if (0 == strncmp (av[CLcount], "-n", 2) || 0 == strncmp (av[CLcount], "-N", 2)) // A file parameter? + { + conf_read_check (sscanf(av[CLcount+1],"%d", &p_Inp->iDecFrmNum), 1); + CLcount += 2; + } +#if (MVC_EXTENSION_ENABLE) + else if (0 == strncmp (av[CLcount], "-mpr", 4) || 0 == strncmp (av[CLcount], "-MPR", 4)) // A file parameter? + { + conf_read_check (sscanf(av[CLcount+1],"%d", &p_Inp->DecodeAllLayers), 1); + CLcount += 2; + } +#endif + else if (0 == strncmp (av[CLcount], "-p", 2) || 0 == strncmp (av[CLcount], "-P", 2)) // A config change? + { + // Collect all data until next parameter (starting with - (x is any character)), + // put it into content, and parse content. + + ++CLcount; + ContentLen = 0; + NumberParams = CLcount; + + // determine the necessary size for content + while (NumberParams < ac && av[NumberParams][0] != '-') + ContentLen += (int) strlen (av[NumberParams++]); // Space for all the strings + ContentLen += 1000; // Additional 1000 bytes for spaces and \0s + + + if ((content = malloc (ContentLen))==NULL) no_mem_exit("Configure: content");; + content[0] = '\0'; + + // concatenate all parameters identified before + + while (CLcount < NumberParams) + { + char *source = &av[CLcount][0]; + char *destin = &content[(int) strlen (content)]; + + while (*source != '\0') + { + if (*source == '=') // The Parser expects whitespace before and after '=' + { + *destin++=' '; *destin++='='; *destin++=' '; // Hence make sure we add it + } + else + *destin++=*source; + source++; + } + *destin = '\0'; + CLcount++; + } + printf ("Parsing command line string '%s'", content); + ParseContent (p_Inp, Map, content, (int) strlen(content)); + free (content); + printf ("\n"); + } + else + { + snprintf (errortext, ET_SIZE, "Error in command line, ac %d, around string '%s', missing -f or -p parameters?", CLcount, av[CLcount]); + error (errortext, 300); + } + } + printf ("\n"); + + PatchInp(p_Inp); + cfgparams = *p_Inp; + p_Inp->enable_32_pulldown = 0; + if (p_Inp->bDisplayDecParams) + DisplayParams(Map, "Decoder Parameters"); +} + + +/*! + *********************************************************************** + * \brief + * Checks the input parameters for consistency. + *********************************************************************** + */ +static void PatchInp (InputParameters *p_Inp) +{ + //int i; + //int storedBplus1; + TestParams(Map, NULL); + if(p_Inp->export_views == 1) + p_Inp->dpb_plus[1] = imax(1, p_Inp->dpb_plus[1]); +} + diff --git a/ldecod/src/context_ini.c b/ldecod/src/context_ini.c new file mode 100644 index 0000000..27f244c --- /dev/null +++ b/ldecod/src/context_ini.c @@ -0,0 +1,122 @@ + +/*! + ************************************************************************************* + * \file context_ini.c + * + * \brief + * CABAC context initializations + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Heiko Schwarz + ************************************************************************************** + */ + +#define CONTEXT_INI_C + +#include "defines.h" +#include "global.h" +#include "biaridecod.h" +#include "ctx_tables.h" + + +#define IBIARI_CTX_INIT2(ii,jj,ctx,tab,num, qp) \ +{ \ + for (i=0; imot_ctx; + TextureInfoContexts* tc = currSlice->tex_ctx; + int i, j; + int qp = imax(0, currSlice->qp); //p_Vid->qp); + int model_number = currSlice->model_number; + + //printf("%d -", p_Vid->currentSlice->model_number); + + //--- motion coding contexts --- + if ((currSlice->slice_type == I_SLICE)||(currSlice->slice_type == SI_SLICE)) + { + IBIARI_CTX_INIT2 (3, NUM_MB_TYPE_CTX, mc->mb_type_contexts, INIT_MB_TYPE, model_number, qp); + IBIARI_CTX_INIT2 (2, NUM_B8_TYPE_CTX, mc->b8_type_contexts, INIT_B8_TYPE, model_number, qp); + IBIARI_CTX_INIT2 (2, NUM_MV_RES_CTX, mc->mv_res_contexts, INIT_MV_RES, model_number, qp); + IBIARI_CTX_INIT2 (2, NUM_REF_NO_CTX, mc->ref_no_contexts, INIT_REF_NO, model_number, qp); + IBIARI_CTX_INIT1 ( NUM_DELTA_QP_CTX, mc->delta_qp_contexts, INIT_DELTA_QP, model_number, qp); + IBIARI_CTX_INIT1 ( NUM_MB_AFF_CTX, mc->mb_aff_contexts, INIT_MB_AFF, model_number, qp); + + //--- texture coding contexts --- + IBIARI_CTX_INIT1 ( NUM_TRANSFORM_SIZE_CTX, tc->transform_size_contexts, INIT_TRANSFORM_SIZE, model_number, qp); + IBIARI_CTX_INIT1 ( NUM_IPR_CTX, tc->ipr_contexts, INIT_IPR, model_number, qp); + IBIARI_CTX_INIT1 ( NUM_CIPR_CTX, tc->cipr_contexts, INIT_CIPR, model_number, qp); + IBIARI_CTX_INIT2 (3, NUM_CBP_CTX, tc->cbp_contexts, INIT_CBP, model_number, qp); + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts, INIT_BCBP, model_number, qp); + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[0], INIT_MAP, model_number, qp); +#if ENABLE_FIELD_CTX + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[1], INIT_FLD_MAP, model_number, qp); + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[1], INIT_FLD_LAST, model_number, qp); +#endif + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[0], INIT_LAST, model_number, qp); + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts, INIT_ONE, model_number, qp); + IBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts, INIT_ABS, model_number, qp); + } + else + { + PBIARI_CTX_INIT2 (3, NUM_MB_TYPE_CTX, mc->mb_type_contexts, INIT_MB_TYPE, model_number, qp); + PBIARI_CTX_INIT2 (2, NUM_B8_TYPE_CTX, mc->b8_type_contexts, INIT_B8_TYPE, model_number, qp); + PBIARI_CTX_INIT2 (2, NUM_MV_RES_CTX, mc->mv_res_contexts, INIT_MV_RES, model_number, qp); + PBIARI_CTX_INIT2 (2, NUM_REF_NO_CTX, mc->ref_no_contexts, INIT_REF_NO, model_number, qp); + PBIARI_CTX_INIT1 ( NUM_DELTA_QP_CTX, mc->delta_qp_contexts, INIT_DELTA_QP, model_number, qp); + PBIARI_CTX_INIT1 ( NUM_MB_AFF_CTX, mc->mb_aff_contexts, INIT_MB_AFF, model_number, qp); + + //--- texture coding contexts --- + PBIARI_CTX_INIT1 ( NUM_TRANSFORM_SIZE_CTX, tc->transform_size_contexts, INIT_TRANSFORM_SIZE, model_number, qp); + PBIARI_CTX_INIT1 ( NUM_IPR_CTX, tc->ipr_contexts, INIT_IPR, model_number, qp); + PBIARI_CTX_INIT1 ( NUM_CIPR_CTX, tc->cipr_contexts, INIT_CIPR, model_number, qp); + PBIARI_CTX_INIT2 (3, NUM_CBP_CTX, tc->cbp_contexts, INIT_CBP, model_number, qp); + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts, INIT_BCBP, model_number, qp); + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[0], INIT_MAP, model_number, qp); +#if ENABLE_FIELD_CTX + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[1], INIT_FLD_MAP, model_number, qp); + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[1], INIT_FLD_LAST, model_number, qp); +#endif + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[0], INIT_LAST, model_number, qp); + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts, INIT_ONE, model_number, qp); + PBIARI_CTX_INIT2 (NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts, INIT_ABS, model_number, qp); + } +} + diff --git a/ldecod/src/dec_statistics.c b/ldecod/src/dec_statistics.c new file mode 100644 index 0000000..81f8038 --- /dev/null +++ b/ldecod/src/dec_statistics.c @@ -0,0 +1,71 @@ +/*! + *********************************************************************** + * \file + * dec_statistics.c + * \brief + * Decoder statistics handling. + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + *********************************************************************** + */ + +#include "global.h" +#include "dec_statistics.h" +#include "memalloc.h" + +/*! + *********************************************************************** + * \brief + * allocates and initializes decoder statistics memory + * \param stats + * Decoder statistics + * \return + *********************************************************************** + */ +void init_dec_stats(DecStatParameters *stats) +{ + int i, j; + int64 *hist; + for (i = 0; i < NUM_SLICE_TYPES; i++) + { + stats->frame_ctr[i] = 0; + for (j = 0; j < MAXMODE; j++) + { + stats->mode_use [i][j] = 0; + stats->mode_use_transform[i][j][0] = 0; + stats->mode_use_transform[i][j][1] = 0; + } + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if ((hist = (int64 *) malloc (4096 * sizeof (int64)))== NULL) + no_mem_exit ("init_dec_stats: stats->histogram_mv"); + memset(hist, 0, 4096 * sizeof (int64)); + stats->histogram_mv[i][j] = hist + 2048; + } + if ((hist = (int64 *) malloc (17 * sizeof (int64)))== NULL) + no_mem_exit ("init_dec_stats: stats->histogram_refs"); + memset(hist, 0, 17 * sizeof (int64)); + stats->histogram_refs[i] = hist + 1; + } +} + +void delete_dec_stats(DecStatParameters *stats) +{ + int i, j; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + stats->histogram_mv[i][j] -= 2048; + free(stats->histogram_mv[i][j]); + } + stats->histogram_refs[i] -= 1; + free(stats->histogram_refs[i]); + } +} diff --git a/ldecod/src/decoder_test.c b/ldecod/src/decoder_test.c new file mode 100644 index 0000000..8c61c4a --- /dev/null +++ b/ldecod/src/decoder_test.c @@ -0,0 +1,305 @@ + +/*! +*********************************************************************** +* \file +* decoder_test.c +* \brief +* H.264/AVC decoder test +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Yuwen He +*********************************************************************** +*/ + +#include "contributors.h" +#include + +//#include "global.h" +#include "win32.h" +#include "h264decoder.h" +#include "configfile.h" + +#if( DISPLAY_OUTPUTED_FRAMES ) +#include "debug_functions.h" +#endif + +#define DECOUTPUT_TEST 0 + +#define PRINT_OUTPUT_POC 0 +#define BITSTREAM_FILENAME "test.264" +#define DECRECON_FILENAME "test_dec.yuv" +#define ENCRECON_FILENAME "test_rec.yuv" +#define FCFR_DEBUG_FILENAME "fcfr_dec_rpu_stats.txt" +#define DECOUTPUT_VIEW0_FILENAME "H264_Decoder_Output_View0.yuv" +#define DECOUTPUT_VIEW1_FILENAME "H264_Decoder_Output_View1.yuv" + +//#if (_DEBUG) +//#define _CRTDBG_MAP_ALLOC +//#include +//#include +//#endif + + +static void Configure(InputParameters *p_Inp, int ac, char *av[]) +{ + //char *config_filename=NULL; + //char errortext[ET_SIZE]; + memset(p_Inp, 0, sizeof(InputParameters)); + strcpy(p_Inp->infile, BITSTREAM_FILENAME); //! set default bitstream name + strcpy(p_Inp->outfile, DECRECON_FILENAME); //! set default output file name + strcpy(p_Inp->reffile, ENCRECON_FILENAME); //! set default reference file name + + + +#ifdef _LEAKYBUCKET_ + strcpy(p_Inp->LeakyBucketParamFile,"leakybucketparam.cfg"); // file where Leaky Bucket parameters (computed by encoder) are stored +#endif + + ParseCommand(p_Inp, ac, av); + + printf("----------------------------- JM %s %s -----------------------------\n", VERSION, EXT_VERSION); + //printf(" Decoder config file : %s \n",config_filename); + if(!p_Inp->bDisplayDecParams) + { + printf("--------------------------------------------------------------------------\n"); + printf(" Input H.264 bitstream : %s \n",p_Inp->infile); + printf(" Output decoded YUV : %s \n",p_Inp->outfile); + //printf(" Output status file : %s \n",LOGFILE); + printf(" Input reference file : %s \n",p_Inp->reffile); + + printf("--------------------------------------------------------------------------\n"); +#ifdef _LEAKYBUCKET_ + printf(" Rate_decoder : %8ld \n",p_Inp->R_decoder); + printf(" B_decoder : %8ld \n",p_Inp->B_decoder); + printf(" F_decoder : %8ld \n",p_Inp->F_decoder); + printf(" LeakyBucketParamFile: %s \n",p_Inp->LeakyBucketParamFile); // Leaky Bucket Param file + calc_buffer(p_Inp); + printf("--------------------------------------------------------------------------\n"); +#endif + } + +} + +/********************************************************* +if bOutputAllFrames is 1, then output all valid frames to file onetime; +else output the first valid frame and move the buffer to the end of list; +*********************************************************/ +static int WriteOneFrame(DecodedPicList *pDecPic, int hFileOutput0, int hFileOutput1, int bOutputAllFrames) +{ + int iOutputFrame=0; + DecodedPicList *pPic = pDecPic; + + if(pPic && (((pPic->iYUVStorageFormat==2) && pPic->bValid==3) || ((pPic->iYUVStorageFormat!=2) && pPic->bValid==1)) ) + { + int i, iWidth, iHeight, iStride, iWidthUV, iHeightUV, iStrideUV; + byte *pbBuf; + int hFileOutput; + int res; + + iWidth = pPic->iWidth*((pPic->iBitDepth+7)>>3); + iHeight = pPic->iHeight; + iStride = pPic->iYBufStride; + if(pPic->iYUVFormat != YUV444) + iWidthUV = pPic->iWidth>>1; + else + iWidthUV = pPic->iWidth; + if(pPic->iYUVFormat == YUV420) + iHeightUV = pPic->iHeight>>1; + else + iHeightUV = pPic->iHeight; + iWidthUV *= ((pPic->iBitDepth+7)>>3); + iStrideUV = pPic->iUVBufStride; + + do + { + if(pPic->iYUVStorageFormat==2) + hFileOutput = (pPic->iViewId&0xffff)? hFileOutput1 : hFileOutput0; + else + hFileOutput = hFileOutput0; + if(hFileOutput >=0) + { + //Y; + pbBuf = pPic->pY; + for(i=0; iiYUVFormat != YUV400) + { + //U; + pbBuf = pPic->pU; + for(i=0; ipV; + for(i=0; iiYUVStorageFormat==2)) + { + hFileOutput = ((pPic->iViewId>>16)&0xffff)? hFileOutput1 : hFileOutput0; + if(hFileOutput>=0) + { + int iPicSize =iHeight*iStride; + //Y; + pbBuf = pPic->pY+iPicSize; + for(i=0; iiYUVFormat != YUV400) + { + iPicSize = iHeightUV*iStrideUV; + //U; + pbBuf = pPic->pU+iPicSize; + for(i=0; ipV+iPicSize; + for(i=0; iiPOC, pPic->iViewId); +#endif + pPic->bValid = 0; + pPic = pPic->pNext; + }while(pPic != NULL && pPic->bValid && bOutputAllFrames); + } +#if PRINT_OUTPUT_POC + else + printf( "\nNone frame output\n"); +#endif + + return iOutputFrame; +} + +/*! +*********************************************************************** +* \brief +* main function for JM decoder +*********************************************************************** +*/ +int main(int argc, char **argv) +{ + int iRet; + DecodedPicList *pDecPicList; + int hFileDecOutput0=-1, hFileDecOutput1=-1; + int iFramesOutput=0, iFramesDecoded=0; + InputParameters InputParams; + +#if DECOUTPUT_TEST + hFileDecOutput0 = open(DECOUTPUT_VIEW0_FILENAME, OPENFLAGS_WRITE, OPEN_PERMISSIONS); + printf( "Decoder output view0: %s\n", DECOUTPUT_VIEW0_FILENAME); + hFileDecOutput1 = open(DECOUTPUT_VIEW1_FILENAME, OPENFLAGS_WRITE, OPEN_PERMISSIONS); + printf( "Decoder output view1: %s\n", DECOUTPUT_VIEW1_FILENAME); +#endif + +//#if (_DEBUG) +// _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); +//#endif + + init_time(); + + //get input parameters; + Configure(&InputParams, argc, argv); + //open decoder; + iRet = OpenDecoder(&InputParams); + if(iRet != DEC_OPEN_NOERR) + { + printf( "Open encoder failed: 0x%x!\n", iRet); + return -1; //failed; + } + + //decoding; + do + { + iRet = DecodeOneFrame(&pDecPicList); + if(iRet==DEC_EOS || iRet==DEC_SUCCEED) + { + //process the decoded picture, output or display; + iFramesOutput += WriteOneFrame(pDecPicList, hFileDecOutput0, hFileDecOutput1, 0); + iFramesDecoded++; + } + else + { + //error handling; + printf( "Error in decoding process: 0x%x\n", iRet); + } + }while((iRet == DEC_SUCCEED) && ((p_Dec->p_Inp->iDecFrmNum==0) || (iFramesDecodedp_Inp->iDecFrmNum))); + + iRet = FinitDecoder(&pDecPicList); + iFramesOutput += WriteOneFrame(pDecPicList, hFileDecOutput0, hFileDecOutput1 , 1); + iRet = CloseDecoder(); + + //quit; + if(hFileDecOutput0>=0) + { + close(hFileDecOutput0); + } + if(hFileDecOutput1>=0) + { + close(hFileDecOutput1); + } + +// printf("%d frames are decoded.\n", iFramesDecoded); + +#if( DISPLAY_OUTPUTED_FRAMES ) + Debug_Close_Windows("Outputed Frame"); +#endif + +//#if (_DEBUG) +// _CrtDumpMemoryLeaks(); +// //_crtBreakAlloc=19044 +//#if( WIN32 ) +// system("pause"); +//#endif +//#endif + fflush(stdout); + return 0; +} + + diff --git a/ldecod/src/erc_api.c b/ldecod/src/erc_api.c new file mode 100644 index 0000000..c215255 --- /dev/null +++ b/ldecod/src/erc_api.c @@ -0,0 +1,482 @@ + +/*! + ************************************************************************************* + * \file erc_api.c + * + * \brief + * External (still inside video decoder) interface for error concealment module + * + * \author + * - Ari Hourunranta + * - Viktor Varsa + * - Ye-Kui Wang + * + ************************************************************************************* + */ + + +#include "global.h" +#include "memalloc.h" +#include "erc_api.h" +#include "fast_memory.h" + + +/*! +************************************************************************ +* \brief +* write the encoding mode and motion vectors of current +* MB to the buffer of the error concealment module. +************************************************************************ +*/ +void ercWriteMBMODEandMV(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int i, ii, jj, currMBNum = currMB->mbAddrX; //p_Vid->currentSlice->current_mb_nr; + StorablePicture *dec_picture = p_Vid->dec_picture; + int mbx = xPosMB(currMBNum, dec_picture->size_x), mby = yPosMB(currMBNum, dec_picture->size_x); + objectBuffer_t *currRegion, *pRegion; + + currRegion = p_Vid->erc_object_list + (currMBNum<<2); + + if(p_Vid->type != B_SLICE) //non-B frame + { + for (i=0; i<4; ++i) + { + pRegion = currRegion + i; + pRegion->regionMode = (currMB->mb_type ==I16MB ? REGMODE_INTRA : + currMB->b8mode[i]==IBLOCK ? REGMODE_INTRA_8x8 : + currMB->b8mode[i]==0 ? REGMODE_INTER_COPY : + currMB->b8mode[i]==1 ? REGMODE_INTER_PRED : REGMODE_INTER_PRED_8x8); + if (currMB->b8mode[i]==0 || currMB->b8mode[i]==IBLOCK) // INTRA OR COPY + { + pRegion->mv[0] = 0; + pRegion->mv[1] = 0; + pRegion->mv[2] = 0; + } + else + { + ii = 4*mbx + (i & 0x01)*2;// + BLOCK_SIZE; + jj = 4*mby + (i >> 1 )*2; + if (currMB->b8mode[i]>=5 && currMB->b8mode[i]<=7) // SMALL BLOCKS + { + pRegion->mv[0] = (dec_picture->mv_info[jj][ii].mv[LIST_0].mv_x + dec_picture->mv_info[jj][ii + 1].mv[LIST_0].mv_x + dec_picture->mv_info[jj + 1][ii].mv[LIST_0].mv_x + dec_picture->mv_info[jj + 1][ii + 1].mv[LIST_0].mv_x + 2)/4; + pRegion->mv[1] = (dec_picture->mv_info[jj][ii].mv[LIST_0].mv_y + dec_picture->mv_info[jj][ii + 1].mv[LIST_0].mv_y + dec_picture->mv_info[jj + 1][ii].mv[LIST_0].mv_y + dec_picture->mv_info[jj + 1][ii + 1].mv[LIST_0].mv_y + 2)/4; + } + else // 16x16, 16x8, 8x16, 8x8 + { + pRegion->mv[0] = dec_picture->mv_info[jj][ii].mv[LIST_0].mv_x; + pRegion->mv[1] = dec_picture->mv_info[jj][ii].mv[LIST_0].mv_y; + // pRegion->mv[0] = dec_picture->motion.mv[LIST_0][4*mby+(i/2)*2][4*mbx+(i%2)*2+BLOCK_SIZE][0]; + // pRegion->mv[1] = dec_picture->motion.mv[LIST_0][4*mby+(i/2)*2][4*mbx+(i%2)*2+BLOCK_SIZE][1]; + } + currMB->p_Slice->erc_mvperMB += iabs(pRegion->mv[0]) + iabs(pRegion->mv[1]); + pRegion->mv[2] = dec_picture->mv_info[jj][ii].ref_idx[LIST_0]; + } + } + } + else //B-frame + { + for (i=0; i<4; ++i) + { + ii = 4*mbx + (i%2)*2;// + BLOCK_SIZE; + jj = 4*mby + (i/2)*2; + pRegion = currRegion + i; + pRegion->regionMode = (currMB->mb_type ==I16MB ? REGMODE_INTRA : + currMB->b8mode[i]==IBLOCK ? REGMODE_INTRA_8x8 : REGMODE_INTER_PRED_8x8); + if (currMB->mb_type==I16MB || currMB->b8mode[i]==IBLOCK) // INTRA + { + pRegion->mv[0] = 0; + pRegion->mv[1] = 0; + pRegion->mv[2] = 0; + } + else + { + int idx = (dec_picture->mv_info[jj][ii].ref_idx[0] < 0) ? 1 : 0; + // int idx = (currMB->b8mode[i]==0 && currMB->b8pdir[i]==2 ? LIST_0 : currMB->b8pdir[i]==1 ? LIST_1 : LIST_0); + // int idx = currMB->b8pdir[i]==0 ? LIST_0 : LIST_1; + pRegion->mv[0] = (dec_picture->mv_info[jj][ii].mv[idx].mv_x + + dec_picture->mv_info[jj][ii+1].mv[idx].mv_x + + dec_picture->mv_info[jj+1][ii].mv[idx].mv_x + + dec_picture->mv_info[jj+1][ii+1].mv[idx].mv_x + 2)/4; + pRegion->mv[1] = (dec_picture->mv_info[jj][ii].mv[idx].mv_y + + dec_picture->mv_info[jj][ii+1].mv[idx].mv_y + + dec_picture->mv_info[jj+1][ii].mv[idx].mv_y + + dec_picture->mv_info[jj+1][ii+1].mv[idx].mv_y + 2)/4; + currMB->p_Slice->erc_mvperMB += iabs(pRegion->mv[0]) + iabs(pRegion->mv[1]); + + pRegion->mv[2] = (dec_picture->mv_info[jj][ii].ref_idx[idx]); + /* + if (currMB->b8pdir[i]==0 || (currMB->b8pdir[i]==2 && currMB->b8mode[i]!=0)) // forward or bidirect + { + pRegion->mv[2] = (dec_picture->motion.ref_idx[LIST_0][jj][ii]); + ///???? is it right, not only "p_Vid->fw_refFrArr[jj][ii-4]" + } + else + { + pRegion->mv[2] = (dec_picture->motion.ref_idx[LIST_1][jj][ii]); + // pRegion->mv[2] = 0; + } + */ + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Initinize the error concealment module + ************************************************************************ + */ +void ercInit(VideoParameters *p_Vid, int pic_sizex, int pic_sizey, int flag) +{ + ercClose(p_Vid, p_Vid->erc_errorVar); + p_Vid->erc_object_list = (objectBuffer_t *) calloc((pic_sizex * pic_sizey) >> 6, sizeof(objectBuffer_t)); + if (p_Vid->erc_object_list == NULL) no_mem_exit("ercInit: erc_object_list"); + + // the error concealment instance is allocated + p_Vid->erc_errorVar = ercOpen(); + + // set error concealment ON + ercSetErrorConcealment(p_Vid->erc_errorVar, flag); +} + +/*! + ************************************************************************ + * \brief + * Allocates data structures used in error concealment. + *\return + * The allocated ercVariables_t is returned. + ************************************************************************ + */ +ercVariables_t *ercOpen( void ) +{ + ercVariables_t *errorVar = NULL; + + errorVar = (ercVariables_t *)malloc( sizeof(ercVariables_t)); + if ( errorVar == NULL ) no_mem_exit("ercOpen: errorVar"); + + errorVar->nOfMBs = 0; + errorVar->segments = NULL; + errorVar->currSegment = 0; + errorVar->yCondition = NULL; + errorVar->uCondition = NULL; + errorVar->vCondition = NULL; + errorVar->prevFrameYCondition = NULL; + + errorVar->concealment = 1; + + return errorVar; +} + +/*! + ************************************************************************ + * \brief + * Resets the variables used in error detection. + * Should be called always when starting to decode a new frame. + * \param errorVar + * Variables for error concealment + * \param nOfMBs + * Number of macroblocks in a frame + * \param numOfSegments + * Estimated number of segments (memory reserved) + * \param picSizeX + * Width of the frame in pixels. + ************************************************************************ + */ +void ercReset( ercVariables_t *errorVar, int nOfMBs, int numOfSegments, int picSizeX ) +{ + char *tmp = NULL; + int i = 0; + + if ( errorVar && errorVar->concealment ) + { + ercSegment_t *segments = NULL; + // If frame size has been changed + if ( nOfMBs != errorVar->nOfMBs && errorVar->yCondition != NULL ) + { + free( errorVar->yCondition ); + errorVar->yCondition = NULL; + free( errorVar->prevFrameYCondition ); + errorVar->prevFrameYCondition = NULL; + free( errorVar->uCondition ); + errorVar->uCondition = NULL; + free( errorVar->vCondition ); + errorVar->vCondition = NULL; + free( errorVar->segments ); + errorVar->segments = NULL; + } + + // If the structures are uninitialized (first frame, or frame size is changed) + if ( errorVar->yCondition == NULL ) + { + errorVar->segments = (ercSegment_t *)malloc( numOfSegments*sizeof(ercSegment_t) ); + if ( errorVar->segments == NULL ) no_mem_exit("ercReset: errorVar->segments"); + fast_memset( errorVar->segments, 0, numOfSegments*sizeof(ercSegment_t)); + errorVar->nOfSegments = numOfSegments; + + errorVar->yCondition = (char *)malloc( 4*nOfMBs*sizeof(char) ); + if ( errorVar->yCondition == NULL ) no_mem_exit("ercReset: errorVar->yCondition"); + errorVar->prevFrameYCondition = (char *)malloc( 4*nOfMBs*sizeof(char) ); + if ( errorVar->prevFrameYCondition == NULL ) no_mem_exit("ercReset: errorVar->prevFrameYCondition"); + errorVar->uCondition = (char *)malloc( nOfMBs*sizeof(char) ); + if ( errorVar->uCondition == NULL ) no_mem_exit("ercReset: errorVar->uCondition"); + errorVar->vCondition = (char *)malloc( nOfMBs*sizeof(char) ); + if ( errorVar->vCondition == NULL ) no_mem_exit("ercReset: errorVar->vCondition"); + errorVar->nOfMBs = nOfMBs; + } + else + { + // Store the yCondition struct of the previous frame + tmp = errorVar->prevFrameYCondition; + errorVar->prevFrameYCondition = errorVar->yCondition; + errorVar->yCondition = tmp; + } + + // Reset tables and parameters + fast_memset( errorVar->yCondition, 0, 4*nOfMBs*sizeof(*errorVar->yCondition)); + fast_memset( errorVar->uCondition, 0, nOfMBs*sizeof(*errorVar->uCondition)); + fast_memset( errorVar->vCondition, 0, nOfMBs*sizeof(*errorVar->vCondition)); + + if (errorVar->nOfSegments != numOfSegments) + { + free( errorVar->segments ); + errorVar->segments = NULL; + errorVar->segments = (ercSegment_t *)malloc( numOfSegments*sizeof(ercSegment_t) ); + if ( errorVar->segments == NULL ) no_mem_exit("ercReset: errorVar->segments"); + errorVar->nOfSegments = numOfSegments; + } + + //memset( errorVar->segments, 0, errorVar->nOfSegments * sizeof(ercSegment_t)); + + segments = errorVar->segments; + for ( i = 0; i < errorVar->nOfSegments; i++ ) + { + segments->startMBPos = 0; + segments->endMBPos = (short) (nOfMBs - 1); + (segments++)->fCorrupted = 1; //! mark segments as corrupted + } + + errorVar->currSegment = 0; + errorVar->nOfCorruptedSegments = 0; + } +} + +/*! + ************************************************************************ + * \brief + * Resets the variables used in error detection. + * Should be called always when starting to decode a new frame. + * \param p_Vid + * VideoParameters variable + * \param errorVar + * Variables for error concealment + ************************************************************************ + */ +void ercClose(VideoParameters *p_Vid, ercVariables_t *errorVar ) +{ + if ( errorVar != NULL ) + { + if (errorVar->yCondition != NULL) + { + free( errorVar->segments ); + free( errorVar->yCondition ); + free( errorVar->uCondition ); + free( errorVar->vCondition ); + free( errorVar->prevFrameYCondition ); + } + free( errorVar ); + errorVar = NULL; + } + + if (p_Vid->erc_object_list) + { + free(p_Vid->erc_object_list); + p_Vid->erc_object_list=NULL; + } +} + +/*! + ************************************************************************ + * \brief + * Sets error concealment ON/OFF. Can be invoked only between frames, not during a frame + * \param errorVar + * Variables for error concealment + * \param value + * New value + ************************************************************************ + */ +void ercSetErrorConcealment( ercVariables_t *errorVar, int value ) +{ + if ( errorVar != NULL ) + errorVar->concealment = value; +} + +/*! + ************************************************************************ + * \brief + * Creates a new segment in the segment-list, and marks the start MB and bit position. + * If the end of the previous segment was not explicitly marked by "ercStopSegment", + * also marks the end of the previous segment. + * If needed, it reallocates the segment-list for a larger storage place. + * \param currMBNum + * The MB number where the new slice/segment starts + * \param segment + * Segment/Slice No. counted by the caller + * \param bitPos + * Bitstream pointer: number of bits read from the buffer. + * \param errorVar + * Variables for error detector + ************************************************************************ + */ +void ercStartSegment( int currMBNum, int segment, unsigned int bitPos, ercVariables_t *errorVar ) +{ + if ( errorVar && errorVar->concealment ) + { + errorVar->currSegmentCorrupted = 0; + + errorVar->segments[ segment ].fCorrupted = 0; + errorVar->segments[ segment ].startMBPos = (short) currMBNum; + + } +} + +/*! + ************************************************************************ + * \brief + * Marks the end position of a segment. + * \param currMBNum + * The last MB number of the previous segment + * \param segment + * Segment/Slice No. counted by the caller + * If (segment<0) the internal segment counter is used. + * \param bitPos + * Bitstream pointer: number of bits read from the buffer. + * \param errorVar + * Variables for error detector + ************************************************************************ + */ +void ercStopSegment( int currMBNum, int segment, unsigned int bitPos, ercVariables_t *errorVar ) +{ + if ( errorVar && errorVar->concealment ) + { + errorVar->segments[ segment ].endMBPos = (short) currMBNum; + errorVar->currSegment++; + } +} + +/*! + ************************************************************************ + * \brief + * Marks the current segment (the one which has the "currMBNum" MB in it) + * as lost: all the blocks of the MBs in the segment as corrupted. + * \param picSizeX + * Width of the frame in pixels. + * \param errorVar + * Variables for error detector + ************************************************************************ + */ +void ercMarkCurrSegmentLost(int picSizeX, ercVariables_t *errorVar ) +{ + int j = 0; + int current_segment; + + current_segment = errorVar->currSegment-1; + if ( errorVar && errorVar->concealment ) + { + if (errorVar->currSegmentCorrupted == 0) + { + errorVar->nOfCorruptedSegments++; + errorVar->currSegmentCorrupted = 1; + } + + for ( j = errorVar->segments[current_segment].startMBPos; j <= errorVar->segments[current_segment].endMBPos; j++ ) + { + errorVar->yCondition[MBNum2YBlock (j, 0, picSizeX)] = ERC_BLOCK_CORRUPTED; + errorVar->yCondition[MBNum2YBlock (j, 1, picSizeX)] = ERC_BLOCK_CORRUPTED; + errorVar->yCondition[MBNum2YBlock (j, 2, picSizeX)] = ERC_BLOCK_CORRUPTED; + errorVar->yCondition[MBNum2YBlock (j, 3, picSizeX)] = ERC_BLOCK_CORRUPTED; + errorVar->uCondition[j] = ERC_BLOCK_CORRUPTED; + errorVar->vCondition[j] = ERC_BLOCK_CORRUPTED; + } + errorVar->segments[current_segment].fCorrupted = 1; + } +} + +/*! + ************************************************************************ + * \brief + * Marks the current segment (the one which has the "currMBNum" MB in it) + * as OK: all the blocks of the MBs in the segment as OK. + * \param picSizeX + * Width of the frame in pixels. + * \param errorVar + * Variables for error detector + ************************************************************************ + */ +void ercMarkCurrSegmentOK(int picSizeX, ercVariables_t *errorVar ) +{ + int j = 0; + int current_segment; + + current_segment = errorVar->currSegment-1; + if ( errorVar && errorVar->concealment ) + { + // mark all the Blocks belonging to the segment as OK */ + for ( j = errorVar->segments[current_segment].startMBPos; j <= errorVar->segments[current_segment].endMBPos; j++ ) + { + errorVar->yCondition[MBNum2YBlock (j, 0, picSizeX)] = ERC_BLOCK_OK; + errorVar->yCondition[MBNum2YBlock (j, 1, picSizeX)] = ERC_BLOCK_OK; + errorVar->yCondition[MBNum2YBlock (j, 2, picSizeX)] = ERC_BLOCK_OK; + errorVar->yCondition[MBNum2YBlock (j, 3, picSizeX)] = ERC_BLOCK_OK; + errorVar->uCondition[j] = ERC_BLOCK_OK; + errorVar->vCondition[j] = ERC_BLOCK_OK; + } + errorVar->segments[current_segment].fCorrupted = 0; + } +} + +/*! + ************************************************************************ + * \brief + * Marks the Blocks of the given component (YUV) of the current MB as concealed. + * \param currMBNum + * Selects the segment where this MB number is in. + * \param comp + * Component to mark (0:Y, 1:U, 2:V, <0:All) + * \param picSizeX + * Width of the frame in pixels. + * \param errorVar + * Variables for error detector + ************************************************************************ + */ +void ercMarkCurrMBConcealed( int currMBNum, int comp, int picSizeX, ercVariables_t *errorVar ) +{ + int setAll = 0; + + if ( errorVar && errorVar->concealment ) + { + if (comp < 0) + { + setAll = 1; + comp = 0; + } + + switch (comp) + { + case 0: + errorVar->yCondition[MBNum2YBlock (currMBNum, 0, picSizeX)] = ERC_BLOCK_CONCEALED; + errorVar->yCondition[MBNum2YBlock (currMBNum, 1, picSizeX)] = ERC_BLOCK_CONCEALED; + errorVar->yCondition[MBNum2YBlock (currMBNum, 2, picSizeX)] = ERC_BLOCK_CONCEALED; + errorVar->yCondition[MBNum2YBlock (currMBNum, 3, picSizeX)] = ERC_BLOCK_CONCEALED; + if (!setAll) + break; + case 1: + errorVar->uCondition[currMBNum] = ERC_BLOCK_CONCEALED; + if (!setAll) + break; + case 2: + errorVar->vCondition[currMBNum] = ERC_BLOCK_CONCEALED; + } + } +} diff --git a/ldecod/src/erc_do_i.c b/ldecod/src/erc_do_i.c new file mode 100644 index 0000000..cb1c8ff --- /dev/null +++ b/ldecod/src/erc_do_i.c @@ -0,0 +1,544 @@ + +/*! + ************************************************************************************* + * \file + * erc_do_i.c + * + * \brief + * Intra (I) frame error concealment algorithms for decoder + * + * \author + * - Ari Hourunranta + * - Viktor Varsa + * - Ye-Kui Wang + * + ************************************************************************************* + */ + +#include "global.h" +#include "erc_do.h" + +static void concealBlocks ( VideoParameters *p_Vid, int lastColumn, int lastRow, int comp, frame *recfr, int picSizeX, char *condition ); +static void pixMeanInterpolateBlock( VideoParameters *p_Vid, imgpel *src[], imgpel *block, int blockSize, int frameWidth ); + +/*! + ************************************************************************ + * \brief + * The main function for Intra frame concealment. + * Calls "concealBlocks" for each color component (Y,U,V) separately + * \return + * 0, if the concealment was not successful and simple concealment should be used + * 1, otherwise (even if none of the blocks were concealed) + * \param p_Vid + * video encoding parameters for current picture + * \param recfr + * Reconstructed frame buffer + * \param picSizeX + * Width of the frame in pixels + * \param picSizeY + * Height of the frame in pixels + * \param errorVar + * Variables for error concealment + ************************************************************************ + */ +int ercConcealIntraFrame( VideoParameters *p_Vid, frame *recfr, int picSizeX, int picSizeY, ercVariables_t *errorVar ) +{ + int lastColumn = 0, lastRow = 0; + + // if concealment is on + if ( errorVar && errorVar->concealment ) + { + // if there are segments to be concealed + if ( errorVar->nOfCorruptedSegments ) + { + // Y + lastRow = (int) (picSizeY>>3); + lastColumn = (int) (picSizeX>>3); + concealBlocks( p_Vid, lastColumn, lastRow, 0, recfr, picSizeX, errorVar->yCondition ); + + // U (dimensions halved compared to Y) + lastRow = (int) (picSizeY>>4); + lastColumn = (int) (picSizeX>>4); + concealBlocks( p_Vid, lastColumn, lastRow, 1, recfr, picSizeX, errorVar->uCondition ); + + // V ( dimensions equal to U ) + concealBlocks( p_Vid, lastColumn, lastRow, 2, recfr, picSizeX, errorVar->vCondition ); + } + return 1; + } + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * Conceals the MB at position (row, column) using pixels from predBlocks[] + * using pixMeanInterpolateBlock() + * \param p_Vid + * video encoding parameters for current picture + * \param currFrame + * current frame + * \param row + * y coordinate in blocks + * \param column + * x coordinate in blocks + * \param predBlocks[] + * list of neighboring source blocks (numbering 0 to 7, 1 means: use the neighbor) + * \param frameWidth + * width of frame in pixels + * \param mbWidthInBlocks + * 2 for Y, 1 for U/V components + ************************************************************************ + */ +void ercPixConcealIMB(VideoParameters *p_Vid, imgpel *currFrame, int row, int column, int predBlocks[], int frameWidth, int mbWidthInBlocks) +{ + imgpel *src[8]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + imgpel *currBlock = NULL; + + // collect the reliable neighboring blocks + if (predBlocks[0]) + src[0] = currFrame + (row-mbWidthInBlocks)*frameWidth*8 + (column+mbWidthInBlocks)*8; + if (predBlocks[1]) + src[1] = currFrame + (row-mbWidthInBlocks)*frameWidth*8 + (column-mbWidthInBlocks)*8; + if (predBlocks[2]) + src[2] = currFrame + (row+mbWidthInBlocks)*frameWidth*8 + (column-mbWidthInBlocks)*8; + if (predBlocks[3]) + src[3] = currFrame + (row+mbWidthInBlocks)*frameWidth*8 + (column+mbWidthInBlocks)*8; + if (predBlocks[4]) + src[4] = currFrame + (row-mbWidthInBlocks)*frameWidth*8 + column*8; + if (predBlocks[5]) + src[5] = currFrame + row*frameWidth*8 + (column-mbWidthInBlocks)*8; + if (predBlocks[6]) + src[6] = currFrame + (row+mbWidthInBlocks)*frameWidth*8 + column*8; + if (predBlocks[7]) + src[7] = currFrame + row*frameWidth*8 + (column+mbWidthInBlocks)*8; + + currBlock = currFrame + row*frameWidth*8 + column*8; + pixMeanInterpolateBlock( p_Vid, src, currBlock, mbWidthInBlocks*8, frameWidth ); +} + +/*! + ************************************************************************ + * \brief + * This function checks the neighbors of a Macroblock for usability in + * concealment. First the OK macroblocks are marked, and if there is not + * enough of them, then the CONCEALED ones as well. + * A "1" in the the output array means reliable, a "0" non reliable MB. + * The block order in "predBlocks": + * 1 4 0 + * 5 x 7 + * 2 6 3 + * i.e., corners first. + * \return + * Number of useable neighbor macroblocks for concealment. + * \param predBlocks[] + * Array for indicating the valid neighbor blocks + * \param currRow + * Current block row in the frame + * \param currColumn + * Current block column in the frame + * \param condition + * The block condition (ok, lost) table + * \param maxRow + * Number of block rows in the frame + * \param maxColumn + * Number of block columns in the frame + * \param step + * Number of blocks belonging to a MB, when counting + * in vertical/horizontal direction. (Y:2 U,V:1) + * \param fNoCornerNeigh + * No corner neighbors are considered + ************************************************************************ + */ +int ercCollect8PredBlocks( int predBlocks[], int currRow, int currColumn, char *condition, + int maxRow, int maxColumn, int step, byte fNoCornerNeigh ) +{ + int srcCounter = 0; + int srcCountMin = (fNoCornerNeigh ? 2 : 4); + int threshold = ERC_BLOCK_OK; + + memset( predBlocks, 0, 8*sizeof(int) ); + + // collect the reliable neighboring blocks + do + { + srcCounter = 0; + // top + if (currRow > 0 && condition[ (currRow-1)*maxColumn + currColumn ] >= threshold ) + { //ERC_BLOCK_OK (3) or ERC_BLOCK_CONCEALED (2) + predBlocks[4] = condition[ (currRow-1)*maxColumn + currColumn ]; + srcCounter++; + } + // bottom + if ( currRow < (maxRow-step) && condition[ (currRow+step)*maxColumn + currColumn ] >= threshold ) + { + predBlocks[6] = condition[ (currRow+step)*maxColumn + currColumn ]; + srcCounter++; + } + + if ( currColumn > 0 ) + { + // left + if ( condition[ currRow*maxColumn + currColumn - 1 ] >= threshold ) + { + predBlocks[5] = condition[ currRow*maxColumn + currColumn - 1 ]; + srcCounter++; + } + + if ( !fNoCornerNeigh ) + { + // top-left + if ( currRow > 0 && condition[ (currRow-1)*maxColumn + currColumn - 1 ] >= threshold ) + { + predBlocks[1] = condition[ (currRow-1)*maxColumn + currColumn - 1 ]; + srcCounter++; + } + // bottom-left + if ( currRow < (maxRow-step) && condition[ (currRow+step)*maxColumn + currColumn - 1 ] >= threshold ) + { + predBlocks[2] = condition[ (currRow+step)*maxColumn + currColumn - 1 ]; + srcCounter++; + } + } + } + + if ( currColumn < (maxColumn-step) ) + { + // right + if ( condition[ currRow*maxColumn+currColumn + step ] >= threshold ) + { + predBlocks[7] = condition[ currRow*maxColumn+currColumn + step ]; + srcCounter++; + } + + if ( !fNoCornerNeigh ) + { + // top-right + if ( currRow > 0 && condition[ (currRow-1)*maxColumn + currColumn + step ] >= threshold ) + { + predBlocks[0] = condition[ (currRow-1)*maxColumn + currColumn + step ]; + srcCounter++; + } + // bottom-right + if ( currRow < (maxRow-step) && condition[ (currRow+step)*maxColumn + currColumn + step ] >= threshold ) + { + predBlocks[3] = condition[ (currRow+step)*maxColumn + currColumn + step ]; + srcCounter++; + } + } + } + // prepare for the next round + threshold--; + if (threshold < ERC_BLOCK_CONCEALED) + break; + } while ( srcCounter < srcCountMin); + + return srcCounter; +} + +/*! + ************************************************************************ + * \brief + * collects prediction blocks only from the current column + * \return + * Number of usable neighbour Macroblocks for concealment. + * \param predBlocks[] + * Array for indicating the valid neighbor blocks + * \param currRow + * Current block row in the frame + * \param currColumn + * Current block column in the frame + * \param condition + * The block condition (ok, lost) table + * \param maxRow + * Number of block rows in the frame + * \param maxColumn + * Number of block columns in the frame + * \param step + * Number of blocks belonging to a MB, when counting + * in vertical/horizontal direction. (Y:2 U,V:1) + ************************************************************************ + */ +int ercCollectColumnBlocks( int predBlocks[], int currRow, int currColumn, char *condition, int maxRow, int maxColumn, int step ) +{ + int srcCounter = 0, threshold = ERC_BLOCK_CORRUPTED; + + memset( predBlocks, 0, 8*sizeof(int) ); + + // in this case, row > 0 and row < 17 + if ( condition[ (currRow-1)*maxColumn + currColumn ] > threshold ) + { + predBlocks[4] = 1; + srcCounter++; + } + if ( condition[ (currRow+step)*maxColumn + currColumn ] > threshold ) + { + predBlocks[6] = 1; + srcCounter++; + } + + return srcCounter; +} + +/*! + ************************************************************************ + * \brief + * Core for the Intra blocks concealment. + * It is called for each color component (Y,U,V) separately + * Finds the corrupted blocks and calls pixel interpolation functions + * to correct them, one block at a time. + * Scanning is done vertically and each corrupted column is corrected + * bi-directionally, i.e., first block, last block, first block+1, last block -1 ... + * \param p_Vid + * video encoding parameters for current picture + * \param lastColumn + * Number of block columns in the frame + * \param lastRow + * Number of block rows in the frame + * \param comp + * color component + * \param recfr + * Reconstructed frame buffer + * \param picSizeX + * Width of the frame in pixels + * \param condition + * The block condition (ok, lost) table + ************************************************************************ + */ +static void concealBlocks( VideoParameters *p_Vid, int lastColumn, int lastRow, int comp, frame *recfr, int picSizeX, char *condition ) +{ + int row, column, srcCounter = 0, thr = ERC_BLOCK_CORRUPTED, + lastCorruptedRow = -1, firstCorruptedRow = -1, currRow = 0, + areaHeight = 0, i = 0, smoothColumn = 0; + int predBlocks[8], step = 1; + + // in the Y component do the concealment MB-wise (not block-wise): + // this is useful if only whole MBs can be damaged or lost + if ( comp == 0 ) + step = 2; + else + step = 1; + + for ( column = 0; column < lastColumn; column += step ) + { + for ( row = 0; row < lastRow; row += step ) + { + if ( condition[row*lastColumn+column] <= thr ) + { + firstCorruptedRow = row; + // find the last row which has corrupted blocks (in same continuous area) + for ( lastCorruptedRow = row+step; lastCorruptedRow < lastRow; lastCorruptedRow += step ) + { + // check blocks in the current column + if ( condition[ lastCorruptedRow*lastColumn + column ] > thr ) + { + // current one is already OK, so the last was the previous one + lastCorruptedRow -= step; + break; + } + } + if ( lastCorruptedRow >= lastRow ) + { + // correct only from above + lastCorruptedRow = lastRow-step; + for ( currRow = firstCorruptedRow; currRow < lastRow; currRow += step ) + { + srcCounter = ercCollect8PredBlocks( predBlocks, currRow, column, condition, lastRow, lastColumn, step, 1 ); + + switch( comp ) + { + case 0 : + ercPixConcealIMB( p_Vid, recfr->yptr, currRow, column, predBlocks, picSizeX, 2 ); + break; + case 1 : + ercPixConcealIMB( p_Vid, recfr->uptr, currRow, column, predBlocks, (picSizeX>>1), 1 ); + break; + case 2 : + ercPixConcealIMB( p_Vid, recfr->vptr, currRow, column, predBlocks, (picSizeX>>1), 1 ); + break; + } + + if ( comp == 0 ) + { + condition[ currRow*lastColumn+column] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + 1] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + lastColumn] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + lastColumn + 1] = ERC_BLOCK_CONCEALED; + } + else + { + condition[ currRow*lastColumn+column] = ERC_BLOCK_CONCEALED; + } + + } + row = lastRow; + } + else if ( firstCorruptedRow == 0 ) + { + // correct only from below + for ( currRow = lastCorruptedRow; currRow >= 0; currRow -= step ) + { + srcCounter = ercCollect8PredBlocks( predBlocks, currRow, column, condition, lastRow, lastColumn, step, 1 ); + + switch( comp ) + { + case 0 : + ercPixConcealIMB( p_Vid, recfr->yptr, currRow, column, predBlocks, picSizeX, 2 ); + break; + case 1 : + ercPixConcealIMB( p_Vid, recfr->uptr, currRow, column, predBlocks, (picSizeX>>1), 1 ); + break; + case 2 : + ercPixConcealIMB( p_Vid, recfr->vptr, currRow, column, predBlocks, (picSizeX>>1), 1 ); + break; + } + + if ( comp == 0 ) + { + condition[ currRow*lastColumn+column] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + 1] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + lastColumn] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + lastColumn + 1] = ERC_BLOCK_CONCEALED; + } + else + { + condition[ currRow*lastColumn+column] = ERC_BLOCK_CONCEALED; + } + + } + + row = lastCorruptedRow+step; + } + else + { + // correct bi-directionally + + row = lastCorruptedRow+step; + areaHeight = lastCorruptedRow-firstCorruptedRow+step; + + // Conceal the corrupted area switching between the up and the bottom rows + for ( i = 0; i < areaHeight; i += step ) + { + if ( i % 2 ) + { + currRow = lastCorruptedRow; + lastCorruptedRow -= step; + } + else + { + currRow = firstCorruptedRow; + firstCorruptedRow += step; + } + + if (smoothColumn > 0) + { + srcCounter = ercCollectColumnBlocks( predBlocks, currRow, column, condition, lastRow, lastColumn, step ); + } + else + { + srcCounter = ercCollect8PredBlocks( predBlocks, currRow, column, condition, lastRow, lastColumn, step, 1 ); + } + + switch( comp ) + { + case 0 : + ercPixConcealIMB( p_Vid, recfr->yptr, currRow, column, predBlocks, picSizeX, 2 ); + break; + + case 1 : + ercPixConcealIMB( p_Vid, recfr->uptr, currRow, column, predBlocks, (picSizeX>>1), 1 ); + break; + + case 2 : + ercPixConcealIMB( p_Vid, recfr->vptr, currRow, column, predBlocks, (picSizeX>>1), 1 ); + break; + } + + if ( comp == 0 ) + { + condition[ currRow*lastColumn+column] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + 1] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + lastColumn] = ERC_BLOCK_CONCEALED; + condition[ currRow*lastColumn+column + lastColumn + 1] = ERC_BLOCK_CONCEALED; + } + else + { + condition[ currRow*lastColumn+column ] = ERC_BLOCK_CONCEALED; + } + } + } + + lastCorruptedRow = -1; + firstCorruptedRow = -1; + + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Does the actual pixel based interpolation for block[] + * using weighted average + * \param p_Vid + * video encoding parameters for current picture + * \param src[] + * pointers to neighboring source blocks + * \param block + * destination block + * \param blockSize + * 16 for Y, 8 for U/V components + * \param frameWidth + * Width of the frame in pixels + ************************************************************************ + */ +static void pixMeanInterpolateBlock( VideoParameters *p_Vid, imgpel *src[], imgpel *block, int blockSize, int frameWidth ) +{ + int row, column, k, tmp, srcCounter = 0, weight = 0, bmax = blockSize - 1; + + k = 0; + for ( row = 0; row < blockSize; row++ ) + { + for ( column = 0; column < blockSize; column++ ) + { + tmp = 0; + srcCounter = 0; + // above + if ( src[4] != NULL ) + { + weight = blockSize-row; + tmp += weight * (*(src[4]+bmax*frameWidth+column)); + srcCounter += weight; + } + // left + if ( src[5] != NULL ) + { + weight = blockSize-column; + tmp += weight * (*(src[5]+row*frameWidth+bmax)); + srcCounter += weight; + } + // below + if ( src[6] != NULL ) + { + weight = row+1; + tmp += weight * (*(src[6]+column)); + srcCounter += weight; + } + // right + if ( src[7] != NULL ) + { + weight = column+1; + tmp += weight * (*(src[7]+row*frameWidth)); + srcCounter += weight; + } + + if ( srcCounter > 0 ) + block[ k + column ] = (imgpel)(tmp/srcCounter); + else + block[ k + column ] = (imgpel) (blockSize == 8 ? p_Vid->dc_pred_value_comp[1] : p_Vid->dc_pred_value_comp[0]); + } + k += frameWidth; + } +} diff --git a/ldecod/src/erc_do_p.c b/ldecod/src/erc_do_p.c new file mode 100644 index 0000000..8a59a7a --- /dev/null +++ b/ldecod/src/erc_do_p.c @@ -0,0 +1,1862 @@ + +/*! + ************************************************************************************* + * \file + * erc_do_p.c + * + * \brief + * Inter (P) frame error concealment algorithms for decoder + * + * \author + * - Viktor Varsa + * - Ye-Kui Wang + * - Jill Boyce + * - Saurav K Bandyopadhyay + * - Zhenyu Wu + * - Purvin Pandit + * + ************************************************************************************* + */ + +#include "global.h" +#include "mbuffer.h" +#include "memalloc.h" +#include "erc_do.h" +#include "image.h" +#include "mc_prediction.h" +#include "macroblock.h" + + +// static function declarations +static int concealByCopy(frame *recfr, int currMBNum, objectBuffer_t *object_list, int picSizeX); +static int concealByTrial(frame *recfr, imgpel *predMB, + int currMBNum, objectBuffer_t *object_list, int predBlocks[], + int picSizeX, int picSizeY, char *yCondition); +static int edgeDistortion (int predBlocks[], int currYBlockNum, imgpel *predMB, + imgpel *recY, int picSizeX, int regionSize); +static void copyBetweenFrames (frame *recfr, int currYBlockNum, int picSizeX, int regionSize); +static void buildPredRegionYUV(VideoParameters *p_Vid, int *mv, int x, int y, imgpel *predMB); + +// picture error concealment +static void buildPredblockRegionYUV(VideoParameters *p_Vid, int *mv, + int x, int y, imgpel *predMB, int list, int mb); +static void CopyImgData(imgpel **inputY, imgpel ***inputUV, imgpel **outputY, imgpel ***outputUV, + int img_width, int img_height, int img_width_cr, int img_height_cr); + +static void copyPredMB (int currYBlockNum, imgpel *predMB, frame *recfr, + int picSizeX, int regionSize); +static void add_node ( VideoParameters *p_Vid, struct concealment_node *ptr ); +static void delete_node( VideoParameters *p_Vid, struct concealment_node *ptr ); + +static const int uv_div[2][4] = {{0, 1, 1, 0}, {0, 1, 0, 0}}; //[x/y][yuv_format] + +/*! + ************************************************************************ + * \brief + * The main function for Inter (P) frame concealment. + * \return + * 0, if the concealment was not successful and simple concealment should be used + * 1, otherwise (even if none of the blocks were concealed) + * \param recfr + * Reconstructed frame buffer + * \param object_list + * Motion info for all MBs in the frame + * \param picSizeX + * Width of the frame in pixels + * \param picSizeY + * Height of the frame in pixels + * \param errorVar + * Variables for error concealment + * \param chroma_format_idc + * Chroma format IDC + ************************************************************************ + */ +int ercConcealInterFrame(frame *recfr, objectBuffer_t *object_list, + int picSizeX, int picSizeY, ercVariables_t *errorVar, int chroma_format_idc ) +{ + VideoParameters *p_Vid = recfr->p_Vid; + int lastColumn = 0, lastRow = 0, predBlocks[8]; + int lastCorruptedRow = -1, firstCorruptedRow = -1; + int currRow = 0, row, column, columnInd, areaHeight = 0, i = 0; + imgpel *predMB; + + /* if concealment is on */ + if ( errorVar && errorVar->concealment ) + { + /* if there are segments to be concealed */ + if ( errorVar->nOfCorruptedSegments ) + { + if (chroma_format_idc != YUV400) + predMB = (imgpel *) malloc ( (256 + (p_Vid->mb_cr_size)*2) * sizeof (imgpel)); + else + predMB = (imgpel *) malloc(256 * sizeof (imgpel)); + + if ( predMB == NULL ) no_mem_exit("ercConcealInterFrame: predMB"); + + lastRow = (int) (picSizeY>>4); + lastColumn = (int) (picSizeX>>4); + + for ( columnInd = 0; columnInd < lastColumn; columnInd ++) + { + + column = ((columnInd%2) ? (lastColumn - columnInd/2 -1) : (columnInd/2)); + + for ( row = 0; row < lastRow; row++) + { + + if ( errorVar->yCondition[MBxy2YBlock(column, row, 0, picSizeX)] <= ERC_BLOCK_CORRUPTED ) + { // ERC_BLOCK_CORRUPTED (1) or ERC_BLOCK_EMPTY (0) + firstCorruptedRow = row; + /* find the last row which has corrupted blocks (in same continuous area) */ + for ( lastCorruptedRow = row+1; lastCorruptedRow < lastRow; lastCorruptedRow++) + { + /* check blocks in the current column */ + if (errorVar->yCondition[MBxy2YBlock(column, lastCorruptedRow, 0, picSizeX)] > ERC_BLOCK_CORRUPTED) + { + /* current one is already OK, so the last was the previous one */ + lastCorruptedRow --; + break; + } + } + if ( lastCorruptedRow >= lastRow ) + { + /* correct only from above */ + lastCorruptedRow = lastRow-1; + for ( currRow = firstCorruptedRow; currRow < lastRow; currRow++ ) + { + + ercCollect8PredBlocks (predBlocks, (currRow<<1), (column<<1), + errorVar->yCondition, (lastRow<<1), (lastColumn<<1), 2, 0); + + if(p_Vid->erc_mvperMB >= MVPERMB_THR) + concealByTrial(recfr, predMB, + currRow*lastColumn+column, object_list, predBlocks, + picSizeX, picSizeY, + errorVar->yCondition); + else + concealByCopy(recfr, currRow*lastColumn+column, + object_list, picSizeX); + + ercMarkCurrMBConcealed (currRow*lastColumn+column, -1, picSizeX, errorVar); + } + row = lastRow; + } + else if ( firstCorruptedRow == 0 ) + { + /* correct only from below */ + for ( currRow = lastCorruptedRow; currRow >= 0; currRow-- ) + { + + ercCollect8PredBlocks (predBlocks, (currRow<<1), (column<<1), + errorVar->yCondition, (lastRow<<1), (lastColumn<<1), 2, 0); + + if(p_Vid->erc_mvperMB >= MVPERMB_THR) + concealByTrial(recfr, predMB, + currRow*lastColumn+column, object_list, predBlocks, + picSizeX, picSizeY, + errorVar->yCondition); + else + concealByCopy(recfr, currRow*lastColumn+column, + object_list, picSizeX); + + ercMarkCurrMBConcealed (currRow*lastColumn+column, -1, picSizeX, errorVar); + } + + row = lastCorruptedRow+1; + } + else + { + /* correct bi-directionally */ + + row = lastCorruptedRow+1; + + areaHeight = lastCorruptedRow-firstCorruptedRow+1; + + /* + * Conceal the corrupted area switching between the up and the bottom rows + */ + for ( i = 0; i < areaHeight; i++) + { + if ( i % 2 ) + { + currRow = lastCorruptedRow; + lastCorruptedRow --; + } + else + { + currRow = firstCorruptedRow; + firstCorruptedRow ++; + } + + ercCollect8PredBlocks (predBlocks, (currRow<<1), (column<<1), + errorVar->yCondition, (lastRow<<1), (lastColumn<<1), 2, 0); + + if(p_Vid->erc_mvperMB >= MVPERMB_THR) + concealByTrial(recfr, predMB, + currRow*lastColumn+column, object_list, predBlocks, + picSizeX, picSizeY, + errorVar->yCondition); + else + concealByCopy(recfr, currRow*lastColumn+column, + object_list, picSizeX); + + ercMarkCurrMBConcealed (currRow*lastColumn+column, -1, picSizeX, errorVar); + + } + } + lastCorruptedRow = -1; + firstCorruptedRow = -1; + } + } + } + + free(predMB); + } + return 1; + } + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * It conceals a given MB by simply copying the pixel area from the reference image + * that is at the same location as the macroblock in the current image. This correcponds + * to COPY MBs. + * \return + * Always zero (0). + * \param recfr + * Reconstructed frame buffer + * \param currMBNum + * current MB index + * \param object_list + * Motion info for all MBs in the frame + * \param picSizeX + * Width of the frame in pixels + ************************************************************************ + */ +static int concealByCopy(frame *recfr, int currMBNum, + objectBuffer_t *object_list, int picSizeX) +{ + objectBuffer_t *currRegion; + + currRegion = object_list+(currMBNum<<2); + currRegion->regionMode = REGMODE_INTER_COPY; + + currRegion->xMin = (xPosMB(currMBNum,picSizeX)<<4); + currRegion->yMin = (yPosMB(currMBNum,picSizeX)<<4); + + copyBetweenFrames (recfr, MBNum2YBlock(currMBNum,0,picSizeX), picSizeX, 16); + + return 0; +} + +/*! + ************************************************************************ + * \brief + * Copies the co-located pixel values from the reference to the current frame. + * Used by concealByCopy + * \param recfr + * Reconstructed frame buffer + * \param currYBlockNum + * index of the block (8x8) in the Y plane + * \param picSizeX + * Width of the frame in pixels + * \param regionSize + * can be 16 or 8 to tell the dimension of the region to copy + ************************************************************************ + */ +static void copyBetweenFrames (frame *recfr, int currYBlockNum, int picSizeX, int regionSize) +{ + VideoParameters *p_Vid = recfr->p_Vid; + StorablePicture *dec_picture = p_Vid->dec_picture; + int j, k, location, xmin, ymin; + StorablePicture* refPic = p_Vid->ppSliceList[0]->listX[0][0]; + + /* set the position of the region to be copied */ + xmin = (xPosYBlock(currYBlockNum,picSizeX)<<3); + ymin = (yPosYBlock(currYBlockNum,picSizeX)<<3); + + for (j = ymin; j < ymin + regionSize; j++) + for (k = xmin; k < xmin + regionSize; k++) + { + location = j * picSizeX + k; +//th recfr->yptr[location] = dec_picture->imgY[j][k]; + recfr->yptr[location] = refPic->imgY[j][k]; + } + + for (j = ymin >> uv_div[1][dec_picture->chroma_format_idc]; j < (ymin + regionSize) >> uv_div[1][dec_picture->chroma_format_idc]; j++) + for (k = xmin >> uv_div[0][dec_picture->chroma_format_idc]; k < (xmin + regionSize) >> uv_div[0][dec_picture->chroma_format_idc]; k++) + { +// location = j * picSizeX / 2 + k; + location = ((j * picSizeX) >> uv_div[0][dec_picture->chroma_format_idc]) + k; + +//th recfr->uptr[location] = dec_picture->imgUV[0][j][k]; +//th recfr->vptr[location] = dec_picture->imgUV[1][j][k]; + recfr->uptr[location] = refPic->imgUV[0][j][k]; + recfr->vptr[location] = refPic->imgUV[1][j][k]; + } +} + +/*! + ************************************************************************ + * \brief + * It conceals a given MB by using the motion vectors of one reliable neighbor. That MV of a + * neighbor is selected wich gives the lowest pixel difference at the edges of the MB + * (see function edgeDistortion). This corresponds to a spatial smoothness criteria. + * \return + * Always zero (0). + * \param recfr + * Reconstructed frame buffer + * \param predMB + * memory area for storing temporary pixel values for a macroblock + * the Y,U,V planes are concatenated y = predMB, u = predMB+256, v = predMB+320 + * \param currMBNum + * current MB index + * \param object_list + * array of region structures storing region mode and mv for each region + * \param predBlocks + * status array of the neighboring blocks (if they are OK, concealed or lost) + * \param picSizeX + * Width of the frame in pixels + * \param picSizeY + * Height of the frame in pixels + * \param yCondition + * array for conditions of Y blocks from ercVariables_t + ************************************************************************ + */ +static int concealByTrial(frame *recfr, imgpel *predMB, + int currMBNum, objectBuffer_t *object_list, int predBlocks[], + int picSizeX, int picSizeY, char *yCondition) +{ + VideoParameters *p_Vid = recfr->p_Vid; + + int predMBNum = 0, numMBPerLine, + compSplit1 = 0, compSplit2 = 0, compLeft = 1, comp = 0, compPred, order = 1, + fInterNeighborExists, numIntraNeighbours, + fZeroMotionChecked, predSplitted = 0, + threshold = ERC_BLOCK_OK, + minDist, currDist, i, k; + int regionSize; + objectBuffer_t *currRegion; + int mvBest[3] = {0, 0, 0}, mvPred[3] = {0, 0, 0}, *mvptr; + + numMBPerLine = (int) (picSizeX>>4); + + comp = 0; + regionSize = 16; + + do + { /* 4 blocks loop */ + + currRegion = object_list+(currMBNum<<2)+comp; + + /* set the position of the region to be concealed */ + + currRegion->xMin = (xPosYBlock(MBNum2YBlock(currMBNum,comp,picSizeX),picSizeX)<<3); + currRegion->yMin = (yPosYBlock(MBNum2YBlock(currMBNum,comp,picSizeX),picSizeX)<<3); + + do + { /* reliability loop */ + + minDist = 0; + fInterNeighborExists = 0; + numIntraNeighbours = 0; + fZeroMotionChecked = 0; + + /* loop the 4 neighbours */ + for (i = 4; i < 8; i++) + { + + /* if reliable, try it */ + if (predBlocks[i] >= threshold) + { + switch (i) + { + case 4: + predMBNum = currMBNum-numMBPerLine; + compSplit1 = 2; + compSplit2 = 3; + break; + + case 5: + predMBNum = currMBNum-1; + compSplit1 = 1; + compSplit2 = 3; + break; + + case 6: + predMBNum = currMBNum+numMBPerLine; + compSplit1 = 0; + compSplit2 = 1; + break; + + case 7: + predMBNum = currMBNum+1; + compSplit1 = 0; + compSplit2 = 2; + break; + } + + /* try the concealment with the Motion Info of the current neighbour + only try if the neighbour is not Intra */ + if (isBlock(object_list,predMBNum,compSplit1,INTRA) || + isBlock(object_list,predMBNum,compSplit2,INTRA)) + { + numIntraNeighbours++; + } + else + { + /* if neighbour MB is splitted, try both neighbour blocks */ + for (predSplitted = isSplitted(object_list, predMBNum), + compPred = compSplit1; + predSplitted >= 0; + compPred = compSplit2, + predSplitted -= ((compSplit1 == compSplit2) ? 2 : 1)) + { + + /* if Zero Motion Block, do the copying. This option is tried only once */ + if (isBlock(object_list, predMBNum, compPred, INTER_COPY)) + { + + if (fZeroMotionChecked) + { + continue; + } + else + { + fZeroMotionChecked = 1; + + mvPred[0] = mvPred[1] = 0; + mvPred[2] = 0; + + buildPredRegionYUV(p_Vid->erc_img, mvPred, currRegion->xMin, currRegion->yMin, predMB); + } + } + /* build motion using the neighbour's Motion Parameters */ + else if (isBlock(object_list,predMBNum,compPred,INTRA)) + { + continue; + } + else + { + mvptr = getParam(object_list, predMBNum, compPred, mv); + + mvPred[0] = mvptr[0]; + mvPred[1] = mvptr[1]; + mvPred[2] = mvptr[2]; + + buildPredRegionYUV(p_Vid->erc_img, mvPred, currRegion->xMin, currRegion->yMin, predMB); + } + + /* measure absolute boundary pixel difference */ + currDist = edgeDistortion(predBlocks, + MBNum2YBlock(currMBNum,comp,picSizeX), + predMB, recfr->yptr, picSizeX, regionSize); + + /* if so far best -> store the pixels as the best concealment */ + if (currDist < minDist || !fInterNeighborExists) + { + + minDist = currDist; + + for (k=0;k<3;k++) + mvBest[k] = mvPred[k]; + + currRegion->regionMode = + (isBlock(object_list, predMBNum, compPred, INTER_COPY)) ? + ((regionSize == 16) ? REGMODE_INTER_COPY : REGMODE_INTER_COPY_8x8) : + ((regionSize == 16) ? REGMODE_INTER_PRED : REGMODE_INTER_PRED_8x8); + + copyPredMB(MBNum2YBlock(currMBNum,comp,picSizeX), predMB, recfr, + picSizeX, regionSize); + } + + fInterNeighborExists = 1; + } + } + } + } + + threshold--; + + } while ((threshold >= ERC_BLOCK_CONCEALED) && (fInterNeighborExists == 0)); + + /* always try zero motion */ + if (!fZeroMotionChecked) + { + mvPred[0] = mvPred[1] = 0; + mvPred[2] = 0; + + buildPredRegionYUV(p_Vid->erc_img, mvPred, currRegion->xMin, currRegion->yMin, predMB); + + currDist = edgeDistortion(predBlocks, + MBNum2YBlock(currMBNum,comp,picSizeX), + predMB, recfr->yptr, picSizeX, regionSize); + + if (currDist < minDist || !fInterNeighborExists) + { + + minDist = currDist; + for (k=0;k<3;k++) + mvBest[k] = mvPred[k]; + + currRegion->regionMode = + ((regionSize == 16) ? REGMODE_INTER_COPY : REGMODE_INTER_COPY_8x8); + + copyPredMB(MBNum2YBlock(currMBNum,comp,picSizeX), predMB, recfr, + picSizeX, regionSize); + } + } + + for (i=0; i<3; i++) + currRegion->mv[i] = mvBest[i]; + + yCondition[MBNum2YBlock(currMBNum,comp,picSizeX)] = ERC_BLOCK_CONCEALED; + comp = (comp+order+4)%4; + compLeft--; + + } while (compLeft); + + return 0; +} + +/*! +************************************************************************ +* \brief +* Builds the motion prediction pixels from the given location (in 1/4 pixel units) +* of the reference frame. It not only copies the pixel values but builds the interpolation +* when the pixel positions to be copied from is not full pixel (any 1/4 pixel position). +* It copies the resulting pixel vlaues into predMB. +* \param p_Vid +* The pointer of video_par structure of current frame +* \param mv +* The pointer of the predicted MV of the current (being concealed) MB +* \param x +* The x-coordinate of the above-left corner pixel of the current MB +* \param y +* The y-coordinate of the above-left corner pixel of the current MB +* \param predMB +* memory area for storing temporary pixel values for a macroblock +* the Y,U,V planes are concatenated y = predMB, u = predMB+256, v = predMB+320 +************************************************************************ +*/ +static void buildPredRegionYUV(VideoParameters *p_Vid, int *mv, int x, int y, imgpel *predMB) +{ + imgpel **tmp_block; + int i=0, j=0, ii=0, jj=0,i1=0,j1=0,j4=0,i4=0; + int uv; + int vec1_x=0,vec1_y=0; + int ioff,joff; + imgpel *pMB = predMB; + Slice *currSlice;// = p_Vid->currentSlice; + StorablePicture *dec_picture = p_Vid->dec_picture; + int ii0,jj0,ii1,jj1,if1,jf1,if0,jf0; + int mv_mul; + + //FRExt + int f1_x, f1_y, f2_x, f2_y, f3, f4; + int b8, b4; + int yuv = dec_picture->chroma_format_idc - 1; + + int ref_frame = imax (mv[2], 0); // !!KS: quick fix, we sometimes seem to get negative ref_pic here, so restrict to zero and above + int mb_nr = y/16*(p_Vid->width/16)+x/16; ///currSlice->current_mb_nr; + int **tmp_res = NULL; + + Macroblock *currMB = &p_Vid->mb_data[mb_nr]; // intialization code deleted, see below, StW + currSlice = currMB->p_Slice; + tmp_res = currSlice->tmp_res; + + // This should be allocated only once. + get_mem2Dpel(&tmp_block, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + /* Update coordinates of the current concealed macroblock */ + currMB->mb.x = (short) (x/MB_BLOCK_SIZE); + currMB->mb.y = (short) (y/MB_BLOCK_SIZE); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x; + + mv_mul=4; + + // luma ******************************************************* + + for(j=0;jblock_y+j; + for(i=0;iblock_x+i; + + vec1_x = i4*4*mv_mul + mv[0]; + vec1_y = j4*4*mv_mul + mv[1]; + + get_block_luma(currSlice->listX[0][ref_frame], vec1_x, vec1_y, BLOCK_SIZE, BLOCK_SIZE, + tmp_block, + dec_picture->iLumaStride,dec_picture->size_x_m1, + (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1,tmp_res, + p_Vid->max_pel_value_comp[PLANE_Y],(imgpel) p_Vid->dc_pred_value_comp[PLANE_Y], currMB); + + for(ii=0;iimb_pred[LumaComp][jj+joff][ii+ioff]=tmp_block[jj][ii]; + } + } + + + for (j = 0; j < 16; j++) + { + for (i = 0; i < 16; i++) + { + pMB[j*16+i] = currSlice->mb_pred[LumaComp][j][i]; + } + } + pMB += 256; + + if (dec_picture->chroma_format_idc != YUV400) + { + // chroma ******************************************************* + f1_x = 64/p_Vid->mb_cr_size_x; + f2_x=f1_x-1; + + f1_y = 64/p_Vid->mb_cr_size_y; + f2_y=f1_y-1; + + f3=f1_x*f1_y; + f4=f3>>1; + + for(uv=0;uv<2;uv++) + { + for (b8=0;b8<(p_Vid->num_uv_blocks);b8++) + { + for(b4=0;b4<4;b4++) + { + joff = subblk_offset_y[yuv][b8][b4]; + j4=currMB->pix_c_y+joff; + ioff = subblk_offset_x[yuv][b8][b4]; + i4=currMB->pix_c_x+ioff; + + for(jj=0;jj<4;jj++) + { + for(ii=0;ii<4;ii++) + { + i1=(i4+ii)*f1_x + mv[0]; + j1=(j4+jj)*f1_y + mv[1]; + + ii0=iClip3 (0, dec_picture->size_x_cr-1, i1/f1_x); + jj0=iClip3 (0, dec_picture->size_y_cr-1, j1/f1_y); + ii1=iClip3 (0, dec_picture->size_x_cr-1, ((i1+f2_x)/f1_x)); + jj1=iClip3 (0, dec_picture->size_y_cr-1, ((j1+f2_y)/f1_y)); + + if1=(i1 & f2_x); + jf1=(j1 & f2_y); + if0=f1_x-if1; + jf0=f1_y-jf1; + + currSlice->mb_pred[uv + 1][jj+joff][ii+ioff] = (imgpel) + ((if0*jf0*currSlice->listX[0][ref_frame]->imgUV[uv][jj0][ii0]+ + if1*jf0*currSlice->listX[0][ref_frame]->imgUV[uv][jj0][ii1]+ + if0*jf1*currSlice->listX[0][ref_frame]->imgUV[uv][jj1][ii0]+ + if1*jf1*currSlice->listX[0][ref_frame]->imgUV[uv][jj1][ii1]+f4)/f3); + } + } + } + } + + for (j = 0; j < 8; j++) + { + for (i = 0; i < 8; i++) + { + pMB[j*8+i] = currSlice->mb_pred[uv + 1][j][i]; + } + } + pMB += 64; + + } + } + // We should allocate this memory only once. + free_mem2Dpel(tmp_block); +} +/*! + ************************************************************************ + * \brief + * Copies pixel values between a YUV frame and the temporary pixel value storage place. This is + * used to save some pixel values temporarily before overwriting it, or to copy back to a given + * location in a frame the saved pixel values. + * \param currYBlockNum + * index of the block (8x8) in the Y plane + * \param predMB + * memory area where the temporary pixel values are stored + * the Y,U,V planes are concatenated y = predMB, u = predMB+256, v = predMB+320 + * \param recfr + * pointer to a YUV frame + * \param picSizeX + * picture width in pixels + * \param regionSize + * can be 16 or 8 to tell the dimension of the region to copy + ************************************************************************ + */ +static void copyPredMB (int currYBlockNum, imgpel *predMB, frame *recfr, + int picSizeX, int regionSize) +{ + VideoParameters *p_Vid = recfr->p_Vid; + StorablePicture *dec_picture = p_Vid->dec_picture; + int j, k, xmin, ymin, xmax, ymax; + int locationTmp; + int uv_x = uv_div[0][dec_picture->chroma_format_idc]; + int uv_y = uv_div[1][dec_picture->chroma_format_idc]; + + xmin = (xPosYBlock(currYBlockNum,picSizeX)<<3); + ymin = (yPosYBlock(currYBlockNum,picSizeX)<<3); + xmax = xmin + regionSize -1; + ymax = ymin + regionSize -1; + + for (j = ymin; j <= ymax; j++) + { + for (k = xmin; k <= xmax; k++) + { + locationTmp = (j-ymin) * 16 + (k-xmin); + dec_picture->imgY[j][k] = predMB[locationTmp]; + } + } + + if (dec_picture->chroma_format_idc != YUV400) + { + for (j = (ymin>>uv_y); j <= (ymax>>uv_y); j++) + { + for (k = (xmin>>uv_x); k <= (xmax>>uv_x); k++) + { + locationTmp = (j-(ymin>>uv_y)) * p_Vid->mb_cr_size_x + (k-(xmin>>1)) + 256; + dec_picture->imgUV[0][j][k] = predMB[locationTmp]; + + locationTmp += 64; + + dec_picture->imgUV[1][j][k] = predMB[locationTmp]; + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Calculates a weighted pixel difference between edge Y pixels of the macroblock stored in predMB + * and the pixels in the given Y plane of a frame (recY) that would become neighbor pixels if + * predMB was placed at currYBlockNum block position into the frame. This "edge distortion" value + * is used to determine how well the given macroblock in predMB would fit into the frame when + * considering spatial smoothness. If there are correctly received neighbor blocks (status stored + * in predBlocks) only they are used in calculating the edge distorion; otherwise also the already + * concealed neighbor blocks can also be used. + * \return + * The calculated weighted pixel difference at the edges of the MB. + * \param predBlocks + * status array of the neighboring blocks (if they are OK, concealed or lost) + * \param currYBlockNum + * index of the block (8x8) in the Y plane + * \param predMB + * memory area where the temporary pixel values are stored + * the Y,U,V planes are concatenated y = predMB, u = predMB+256, v = predMB+320 + * \param recY + * pointer to a Y plane of a YUV frame + * \param picSizeX + * picture width in pixels + * \param regionSize + * can be 16 or 8 to tell the dimension of the region to copy + ************************************************************************ + */ +static int edgeDistortion (int predBlocks[], int currYBlockNum, imgpel *predMB, + imgpel *recY, int picSizeX, int regionSize) +{ + int i, j, distortion, numOfPredBlocks, threshold = ERC_BLOCK_OK; + imgpel *currBlock = NULL, *neighbor = NULL; + int currBlockOffset = 0; + + currBlock = recY + (yPosYBlock(currYBlockNum,picSizeX)<<3)*picSizeX + (xPosYBlock(currYBlockNum,picSizeX)<<3); + + do + { + + distortion = 0; numOfPredBlocks = 0; + + // loop the 4 neighbors + for (j = 4; j < 8; j++) + { + /* if reliable, count boundary pixel difference */ + if (predBlocks[j] >= threshold) + { + + switch (j) + { + case 4: + neighbor = currBlock - picSizeX; + for ( i = 0; i < regionSize; i++ ) + { + distortion += iabs((int)(predMB[i] - neighbor[i])); + } + break; + case 5: + neighbor = currBlock - 1; + for ( i = 0; i < regionSize; i++ ) + { + distortion += iabs((int)(predMB[i*16] - neighbor[i*picSizeX])); + } + break; + case 6: + neighbor = currBlock + regionSize*picSizeX; + currBlockOffset = (regionSize-1)*16; + for ( i = 0; i < regionSize; i++ ) + { + distortion += iabs((int)(predMB[i+currBlockOffset] - neighbor[i])); + } + break; + case 7: + neighbor = currBlock + regionSize; + currBlockOffset = regionSize-1; + for ( i = 0; i < regionSize; i++ ) + { + distortion += iabs((int)(predMB[i*16+currBlockOffset] - neighbor[i*picSizeX])); + } + break; + } + + numOfPredBlocks++; + } + } + + threshold--; + if (threshold < ERC_BLOCK_CONCEALED) + break; + } while (numOfPredBlocks == 0); + + if(numOfPredBlocks == 0) + { + return 0; + // assert (numOfPredBlocks != 0); !!!KS hmm, trying to continue... + } + return (distortion/numOfPredBlocks); +} + +// picture error concealment below + +/*! +************************************************************************ +* \brief +* The motion prediction pixels are calculated from the given location (in +* 1/4 pixel units) of the referenced frame. It copies the sub block from the +* corresponding reference to the frame to be concealed. +* +************************************************************************* +*/ +static void buildPredblockRegionYUV(VideoParameters *p_Vid, int *mv, + int x, int y, imgpel *predMB, int list, int current_mb_nr) +{ + imgpel **tmp_block; + int i=0,j=0,ii=0,jj=0,i1=0,j1=0,j4=0,i4=0; + int uv; + int vec1_x=0,vec1_y=0; + int ioff,joff; + + StorablePicture *dec_picture = p_Vid->dec_picture; + imgpel *pMB = predMB; + + int ii0,jj0,ii1,jj1,if1,jf1,if0,jf0; + int mv_mul; + + //FRExt + int f1_x, f1_y, f2_x, f2_y, f3, f4; + int yuv = dec_picture->chroma_format_idc - 1; + + int ref_frame = mv[2]; + int mb_nr = current_mb_nr; + + Macroblock *currMB = &p_Vid->mb_data[mb_nr]; // intialization code deleted, see below, StW + Slice *currSlice = currMB->p_Slice; + + get_mem2Dpel(&tmp_block, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + /* Update coordinates of the current concealed macroblock */ + + currMB->mb.x = (short) (x/BLOCK_SIZE); + currMB->mb.y = (short) (y/BLOCK_SIZE); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y/4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x/4; + + mv_mul=4; + + // luma ******************************************************* + + vec1_x = x*mv_mul + mv[0]; + vec1_y = y*mv_mul + mv[1]; + get_block_luma(currSlice->listX[list][ref_frame], vec1_x, vec1_y, BLOCK_SIZE, BLOCK_SIZE, tmp_block, + dec_picture->iLumaStride,dec_picture->size_x_m1, (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1,currSlice->tmp_res, + p_Vid->max_pel_value_comp[PLANE_Y],(imgpel) p_Vid->dc_pred_value_comp[PLANE_Y], currMB); + + for(jj=0;jjmb_pred[LumaComp][jj][ii]=tmp_block[jj][ii]; + + + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + pMB[j*4+i] = currSlice->mb_pred[LumaComp][j][i]; + } + } + pMB += 16; + + if (dec_picture->chroma_format_idc != YUV400) + { + // chroma ******************************************************* + f1_x = 64/(p_Vid->mb_cr_size_x); + f2_x=f1_x-1; + + f1_y = 64/(p_Vid->mb_cr_size_y); + f2_y=f1_y-1; + + f3=f1_x*f1_y; + f4=f3>>1; + + for(uv=0;uv<2;uv++) + { + joff = subblk_offset_y[yuv][0][0]; + j4=currMB->pix_c_y+joff; + ioff = subblk_offset_x[yuv][0][0]; + i4=currMB->pix_c_x+ioff; + + for(jj=0;jj<2;jj++) + { + for(ii=0;ii<2;ii++) + { + i1=(i4+ii)*f1_x + mv[0]; + j1=(j4+jj)*f1_y + mv[1]; + + ii0=iClip3 (0, dec_picture->size_x_cr-1, i1/f1_x); + jj0=iClip3 (0, dec_picture->size_y_cr-1, j1/f1_y); + ii1=iClip3 (0, dec_picture->size_x_cr-1, ((i1+f2_x)/f1_x)); + jj1=iClip3 (0, dec_picture->size_y_cr-1, ((j1+f2_y)/f1_y)); + + if1=(i1 & f2_x); + jf1=(j1 & f2_y); + if0=f1_x-if1; + jf0=f1_y-jf1; + + currSlice->mb_pred[uv + 1][jj][ii]=(imgpel) ((if0*jf0*currSlice->listX[list][ref_frame]->imgUV[uv][jj0][ii0]+ + if1*jf0*currSlice->listX[list][ref_frame]->imgUV[uv][jj0][ii1]+ + if0*jf1*currSlice->listX[list][ref_frame]->imgUV[uv][jj1][ii0]+ + if1*jf1*currSlice->listX[list][ref_frame]->imgUV[uv][jj1][ii1]+f4)/f3); + } + } + + for (j = 0; j < 2; j++) + { + for (i = 0; i < 2; i++) + { + pMB[j*2+i] = currSlice->mb_pred[uv + 1][j][i]; + } + } + pMB += 4; + + } + } + free_mem2Dpel(tmp_block); +} + +/*! +************************************************************************ +* \brief +* compares two stored pictures by picture number for qsort in descending order +* +************************************************************************ +*/ +static inline int compare_pic_by_pic_num_desc( const void *arg1, const void *arg2 ) +{ + int pic_num1 = (*(StorablePicture**)arg1)->pic_num; + int pic_num2 = (*(StorablePicture**)arg2)->pic_num; + + if (pic_num1 < pic_num2) + return 1; + if (pic_num1 > pic_num2) + return -1; + else + return 0; +} + +/*! +************************************************************************ +* \brief +* compares two stored pictures by picture number for qsort in descending order +* +************************************************************************ +*/ +static inline int compare_pic_by_lt_pic_num_asc( const void *arg1, const void *arg2 ) +{ + int long_term_pic_num1 = (*(StorablePicture**)arg1)->long_term_pic_num; + int long_term_pic_num2 = (*(StorablePicture**)arg2)->long_term_pic_num; + if ( long_term_pic_num1 < long_term_pic_num2) + return -1; + + if ( long_term_pic_num1 > long_term_pic_num2) + return 1; + else + return 0; +} + +/*! +************************************************************************ +* \brief +* compares two stored pictures by poc for qsort in ascending order +* +************************************************************************ +*/ +static inline int compare_pic_by_poc_asc( const void *arg1, const void *arg2 ) +{ + int poc1 = (*(StorablePicture**)arg1)->poc; + int poc2 = (*(StorablePicture**)arg2)->poc; + + if ( poc1 < poc2) + return -1; + if ( poc1 > poc2) + return 1; + else + return 0; +} + + +///*! +//************************************************************************ +//* \brief +//* compares two stored pictures by poc for qsort in descending order +//* +//************************************************************************ +//*/ +//static inline int compare_pic_by_poc_desc( const void *arg1, const void *arg2 ) +//{ +// int poc1 = (*(StorablePicture**)arg1)->poc; +// int poc2 = (*(StorablePicture**)arg2)->poc; +// +// if (poc1 < poc2) +// return 1; +// if (poc1 > poc2) +// return -1; +// else +// return 0; +//} +// +///*! +//************************************************************************ +//* \brief +//* Copy image data from one array to another array +//************************************************************************ +//*/ +// +//static void CopyImgData(imgpel **inputY, imgpel ***inputUV, imgpel **outputY, imgpel ***outputUV, +// int img_width, int img_height, int img_width_cr, int img_height_cr) +//{ +// int x, y; +// +// for (y=0; yused_size - 1; +// int i; +// +// for(i = used_size; i >= 0; i--) +// { +// if (p_Dpb->fs[i]->is_used==3) +// { +// if (((p_Dpb->fs[i]->frame->used_for_reference) && +// (!p_Dpb->fs[i]->frame->is_long_term)) /*|| ((p_Dpb->fs[i]->frame->used_for_reference==0) +// && (p_Dpb->fs[i]->frame->slice_type == P_SLICE))*/ ) +// { +// return p_Dpb->fs[i]->frame; +// } +// } +// } +// +// return NULL; +//} +// +///*! +//************************************************************************ +//* \brief +//* Conceals the lost reference or non reference frame by either frame copy +//* or motion vector copy concealment. +//* +//************************************************************************ +//*/ +// +//static void copy_to_conceal(StorablePicture *src, StorablePicture *dst, VideoParameters *p_Vid) +//{ +// int i=0; +// int mv[3]; +// int multiplier; +// imgpel *predMB, *storeYUV; +// int j, y, x, mb_height, mb_width, ii=0, jj=0; +// int uv; +// int mm, nn; +// int scale = 1; +// StorablePicture *dec_picture = p_Vid->dec_picture; +// // InputParameters *test; +// +// int current_mb_nr = 0; +// +// dst->PicSizeInMbs = src->PicSizeInMbs; +// +// dst->slice_type = src->slice_type = p_Vid->conceal_slice_type; +// +// dst->idr_flag = FALSE; //since we do not want to clears the ref list +// +// dst->no_output_of_prior_pics_flag = src->no_output_of_prior_pics_flag; +// dst->long_term_reference_flag = src->long_term_reference_flag; +// dst->adaptive_ref_pic_buffering_flag = src->adaptive_ref_pic_buffering_flag = 0; +// dst->chroma_format_idc = src->chroma_format_idc; +// dst->frame_mbs_only_flag = src->frame_mbs_only_flag; +// dst->frame_cropping_flag = src->frame_cropping_flag; +// dst->frame_crop_left_offset = src->frame_crop_left_offset; +// dst->frame_crop_right_offset = src->frame_crop_right_offset; +// dst->frame_crop_bottom_offset = src->frame_crop_bottom_offset; +// dst->frame_crop_top_offset = src->frame_crop_top_offset; +// +// dst->qp = src->qp; +// dst->slice_qp_delta = src->slice_qp_delta; +// +// dec_picture = src; +// +// // Conceals the missing frame by frame copy concealment +// if (p_Vid->conceal_mode==1) +// { +// // We need these initializations for using deblocking filter for frame copy +// // concealment as well. +// dst->PicWidthInMbs = src->PicWidthInMbs; +// dst->PicSizeInMbs = src->PicSizeInMbs; +// +// CopyImgData( src->imgY, src->imgUV, dst->imgY, dst->imgUV, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr); +// } +// +// // Conceals the missing frame by motion vector copy concealment +// if (p_Vid->conceal_mode==2) +// { +// if (dec_picture->chroma_format_idc != YUV400) +// { +// storeYUV = (imgpel *) malloc ( (16 + (p_Vid->mb_cr_size_x*p_Vid->mb_cr_size_y)*2/16) * sizeof (imgpel)); +// } +// else +// { +// storeYUV = (imgpel *) malloc (16 * sizeof (imgpel)); +// } +// +// p_Vid->erc_img = p_Vid; +// +// dst->PicWidthInMbs = src->PicWidthInMbs; +// dst->PicSizeInMbs = src->PicSizeInMbs; +// mb_width = dst->PicWidthInMbs; +// mb_height = (dst->PicSizeInMbs)/(dst->PicWidthInMbs); +// scale = (p_Vid->conceal_slice_type == B_SLICE) ? 2 : 1; +// +// if(p_Vid->conceal_slice_type == B_SLICE) +// { +// init_lists_for_non_reference_loss( +// p_Vid->p_Dpb_layer[0], +// dst->slice_type, p_Vid->ppSliceList[0]->structure); +// } +// else +// p_Vid->ppSliceList[0]->init_lists(p_Vid->ppSliceList[0]); //p_Vid->currentSlice); +// +// multiplier = BLOCK_SIZE; +// +// for(i=0;imv_info[i][j].mv[LIST_0].mv_x / scale; +// mv[1] = src->mv_info[i][j].mv[LIST_0].mv_y / scale; +// mv[2] = src->mv_info[i][j].ref_idx[LIST_0]; +// +// if(mv[2]<0) +// mv[2]=0; +// +// dst->mv_info[i][j].mv[LIST_0].mv_x = (short) mv[0]; +// dst->mv_info[i][j].mv[LIST_0].mv_y = (short) mv[1]; +// dst->mv_info[i][j].ref_idx[LIST_0] = (char) mv[2]; +// +// x = (j) * multiplier; +// y = (i) * multiplier; +// +// if ((mm%16==0) && (nn%16==0)) +// current_mb_nr++; +// +// buildPredblockRegionYUV(p_Vid->erc_img, mv, x, y, storeYUV, LIST_0, current_mb_nr); +// +// predMB = storeYUV; +// +// for(ii=0;iiimgY[i*multiplier+ii][j*multiplier+jj] = predMB[ii*(multiplier)+jj]; +// } +// } +// +// predMB = predMB + (multiplier*multiplier); +// +// if (dec_picture->chroma_format_idc != YUV400) +// { +// +// for(uv=0;uv<2;uv++) +// { +// for(ii=0;ii< (multiplier/2);ii++) +// { +// for(jj=0;jj< (multiplier/2);jj++) +// { +// dst->imgUV[uv][i*multiplier/2 +ii][j*multiplier/2 +jj] = predMB[ii*(multiplier/2)+jj]; +// } +// } +// predMB = predMB + (multiplier*multiplier/4); +// } +// } +// } +// } +// free(storeYUV); +// } +//} +// +///*! +//************************************************************************ +//* \brief +//* Uses the previous reference pic for concealment of reference frames +//* +//************************************************************************ +//*/ +// +//static void +//copy_prev_pic_to_concealed_pic(StorablePicture *picture, DecodedPictureBuffer *p_Dpb) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// /* get the last ref pic in dpb */ +// StorablePicture *ref_pic = get_last_ref_pic_from_dpb(p_Dpb); +// +// assert(ref_pic != NULL); +// +// /* copy all the struc from this to current concealment pic */ +// p_Vid->conceal_slice_type = P_SLICE; +// copy_to_conceal(ref_pic, picture, p_Vid); +//} +// +// +///*! +//************************************************************************ +//* \brief +//* This function conceals a missing reference frame. The routine is called +//* based on the difference in frame number. It conceals an IDR frame loss +//* based on the sudden decrease in frame number. +//* +//************************************************************************ +//*/ +// +//void conceal_lost_frames(DecodedPictureBuffer *p_Dpb, Slice *pSlice) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// int CurrFrameNum; +// int UnusedShortTermFrameNum; +// StorablePicture *picture = NULL; +// int tmp1 = pSlice->delta_pic_order_cnt[0]; +// int tmp2 = pSlice->delta_pic_order_cnt[1]; +// int i; +// +// pSlice->delta_pic_order_cnt[0] = pSlice->delta_pic_order_cnt[1] = 0; +// +// // printf("A gap in frame number is found, try to fill it.\n"); +// +// if(p_Vid->IDR_concealment_flag == 1) +// { +// // Conceals an IDR frame loss. Uses the reference frame in the previous +// // GOP for concealment. +// UnusedShortTermFrameNum = 0; +// p_Vid->last_ref_pic_poc = -p_Vid->poc_gap; +// p_Vid->earlier_missing_poc = 0; +// } +// else +// UnusedShortTermFrameNum = (p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num; +// +// CurrFrameNum = pSlice->frame_num; +// +// while (CurrFrameNum != UnusedShortTermFrameNum) +// { +// picture = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); +// +// picture->coded_frame = 1; +// picture->pic_num = UnusedShortTermFrameNum; +// picture->frame_num = UnusedShortTermFrameNum; +// picture->non_existing = 0; +// picture->is_output = 0; +// picture->used_for_reference = 1; +// picture->concealed_pic = 1; +// +// picture->adaptive_ref_pic_buffering_flag = 0; +// +// pSlice->frame_num = UnusedShortTermFrameNum; +// +// picture->top_poc=p_Vid->last_ref_pic_poc + p_Vid->ref_poc_gap; +// picture->bottom_poc=picture->top_poc; +// picture->frame_poc=picture->top_poc; +// picture->poc=picture->top_poc; +// p_Vid->last_ref_pic_poc = picture->poc; +// +// copy_prev_pic_to_concealed_pic(picture, p_Dpb); +// +// //if (UnusedShortTermFrameNum == 0) +// if(p_Vid->IDR_concealment_flag == 1) +// { +// picture->slice_type = I_SLICE; +// picture->idr_flag = TRUE; +// flush_dpb(p_Dpb); +// picture->top_poc= 0; +// picture->bottom_poc=picture->top_poc; +// picture->frame_poc=picture->top_poc; +// picture->poc=picture->top_poc; +// p_Vid->last_ref_pic_poc = picture->poc; +// } +// +// store_picture_in_dpb(p_Vid->p_Dpb_layer[0], picture); +// +// picture=NULL; +// +// p_Vid->pre_frame_num = UnusedShortTermFrameNum; +// UnusedShortTermFrameNum = (UnusedShortTermFrameNum + 1) % p_Vid->max_frame_num; +// +// // update reference flags and set current flag. +// for(i=16;i>0;i--) +// { +// pSlice->ref_flag[i] = pSlice->ref_flag[i-1]; +// } +// pSlice->ref_flag[0] = 0; +// } +// pSlice->delta_pic_order_cnt[0] = tmp1; +// pSlice->delta_pic_order_cnt[1] = tmp2; +// pSlice->frame_num = CurrFrameNum; +//} +// +///*! +//************************************************************************ +//* \brief +//* Updates the reference list for motion vector copy concealment for non- +//* reference frame loss. +//* +//************************************************************************ +//*/ +// +//void update_ref_list_for_concealment(DecodedPictureBuffer *p_Dpb) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// unsigned i, j= 0; +// +// for (i = 0; i < p_Dpb->used_size; i++) +// { +// if (p_Dpb->fs[i]->concealment_reference) +// { +// p_Dpb->fs_ref[j++] = p_Dpb->fs[i]; +// } +// } +// +// p_Dpb->ref_frames_in_buffer = p_Vid->active_pps->num_ref_idx_l0_default_active_minus1; +//} +// +///*! +//************************************************************************ +//* \brief +//* Initialize the list based on the B frame or non reference 'p' frame +//* to be concealed. The function initialize currSlice->listX[0] and list 1 depending +//* on current picture type +//* +//************************************************************************ +//*/ +//void init_lists_for_non_reference_loss(DecodedPictureBuffer *p_Dpb, int currSliceType, PictureStructure currPicStructure) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; +// +// unsigned i; +// int j; +// int max_frame_num = 1 << (active_sps->log2_max_frame_num_minus4 + 4); +// int diff; +// +// int list0idx = 0; +// int list0idx_1 = 0; +// +// StorablePicture *tmp_s; +// +// if (currPicStructure == FRAME) +// { +// for(i=0;iref_frames_in_buffer; i++) +// { +// if(p_Dpb->fs[i]->concealment_reference == 1) +// { +// if(p_Dpb->fs[i]->frame_num > p_Vid->frame_to_conceal) +// p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs[i]->frame_num - max_frame_num; +// else +// p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs[i]->frame_num; +// p_Dpb->fs_ref[i]->frame->pic_num = p_Dpb->fs_ref[i]->frame_num_wrap; +// } +// } +// } +// +// if (currSliceType == P_SLICE) +// { +// // Calculate FrameNumWrap and PicNum +// if (currPicStructure == FRAME) +// { +// for(i=0;iused_size; i++) +// { +// if(p_Dpb->fs[i]->concealment_reference == 1) +// { +// p_Vid->ppSliceList[0]->listX[0][list0idx++] = p_Dpb->fs[i]->frame; +// } +// } +// // order list 0 by PicNum +// qsort((void *)p_Vid->ppSliceList[0]->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc); +// p_Vid->ppSliceList[0]->listXsize[0] = (char) list0idx; +// } +// } +// +// if (currSliceType == B_SLICE) +// { +// if (currPicStructure == FRAME) +// { +// // for(i=0;iref_frames_in_buffer; i++) +// for(i=0;iused_size; i++) +// { +// if(p_Dpb->fs[i]->concealment_reference == 1) +// { +// if(p_Vid->earlier_missing_poc > p_Dpb->fs[i]->frame->poc) +// p_Vid->ppSliceList[0]->listX[0][list0idx++] = p_Dpb->fs[i]->frame; +// } +// } +// +// qsort((void *)p_Vid->ppSliceList[0]->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_poc_desc); +// list0idx_1 = list0idx; +// +// // for(i=0;iref_frames_in_buffer; i++) +// for(i=0;iused_size; i++) +// { +// if(p_Dpb->fs[i]->concealment_reference == 1) +// { +// if(p_Vid->earlier_missing_poc < p_Dpb->fs[i]->frame->poc) +// p_Vid->ppSliceList[0]->listX[0][list0idx++] = p_Dpb->fs[i]->frame; +// } +// } +// +// qsort((void *)&p_Vid->ppSliceList[0]->listX[0][list0idx_1], list0idx-list0idx_1, sizeof(StorablePicture*), compare_pic_by_poc_asc); +// +// for (j=0; jppSliceList[0]->listX[1][list0idx-list0idx_1+j]=p_Vid->ppSliceList[0]->listX[0][j]; +// } +// for (j=list0idx_1; jppSliceList[0]->listX[1][j-list0idx_1]=p_Vid->ppSliceList[0]->listX[0][j]; +// } +// +// p_Vid->ppSliceList[0]->listXsize[0] = p_Vid->ppSliceList[0]->listXsize[1] = (char) list0idx; +// +// qsort((void *)&p_Vid->ppSliceList[0]->listX[0][(short) p_Vid->ppSliceList[0]->listXsize[0]], list0idx-p_Vid->ppSliceList[0]->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); +// qsort((void *)&p_Vid->ppSliceList[0]->listX[1][(short) p_Vid->ppSliceList[0]->listXsize[0]], list0idx-p_Vid->ppSliceList[0]->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); +// p_Vid->ppSliceList[0]->listXsize[0] = p_Vid->ppSliceList[0]->listXsize[1] = (char) list0idx; +// } +// } +// +// if ((p_Vid->ppSliceList[0]->listXsize[0] == p_Vid->ppSliceList[0]->listXsize[1]) && (p_Vid->ppSliceList[0]->listXsize[0] > 1)) +// { +// // check if lists are identical, if yes swap first two elements of listX[1] +// diff=0; +// for (j = 0; j< p_Vid->ppSliceList[0]->listXsize[0]; j++) +// { +// if (p_Vid->ppSliceList[0]->listX[0][j]!=p_Vid->ppSliceList[0]->listX[1][j]) +// diff=1; +// } +// if (!diff) +// { +// tmp_s = p_Vid->ppSliceList[0]->listX[1][0]; +// p_Vid->ppSliceList[0]->listX[1][0]=p_Vid->ppSliceList[0]->listX[1][1]; +// p_Vid->ppSliceList[0]->listX[1][1]=tmp_s; +// } +// } +// +// // set max size +// p_Vid->ppSliceList[0]->listXsize[0] = (char) imin (p_Vid->ppSliceList[0]->listXsize[0], (int)active_sps->num_ref_frames); +// p_Vid->ppSliceList[0]->listXsize[1] = (char) imin (p_Vid->ppSliceList[0]->listXsize[1], (int)active_sps->num_ref_frames); +// +// p_Vid->ppSliceList[0]->listXsize[1] = 0; +// // set the unused list entries to NULL +// for (i=p_Vid->ppSliceList[0]->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) +// { +// p_Vid->ppSliceList[0]->listX[0][i] = NULL; +// } +// for (i=p_Vid->ppSliceList[0]->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) +// { +// p_Vid->ppSliceList[0]->listX[1][i] = NULL; +// } +//} +// +// +///*! +//************************************************************************ +//* \brief +//* Get from the dpb the picture corresponding to a POC. The POC varies +//* depending on whether it is a frame copy or motion vector copy concealment. +//* The frame corresponding to the POC is returned. +//* +//************************************************************************ +//*/ +// +//static StorablePicture *get_pic_from_dpb(DecodedPictureBuffer *p_Dpb, int missingpoc, unsigned int *pos) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// int used_size = p_Dpb->used_size - 1; +// int i, concealfrom = 0; +// +// if(p_Vid->conceal_mode == 1) +// concealfrom = missingpoc - p_Vid->poc_gap; +// else if (p_Vid->conceal_mode == 2) +// concealfrom = missingpoc + p_Vid->poc_gap; +// +// for(i = used_size; i >= 0; i--) +// { +// if(p_Dpb->fs[i]->poc == concealfrom) +// { +// *pos = i; +// return p_Dpb->fs[i]->frame; +// } +// } +// +// return NULL; +//} +// +///*! +//************************************************************************ +//* \brief +//* Function to sort the POC and find the lowest number in the POC list +//* Compare the integers +//* +//************************************************************************ +//*/ +// +//int comp(const void *i, const void *j) +//{ +// return *(int *)i - *(int *)j; +//} +// +///*! +//************************************************************************ +//* \brief +//* Initialises a node, allocates memory for the node, and returns +//* a pointer to the new node. +//* +//************************************************************************ +//*/ +// +//struct concealment_node * init_node( StorablePicture* picture, int missingpoc ) +//{ +// struct concealment_node *ptr; +// +// ptr = (struct concealment_node *) calloc( 1, sizeof(struct concealment_node ) ); +// +// if( ptr == NULL ) +// return (struct concealment_node *) NULL; +// else { +// ptr->picture = picture; +// ptr->missingpocs = missingpoc; +// ptr->next = NULL; +// return ptr; +// } +//} +// +///*! +//************************************************************************ +//* \brief +//* Prints the details of a node +//* +//************************************************************************ +//*/ +// +//void print_node( struct concealment_node *ptr ) +//{ +// printf("Missing POC=%d\n", ptr->missingpocs ); +//} +// +// +///*! +//************************************************************************ +//* \brief +//* Prints all nodes from the current address passed to it. +//* +//************************************************************************ +//*/ +// +//void print_list( struct concealment_node *ptr ) +//{ +// while( ptr != NULL ) +// { +// print_node( ptr ); +// ptr = ptr->next; +// } +//} +// +///*! +//************************************************************************ +//* \brief +//* Adds a node to the end of the list. +//* +//************************************************************************ +//*/ +// +// +//static void add_node( VideoParameters *p_Vid, struct concealment_node *concealment_new ) +//{ + // if( p_Vid->concealment_head == NULL ) +// { +// p_Vid->concealment_end = p_Vid->concealment_head = concealment_new; +// return; +// } +// p_Vid->concealment_end->next = concealment_new; +// p_Vid->concealment_end = concealment_new; +//} +// +// +///*! +//************************************************************************ +//* \brief +//* Deletes the specified node pointed to by 'ptr' from the list +//* +//************************************************************************ +//*/ +// +// +//static void delete_node( VideoParameters *p_Vid, struct concealment_node *ptr ) +//{ +// // We only need to delete the first node in the linked list +// if( ptr == p_Vid->concealment_head ) +// { +// p_Vid->concealment_head = p_Vid->concealment_head->next; +// if( p_Vid->concealment_end == ptr ) +// p_Vid->concealment_end = p_Vid->concealment_end->next; +// free(ptr); +// } +//} +// +///*! +//************************************************************************ +//* \brief +//* Deletes all nodes from the place specified by ptr +//* +//************************************************************************ +//*/ +// +//void delete_list( VideoParameters *p_Vid, struct concealment_node *ptr ) +//{ +// struct concealment_node *temp; +// +// if( p_Vid->concealment_head == NULL ) return; +// +// if( ptr == p_Vid->concealment_head ) +// { +// p_Vid->concealment_head = NULL; +// p_Vid->concealment_end = NULL; +// } +// else +// { +// temp = p_Vid->concealment_head; +// +// while( temp->next != ptr ) +// temp = temp->next; +// p_Vid->concealment_end = temp; +// } +// +// while( ptr != NULL ) +// { +// temp = ptr->next; +// free( ptr ); +// ptr = temp; +// } +//} +// +///*! +//************************************************************************ +//* \brief +//* Stores the missing non reference frames in the concealment buffer. The +//* detection is based on the POC difference in the sorted POC array. A missing +//* non reference frame is detected when the dpb is full. A singly linked list +//* is maintained for storing the missing non reference frames. +//* +//************************************************************************ +//*/ +// +//void conceal_non_ref_pics(DecodedPictureBuffer *p_Dpb, int diff) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// int missingpoc = 0; +// unsigned int i, pos = 0; +// StorablePicture *conceal_from_picture = NULL; +// StorablePicture *conceal_to_picture = NULL; +// struct concealment_node *concealment_ptr = NULL; +// int temp_used_size = p_Dpb->used_size; +// +// if(p_Dpb->used_size == 0 ) +// return; +// +// qsort(p_Vid->pocs_in_dpb, p_Dpb->size, sizeof(int), comp); +// +// for(i=0;isize-diff;i++) +// { +// p_Dpb->used_size = p_Dpb->size; +// if((p_Vid->pocs_in_dpb[i+1] - p_Vid->pocs_in_dpb[i]) > p_Vid->poc_gap) +// { +// conceal_to_picture = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); +// +// missingpoc = p_Vid->pocs_in_dpb[i] + p_Vid->poc_gap; +// // Diagnostics +// // printf("\n missingpoc = %d\n",missingpoc); +// +// if(missingpoc > p_Vid->earlier_missing_poc) +// { +// p_Vid->earlier_missing_poc = missingpoc; +// conceal_to_picture->top_poc = missingpoc; +// conceal_to_picture->bottom_poc = missingpoc; +// conceal_to_picture->frame_poc = missingpoc; +// conceal_to_picture->poc = missingpoc; +// conceal_from_picture = get_pic_from_dpb(p_Dpb, missingpoc, &pos); +// +// assert(conceal_from_picture != NULL); +// +// p_Dpb->used_size = pos + 1; +// +// p_Vid->frame_to_conceal = conceal_from_picture->frame_num + 1; +// +// update_ref_list_for_concealment(p_Dpb); +// p_Vid->conceal_slice_type = B_SLICE; +// copy_to_conceal(conceal_from_picture, conceal_to_picture, p_Vid); +// concealment_ptr = init_node( conceal_to_picture, missingpoc ); +// add_node(p_Vid, concealment_ptr); +// // Diagnostics +// // print_node(concealment_ptr); +// } +// } +// } +// +// //restore the original value +// //p_Dpb->used_size = p_Dpb->size; +// p_Dpb->used_size = temp_used_size; +//} +// +///*! +//************************************************************************ +//* \brief +//* Perform Sliding window decoded reference picture marking process. It +//* maintains the POC s stored in the dpb at a specific instance. +//* +//************************************************************************ +//*/ +// +//void sliding_window_poc_management(DecodedPictureBuffer *p_Dpb, StorablePicture *p) +//{ +// if (p_Dpb->used_size == p_Dpb->size) +// { +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// unsigned int i; +// +// for(i=0;isize-1; i++) +// p_Vid->pocs_in_dpb[i] = p_Vid->pocs_in_dpb[i+1]; +// } +//} +// +// +///*! +//************************************************************************ +//* \brief +//* Outputs the non reference frames. The POCs in the concealment buffer are +//* sorted in ascending order and outputted when the lowest POC in the +//* concealment buffer is lower than the lowest in the p_Dpb-> The linked list +//* entry corresponding to the outputted POC is immediately deleted. +//* +//************************************************************************ +//*/ +// +//void write_lost_non_ref_pic(DecodedPictureBuffer *p_Dpb, int poc, int p_out) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// FrameStore concealment_fs; +// if(poc > 0) +// { +// if((poc - p_Dpb->last_output_poc) > p_Vid->poc_gap) +// { +// +// concealment_fs.frame = p_Vid->concealment_head->picture; +// concealment_fs.is_output = 0; +// concealment_fs.is_reference = 0; +// concealment_fs.is_used = 3; +// +// write_stored_frame(p_Vid, &concealment_fs, p_out); +// delete_node(p_Vid, p_Vid->concealment_head); +// } +// } +//} +// +///*! +//************************************************************************ +//* \brief +//* Conceals frame loss immediately after the IDR. This special case produces +//* the same result for either frame copy or motion vector copy concealment. +//* +//************************************************************************ +//*/ +// +//void write_lost_ref_after_idr(DecodedPictureBuffer *p_Dpb, int pos) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// +// int temp = 1; +// +// if(p_Vid->last_out_fs->frame == NULL) +// { +// p_Vid->last_out_fs->frame = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, +// p_Vid->width_cr, p_Vid->height_cr, 1); +// p_Vid->last_out_fs->is_used = 3; +// } +// +// if(p_Vid->conceal_mode == 2) +// { +// temp = 2; +// p_Vid->conceal_mode = 1; +// } +// copy_to_conceal(p_Dpb->fs[pos]->frame, p_Vid->last_out_fs->frame, p_Vid); +// +// p_Vid->conceal_mode = temp; +//} + diff --git a/ldecod/src/errorconcealment.c b/ldecod/src/errorconcealment.c new file mode 100644 index 0000000..06df1e1 --- /dev/null +++ b/ldecod/src/errorconcealment.c @@ -0,0 +1,220 @@ + +/*! + *********************************************************************** + * \file errorconcealment.c + * + * \brief + * Implements error concealment scheme for H.264 decoder + * + * \date + * 6.10.2000 + * + * \version + * 1.0 + * + * \note + * This simple error concealment implemented in this decoder uses + * the existing dependencies of syntax elements. + * In case that an element is detected as false this elements and all + * dependend elements are marked as elements to conceal in the p_Vid->ec_flag[] + * array. If the decoder requests a new element by the function + * readSyntaxElement_xxxx() this array is checked first if an error concealment has + * to be applied on this element. + * In case that an error occured a concealed element is given to the + * decoding function in macroblock(). + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Sebastian Purreiter + *********************************************************************** + */ + +#include "contributors.h" +#include "global.h" +#include "elements.h" + + + +/*! + *********************************************************************** + * \brief + * set concealment for all elements in same partition + * and dependend syntax elements + * \param p_Vid + * video encoding parameters for current picture + * \param se + * type of syntax element to conceal + * \return + * EC_REQ, elements of same type or depending type need error concealment. \n + * EX_SYNC sync on next header + *********************************************************************** + */ +int set_ec_flag(VideoParameters *p_Vid, int se) +{ + + /* + if (p_Vid->ec_flag[se] == NO_EC) + printf("Error concealment on element %s\n",SEtypes[se]); + */ + switch (se) + { + case SE_HEADER : + p_Vid->ec_flag[SE_HEADER] = EC_REQ; + case SE_PTYPE : + p_Vid->ec_flag[SE_PTYPE] = EC_REQ; + case SE_MBTYPE : + p_Vid->ec_flag[SE_MBTYPE] = EC_REQ; + + case SE_REFFRAME : + p_Vid->ec_flag[SE_REFFRAME] = EC_REQ; + p_Vid->ec_flag[SE_MVD] = EC_REQ; // set all motion vectors to zero length + se = SE_CBP_INTER; // conceal also Inter texture elements + break; + + case SE_INTRAPREDMODE : + p_Vid->ec_flag[SE_INTRAPREDMODE] = EC_REQ; + se = SE_CBP_INTRA; // conceal also Intra texture elements + break; + case SE_MVD : + p_Vid->ec_flag[SE_MVD] = EC_REQ; + se = SE_CBP_INTER; // conceal also Inter texture elements + break; + + default: + break; + } + + switch (se) + { + case SE_CBP_INTRA : + p_Vid->ec_flag[SE_CBP_INTRA] = EC_REQ; + case SE_LUM_DC_INTRA : + p_Vid->ec_flag[SE_LUM_DC_INTRA] = EC_REQ; + case SE_CHR_DC_INTRA : + p_Vid->ec_flag[SE_CHR_DC_INTRA] = EC_REQ; + case SE_LUM_AC_INTRA : + p_Vid->ec_flag[SE_LUM_AC_INTRA] = EC_REQ; + case SE_CHR_AC_INTRA : + p_Vid->ec_flag[SE_CHR_AC_INTRA] = EC_REQ; + break; + + case SE_CBP_INTER : + p_Vid->ec_flag[SE_CBP_INTER] = EC_REQ; + case SE_LUM_DC_INTER : + p_Vid->ec_flag[SE_LUM_DC_INTER] = EC_REQ; + case SE_CHR_DC_INTER : + p_Vid->ec_flag[SE_CHR_DC_INTER] = EC_REQ; + case SE_LUM_AC_INTER : + p_Vid->ec_flag[SE_LUM_AC_INTER] = EC_REQ; + case SE_CHR_AC_INTER : + p_Vid->ec_flag[SE_CHR_AC_INTER] = EC_REQ; + break; + case SE_DELTA_QUANT_INTER : + p_Vid->ec_flag[SE_DELTA_QUANT_INTER] = EC_REQ; + break; + case SE_DELTA_QUANT_INTRA : + p_Vid->ec_flag[SE_DELTA_QUANT_INTRA] = EC_REQ; + break; + default: + break; + + } + return EC_REQ; +} + +/*! + *********************************************************************** + * \brief + * resets EC_Flags called at the start of each slice + * + *********************************************************************** + */ +void reset_ec_flags(VideoParameters *p_Vid) +{ + int i; + for (i=0; iec_flag[i] = NO_EC; +} + + +/*! + *********************************************************************** + * \brief + * get error concealed element in dependence of syntax + * element se. \n + * This function implements the error concealment. + * \return + * NO_EC if no error concealment required \n + * EC_REQ if element requires error concealment + *********************************************************************** + */ +int get_concealed_element(VideoParameters *p_Vid, SyntaxElement *sym) +{ + if (p_Vid->ec_flag[sym->type] == NO_EC) + return NO_EC; + /* +#if TRACE + printf("TRACE: get concealed element for %s!!!\n", SEtypes[sym->type]); +#endif + */ + switch (sym->type) + { + case SE_HEADER : + sym->len = 31; + sym->inf = 0; // Picture Header + break; + + case SE_PTYPE : // inter_img_1 + case SE_MBTYPE : // set COPY_MB + case SE_REFFRAME : + sym->len = 1; + sym->inf = 0; + break; + + case SE_INTRAPREDMODE : + case SE_MVD : + sym->len = 1; + sym->inf = 0; // set vector to zero length + break; + + case SE_CBP_INTRA : + sym->len = 5; + sym->inf = 0; // codenumber 3 <=> no CBP information for INTRA images + break; + + case SE_LUM_DC_INTRA : + case SE_CHR_DC_INTRA : + case SE_LUM_AC_INTRA : + case SE_CHR_AC_INTRA : + sym->len = 1; + sym->inf = 0; // return EOB + break; + + case SE_CBP_INTER : + sym->len = 1; + sym->inf = 0; // codenumber 1 <=> no CBP information for INTER images + break; + + case SE_LUM_DC_INTER : + case SE_CHR_DC_INTER : + case SE_LUM_AC_INTER : + case SE_CHR_AC_INTER : + sym->len = 1; + sym->inf = 0; // return EOB + break; + + case SE_DELTA_QUANT_INTER: + sym->len = 1; + sym->inf = 0; + break; + case SE_DELTA_QUANT_INTRA: + sym->len = 1; + sym->inf = 0; + break; + default: + break; + } + + return EC_REQ; +} + diff --git a/ldecod/src/ferc/ferc_api.c b/ldecod/src/ferc/ferc_api.c new file mode 100644 index 0000000..87378ee --- /dev/null +++ b/ldecod/src/ferc/ferc_api.c @@ -0,0 +1,1419 @@ +/*! + ************************************************************************ + * \file ferc_api.c + * + * \brief + * Definitions for frame lost error concealment. + * + * Based on Thomson APIs for concealing entire frame loss. + * Modification to be compatible with frame loss in auxiliary view, + * and some improvements in error concealment strategies + * + * \author + * Previous work + * - Jill Boyce + * - Saurav K Bandyopadhyay + * - Zhenyu Wu + * - Purvin Pandit + * Actual Work + * - João Carreira + * + ************************************************************************ + */ + +#include "ferc_api.h" +#include "ferc_internals.h" +#include "image.h" +#include "stream_parser.h" +#include "mbuffer_common.h" +#include "output.h" +#include "loopfilter.h" +#include +#include + +//! OpenCV +#include "ferc_opencv_api.h" + +void sliding_window_memory_management( DecodedPictureBuffer *p_Dpb, StorablePicture* p ); + +static void Report_Frame_Info( VideoParameters *p_Vid, StorablePicture *Picture ) +{ + char ref_char = ' ', yuv_types[4][6] = + { "4:0:0", "4:2:0", "4:2:2", "4:4:4" }; + int64 tmp_time; + + gettime( &( p_Vid->end_time ) ); // end time + tmp_time = timediff( &( p_Vid->start_time ), &( p_Vid->end_time ) ); + //p_Vid->tot_time += tmp_time; + tmp_time = timenorm( tmp_time ); + + if( p_Vid->p_Inp->silent == FALSE ) + { + SNRParameters *snr = p_Vid->snr[Picture->view_id]; + +#if(MVC_EXTENSION_ENABLE) + if( p_Vid->p_ref_mvc[GetViewIdx( p_Vid, Picture->view_id )] != -1 ) + find_snr( p_Vid, Picture, &( p_Vid->p_ref_mvc[GetViewIdx( p_Vid, Picture->view_id )] ) ); +#else + if( p_Vid->p_ref != -1) + find_snr( p_Vid, (*dec_picture) , &p_Vid->p_ref); +#endif + + if( Picture->used_for_reference ) + { + ref_char = 'C'; + } + else + { + ref_char = 'c'; + } + +#if( MVC_EXTENSION_ENABLE) + if( p_Vid->p_ref_mvc[Picture->view_id] != -1 ) +#else + if (p_Vid->p_ref != -1) +#endif + { + printf( "%05d( %c ) %5d|%2d %5d %5d %8.4f %8.4f %8.4f %s %7d\n", p_Vid->frame_no, ref_char, Picture->poc, GetViewIdx( p_Vid, Picture->view_id ), + Picture->pic_num, Picture->qp, snr->snr[0], snr->snr[1], snr->snr[2], yuv_types[Picture->chroma_format_idc], ( int )tmp_time ); + } + else + { + printf( "%05d( %c ) %5d|%2d %5d %5d %s %7d\n", p_Vid->frame_no, ref_char, Picture->poc, + GetViewIdx( p_Vid, Picture->view_id ), Picture->pic_num, Picture->qp, yuv_types[Picture->chroma_format_idc], ( int )tmp_time ); + } + } + fflush( stdout ); +} + +/*! + ************************************************************************ + * \brief + * Updates the reference list for motion vector copy concealment for non- + * reference frame loss. + * + ************************************************************************ + */ +//static void mark_frame_as_used(DecodedPictureBuffer *p_Dpb) +//{ +// VideoParameters *p_Vid = p_Dpb->p_Vid; +// unsigned i, j= 0; +// +// for (i = 0; i < p_Dpb->used_size; i++) +// { +// p_Dpb->fs[i]->unused_concealment = 0; +// } +//} +/*! + ************************************************************************ + * \brief + * Mark frame as used as reference to create the correct reference list + ************************************************************************ + */ +//static void mark_frame_as_reference(DecodedPictureBuffer *p_Dpb) +//{ +// unsigned i; +// +// for (i = 0; i < p_Dpb->used_size; i++) +// { +// p_Dpb->fs[i]->temp_is_reference = p_Dpb->fs[i]->is_reference; +// p_Dpb->fs[i]->frame->temp_used_for_reference = p_Dpb->fs[i]->frame->used_for_reference; +// +// p_Dpb->fs[i]->is_reference = 3; +// p_Dpb->fs[i]->frame->used_for_reference = 1; +// } +//} +//static void restore_reference_flag(DecodedPictureBuffer *p_Dpb) +//{ +// unsigned i; +// for (i = 0; i < p_Dpb->used_size; i++) +// { +// p_Dpb->fs[i]->is_reference = p_Dpb->fs[i]->temp_is_reference; +// p_Dpb->fs[i]->frame->used_for_reference = p_Dpb->fs[i]->frame->temp_used_for_reference; +// } +//} +void FillImageBorder( VideoParameters *p_Vid, StorablePicture *Conceal_to_picture ) +{ + int x, y, pad; + + // Left / Right + for( y = 0; y < p_Vid->height; y++ ) + { + for( pad = 0; pad < p_Vid->iLumaPadX; pad++ ) + { + Conceal_to_picture->imgY[y][-pad] = Conceal_to_picture->imgY[y][+pad]; + Conceal_to_picture->imgY[y][p_Vid->width - 1 + pad] = Conceal_to_picture->imgY[y][p_Vid->width - 1 - pad]; + } + } + for( y = 0; y < p_Vid->height_cr; y++ ) + { + for( pad = 0; pad < p_Vid->iChromaPadX; pad++ ) + { + Conceal_to_picture->imgUV[0][y][-pad] = Conceal_to_picture->imgUV[0][y][+pad]; + Conceal_to_picture->imgUV[1][y][-pad] = Conceal_to_picture->imgUV[1][y][+pad]; + + Conceal_to_picture->imgUV[0][y][p_Vid->width_cr - 1 + pad] = Conceal_to_picture->imgUV[0][y][p_Vid->width_cr - 1 - pad]; + Conceal_to_picture->imgUV[1][y][p_Vid->width_cr - 1 + pad] = Conceal_to_picture->imgUV[1][y][p_Vid->width_cr - 1 - pad]; + + } + } + + // Top / Bottom + for( x = 0; x < p_Vid->width; x++ ) + { + for( pad = 0; pad < p_Vid->iLumaPadY; pad++ ) + { + Conceal_to_picture->imgY[-pad][x] = Conceal_to_picture->imgY[+pad][x]; + Conceal_to_picture->imgY[p_Vid->height - 1 + pad][x] = Conceal_to_picture->imgY[p_Vid->height - 1 - pad][x]; + } + } + for( x = 0; x < p_Vid->width_cr; x++ ) + { + for( pad = 0; pad < p_Vid->iChromaPadY; pad++ ) + { + Conceal_to_picture->imgUV[0][-pad][x] = Conceal_to_picture->imgUV[0][+pad][x]; + Conceal_to_picture->imgUV[1][-pad][x] = Conceal_to_picture->imgUV[1][+pad][x]; + + Conceal_to_picture->imgUV[0][p_Vid->height_cr - 1 + pad][x] = Conceal_to_picture->imgUV[0][p_Vid->height_cr - 1 - pad][x]; + Conceal_to_picture->imgUV[1][p_Vid->height_cr - 1 + pad][x] = Conceal_to_picture->imgUV[1][p_Vid->height_cr - 1 - pad][x]; + } + } + +} + +void fercCloseFrameConcealment( VideoParameters *p_Vid ) +{ + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + int view; + + for( view = 0; view < MAX_VIEW_NUM; view++ ) + { + if( p_FrameConc->last_out_fs[view] ) + { + free_frame_store( p_FrameConc->last_out_fs[view] ); + } + } + + if( p_Vid->p_FrameConc ) + free( p_Vid->p_FrameConc ); + +} + +void fercOpenFrameConcealment( VideoParameters *p_Vid ) +{ + ConcealParameters *p_FrameConc; + + if( ( p_Vid->p_FrameConc = ( ConcealParameters * )calloc( 1, sizeof(ConcealParameters) ) ) == NULL ) + no_mem_exit( "alloc_video_params: p_Vid->p_FrameConc" ); + + p_FrameConc = p_Vid->p_FrameConc; + + p_FrameConc->use_DisparityProjection = 1; + + if( p_Vid->p_Inp->conceal_mode == MOTION_INTERVIEW || p_Vid->p_Inp->conceal_mode == MOTION_INTERVIEW_FIRST + || p_Vid->p_Inp->conceal_mode == MOTION_INTRA_INTER_SAD ) + { + if( !CheckOpenCVUsage() ) + { + printf( " Cannot use this concealment method without opencv!\n Disabling concealment methods!\n" ); + p_Vid->conceal_mode = MOTION_INTRAVIEW; + //fercCloseFrameConcealment( p_Vid ); + } + } +} + +/*! + ************************************************************************ + * \brief + * Save the current reference list of the last decoded frame + ************************************************************************ + */ +void fercSaveListsInfo( VideoParameters *p_Vid, Slice *currSlice ) +{ + StorablePicture *decodedPicture = p_Vid->dec_picture; + + int i; + + decodedPicture->Conc_listXInterviewPos[LIST_0] = -1; + decodedPicture->Conc_listXInterviewPos[LIST_1] = -1; + + for( i = 0; i < currSlice->listXsize[LIST_0]; i++ ) + { + decodedPicture->Conc_listX[LIST_0][i] = currSlice->listX[LIST_0][i]; + if( currSlice->listX[LIST_0][i]->poc == decodedPicture->poc ) + { + decodedPicture->Conc_listXInterviewPos[LIST_0] = i; + } + } + for( i = 0; i < currSlice->listXsize[LIST_1]; i++ ) + { + decodedPicture->Conc_listX[LIST_1][i] = currSlice->listX[LIST_1][i]; + if( currSlice->listX[LIST_1][i]->poc == decodedPicture->poc ) + { + decodedPicture->Conc_listXInterviewPos[LIST_1] = i; + } + } + decodedPicture->Conc_listXsize[LIST_0] = currSlice->listXsize[LIST_0]; + decodedPicture->Conc_listXsize[LIST_1] = currSlice->listXsize[LIST_1]; + +} + +void fercCopyImg( VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest ) +{ + int x, y; + //! Y + for( y = 0; y < p_Vid->height; y++ ) + for( x = 0; x < p_Vid->width; x++ ) + Dest->imgY[y][x] = Source->imgY[y][x]; + //!UV + for( y = 0; y < p_Vid->height_cr; y++ ) + for( x = 0; x < p_Vid->width_cr; x++ ) + { + Dest->imgUV[0][y][x] = Source->imgUV[0][y][x]; + Dest->imgUV[1][y][x] = Source->imgUV[1][y][x]; + } +} + +/*! + ************************************************************************ + * \brief + * This function conceals a lost frame. This is the commomn operations + * that need to be performed to conceal a lost frame + * + ************************************************************************ + */ +static void CopyCommonInformation( StorablePicture *Source, StorablePicture *Dest ) +{ + Dest->PicSizeInMbs = Source->PicSizeInMbs; + Dest->slice_type = Source->slice_type; + Dest->idr_flag = FALSE; //since we do not want to clears the ref list + Dest->no_output_of_prior_pics_flag = Source->no_output_of_prior_pics_flag; + Dest->long_term_reference_flag = Source->long_term_reference_flag; + Dest->adaptive_ref_pic_buffering_flag = Source->adaptive_ref_pic_buffering_flag = 0; + Dest->chroma_format_idc = Source->chroma_format_idc; + Dest->frame_mbs_only_flag = Source->frame_mbs_only_flag; + Dest->frame_cropping_flag = Source->frame_cropping_flag; + Dest->frame_crop_left_offset = Source->frame_crop_left_offset; + Dest->frame_crop_right_offset = Source->frame_crop_right_offset; + Dest->frame_crop_bottom_offset = Source->frame_crop_bottom_offset; + Dest->frame_crop_top_offset = Source->frame_crop_top_offset; + Dest->qp = Source->qp; + Dest->chroma_format_idc = Source->chroma_format_idc; + Dest->concealed_pic = Source->concealed_pic; + //! Inter view prediction flags + Dest->inter_view_flag = Source->inter_view_flag; + + Dest->layer_id = Source->layer_id; + + // We need these initializations for using deblocking filter for frame copy and motion copy concealment. + Dest->PicWidthInMbs = Source->PicWidthInMbs; + Dest->PicSizeInMbs = Source->PicSizeInMbs; +} +static int fercConcealOneLostFrame( VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb, StorablePicture *ConcealToPicture, int is_reference ) +{ + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + StorablePicture *ConcealFromPicture = NULL; + unsigned int pos, temp_used_size; + int search_mode = 0, search_poc, search_view, tmp_slice_type; + StorablePicture *temp_dec_picture = p_Vid->dec_picture; + + p_FrameConc->ConcealmentMode = p_Vid->conceal_mode; + + p_Vid->dec_picture = ConcealToPicture; + + tmp_slice_type = p_Vid->type; + + // keep values of buffer used size + temp_used_size = p_Dpb->used_size; + p_Dpb->used_size_concealment = p_Dpb->used_size; + + // sort buffer frame_num up + qsort( p_Dpb->fs, p_Dpb->used_size, sizeof(FrameStore*), sort_by_frame_num_up ); + + //First time the concealment should be done using the closest frame in buffer + search_mode = 1; + search_poc = ConcealToPicture->poc; + search_view = ConcealToPicture->view_id; + do + { + + // Restore Buffer size + p_Dpb->used_size = temp_used_size; + + // Proctect from perfom a impossible concealment method + if( p_FrameConc->ConcealmentMode == FRAME_COPY_BC && ConcealToPicture->view_id == BASE_VIEW_IDX ) + p_FrameConc->ConcealmentMode = FRAME_COPY_FF; + + switch( p_FrameConc->ConcealmentMode ) + { + case FRAME_COPY_FF: + p_FrameConc->ConcealFuction = Conceal_by_FrameCopy; + if( ConcealToPicture->used_for_reference == 1 ) + { + search_mode = CLOSEST_ALL; + } + else + { + search_mode = CLOSEST_FUTURE; + } + break; + case FRAME_COPY_BC: + p_FrameConc->ConcealFuction = Conceal_by_FrameCopy; + search_mode = EXACT; + search_view = BASE_VIEW_IDX; + break; + case MOTION_COPY_TEMPORAL: + case MOTION_COPY_SPATIAL: + case MOTION_COPY_TEMPORAL_SPATIAL: + p_FrameConc->ConcealFuction = Conceal_by_MotionCopy_Ref; + search_mode = CLOSEST_FUTURE; + break; + /*case MOTION_COPY_ENHANCED: + p_FrameConc->ConcealmentMode = MOTION_COPY_TEMPORAL_SPATIAL; + p_FrameConc->ConcealFuction = Conceal_by_MotionCopyEnhanced; + search_mode = CLOSEST_FUTURE; + search_view = BASE_VIEW_IDX; + break;*/ + case REF_DFDP: + p_FrameConc->ConcealmentMode = REF_DFDP; + p_FrameConc->ConcealFuction = Conceal_by_DisparityBasedFrameDifferenceProjection; + search_mode = CLOSEST_FUTURE; + break; + case REF_ISMID: + p_FrameConc->ConcealmentMode = REF_ISMID; + p_FrameConc->ConcealFuction = Conceal_by_InterViewSimilarityMotion; + search_mode = CLOSEST_FUTURE; + break; +// case MOTION_INTRA_INTER_SAD: +// p_FrameConc->ConcealFuction = Conceal_by_IntraInterMotionCopy; +// search_mode = CLOSEST_FUTURE; +// break; + case INTERVIEW_COPY: + case MOTION_INTRAVIEW: + case MOTION_INTERVIEW: + case MOTION_INTERVIEW_FIRST: + case MOTION_INTERVIEW_MVE_INTERCOPY: + case MOTION_SMART_MOTION_BASED: + case ENHANCED_MVE: + case MOTION_ITERATIONS: + p_FrameConc->ConcealFuction = Conceal_by_IntraInterMotionCopy_V2; + search_mode = CLOSEST_FUTURE; + break; + default: + return 0; + } + + ConcealFromPicture = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[search_view], ConcealToPicture->poc, search_view, search_mode, 0, &pos ); + + if( ConcealFromPicture == NULL ) + { + printf( "[FERC] An unintentional loss of pictures occurs! Exit\n" ); + return 0; // Cannot conceal this frame + } + + break; + } + while( 1 ); + + // copy all the struc from this to current concealment pic + p_Vid->frame_to_conceal = ConcealFromPicture->frame_num + 1; + p_Vid->earlier_missing_poc = ConcealToPicture->poc; + + p_Vid->type = ConcealFromPicture->slice_type; + + CopyCommonInformation( ConcealFromPicture, ConcealToPicture ); + + ConcealToPicture->concealed_pic = 1; + ConcealToPicture->PicSlice = malloc_slice( p_Vid->p_Inp, p_Vid ); + ConcealToPicture->PicSlice->chroma444_not_separate = 0; + + //! Report some debug information + printf( "[FERC] Concealing Frame %4d|%2d using frame %4d|%2d with Method %2d\n", ConcealToPicture->poc, ConcealToPicture->view_id, ConcealFromPicture->poc, + ConcealFromPicture->view_id, p_FrameConc->ConcealmentMode ); + + p_FrameConc->ConcealFuction( p_Vid, ConcealFromPicture, ConcealToPicture ); + + // Restore Buffer size + p_Dpb->used_size = temp_used_size; + + //update_ref_list(p_Vid->p_Dpb_layer[Conceal_from_picture->view_id]); + //restore_reference_flag(p_Dpb); + + DeblockPicture( p_Vid, ConcealToPicture ); + + FillImageBorder( p_Vid, ConcealToPicture ); + + if( ConcealToPicture->PicSlice ) + free_slice( ConcealToPicture->PicSlice ); + + calculate_frame_no( p_Vid, ConcealToPicture ); + + Report_Frame_Info( p_Vid, ConcealToPicture ); + +#if( _DEBUG ) + //showStorablePicture (p_Vid , Conceal_to_picture, 1,1, "[FERC] Concealed Frame", 0); +#endif + + //{ + // char FileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + // strcpy( chBuf , p_Vid->p_Inp->outfile ); + // pch = strrchr( chBuf , '.' ); + // if(pch) + // *pch = '\0'; + // if( strcmp("nul", chBuf) ) + // { + // sprintf( FileName , "%s_ViewId%02d_Frame%2d_CMethod%d.pgm" , chBuf, ConcealToPicture->view_id, ConcealToPicture->poc, p_FrameConc->ConcealmentMode); + // saveStorablePicture( p_Vid , FileName , ConcealToPicture , 0 , 0 ); + // } + //} + + p_Vid->dec_picture = temp_dec_picture; + p_Vid->type = tmp_slice_type; + return 1; + +} + +void fercModLostRefFrames( VideoParameters *p_Vid, StorablePicture *DecPicture ) +{ + StorablePicture *ConcealFromPicture; + unsigned int pos; +#if( MVC_EXTENSION_ENABLE ) + int ViewID = DecPicture->view_id; +#else + int ViewID = 0; +#endif + + ConcealFromPicture = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[ViewID], + DecPicture->poc, ViewID, CLOSEST_ALL, 0, &pos ); + + if( ConcealFromPicture != NULL) + { + printf("[FERC] Conceal Picture %d using FC from picture %d", + DecPicture->poc, ConcealFromPicture->poc); + fercCopyImg( p_Vid, ConcealFromPicture, DecPicture ); + } +} + +/*! + ************************************************************************ + * \brief + * This function conceals a missing reference frame. The routine is called + * based on the difference in frame number. It conceals an IDR frame loss + * based on the sudden decrease in frame number. + * + * Edit by João Carreira + * Function edited + * + ************************************************************************ + */ +void fercConcealLostRefFrames( DecodedPictureBuffer *p_Dpb, Slice *currSlice, int is_IDR ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + + StorablePicture *tempPicture, *conceal_to_picture = NULL; + int pos = 0; + int tmp1 = currSlice->delta_pic_order_cnt[0]; + int tmp2 = currSlice->delta_pic_order_cnt[1]; + int CurrFrameNum, UnusedShortTermFrameNum, i, tmp_concealmode = p_Vid->conceal_mode; + + if( currSlice->structure == FRAME || currSlice->structure == TOP_FIELD ) + { + gettime( &( p_Vid->start_time ) ); // start time + } + + currSlice->delta_pic_order_cnt[0] = currSlice->delta_pic_order_cnt[1] = 0; + + // printf("A gap in frame number is found, try to fill it.\n"); + + if( is_IDR ) + { + // Conceals an IDR frame loss. Uses the reference frame in the previous + // GOP for concealment. + UnusedShortTermFrameNum = 0; + p_Vid->last_ref_pic_poc[currSlice->view_id] = -p_Vid->poc_gap; + } + else + UnusedShortTermFrameNum = ( p_Vid->pre_frame_num[currSlice->view_id] + 1 ) % p_Vid->max_frame_num; + + CurrFrameNum = currSlice->frame_num; + + while( CurrFrameNum != UnusedShortTermFrameNum ) + { + int search_view = 0, search_mode, search_poc; + int find = 0; + + // check duplicate concealment + for( i = 0; i < p_Dpb->used_size; i++ ) + { + if( p_Dpb->fs[i]->frame->frame_num == UnusedShortTermFrameNum && p_Dpb->fs[i]->frame->concealed_pic != 0 ) + { + p_Dpb->fs[i]->frame->used_for_reference = 1; + // maybe this is not the best approach + //if (p_Dpb->fs[i]->frame->used_for_reference) + { + p_Dpb->fs[i]->is_reference = 3; + p_Dpb->fs[i]->is_orig_reference = 3; + if( p_Dpb->fs[i]->frame->is_long_term ) + { + p_Dpb->fs[i]->is_long_term = 3; + p_Dpb->fs[i]->long_term_frame_idx = p_Dpb->fs[i]->frame->long_term_frame_idx; + } + } + sliding_window_memory_management( p_Dpb, p_Dpb->fs[i]->frame ); + find = 1; + break; + } + } + if( !find ) + { + // alloc new Pic + conceal_to_picture = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + + //init Pic params + conceal_to_picture->coded_frame = 1; + conceal_to_picture->pic_num = UnusedShortTermFrameNum; //??? + conceal_to_picture->frame_num = UnusedShortTermFrameNum; + conceal_to_picture->view_id = currSlice->view_id; + conceal_to_picture->non_existing = 0; + conceal_to_picture->is_output = 0; + conceal_to_picture->used_for_reference = 1; + /*! Mark Concealed picture -> Conceal reference */ + conceal_to_picture->concealed_pic = 1; + conceal_to_picture->adaptive_ref_pic_buffering_flag = 0; + + conceal_to_picture->layer_id = currSlice->layer_id; + + if( is_IDR ) + { + conceal_to_picture->poc = 0; + } + else if( p_Vid->p_Inp->GOP_Size == 1) + { + conceal_to_picture->poc = p_Vid->last_ref_pic_poc[currSlice->view_id] + p_Vid->p_Inp->ref_poc_gap; + } + else + { + int GOPSize = p_Vid->p_Inp->GOP_Size; + int i, hierarchical_layer; + int RefPeriod; + if( p_Vid->last_ref_pic_poc[currSlice->view_id] == 0 ) + { + hierarchical_layer = 0; + } + else + { + for( i = 1; i < RoundLog2( GOPSize ); i++ ) + { + if( ( ( p_Vid->last_ref_pic_poc[currSlice->view_id] / p_Vid->p_Inp->poc_scale ) % GOPSize / power2( i - 1 ) ) == 0 ) + break; + } + hierarchical_layer = i; + } + RefPeriod = GOPSize / power2( imin( hierarchical_layer + 1, RoundLog2( GOPSize ) ) - 1 ) * p_Vid->p_Inp->poc_scale; + + if( p_Vid->last_ref_hier0_poc[currSlice->view_id] == 0 ) + { + for( i = p_Vid->last_ref_hier0_poc[currSlice->view_id]; + i <= p_Vid->last_ref_hier0_poc[currSlice->view_id] + ( GOPSize ) * p_Vid->p_Inp->poc_scale; i += RefPeriod ) + { + if( fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[currSlice->view_id], i, currSlice->view_id, EXACT, 1, NULL ) == NULL ) + { + conceal_to_picture->poc = i; + break; + } + } + } + else + { + for( i = p_Vid->last_ref_hier0_poc[currSlice->view_id] - ( GOPSize ) * p_Vid->p_Inp->poc_scale + RefPeriod; + i < p_Vid->last_ref_hier0_poc[currSlice->view_id]; i += RefPeriod ) + { + if( fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[currSlice->view_id], i, currSlice->view_id, EXACT, 1, NULL ) == NULL ) + { + conceal_to_picture->poc = i; + break; + } + } + } + } + + // conceal_to_picture->poc = 2; + + conceal_to_picture->bottom_poc = conceal_to_picture->poc; + conceal_to_picture->frame_poc = conceal_to_picture->poc; + conceal_to_picture->top_poc = conceal_to_picture->poc; + + //refresh p_Vid params + p_Vid->last_ref_pic_poc[currSlice->view_id] = conceal_to_picture->poc; + + //get a prev pic to conceal lost pic + search_view = conceal_to_picture->view_id; + search_poc = conceal_to_picture->poc; + search_mode = p_Vid->p_Inp->search_mode_ref; + + if( UnusedShortTermFrameNum == 0 ) + { + // First frame can only be concealed by frame copy method + p_Vid->conceal_mode = FRAME_COPY_BC; + } + else if( UnusedShortTermFrameNum == 1 && p_Vid->conceal_mode > FRAME_COPY_BC ) + { + // Second frame of GOP dont have motion vector references so need to be frame copy + p_Vid->conceal_mode = FRAME_COPY_FF; + } + + currSlice->frame_num = UnusedShortTermFrameNum; + + //! This picture may be already concealed + if( ( tempPicture = fercGetPictureForConcealFromDpb( p_Dpb, conceal_to_picture->poc, conceal_to_picture->view_id, EXACT, 1, &pos ) ) != NULL ) + { + CopyCommonInformation( tempPicture, conceal_to_picture ); + fercCopyImg( p_Vid, tempPicture, conceal_to_picture ); + calculate_frame_no( p_Vid, conceal_to_picture ); + remove_frame_from_dpb( p_Dpb, pos ); + } + else + { + if( !fercConcealOneLostFrame( p_Vid, p_Dpb, conceal_to_picture, 1 ) ) + printf( "[FERC] Cannot conceal current loss picture\n" ); + //regist the concealed frame +#if( MVC_EXTENSION_ENABLE) + p_Vid->nFramesConceal[currSlice->view_id]++; +#endif + } + + //if (UnusedShortTermFrameNum == 0) + if( is_IDR ) + { + conceal_to_picture->slice_type = I_SLICE; + conceal_to_picture->idr_flag = TRUE; +#if (MVC_EXTENSION_ENABLE) + //for( i=currSlice->view_id; i< MAX_NUM_DPB_LAYERS;i++) + idr_memory_management( p_Vid->p_Dpb_layer[currSlice->layer_id], conceal_to_picture ); +#else + flush_dpb(p_Dpb); +#endif + p_Vid->last_ref_pic_poc[currSlice->view_id] = conceal_to_picture->poc; + } + + update_ref_list( p_Dpb ); + //dump_dpb(p_Dpb); + + store_picture_in_dpb( p_Dpb, conceal_to_picture ); + + } +#if (MVC_EXTENSION_ENABLE) + update_ref_list( p_Dpb ); + update_ltref_list( p_Dpb ); +#endif + + p_Vid->pre_frame_num[currSlice->view_id] = UnusedShortTermFrameNum; + UnusedShortTermFrameNum = ( UnusedShortTermFrameNum + 1 ) % p_Vid->max_frame_num; + // update reference flags and set current flag. + for( i = 16; i > 0; i-- ) + { + currSlice->ref_flag[i] = currSlice->ref_flag[i - 1]; + } + currSlice->ref_flag[0] = 0; + } + currSlice->delta_pic_order_cnt[0] = tmp1; + currSlice->delta_pic_order_cnt[1] = tmp2; + currSlice->frame_num = CurrFrameNum; + p_Vid->conceal_mode = tmp_concealmode; +} + +void fercFillCurrPicture( VideoParameters *p_Vid, StorablePicture *currPicture ) +{ + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[currPicture->view_id]; + StorablePicture *auxPicture; + unsigned int pos; + auxPicture = fercGetPictureForConcealFromDpb( p_Dpb, currPicture->poc, currPicture->view_id, CLOSEST_ALL, 1, &pos ); + if( auxPicture != NULL ) + fercCopyImg( p_Vid, auxPicture, currPicture ); +} + +/*! + ************************************************************************ + * \brief + * + * + * + * + ************************************************************************ + */ +void fercConcealLostInterviewRefFrames( DecodedPictureBuffer *p_Dpb, StorablePicture **LostPicture, Slice *currSlice, int MissingView ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + StorablePicture *conceal_to_picture; + int MissingPoc = currSlice->framepoc; + + conceal_to_picture = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + conceal_to_picture->poc = conceal_to_picture->frame_poc = conceal_to_picture->top_poc = conceal_to_picture->bottom_poc = MissingPoc; + conceal_to_picture->view_id = MissingView; + + conceal_to_picture->pic_num = currSlice->frame_num; + conceal_to_picture->frame_num = currSlice->frame_num; + + /* Mark Concealed picture -> Conceal reference */ + conceal_to_picture->concealed_pic = 1; + conceal_to_picture->used_for_reference = 0; + + /* Set InterView Flag */ + conceal_to_picture->inter_view_flag = 1; + + if( !fercConcealOneLostFrame( p_Vid, p_Dpb, conceal_to_picture, 0 ) ) + { + printf( "Cannot conceal current loss picture\n" ); + } + + store_picture_in_dpb( p_Dpb, conceal_to_picture ); +#if (MVC_EXTENSION_ENABLE) + update_ref_list( p_Dpb ); + update_ltref_list( p_Dpb ); +#endif + + *LostPicture = conceal_to_picture; + + p_Vid->nFramesConceal[MissingView]++; + + return; +} + +/*! + ************************************************************************ + * \brief + * Perform Sliding window decoded reference picture marking process. It + * maintains the POC s stored in the dpb at a specific instance. + * + ************************************************************************ + */ +void fercSlindingWindowsOnceFrameRemoved( DecodedPictureBuffer *p_Dpb, int poc ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + unsigned int i, pos; + int layer_id = p_Dpb->layer_id; + + if( p_Vid->conceal_mode == NONE_CONCEAL ) + return; + for( i = 0, pos = 0; i < p_Dpb->used_size; i++ ) + { + if( p_FrameConc->fercPOCinDpb[layer_id][i] == poc ) + { + pos = i; + break; + } + } + for( i = pos; i < p_Dpb->used_size - 1; i++ ) + { + p_FrameConc->fercPOCinDpb[layer_id][i] = p_FrameConc->fercPOCinDpb[layer_id][i + 1]; + } + p_FrameConc->fercPOCinDpb[layer_id][i + 1] = -1; +} + +void fercAddPOC2Dpb( DecodedPictureBuffer *p_Dpb, int poc ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + int layer_id = p_Dpb->layer_id; + + if( p_Vid->conceal_mode == NONE_CONCEAL ) + return; + + p_FrameConc->fercPOCinDpb[layer_id][p_Dpb->used_size] = poc; + +} +void fercResetPOCInDpb( DecodedPictureBuffer *p_Dpb ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + int layer_id = p_Dpb->layer_id; + + if( p_Vid->conceal_mode == NONE_CONCEAL ) + return; + + memset( p_FrameConc->fercPOCinDpb[layer_id], -1, sizeof(int) * 100 ); +} + +/*! + ************************************************************************ + * \brief + * Organize the concealment frames list + ************************************************************************ + */ +static void Add_Concealment_Node( VideoParameters *p_Vid, StorablePicture* ConcealedPicture, int layer ) +{ + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + struct ConcealNode **conceal_list = &( p_FrameConc->ConcealHead[layer] ); + + struct ConcealNode *new_node; + + new_node = ( struct ConcealNode * )calloc( 1, sizeof(struct ConcealNode) ); + + if( new_node == NULL ) + { + no_mem_exit( "alloc_new_concealment_node: p_Vid->p_FrameConc->ConcealHead" ); + } + else + { + new_node->picture = ConcealedPicture; + new_node->MissPoc = ConcealedPicture->poc; + new_node->next = NULL; + } + + if( p_FrameConc->ConcealHead[layer] == NULL ) + { + p_FrameConc->ConcealHead[layer] = new_node; + return; + } + while( *conceal_list != NULL && ( *conceal_list )->MissPoc < new_node->MissPoc ) + conceal_list = &( *conceal_list )->next; + + new_node->next = ( *conceal_list ); + *conceal_list = new_node; + +#if (PRINT_ECNODES) + printf("Added node: "); + printf("Conceal node Frame POC = %5d View = %3d \n", ptr->MissPoc, ptr->MissView ); +#endif + return; +} +static void Delete_Concealment_Node( VideoParameters *p_Vid, struct ConcealNode *ptr, int view_id ) +{ + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + // We only need to delete the first node in the linked list + if( ptr == p_FrameConc->ConcealHead[view_id] ) + { + p_FrameConc->ConcealHead[view_id] = p_FrameConc->ConcealHead[view_id]->next; +#if (PRINT_ECNODES) + printf("deleted node: "); + printf("Conceal node Frame POC = %5d View = %3d \n", ptr->MissPoc, ptr->MissView ); +#endif + free_storable_picture( ptr->picture ); + free( ptr ); + } +} +//static void Print_List( struct ConcealNode *ptr ) +//{ +//#if (PRINT_ECNODES) +// while( ptr != NULL ) +// { +// printf("Conceal node Frame POC = %5d View = %3d \n", ptr->MissPoc, ptr->MissView ); +// ptr = ptr->next; +// } +//#endif +//} +//static void Delete_List( VideoParameters *p_Vid, struct ConcealNode *ptr, int view_id) +//{ +// ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; +// struct ConcealNode *temp; +// +// if( p_FrameConc->ConcealHead[view_id] == NULL ) return; +// +// if( ptr == p_FrameConc->ConcealHead[view_id] ) +// { +// p_FrameConc->ConcealHead[view_id] = NULL; +// } +// else +// { +// temp = p_FrameConc->ConcealHead[view_id]; +// +// while( temp->next != ptr ) +// temp = temp->next; +// } +// +// while( ptr != NULL ) +// { +// temp = ptr->next; +// free( ptr ); +// ptr = temp; +// } +//} + +/*! + ************************************************************************ + * \brief + * Check if the current lost frame have already been concealed + ************************************************************************ + */ +static inline int check_duplicate_concealment( VideoParameters *p_Vid, int poc, int view_id ) +{ + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + struct ConcealNode *temp = p_FrameConc->ConcealHead[view_id]; + if( temp == NULL ) + return 0; + for( temp = p_FrameConc->ConcealHead[view_id]; temp != NULL ; temp = temp->next ) + { + if( temp->MissPoc == poc ) //&& temp->MissView == view_id) + return 1; + } + return 0; +} + +/*! + ************************************************************************ + * \brief + * Stores the missing non reference frames in the concealment buffer. The + * detection is based on the POC difference in the sorted POC array. A missing + * non reference frame is detected when the dpb is full. A singly linked list + * is maintained for storing the missing non reference frames. + * + * Edit by Joao Carreira + * Function edited + * + ************************************************************************ + */ +void fercConcealLostNonRefFrames( DecodedPictureBuffer *p_Dpb, unsigned int diff ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + StorablePicture *conceal_to_picture = NULL; + unsigned int i_pic, j_pic; + int temp_used_size = p_Dpb->used_size; + int missing_poc = 0; + int view_id = 0; + + if( p_Dpb->used_size <= diff + 2 ) + return; + + /* Sort Dpb to get all frames in ascendent order */ + qsort( p_Dpb->fs, p_Dpb->used_size, sizeof(FrameStore*), sort_by_poc_up ); + + for( i_pic = 0; i_pic < ( p_Dpb->used_size - diff - 1 ); i_pic++ ) + { + if( p_Dpb->fs[i_pic]->is_output ) + continue; + + //find the next frame in Dpb with same view_id + //for (j_pic=i_pic+1; (p_Dpb->fs[j_pic]->view_id != p_Dpb->fs[i_pic]->view_id) && (j_pic < p_Dpb->used_size-diff-1) ;j_pic++); + j_pic = i_pic + 1; + + missing_poc = p_Dpb->fs[i_pic]->poc; + +#if(MVC_EXTENSION_ENABLE) + view_id = p_Dpb->fs[i_pic]->view_id; +#else + view_id = 0; +#endif + + while( ( p_Dpb->fs[j_pic]->frame->poc - missing_poc ) > p_Vid->poc_gap ) + { + missing_poc = missing_poc + p_Vid->poc_gap; + + if( check_duplicate_concealment( p_Vid, missing_poc, view_id ) ) + continue; + + if( p_FrameConc->flag_bad_poc_calculation ) + { + unsigned int ii_pic = 0, find = 0; + + for( ; ii_pic < ( p_Dpb->used_size - diff ); ii_pic++ ) + if( p_Dpb->fs[ii_pic]->frame->poc == p_Dpb->fs[ii_pic + 1]->frame->poc ) + { + StorablePicture *conc_pic = p_Dpb->fs[ii_pic]->frame; + + conc_pic->poc = missing_poc; + conc_pic->poc = missing_poc; + + calculate_frame_no( p_Vid, conc_pic ); + // p_Dpb->fs[ii_pic]->frame_no = p_Dpb->fs[ii_pic]->frame->frame_no; + + p_FrameConc->flag_bad_poc_calculation = 0; + break; + } + if( find ) + continue; + } + + // Concealment of Non Reference picture starts here + conceal_to_picture = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + conceal_to_picture->poc = conceal_to_picture->frame_poc = conceal_to_picture->top_poc = conceal_to_picture->bottom_poc = missing_poc; + conceal_to_picture->view_id = view_id; + /* Mark Concealed picture -> Conceal non reference */ + conceal_to_picture->concealed_pic = 2; + + if( !fercConcealOneLostFrame( p_Vid, p_Dpb, conceal_to_picture, 0 ) ) + { + printf( "Cannot conceal current loss picture\n" ); + } + + calculate_frame_no( p_Vid, conceal_to_picture ); + + // re-order picture buffer + qsort( p_Dpb->fs, p_Dpb->used_size, sizeof(FrameStore*), sort_by_poc_up ); + + Add_Concealment_Node( p_Vid, conceal_to_picture, view_id ); + + p_Vid->nFramesConceal[view_id]++; + } + } + p_Dpb->used_size = temp_used_size; + qsort( p_Dpb->fs, p_Dpb->used_size, sizeof(FrameStore*), sort_by_frame_num_up ); +} + +/*! + ************************************************************************ + * \brief + * Outputs the non reference frames. The POCs in the concealment buffer are + * sorted in ascending order and outputted when the lowest POC in the + * concealment buffer is lower than the lowest in the p_Dpb-> The linked list + * entry corresponding to the outputted POC is immediately deleted. + * + ************************************************************************ + */ +void fercWriteConcealedLostNonRefFrames( DecodedPictureBuffer *p_Dpb, int iPoc, int View_Id ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + FrameStore concealment_fs; + StorablePicture *conceal_picture; + // int last_output_poc = p_Dpb->last_output_poc[iView]; + + while( p_FrameConc->ConcealHead[View_Id] != NULL && p_FrameConc->ConcealHead[View_Id]->MissPoc <= iPoc ) + { + if( p_FrameConc->ConcealHead[View_Id]->MissPoc == iPoc ) + { +#if (PRINT_ECNODES) + if (!p_Vid->p_Inp->silent) + printf( "Duplicate frame. Discart concealed frame!\n"); +#endif + Delete_Concealment_Node( p_Vid, p_FrameConc->ConcealHead[View_Id], View_Id ); + p_Vid->nFramesConceal[View_Id]--; + continue; + } + + concealment_fs.frame = conceal_picture = p_FrameConc->ConcealHead[View_Id]->picture; + concealment_fs.view_id = conceal_picture->view_id = View_Id; + concealment_fs.poc = conceal_picture->poc = p_FrameConc->ConcealHead[View_Id]->MissPoc; + concealment_fs.is_output = 0; + concealment_fs.is_reference = 0; + concealment_fs.is_used = 3; + + conceal_picture->concealed_pic = 2; + + p_FrameConc->last_out_frame_no[View_Id] = conceal_picture->frame_no; + +#if (MVC_EXTENSION_ENABLE) + write_stored_frame( p_Vid, &concealment_fs, p_Vid->p_out_mvc[p_Dpb->layer_id] ); +#else + write_stored_frame(p_Vid, &concealment_fs, p_Vid->p_out); +#endif + + Delete_Concealment_Node( p_Vid, p_FrameConc->ConcealHead[View_Id], View_Id ); + } +} + +/*! + ************************************************************************ + * \brief + * Conceals the remaining lost frames. this fuction normally conceal the last + * frames of a GOP + ************************************************************************ + */ +void fercConcealRemainingLostFrames( DecodedPictureBuffer *p_Dpb, FrameStore *fs ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + + int view_id = fs->view_id; + int last_frame_no = p_FrameConc->last_out_frame_no[view_id]; + + if( p_FrameConc->last_out_fs[view_id] == NULL ) + { + p_FrameConc->last_out_fs[view_id] = alloc_frame_store(); + if( p_FrameConc->last_out_fs[view_id]->frame == NULL ) + { + p_FrameConc->last_out_fs[view_id]->frame = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + p_FrameConc->last_out_fs[view_id]->is_used = 3; + } + } + + while( fs->frame->frame_no > last_frame_no + 1 ) + { + StorablePicture *Frame = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + + //dump_dpb(p_Dpb); + + last_frame_no++; + + CopyCommonInformation( p_FrameConc->last_out_fs[view_id]->frame, Frame ); + fercCopyImg( p_Vid, p_FrameConc->last_out_fs[view_id]->frame, Frame ); + + p_Vid->frame_no = Frame->frame_no = last_frame_no; + Frame->view_id = view_id; + + /* Mark Concealed picture -> Conceal final picture */ + Frame->concealed_pic = 3; + + Report_Frame_Info( p_Vid, Frame ); + + direct_output( p_Vid, Frame, p_Vid->p_out_mvc[p_Dpb->layer_id] ); + //write_stored_frame(p_Vid, p_FrameConc->last_out_fs[view_id], p_Vid->p_out_mvc[p_Dpb->layer_id]); + + // free_storable_picture( Frame ); + + p_Vid->nFramesConceal[view_id]++; + } + + p_FrameConc->last_out_frame_no[view_id] = fs->frame->frame_no; + + CopyCommonInformation( fs->frame, p_FrameConc->last_out_fs[view_id]->frame ); + fercCopyImg( p_Vid, fs->frame, p_FrameConc->last_out_fs[view_id]->frame ); +} + +/*! + ************************************************************************ + * \brief + * Get disparity Map for the frame ready to de decoded + ************************************************************************ + */ +void GetDisparityForCurrentSlice( Slice *currSlice ) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + StorablePicture *dec_picture = p_Vid->dec_picture; + StorablePicture *disparity, *new_disparity; + int cont, list, idx; + StorablePicture *Base_Reference, *AuxFrame_Disp, *BaseFrame_Disp; + + imgpel *storeYUV = ( imgpel * )malloc( ( 16 + ( p_Vid->mb_cr_size_x * p_Vid->mb_cr_size_y ) * 2 / 16 ) * sizeof(imgpel) ); + + dec_picture->disparity = NULL; + + return; + + if( currSlice->view_id == BASE_VIEW_IDX ) + return; + + for( list = LIST_0, cont = 0; list < LIST_1; list++ ) + { + for( idx = 0; idx < currSlice->listXsize[list]; idx++ ) + { + cont += currSlice->listX[list][idx]->concealed_pic; + } + } + if( !cont ) + return; + + AuxFrame_Disp = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[1], currSlice->ThisPOC, 1, CLOSEST_ALL, 0, NULL ); + if( !AuxFrame_Disp ) + return; + + BaseFrame_Disp = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[0], AuxFrame_Disp->poc, 0, EXACT, 0, NULL ); + if( !AuxFrame_Disp ) + return; + + disparity = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + new_disparity = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + if( !disparity ) + return; + + //cvDisparity( p_Vid , AuxFrame_Disp , BaseFrame_Disp , disparity, p_Vid->p_Inp->DisparityMethod, p_Vid->p_Inp->DisparityWindow); + + disparity->poc = BaseFrame_Disp->poc; + disparity->PicSizeInMbs = BaseFrame_Disp->PicSizeInMbs; + disparity->PicWidthInMbs = BaseFrame_Disp->PicWidthInMbs; + + Base_Reference = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[0], dec_picture->poc, 0, EXACT, 0, NULL ); + + new_disparity = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + new_disparity->PicSizeInMbs = disparity->PicSizeInMbs; + new_disparity->PicWidthInMbs = disparity->PicWidthInMbs; + + new_disparity->chroma_format_idc = 1; + new_disparity->poc = Base_Reference->poc; + + DisparityProjection( p_Vid, disparity, Base_Reference, currSlice, &new_disparity, BLOCK_SIZE, 1 ); + + free_storable_picture( disparity ); + + dec_picture->disparity = new_disparity; + + //showStorablePicture(p_Vid, new_disparity, 0, "Disparity", 0); +} + +/*! + ************************************************************************ + * \brief + * Try to avoid error propagation + ************************************************************************ + */ +void ChangeInterViewPrediction( Macroblock *currMB, StorablePicture *dec_picture, int pred_dir, int i, int j, int block_size_x, int block_size_y ) +{ + Slice *currSlice = currMB->p_Slice; + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + StorablePicture *IntraRefFrame, *Ref; + char idx, ref_idx, TempIdx = 0; + MotionPropInfo *Matrix_MV_Info = dec_picture->Matrix_MV_Info; + int ii4, jj4, mv[2] = + { 0, 0 }, mv_count = 0; + double scale_factor; + + if( !Matrix_MV_Info ) + return; + + //! Get concealment references + for( idx = 0; idx < currSlice->listXsize[0]; idx++ ) + { + if( currSlice->listX[0][idx]->view_id == currSlice->view_id ) + { + IntraRefFrame = currSlice->listX[0][idx]; + TempIdx = idx; + break; + } + } + + if( ( pred_dir == 0 || pred_dir == 2 ) && ( ref_idx = mv_info->ref_idx[pred_dir] ) >= 0 ) + { // Changes for the LIST_0 + + pred_dir = 0; + + ref_idx = mv_info->ref_idx[pred_dir]; + Ref = currMB->p_Slice->listX[currMB->list_offset + pred_dir][ref_idx]; + if( Ref->concealed_pic && Ref->view_id != currSlice->view_id ) // mv modification + { + for( jj4 = 0; jj4 < block_size_y / 4; jj4++ ) + { + for( ii4 = 0; ii4 < block_size_x / 4; ii4++ ) + { + if( Matrix_MV_Info->mv_info_count[j4 + jj4][i4 + ii4] >= 0 ) + { + mv[0] += Matrix_MV_Info->mv_info[j4 + jj4][i4 + ii4][mv_count].mv[LIST_0].mv_x; + mv[1] += Matrix_MV_Info->mv_info[j4 + jj4][i4 + ii4][mv_count].mv[LIST_0].mv_y; + mv_count++; + } + } + } + mv[0] = ( int )( ( double )( mv[0] ) / mv_count ); + mv[1] = ( int )( ( double )( mv[1] ) / mv_count ); + + // scale_factor = (double)( currSlice->ThisPOC - IntraRefFrame->poc ) / (double)( currSlice->ThisPOC - Ref->poc ); + scale_factor = 1; + mv_info->mv->mv_x = ( short )( ( double )( mv[0] ) * scale_factor ); + mv_info->mv->mv_y = ( short )( ( double )( mv[1] ) * scale_factor ); + mv_info->ref_idx[currMB->list_offset + pred_dir] = TempIdx; + mv_info->ref_pic[currMB->list_offset + pred_dir] = IntraRefFrame; + + } + + } + +} +void ProjectMotionToCurrSlice( VideoParameters *p_Vid, StorablePicture *currPicture, Slice *currSlice ) +{ + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[currSlice->view_id]; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + int use_interview_reference = 1; + char idx, flagNeedMod = 0; + StorablePicture *IntraRefFrame = NULL; + MotionPropInfo *Matrix_MV_Info; + // Reference Slices - Store the information about pseudo Slices + // corresponding to the reference Frames + Slice *pSliceIntraViewReference = NULL; + + if( currPicture->view_id != 1 ) + return; + + //! Ccheck concealed references + for( idx = 0; idx < currSlice->listXsize[LIST_0]; idx++ ) + { + if( currSlice->listX[LIST_0][idx]->view_id != currSlice->view_id && currSlice->listX[LIST_0][idx]->concealed_pic ) + flagNeedMod = 1; + } + if( flagNeedMod == 0 ) + { + return; + } + + //! Get concealment references + for( idx = 0; idx < currSlice->listXsize[0]; idx++ ) + { + if( currSlice->listX[0][idx]->view_id == currSlice->view_id ) + { + IntraRefFrame = currSlice->listX[0][idx]; + break; + } + } + + if( !IntraRefFrame ) + { + return; + } + + if( IntraRefFrame->Conc_listXsize[LIST_0] == 1 && IntraRefFrame->Conc_listXInterviewPos[LIST_0] == 0 ) + { + return; + } + + //! Initialization of reference list for Intra-View Reference + pSliceIntraViewReference = malloc_slice( p_Vid->p_Inp, p_Vid ); + + pSliceIntraViewReference->p_Vid = p_Vid; + pSliceIntraViewReference->p_Dpb = p_Vid->p_Dpb_layer[IntraRefFrame->view_id]; + + pSliceIntraViewReference->ThisPOC = IntraRefFrame->poc; + pSliceIntraViewReference->framepoc = IntraRefFrame->poc; + pSliceIntraViewReference->view_id = IntraRefFrame->view_id; + pSliceIntraViewReference->layer_id = IntraRefFrame->layer_id; + pSliceIntraViewReference->slice_type = IntraRefFrame->slice_type; + + pSliceIntraViewReference->listXsize[LIST_0] = IntraRefFrame->Conc_listXsize[LIST_0]; + pSliceIntraViewReference->listXsize[LIST_1] = IntraRefFrame->Conc_listXsize[LIST_1]; + for( idx = 0; idx < pSliceIntraViewReference->listXsize[LIST_0]; idx++ ) + { + pSliceIntraViewReference->listX[LIST_0][idx] = IntraRefFrame->Conc_listX[LIST_0][idx]; + if( IntraRefFrame->Conc_listXInterviewPos[LIST_0] == idx ) + { + if( use_interview_reference ) + pSliceIntraViewReference->listX[LIST_0][idx] = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[0], IntraRefFrame->poc, 0, EXACT, 1, NULL ); + else + pSliceIntraViewReference->listX[LIST_0][idx] = p_Vid->no_reference_picture; + } + } + for( idx = 0; idx < pSliceIntraViewReference->listXsize[LIST_1]; idx++ ) + { + pSliceIntraViewReference->listX[LIST_1][idx] = IntraRefFrame->Conc_listX[LIST_1][idx]; + if( IntraRefFrame->Conc_listXInterviewPos[LIST_1] == idx ) + { + if( use_interview_reference ) + pSliceIntraViewReference->listX[LIST_1][idx] = p_Dpb->fs_ilref[0]->frame; + else + pSliceIntraViewReference->listX[LIST_1][idx] = p_Vid->no_reference_picture; + } + } + printf( "[FERC] Printing references list for source of vectors\n" ); + dump_ref_lists( pSliceIntraViewReference ); + + if( !currPicture->Matrix_MV_Info ) + currPicture->Matrix_MV_Info = ( MotionPropInfo * )malloc( sizeof(MotionPropInfo) ); + + Matrix_MV_Info = currPicture->Matrix_MV_Info; + + Matrix_MV_Info->mv_info = NULL; + Matrix_MV_Info->mv_info_count = NULL; + + //! TODO: Check this error + //getBestMotionVectorCandidates(p_Vid, IntraRefFrame, pSliceIntraViewReference, currPicture, Matrix_MV_Info, NULL, p_Vid->p_Inp->MotionVectorCandidates, 0 ); + + if( pSliceIntraViewReference ) + free_slice( pSliceIntraViewReference ); + + return; +} +void fercFreeMotionPropInfo( StorablePicture *p ) +{ + MotionPropInfo *Matrix_MV_Info = p->Matrix_MV_Info; + if( Matrix_MV_Info ) + { + if( Matrix_MV_Info->mv_info ) + free_mem3Dmp( Matrix_MV_Info->mv_info ); + + if( Matrix_MV_Info->mv_info ) + free_mem2Dint( Matrix_MV_Info->mv_info_count ); + + free( Matrix_MV_Info ); + } +} diff --git a/ldecod/src/ferc/ferc_dfdp.c b/ldecod/src/ferc/ferc_dfdp.c new file mode 100644 index 0000000..45ce185 --- /dev/null +++ b/ldecod/src/ferc/ferc_dfdp.c @@ -0,0 +1,589 @@ +/*! + ************************************************************************ + * \file ferc_dfdp.c + * + * \brief + * Internal function for ferc API + * Include the method proposed: + * Yibin Chen; Canhui Cai; Kai-Kuang Ma;,"Stereoscopic video error concealment for missing frame recovery using + * disparity-based frame difference projection," Image Processing (ICIP), + * 2009 16th IEEE International Conference on , vol., no., pp.4289-4292, 7-10 Nov. 2009 + * + * \author + * - Jo���o Carreira + * + ************************************************************************ + */ + +#include + +#include "ferc_api.h" +#include "ferc_internals.h" + +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_mvc.h" +#include "memalloc.h" +#include "image.h" +#include "mc_prediction.h" +#include "macroblock.h" +#include "block.h" +#include "mbuffer_common.h" +#include "win32.h" +#include "ferc_opencv_api.h" + +#define NORMALIZATION_VALUE 255 +/*! + ************************************************************************ + * \brief + * Difference of imgpel matrix + * C = A - B + ************************************************************************ + */ +static int i_diff_abs( int a, int b) +{ + return( iabs(a-b) ); +} +static int i_diff( int a, int b) +{ + return( a - b ); +} +static void image_diff( imgpel **A, imgpel **B, int **C, int size_x, int size_y, int absolute ) +{ + int i, j; + int (*funcao_diff)( int a, int b); + + if( absolute ) + funcao_diff = i_diff_abs; + else + funcao_diff = i_diff; + + for(i=0; i Max) + { + Max = A[j][i]; + } + } + } + return Max; +} + +/*! + ************************************************************************ + * \brief + * Minimun value of imgpel matrix + * Min = min(A) + ************************************************************************ + */ +static int min_matrix( int **A, int size_x, int size_y ) +{ + int i, j, Min = INT_MAX; + for(i=0; i= prev_thresh ) + { + sum_g1 += diff[j][i]; + elem_g1 += 1; + } + //! group 2 + else + { + sum_g2 += diff[j][i]; + elem_g2 += 1; + } + } + } + average_g1 = (double)(sum_g1) / (double)(elem_g1); + average_g2 = (double)(sum_g2) / (double)(elem_g2); + + return ( ( average_g2 + average_g1) / 2 ); +} + +/*! + ************************************************************************ + * \brief + * Compute the global disparity for the whole image + ************************************************************************ + */ +static int get_Global_Disparity( StorablePicture *Ref, StorablePicture *NonRef, StorablePicture *CDM, int WindowSize ) +{ + int x, y, d, global_d = 0; + int size_x = Ref->size_x, size_y = Ref->size_y; + unsigned long long int sad, min_sad = ULLONG_MAX; + + for(d=-WindowSize; d<=WindowSize; d++) + { + sad = 0; + for(y=0; yimgY[y][x] > 0 ) + { + sad += iabs( Ref->imgY[y][x] - NonRef->imgY[y][x-d]); + } + } + } + if( sad <= min_sad ) + { + min_sad = sad; + global_d = d; + } + } + return global_d; +} + +/*! + ************************************************************************ + * \brief + * Compute the local disparity for each pixel using a square block + * for a symmetric window + * + * The LocalDisparity are normalized between + * [-GlobalWindowsSize-LocalWindowsSize, GlobalWindowsSize+LocalWindowsSize] + * Disp = Disp + GlobalWindowsSize + LocalWindowsSize; + ************************************************************************ + */ +static void get_GlobalplusLocal_Disparity( StorablePicture *Ref, StorablePicture *NonRef, StorablePicture *CDM, + int GlobalDisparity, int GlobalWindowsSize, int LocalWindowsSize, int BlockSize, + StorablePicture *LocalDisparity) +{ + int x, y, xx, yy, d, local_d; + int size_x = Ref->size_x, size_y = Ref->size_y; + unsigned long long int sad, min_sad; + + for(y=0; yimgY[y][x] > 0) + { + for(d=-LocalWindowsSize; d<=LocalWindowsSize; d++) + { + sad = 0; + for(yy=-(BlockSize/2); yy<=(BlockSize/2); yy++) + { + for(xx=-(BlockSize/2); xx<=(BlockSize/2); xx++) + { + sad += iabs( Ref->imgY[y+yy][x+xx] - NonRef->imgY[y+yy][x+xx-d-GlobalDisparity]); + } + } + if( sad < min_sad ) + { + min_sad = sad; + local_d = d; + } + } + if( GlobalWindowsSize + LocalWindowsSize + GlobalDisparity + local_d >= 0 ) + { + LocalDisparity->imgY[y][x] = ( GlobalWindowsSize + LocalWindowsSize ) + ( GlobalDisparity + local_d ); + } + else + { + LocalDisparity->imgY[y][x] = 0; + printf("Inaccurate disparity value for pixel (%d,%d)\n", x,y); + } + } + else + { + LocalDisparity->imgY[y][x] = 0; + } + } + } + return; +} + +/*! + ************************************************************************ + * \brief + * Conceal missing frame using a method already proposed + * Yibin Chen; Canhui Cai; Kai-Kuang Ma; , + * "Stereoscopic video error concealment for missing frame recovery using + * disparity-based frame difference projection," Image Processing (ICIP), + * 2009 16th IEEE International Conference on , vol., no., pp.4289-4292, 7-10 Nov. 2009 + ************************************************************************ + */ +void Conceal_by_DisparityBasedFrameDifferenceProjection (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest) +{ + + //! Alloc a Slice associated with lost frame + Slice *currSlice = Dest->PicSlice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + int idx, y, x, Temporal_Ref_idx[2] = {-1, -1}; + int y_block4x4, x_block4x4; + unsigned int idx_mb; + Macroblock *currMB; + int mb_width, mb_height; + //! Initialization of reference list + currSlice->p_Vid = p_Vid; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + +#if MVC_EXTENSION_ENABLE + if( Dest->view_id != BASE_VIEW_IDX) + { + currSlice->ThisPOC = Dest->poc; + currSlice->framepoc = currSlice->ThisPOC; + currSlice->view_id = Dest->view_id; + currSlice->layer_id = Dest->layer_id; + + init_mvc_picture(currSlice); + } +#endif + + currSlice->ThisPOC = Source->poc; + currSlice->framepoc = Source->poc; + currSlice->view_id = Source->view_id; + currSlice->layer_id = Source->layer_id; + + currSlice->listXsize[LIST_0] = Source->Conc_listXsize[LIST_0]; + currSlice->listXsize[LIST_1] = Source->Conc_listXsize[LIST_1]; + for( idx=0; idxlistXsize[LIST_0]; idx++) + { + currSlice->listX[LIST_0][idx] = Source->Conc_listX[LIST_0][idx]; + if( Source->Conc_listXInterviewPos[LIST_0] == idx ) + { + currSlice->listX[LIST_0][idx] = p_Dpb->fs_ilref[0]->frame; + } + else if( Temporal_Ref_idx[LIST_0] == -1) + { + Temporal_Ref_idx[LIST_0] = idx; + } + } + + for( idx=0; idxlistXsize[LIST_1]; idx++) + { + currSlice->listX[LIST_1][idx] = Source->Conc_listX[LIST_1][idx]; + if( Source->Conc_listXInterviewPos[LIST_1] == idx ) + { + currSlice->listX[LIST_1][idx] = p_Dpb->fs_ilref[0]->frame; + } + else if( Temporal_Ref_idx[LIST_1] == -1) + { + Temporal_Ref_idx[LIST_1] = idx; + } + } + // End of intialization + + mb_width = Dest->PicWidthInMbs; + mb_height = (Dest->PicSizeInMbs)/(Dest->PicWidthInMbs); + + /* Loop though all motion vectors */ + for( y_block4x4=0; y_block4x4 < ((Dest->PicSizeInMbs)/(Dest->PicWidthInMbs)) * MB_BLOCK_SIZE/BLOCK_SIZE; y_block4x4++) + { + y = y_block4x4 * BLOCK_SIZE; //!< get y cordinates + for( x_block4x4=0; x_block4x4 < (Dest->PicWidthInMbs) * MB_BLOCK_SIZE/BLOCK_SIZE; x_block4x4++) + { + x = x_block4x4 * BLOCK_SIZE; + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idx_mb] ); + + // Update coordinates of the current concealed macroblock + currMB->mb.x = (short) (x/BLOCK_SIZE); + currMB->mb.y = (short) (y/BLOCK_SIZE); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y/4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x/4; + + // configure motion vector + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = Temporal_Ref_idx[LIST_0]; + + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_1] = Temporal_Ref_idx[LIST_1]; + } + } + + fercCopyImg(p_Vid, Source, Dest); + + { + StorablePicture *Frame_Base_T, *Frame_Base_Tminus1 = NULL, *Frame_Aux_Tminus1 = NULL; + StorablePicture *ChangeDectectionMap_Base = NULL, *ChangeDectectionMap_Aux = NULL; + StorablePicture *Disparity = NULL; + + int ***TemporalChangeDetection_Base_I = NULL, ***TemporalChangeDetection_Base = NULL, ***TemporalChangeDetection_Aux = NULL; + int aux_d, i_max, i_min, y, x, GlobalDisparity; + double Average, Threshold, prevThreshold; + + int GlobalWindowSize = 20; + int LocalWindowSize = 20; + + int relatation_y_c = p_Vid->width / p_Vid->width_cr; + + ChangeDectectionMap_Base = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + ChangeDectectionMap_Aux = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + + + + //! Get pictures from the buffer + Frame_Base_T = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[BASE_VIEW_IDX], Dest->poc, BASE_VIEW_IDX, EXACT, 0, NULL); + Frame_Aux_Tminus1 = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[Dest->view_id], Dest->poc, Dest->view_id, CLOSEST_ALL, 0, NULL); + Frame_Base_Tminus1 = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[BASE_VIEW_IDX], Frame_Aux_Tminus1->poc, BASE_VIEW_IDX, EXACT, 0, NULL); + + + + + + + get_mem3Dint( &TemporalChangeDetection_Base_I, 3, p_Vid->height, p_Vid->width ); + + //! Absolute temporal difference + image_diff( Frame_Base_T->imgY, Frame_Base_Tminus1->imgY, TemporalChangeDetection_Base_I[0], p_Vid->width, p_Vid->height, 1 ); + + get_mem3Dint( &TemporalChangeDetection_Base , 3, p_Vid->height, p_Vid->width ); + MeanFilterInt( TemporalChangeDetection_Base_I[0],TemporalChangeDetection_Base[0], p_Vid->width, p_Vid->height, 8 ); + + + //! Exploit a global threshold technique - Section II-A-1) + i_min = min_matrix( TemporalChangeDetection_Base[0], p_Vid->width, p_Vid->height ); + i_max = max_matrix( TemporalChangeDetection_Base[0], p_Vid->width, p_Vid->height ); + + Threshold = (double)( i_max + i_min ) / (double)(2); + + do{ + prevThreshold = Threshold; + Threshold = find_new_threshold( TemporalChangeDetection_Base[0], p_Vid->width, p_Vid->height, prevThreshold ); + }while( dabs( prevThreshold - Threshold ) > 1 ); + + //! Find the change detection map + for(y=0; yheight; y++) + { + for(x=0; xwidth; x++) + { + if( TemporalChangeDetection_Base[0][y][x] >= Threshold ) + ChangeDectectionMap_Base->imgY[y][x] = 255; + else + ChangeDectectionMap_Base->imgY[y][x] = 0; + } + } + + showStorablePicture(p_Vid,ChangeDectectionMap_Base,0,0,"Map Base-view",0); + //saveStorablePicture(p_Vid,"cdm_base.bmp",ChangeDectectionMap_Base,0); + + //! Disparity Estimation using eq. (3,4,5,6) + Disparity = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + GlobalDisparity = get_Global_Disparity( Frame_Base_Tminus1, Frame_Aux_Tminus1, ChangeDectectionMap_Base, GlobalWindowSize ); + get_GlobalplusLocal_Disparity( Frame_Base_Tminus1, Frame_Aux_Tminus1, ChangeDectectionMap_Base, GlobalDisparity, GlobalWindowSize, LocalWindowSize, 8, Disparity); + + //! get the real Temporal change for base view + image_diff( Frame_Base_T->imgY, Frame_Base_Tminus1->imgY, TemporalChangeDetection_Base_I[0], p_Vid->width, p_Vid->height, 0 ); + MeanFilterInt(TemporalChangeDetection_Base_I[0], TemporalChangeDetection_Base[0], p_Vid->width, p_Vid->height, 8 ); + + //! Project the Change dectection from one view to another using eq. (8) + //! Project the Temporal change from one view to another using eq. (9) + get_mem3Dint( &TemporalChangeDetection_Aux, 3, p_Vid->height, p_Vid->width ); + for(y=0; yheight; y++) + { + for(x=0; xwidth; x++) + { + if( ChangeDectectionMap_Base->imgY[y][x] > 0 ) + { + aux_d = (int)(Disparity->imgY[y][x]) - (GlobalWindowSize + LocalWindowSize); + ChangeDectectionMap_Aux->imgY[y][x-aux_d] = ChangeDectectionMap_Base->imgY[y][x]; + TemporalChangeDetection_Aux[0][y][x-aux_d] = TemporalChangeDetection_Base[0][y][x]; + } + } + } + + showStorablePicture(p_Vid,ChangeDectectionMap_Aux,0,0,"Map Aux",0); + //saveStorablePicture(p_Vid,"cdm_aux.bmp",ChangeDectectionMap_Aux,1,0); + + + //for(y=0; yheight; y++) + //{ + // for(x=0; xwidth; x++) + // { + // aux_d = (int)(Disparity->imgY[y][x]) - (GlobalWindowSize + LocalWindowSize); + // if( ChangeDectectionMap_Aux->imgY[y][x-aux_d] > 0 ) + // { + // TemporalChangeDetection_Aux->imgY[y][x-aux_d] = TemporalChangeDetection_Base->imgY[y][x]; + // } + // } + //} + + //for(y=0; yheight_cr; y++) + //{ + // for(x=0; xwidth_cr; x++) + // { + // aux_d = (int)(Disparity->imgUV[0][y][x]) - (GlobalWindowSize - LocalWindowSize); + // aux_d = aux_d / relatation_y_c; + // if( ChangeDectectionMap_Aux->imgY[y][x] > 0 ) + // { + // TemporalChangeDetection_Aux->imgUV[0][y][x-aux_d] = TemporalChangeDetection_Base->imgUV[0][y][x]; + // TemporalChangeDetection_Aux->imgUV[1][y][x-aux_d] = TemporalChangeDetection_Base->imgUV[1][y][x]; + // } + // } + //} + + //! Reconstruct the missing frame + for(y=0; ysize_y; y++) + { + for(x=0; xsize_x; x++) + { + Dest->imgY[y][x] = iClip3( 0, 255, (int)Frame_Aux_Tminus1->imgY[y][x] + TemporalChangeDetection_Aux[0][y][x] ); + } + } + //for(y=0; ysize_y_cr; y++) + //{ + // for(x=0; xsize_x_cr; x++) + // { + // Dest->imgUV[0][y][x] = Frame_Aux_Tminus1->imgUV[0][y][x] + TemporalChangeDetection_Aux->imgUV[0][y][x]; + // Dest->imgUV[1][y][x] = Frame_Aux_Tminus1->imgUV[1][y][x] + TemporalChangeDetection_Aux->imgUV[1][y][x]; + // } + //} + + + showStorablePicture(p_Vid,Dest,0,0,"Destination",0); + + free_storable_picture( Disparity ); + + free_storable_picture( ChangeDectectionMap_Base ); + free_storable_picture( ChangeDectectionMap_Aux ); + + free_mem3Dint( TemporalChangeDetection_Base ); + free_mem3Dint( TemporalChangeDetection_Aux ); + } +} + +//image_diff( Frame_Base_T->imgUV[0], Frame_Base_Tminus1->imgUV[0], TemporalChangeDetection_Base->imgUV[0], p_Vid->width_cr, p_Vid->height_cr ); +//image_diff( Frame_Base_T->imgUV[1], Frame_Base_Tminus1->imgUV[1], TemporalChangeDetection_Base->imgUV[1], p_Vid->width_cr, p_Vid->height_cr ); + +//{ +// char FileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; +// strcpy( chBuf , p_Vid->p_Inp->outfile ); +// pch = strrchr( chBuf , '.' ); +// if(pch) +// *pch = '\0'; +// if( strcmp("nul", chBuf) ) +// { +// sprintf( FileName , "cdm.bmp" ); +// saveStorablePicture( p_Vid , FileName , ChangeDectectionMap_Base , 0 ); +// } +//} + +//{ +// char FileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; +// strcpy( chBuf , p_Vid->p_Inp->outfile ); +// pch = strrchr( chBuf , '.' ); +// if(pch) +// *pch = '\0'; +// if( strcmp("nul", chBuf) ) +// { +// sprintf( FileName , "disp.bmp" ); +// saveStorablePicture( p_Vid , FileName , Disparity , 0 ); +// } +//} diff --git a/ldecod/src/ferc/ferc_internals.c b/ldecod/src/ferc/ferc_internals.c new file mode 100644 index 0000000..170dc5c --- /dev/null +++ b/ldecod/src/ferc/ferc_internals.c @@ -0,0 +1,946 @@ +/*! + ************************************************************************ + * \file ferc_internals.c + * + * \brief + * Internal function for ferc API + * + * \author + * - Jo���o Carreira + * + ************************************************************************ + */ + +#include "ferc_internals.h" +#include "ferc_api.h" +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_mvc.h" +#include "memalloc.h" +#include "image.h" +#include "mc_prediction.h" +#include "macroblock.h" +#include "block.h" +#include "mbuffer_common.h" + +/*! + ************************************************************************ + * \brief + * Sortmotion vector abs up + ************************************************************************ + */ +int sort_mv_abs_up( const void *arg1, const void *arg2 ) +{ + struct partial_mv v_0 = *( ( struct partial_mv * )arg1 ); + struct partial_mv v_1 = *( ( struct partial_mv * )arg2 ); + double avg_v0 = abs_dvec( v_0.mv.mv_x, v_0.mv.mv_y ); + double avg_v1 = abs_dvec( v_1.mv.mv_x, v_1.mv.mv_y ); + + if( avg_v0 > avg_v1 ) + return 1; + else if( avg_v0 < avg_v1 ) + return -1; + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * Sort Dpb by frame_num + * Edit by Joo Carreira + ************************************************************************ + */ +int sort_by_frame_num_up( const void *arg1, const void *arg2 ) +{ + FrameStore *f_0 = *( ( FrameStore ** )arg1 ); + FrameStore *f_1 = *( ( FrameStore ** )arg2 ); + int comp = f_0->frame_num - f_1->frame_num; + if( !comp ) + comp = f_0->poc - f_1->poc; + if( !comp ) + comp = f_0->view_id - f_1->view_id; + return comp; +} + +/*! + ************************************************************************ + * \brief + * Sort Dpb by poc + * Edit by Joao Carreira + ************************************************************************ + */ +int sort_by_poc_up( const void *arg1, const void *arg2 ) +{ + FrameStore *f_0 = *( ( FrameStore ** )arg1 ); + FrameStore *f_1 = *( ( FrameStore ** )arg2 ); + return ( ( int )( ( f_0->poc + f_0->view_id ) - ( f_1->poc + f_1->view_id ) ) ); +} + +/*! + ************************************************************************ + * \brief + * Conceal picture using frame copy method + * Copy image data from one array to another array + ************************************************************************ + */ +void Paint_Withe_Frame( VideoParameters *p_Vid, StorablePicture *Dest ) +{ + int x, y; + //! Y + for( y = 0; y < p_Vid->height; y++ ) + for( x = 0; x < p_Vid->width; x++ ) + Dest->imgY[y][x] = 0; + //!UV + for( y = 0; y < p_Vid->height_cr; y++ ) + for( x = 0; x < p_Vid->width_cr; x++ ) + { + Dest->imgUV[0][y][x] = 0; + Dest->imgUV[1][y][x] = 0; + } +} + +static int sort_imgpel_up( const void *arg1, const void *arg2 ) +{ + int int_arg1 = *( ( imgpel * )( arg1 ) ); + int int_arg2 = *( ( imgpel* )( arg2 ) ); + return int_arg1 - int_arg2; +} + +/*! + ************************************************************************ + * \brief + * Apply a mean filter + ************************************************************************ + */ +void MeanFilter( imgpel **initial_matrix, imgpel **filtrated_matrix, int size_x, int size_y, int kernel_size ) +{ + int x, y, xx, yy, x_start, x_end, y_start, y_end; + double sum; + int count; + + for( x = 0; x < size_x; x++ ) + { + for( y = 0; y < size_y; y++ ) + { + x_start = imax( 0, x - kernel_size / 2 ); + x_end = imin( size_x, x + kernel_size / 2 ); + y_start = imax( 0, y - kernel_size / 2 ); + y_end = imin( size_y, y + kernel_size / 2 ); + + for( xx = x_start, sum = 0, count = 0; xx <= x_end; xx++ ) + { + for( yy = y_start; yy <= y_end; yy++ ) + { + sum += initial_matrix[yy][xx]; + count++; + } + } + filtrated_matrix[y][x] = ( imgpel )( sum / ( double )( count ) ); + } + } + return; +} + +/*! + ************************************************************************ + * \brief + * Apply a median filter + ************************************************************************ + */ +void MedianFilter( imgpel **initial_matrix, imgpel **filtrated_matrix, int size_x, int size_y, int kernel_size ) +{ + imgpel *img_pel = ( imgpel * )malloc( ( kernel_size + 1 ) * ( kernel_size + 1 ) * sizeof(imgpel) ); + int x, y, xx, yy, x_start, x_end, y_start, y_end, elem; + + for( x = 0; x < size_x; x++ ) + { + for( y = 0; y < size_y; y++ ) + { + x_start = imax( 0, x - kernel_size / 2 ); + x_end = imin( size_x - 1, x + kernel_size / 2 ); + y_start = imax( 0, y - kernel_size / 2 ); + y_end = imin( size_y - 1, y + kernel_size / 2 ); + + for( xx = x_start, elem = 0; xx <= x_end; xx++ ) + { + for( yy = y_start; yy <= y_end; yy++ ) + { + img_pel[elem] = initial_matrix[yy][xx]; + elem++; + } + } + qsort( img_pel, elem, sizeof(imgpel), sort_imgpel_up ); + if( elem % 2 ) + filtrated_matrix[y][x] = ( img_pel[elem >> 1] + img_pel[( elem >> 1 ) + 1] + 1 ) >> 1; + else + filtrated_matrix[y][x] = img_pel[elem >> 1]; + } + } + free( img_pel ); + return; +} + + + +/*! + ************************************************************************ + * \brief + * Function to search in decoded picture buffer for a previous decoded frame + * based of input parameters: poc, view_id and search_mode + * + ************************************************************************ + */ +StorablePicture *fercGetPictureForConcealFromDpb( DecodedPictureBuffer *p_Dpb, int poc, int search_view_id, int search_mode, int search_concealed, + unsigned int *position ) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + int BestScore, idxBestScore; + int i; + int j; + + switch( search_mode ) + { + case CLOSEST_ALL: + //Uses the closest frame to conceal (inc concealed frames) + BestScore = 99; + idxBestScore = 0; + for( i = 0; i < p_Dpb->used_size; i++ ) + { + if( p_Dpb->fs[i]->is_used == 3 && p_Dpb->fs[i]->unused_concealment == 0 ) + { + if( p_Dpb->fs[i]->view_id == search_view_id && ( !p_Dpb->fs[i]->frame->concealed_pic || search_concealed ) + && ( p_Dpb->fs[i]->frame->idr_flag != 1 || p_Vid->conceal_mode <= FRAME_COPY_BC ) //|!< Protection for using IDR picture as reference for motion copy + && ( p_Dpb->fs[i]->frame->frame_num != 0 || p_Vid->conceal_mode < 2 ) ) //!< Protection for using first P picture in auxiliary view for motion copy + { + if( abs( p_Dpb->fs[i]->frame->poc - poc ) < BestScore ) + { + BestScore = abs( p_Dpb->fs[i]->frame->poc - poc ); + idxBestScore = i; + } + } + } + } + if( position != NULL ) + *position = i; + return p_Dpb->fs[idxBestScore]->frame; + break; + case CLOSEST_FUTURE: + //Uses the closest future frame to conceal (inc concealed frames) + BestScore = 99; + idxBestScore = 0; + for( i = 0; i < p_Dpb->used_size; i++ ) + { + if( p_Dpb->fs[i]->is_used == 3 && p_Dpb->fs[i]->unused_concealment == 0 ) + { + if( p_Dpb->fs[i]->view_id == search_view_id && ( !p_Dpb->fs[i]->frame->concealed_pic || search_concealed ) + && ( p_Dpb->fs[i]->frame->idr_flag != 1 || p_Vid->conceal_mode <= FRAME_COPY_BC ) //|!< Protection for using IDR picture as reference for motion copy + && ( p_Dpb->fs[i]->frame->frame_num != 0 || p_Vid->conceal_mode <= FRAME_COPY_BC ) ) //!< Protection for using first P picture in auxiliary view for motion copy + { + if( abs( p_Dpb->fs[i]->frame->poc - poc ) <= BestScore ) + { + BestScore = abs( p_Dpb->fs[i]->frame->poc - poc ); + idxBestScore = i; + } + } + } + } + if( position != NULL ) + *position = i; + return p_Dpb->fs[idxBestScore]->frame; + break; + case WELL_RECEIVED_STEREO: + /* + * Return the last frame decoded of view = view_id, corresponding to + * corresponding to a well received stereo pair + */ + BestScore = 99; + idxBestScore = 0; + for( i = 0; i < p_Dpb->used_size; i++ ) + { + if( p_Dpb->fs[i]->is_used == 3 && p_Dpb->fs[i]->unused_concealment == 0 ) + { + if( p_Dpb->fs[i]->is_used == 3 && p_Dpb->fs[i]->view_id == search_view_id && !p_Dpb->fs[i]->frame->concealed_pic + && ( p_Dpb->fs[i]->frame->idr_flag != 1 || p_Vid->conceal_mode <= FRAME_COPY_BC ) ) //|!< Protection for using IDR picture as reference for motion copy + { + for( j = ( p_Dpb->used_size - 1 ); j >= 0; j-- ) + { + if( p_Dpb->fs[j]->frame->poc == p_Dpb->fs[i]->frame->poc && p_Dpb->fs[j]->frame->view_id == ( ( p_Dpb->fs[i]->frame->view_id + 1 ) & 0x01 ) ) + { + if( abs( p_Dpb->fs[i]->frame->poc - poc ) < BestScore ) + { + BestScore = abs( p_Dpb->fs[i]->frame->poc - poc ); + idxBestScore = i; + } + + } + } + } + } + } + if( position != NULL ) + *position = idxBestScore; + return p_Dpb->fs[idxBestScore]->frame; + break; + case EXACT: + /* Return the exact picture or NULL */ + for( i = ( p_Dpb->used_size - 1 ); i >= 0; i-- ) + { + if( p_Dpb->fs[i]->is_used == 3 && p_Dpb->fs[i]->unused_concealment == 0 ) + { + if( p_Dpb->fs[i]->view_id == search_view_id && p_Dpb->fs[i]->frame->poc == poc ) + { + if( position != NULL ) + *position = i; + return p_Dpb->fs[i]->frame; + } + } + } + break; + default: + return NULL ; + } + return NULL ; +} + +/*! + ************************************************************************ + * \brief + * Copy a block to an image + * + ************************************************************************ + */ +void copyPredblockRegionYUVDestination( StorablePicture *Destination, imgpel *predBlock, int x, int y, int BlockSize ) +{ + int ii, jj; + + //! Y Matrix + for( ii = 0; ii < BLOCK_SIZE; ii++ ) + for( jj = 0; jj < BLOCK_SIZE; jj++ ) + Destination->imgY[y + ii][x + jj] = predBlock[ii * ( BlockSize ) + jj]; + + predBlock = predBlock + ( BlockSize * BlockSize ); + + //! UV Matrix + if( Destination->chroma_format_idc != YUV400 ) + { + int uv; + for( uv = 0; uv < 2; uv++ ) + { + for( ii = 0; ii < ( BlockSize / 2 ); ii++ ) + for( jj = 0; jj < ( BlockSize / 2 ); jj++ ) + Destination->imgUV[uv][y / 2 + ii][x / 2 + jj] = predBlock[ii * ( BlockSize / 2 ) + jj]; + predBlock = predBlock + ( BlockSize * BlockSize / 4 ); + } + } +} + +/*! + ************************************************************************ + * \brief + * block bi-prediction + ************************************************************************ + */ +void ferc_bi_prediction( imgpel *mb_pred, imgpel *block_l0, uint8 value_l0, imgpel *block_l1, uint8 value_l1, int ver_block_size, int hor_block_size, + int have_uv ) +{ + int ii; + for( ii = 0; ii < ( int )( hor_block_size * hor_block_size * ( 1 + 0.5 * have_uv ) ); ii++ ) + { + // *(mb_pred++) = (imgpel)((( *(block_l0++) + *(block_l1++) ) + 1) >> 1); + // "+1" garante que nunca se desloca o valor zero -> + *( mb_pred++ ) = ( imgpel )( ( value_l1 * ( *( block_l0++ ) ) + value_l0 * ( *( block_l1++ ) ) + 1 ) / ( value_l0 + value_l1 ) ); + } + return; +} + +/*! + ************************************************************************ + * \brief + * The motion prediction pixels are calculated from the given location (in + * 1/4 pixel units) of the referenced frame. It copies the sub block from the + * corresponding reference to the frame to be concealed. + * + ************************************************************************* + */ +void EnhancedbuildPredblock4x4YUV( VideoParameters *p_Vid, int *mv, int x, int y, imgpel *predMB, int list, int current_mb_nr, imgpel **tmp_block ) +{ + int i = 0, j = 0, ii = 0, jj = 0, i1 = 0, j1 = 0, j4 = 0, i4 = 0; + int uv; + int vec1_x = 0, vec1_y = 0; + int ioff, joff; + int have_tmp; + StorablePicture *dec_picture = p_Vid->dec_picture; + imgpel *pMB = predMB; + + int ii0, jj0, ii1, jj1, if1, jf1, if0, jf0; + int mv_mul; + + //FRExt + int f1_x, f1_y, f2_x, f2_y, f3, f4; + int yuv = dec_picture->chroma_format_idc - 1; + + int ref_frame = mv[2]; + int mb_nr = current_mb_nr; + + Macroblock *currMB = &p_Vid->mb_data[mb_nr]; // intialization code deleted, see below, StW + Slice *currSlice = currMB->p_Slice; + + StorablePicture *ref_picture = currSlice->listX[list][ref_frame]; + + have_tmp = tmp_block ? 1 : 0; + //have_tmp = 0; + + if( !have_tmp ) + get_mem2Dpel( &tmp_block, MB_BLOCK_SIZE, MB_BLOCK_SIZE ); + + /* Update coordinates of the current concealed macroblock */ + + currMB->mb.x = ( short )( x / BLOCK_SIZE ); + currMB->mb.y = ( short )( y / BLOCK_SIZE ); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y / 4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x / 4; + + mv_mul = 4; + + //! redundant information. Why cur_imgY if both point to the same memory block + ref_picture->cur_imgY = ref_picture->imgY; + + // luma ******************************************************* + + vec1_x = x * mv_mul + mv[0]; + vec1_y = y * mv_mul + mv[1]; + get_block_luma( ref_picture, vec1_x, vec1_y, BLOCK_SIZE, BLOCK_SIZE, tmp_block, dec_picture->iLumaStride, dec_picture->size_x_m1, + ( currMB->mb_field ) ? ( dec_picture->size_y >> 1 ) - 1 : dec_picture->size_y_m1, currSlice->tmp_res, p_Vid->max_pel_value_comp[PLANE_Y], + ( imgpel )p_Vid->dc_pred_value_comp[PLANE_Y], currMB ); + + for( jj = 0; jj < MB_BLOCK_SIZE / BLOCK_SIZE; jj++ ) + for( ii = 0; ii < BLOCK_SIZE; ii++ ) + currSlice->mb_pred[LumaComp][jj][ii] = tmp_block[jj][ii]; + + for( j = 0; j < 4; j++ ) + { + for( i = 0; i < 4; i++ ) + { + pMB[j * 4 + i] = currSlice->mb_pred[LumaComp][j][i]; + } + } + pMB += 16; + + if( dec_picture->chroma_format_idc != YUV400 ) + { + // chroma ******************************************************* + f1_x = 64 / ( p_Vid->mb_cr_size_x ); + f2_x = f1_x - 1; + + f1_y = 64 / ( p_Vid->mb_cr_size_y ); + f2_y = f1_y - 1; + + f3 = f1_x * f1_y; + f4 = f3 >> 1; + + for( uv = 0; uv < 2; uv++ ) + { + joff = subblk_offset_y[yuv][0][0]; + j4 = currMB->pix_c_y + joff; + ioff = subblk_offset_x[yuv][0][0]; + i4 = currMB->pix_c_x + ioff; + + for( jj = 0; jj < 2; jj++ ) + { + for( ii = 0; ii < 2; ii++ ) + { + i1 = ( i4 + ii ) * f1_x + mv[0]; + j1 = ( j4 + jj ) * f1_y + mv[1]; + + ii0 = iClip3( 0, dec_picture->size_x_cr - 1, i1 / f1_x ); + jj0 = iClip3( 0, dec_picture->size_y_cr - 1, j1 / f1_y ); + ii1 = iClip3( 0, dec_picture->size_x_cr - 1, ( ( i1 + f2_x ) / f1_x ) ); + jj1 = iClip3( 0, dec_picture->size_y_cr - 1, ( ( j1 + f2_y ) / f1_y ) ); + + if1 = ( i1 & f2_x ); + jf1 = ( j1 & f2_y ); + if0 = f1_x - if1; + jf0 = f1_y - jf1; + + currSlice->mb_pred[uv + 1][jj][ii] = ( imgpel )( ( if0 * jf0 * currSlice->listX[list][ref_frame]->imgUV[uv][jj0][ii0] + + if1 * jf0 * currSlice->listX[list][ref_frame]->imgUV[uv][jj0][ii1] + if0 * jf1 * currSlice->listX[list][ref_frame]->imgUV[uv][jj1][ii0] + + if1 * jf1 * currSlice->listX[list][ref_frame]->imgUV[uv][jj1][ii1] + f4 ) / f3 ); + } + } + + for( j = 0; j < 2; j++ ) + { + for( i = 0; i < 2; i++ ) + { + pMB[j * 2 + i] = currSlice->mb_pred[uv + 1][j][i]; + } + } + pMB += 4; + + } + } + if( !have_tmp ) + free_mem2Dpel( tmp_block ); +} +void EnhancedbuildPredblockRegionYUV( VideoParameters *p_Vid, int *mv, int x, int y, imgpel *predMB, int list, int current_mb_nr, int BlockSize, + imgpel **tmp_block ) +{ + int i, j; + + for( i = 0; i < BlockSize / BLOCK_SIZE; i++ ) + { + for( j = 0; j < BlockSize / BLOCK_SIZE; j++ ) + { + EnhancedbuildPredblock4x4YUV( p_Vid, mv, x, y, &( predMB[i * BlockSize + j * BLOCK_SIZE] ), LIST_0, current_mb_nr, tmp_block ); + } + } +} + +/*! + ************************************************************************ + * \brief + * The motion prediction pixels are calculated from the given location (in + * 1/4 pixel units) of the referenced frame. It copies the sub block from the + * corresponding reference to the frame to be concealed. + * + ************************************************************************* + */ +void buildPredblockRegionYUV( VideoParameters *p_Vid, StorablePicture *ref_picture, Macroblock *currMB, int *mv, int x, int y, imgpel *pMB, int Block_Size, + imgpel **tmp_block, int have_temp ) +{ + int i = 0, j = 0, ii = 0, jj = 0, i1 = 0, j1 = 0, j4 = 0, i4 = 0; + int uv; + int vec1_x = 0, vec1_y = 0; + int ioff, joff; + + int ii0, jj0, ii1, jj1, if1, jf1, if0, jf0, ifx, jf; + + // Interpolation of 1/4 subpixel + int mv_mul = 4; + + //FRExt + int f1_x, f1_y, f2_x, f2_y, f3, f4; + int yuv = ref_picture->chroma_format_idc - 1; + + // int mb_nr = current_mb_nr; + // Macroblock *currMB = &ref_picture->MB_pic_data[current_mb_nr]; + //Macroblock *currMB = &p_Vid->mb_data[current_mb_nr]; // intialization code deleted, see below, StW + Slice *currSlice = currMB->p_Slice; + + // alloc memory for temp blocks + if( !have_temp ) + get_mem2Dpel( &tmp_block, MB_BLOCK_SIZE, MB_BLOCK_SIZE ); + + // luma ******************************************************* + + vec1_x = x * mv_mul + mv[0]; + vec1_y = y * mv_mul + mv[1]; + + //! redundant information. Why cur_imgY if both point to the same memory block + ref_picture->cur_imgY = ref_picture->imgY; + + //void get_block_luma(StorablePicture *curr_ref, int x_pos, int y_pos, int block_size_x, int block_size_y, imgpel **block, + //int shift_x, int maxold_x, + //int maxold_y, int **tmp_res, + //int max_imgpel_value, imgpel no_ref_value, Macroblock *currMB) + get_block_luma( ref_picture, vec1_x, vec1_y, Block_Size, Block_Size, tmp_block, ref_picture->iLumaStride, ref_picture->size_x_m1 - 1, + ( currMB->mb_field ) ? ( ref_picture->size_y >> 1 ) - 1 : ref_picture->size_y_m1, currSlice->tmp_res, p_Vid->max_pel_value_comp[PLANE_Y], + ( imgpel )p_Vid->dc_pred_value_comp[PLANE_Y], currMB ); + + for( jj = 0; jj < MB_BLOCK_SIZE / Block_Size; jj++ ) + for( ii = 0; ii < Block_Size; ii++ ) + currSlice->mb_pred[LumaComp][jj][ii] = tmp_block[jj][ii]; + + for( j = 0; j < 4; j++ ) + { + for( i = 0; i < 4; i++ ) + { + pMB[j * 4 + i] = currSlice->mb_pred[LumaComp][j][i]; + } + } + pMB += 16; + + if( ref_picture->chroma_format_idc != YUV400 ) + { + // chroma ******************************************************* + f1_x = 64 / ( p_Vid->mb_cr_size_x ); + f2_x = f1_x - 1; + + f1_y = 64 / ( p_Vid->mb_cr_size_y ); + f2_y = f1_y - 1; + + f3 = f1_x * f1_y; + f4 = f3 >> 1; + + for( uv = 0; uv < 2; uv++ ) + { + joff = subblk_offset_y[yuv][0][0]; + j4 = currMB->pix_c_y + joff; + ioff = subblk_offset_x[yuv][0][0]; + i4 = currMB->pix_c_x + ioff; + + for( jj = 0; jj < 2; jj++ ) + { + jf = ( j4 + jj ) / ( p_Vid->mb_cr_size_y / Block_Size ); // jf = Subblock_y-coordinate + for( ii = 0; ii < 2; ii++ ) + { + ifx = ( i4 + ii ) / ( p_Vid->mb_cr_size_x / Block_Size ); // ifx = Subblock_x-coordinate + + i1 = ( i4 + ii ) * f1_x + mv[0]; + j1 = ( j4 + jj ) * f1_y + mv[1]; + + ii0 = iClip3( 0, ref_picture->size_x_cr - 1, i1 / f1_x ); + jj0 = iClip3( 0, ref_picture->size_y_cr - 1, j1 / f1_y ); + ii1 = iClip3( 0, ref_picture->size_x_cr - 1, ( ( i1 + f2_x ) / f1_x ) ); + jj1 = iClip3( 0, ref_picture->size_y_cr - 1, ( ( j1 + f2_y ) / f1_y ) ); + + if1 = ( i1 & f2_x ); + jf1 = ( j1 & f2_y ); + if0 = f1_x - if1; + jf0 = f1_y - jf1; + + currSlice->mb_pred[uv + 1][jj][ii] = ( imgpel )( ( if0 * jf0 * ref_picture->imgUV[uv][jj0][ii0] + if1 * jf0 * ref_picture->imgUV[uv][jj0][ii1] + + if0 * jf1 * ref_picture->imgUV[uv][jj1][ii0] + if1 * jf1 * ref_picture->imgUV[uv][jj1][ii1] + f4 ) / f3 ); + } + } + for( j = 0; j < 2; j++ ) + { + for( i = 0; i < 2; i++ ) + { + pMB[j * 2 + i] = currSlice->mb_pred[uv + 1][j][i]; + } + } + pMB += 4; + } + } + if( !have_temp ) + free_mem2Dpel( tmp_block ); +} + +/*! + ************************************************************************ + * \brief + * Predict the bad motion vector with previous know information of + * concealment reference frame + * + ************************************************************************ + */ +void ConcealMotionVector( VideoParameters *p_Vid, StorablePicture *Dest, Slice *Slice, int y_block4x4, int x_block4x4, int method, int list, int conc_mv[3], + int temporal_idx ) +{ + static int MV_PRED_POS[][2] = + {/*zona 1*/ + { 0, -1 }, + { -1, -1 }, + { -1, 0 }, + { -1, 1 },/*zona 2*/ + { 0, -2 }, + { -1, -2 }, + { -2, -2 }, + { -2, -1 }, + { -2, 0 }, + { -2, 1 } }; + //static int MV_PRED_POS[][2]={{-1,0},{0,-1},{1,-1}}; +#define N_MV_PRED_POS 4 + + int i, j; + int use_Disp = 0; + double sum_x = 0, sum_y = 0, scale; + int size_x = Dest->size_x, size_y = Dest->size_y; + int ref_idx, ref_idx_disp = 99, ref_idx_motion = 99, ref_poc; + struct partial_mv par_mv[N_MV_PRED_POS]; + + for( i = 0, j = 0; i < N_MV_PRED_POS; i++ ) + { + if( y_block4x4 + MV_PRED_POS[i][0] >= 0 && x_block4x4 + MV_PRED_POS[i][1] >= 0 && y_block4x4 + MV_PRED_POS[i][0] < size_y / 4 + && x_block4x4 + MV_PRED_POS[i][1] < size_x / 4 ) + { + ref_idx = Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].ref_idx[list]; + if( ref_idx < 0 ) + continue; + ref_poc = Slice->listX[list][ref_idx]->poc; + if( ref_poc == Dest->poc ) + { + ref_idx_disp = ref_idx_disp > ref_idx ? ref_idx : ref_idx_disp; + use_Disp++; + } + else + { + ref_idx_motion = ref_idx_motion > ref_idx ? ref_idx : ref_idx_motion; + use_Disp--; + } + } + } + use_Disp = use_Disp > 0 ? 1 : 0; + + switch( method ) + { + case PREVIOUS: + if( x_block4x4 ) + { + x_block4x4--; + } + else if( y_block4x4 ) + { + y_block4x4--; + } + else + { //impossible to copy previous vector -> use ZERO_MV + method = ZERO_MV; + break; + } + conc_mv[0] = Dest->mv_info[y_block4x4][x_block4x4].mv[list].mv_x; + conc_mv[1] = Dest->mv_info[y_block4x4][x_block4x4].mv[list].mv_y; + conc_mv[2] = Dest->mv_info[y_block4x4][x_block4x4].ref_idx[list]; + return; + case AVERAGE: + for( i = 0, j = 0; i < N_MV_PRED_POS; i++ ) + { + if( y_block4x4 + MV_PRED_POS[i][0] >= 0 && x_block4x4 + MV_PRED_POS[i][1] >= 0 && y_block4x4 + MV_PRED_POS[i][0] < size_y / 4 + && x_block4x4 + MV_PRED_POS[i][1] < size_x / 4 ) + { + ref_idx = Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].ref_idx[list]; + if( ref_idx < 0 ) + continue; + ref_poc = Slice->listX[LIST_0][ref_idx]->poc; + + if( ( use_Disp && Dest->poc != ref_poc ) || ( !use_Disp && Dest->poc == ref_poc ) ) + { + continue; + } + scale = Dest->poc - ref_poc; + scale = scale ? scale : 1; + + sum_x += ( ( double )Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].mv[list].mv_x ) / ( ( double )scale ); + sum_y += ( ( double )Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].mv[list].mv_y ) / ( ( double )scale ); + j++; + } + } + if( j == 0 ) + { + //impossible to use this method -> use ZERO_MV + method = ZERO_MV; + break; + } + if( use_Disp ) + ref_idx = ref_idx_disp; + else + ref_idx = ref_idx_motion; + + ref_poc = Slice->listX[list][ref_idx]->poc; + scale = Dest->poc - ref_poc; + scale = scale ? scale : 1; + conc_mv[0] = ( int )( ( sum_x / ( ( double )j ) ) * ( scale ) ); + conc_mv[1] = ( int )( ( sum_y / ( ( double )j ) ) * ( scale ) ); + conc_mv[2] = ref_idx; + + return; + case MEDIAN: + for( i = 0, j = 0; i < N_MV_PRED_POS; i++ ) + { + if( y_block4x4 + MV_PRED_POS[i][0] >= 0 && x_block4x4 + MV_PRED_POS[i][1] >= 0 && y_block4x4 + MV_PRED_POS[i][0] < size_y / 4 + && x_block4x4 + MV_PRED_POS[i][1] < size_x / 4 ) + { + ref_idx = Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].ref_idx[list]; + if( ref_idx < 0 ) + continue; + ref_poc = Slice->listX[LIST_0][ref_idx]->poc; + + if( ( use_Disp && Dest->poc != ref_poc ) || ( !use_Disp && Dest->poc == ref_poc ) ) + { + continue; + } + scale = Dest->poc - ref_poc; + scale = scale ? scale : 1; + par_mv[j].mv.mv_x = Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].mv[list].mv_x / scale; + par_mv[j].mv.mv_y = Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].mv[list].mv_y / scale; + + par_mv[j].ref_idx = Dest->mv_info[y_block4x4 + MV_PRED_POS[i][0]][x_block4x4 + MV_PRED_POS[i][1]].ref_idx[list]; + j++; + } + } + if( j == 0 ) + { + //impossible to use this method -> use ZERO_MV + method = ZERO_MV; + break; + } + if( use_Disp ) + ref_idx = ref_idx_disp; + else + ref_idx = ref_idx_motion; + ref_poc = Slice->listX[list][ref_idx]->poc; + scale = Dest->poc - ref_poc; + scale = scale ? scale : 1; + + qsort( par_mv, j, sizeof(struct partial_mv), sort_mv_abs_up ); + if( j % 2 == 0 ) + { + conc_mv[0] = ( int )( ( ( par_mv[j >> 1].mv.mv_x + par_mv[( j >> 1 ) - 1].mv.mv_x ) / 2 ) * scale ); + conc_mv[1] = ( int )( ( ( par_mv[j >> 1].mv.mv_y + par_mv[( j >> 1 ) - 1].mv.mv_y ) / 2 ) * scale ); + } + else + { + conc_mv[0] = ( int )( par_mv[j >> 1].mv.mv_x * scale ); + conc_mv[1] = ( int )( par_mv[j >> 1].mv.mv_y * scale ); + } + conc_mv[2] = ref_idx; + return; + } + + if( method == ZERO_MV ) + { // direct copy the colocated block of first ref frame of list + conc_mv[0] = 0; + conc_mv[1] = 0; + conc_mv[2] = temporal_idx; + return; + } +} + +/*! + ************************************************************************ + * \brief + * Conceal picture using frame copy method + * Copy image data from one array to another array + ************************************************************************ + */ +void Conceal_by_FrameCopy( VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest ) +{ + + //! Alloc a Slice associated with lost frame + Slice *currSlice = Dest->PicSlice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + int idx, y, x, Temporal_Ref_idx[2] = + { -1, -1 }; + int y_block4x4, x_block4x4; + unsigned int idx_mb; + Macroblock *currMB; + int mb_width; + + //! Initialization of reference list + currSlice->p_Vid = p_Vid; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + +#if MVC_EXTENSION_ENABLE + if( Dest->view_id > BASE_VIEW_IDX ) + { + currSlice->ThisPOC = Dest->poc; + currSlice->framepoc = currSlice->ThisPOC; + currSlice->view_id = Dest->view_id; + currSlice->layer_id = Dest->layer_id; + + init_mvc_picture( currSlice ); + } +#endif + + currSlice->ThisPOC = Source->poc; + currSlice->framepoc = Source->poc; + currSlice->view_id = Source->view_id; + currSlice->layer_id = Source->layer_id; + + currSlice->listXsize[LIST_0] = Source->Conc_listXsize[LIST_0]; + currSlice->listXsize[LIST_1] = Source->Conc_listXsize[LIST_1]; + if( Dest->view_id > BASE_VIEW_IDX ) + { + for( idx = 0; idx < currSlice->listXsize[LIST_0]; idx++ ) + { + currSlice->listX[LIST_0][idx] = Source->Conc_listX[LIST_0][idx]; + if( Source->Conc_listXInterviewPos[LIST_0] == idx ) + { + currSlice->listX[LIST_0][idx] = p_Dpb->fs_ilref[0]->frame; + } + else if( Temporal_Ref_idx[LIST_0] == -1 ) + { + Temporal_Ref_idx[LIST_0] = idx; + } + } + for( idx = 0; idx < currSlice->listXsize[LIST_1]; idx++ ) + { + currSlice->listX[LIST_1][idx] = Source->Conc_listX[LIST_1][idx]; + if( Source->Conc_listXInterviewPos[LIST_1] == idx ) + { + currSlice->listX[LIST_1][idx] = p_Dpb->fs_ilref[0]->frame; + } + else if( Temporal_Ref_idx[LIST_1] == -1 ) + { + Temporal_Ref_idx[LIST_1] = idx; + } + } + } + else + { + for( idx = 0; idx < currSlice->listXsize[LIST_0]; idx++ ) + { + currSlice->listX[LIST_0][idx] = Source->Conc_listX[LIST_0][idx]; + } + for( idx = 0; idx < currSlice->listXsize[LIST_1]; idx++ ) + { + currSlice->listX[LIST_1][idx] = Source->Conc_listX[LIST_1][idx]; + } + } + // End of intialization + mb_width = Dest->PicWidthInMbs; + + /* Loop though all motion vectors */ + for( y_block4x4 = 0; y_block4x4 < ( ( Dest->PicSizeInMbs ) / ( Dest->PicWidthInMbs ) ) * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++ ) + { + y = y_block4x4 * BLOCK_SIZE; //!< get y cordinates + for( x_block4x4 = 0; x_block4x4 < ( Dest->PicWidthInMbs ) * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++ ) + { + x = x_block4x4 * BLOCK_SIZE; + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idx_mb] ); + + // Update coordinates of the current concealed macroblock + currMB->mb.x = ( short )( x / BLOCK_SIZE ); + currMB->mb.y = ( short )( y / BLOCK_SIZE ); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y / 4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x / 4; + + // configure motion vector + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = Temporal_Ref_idx[LIST_0]; + + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_1] = Temporal_Ref_idx[LIST_1]; + } + } + fercCopyImg( p_Vid, Source, Dest ); +} + +//static MotionVector MotionVectorPrediction(VideoParameters *p_Vid, StorablePicture *Dest, +// StorablePicture *SourceMvReference, Slice *RefSlice, +// int y_block4x4, int x_block4x4) +//{ +// int flag_ViewID = SourceMvReference->view_id; +// PicMotionParams PseudoMotion[5]; +// MotionVector returnVector; +// double scale; +// +// PseudoMotion[0] = SourceMvReference->mv_info[y_block4x4][x_block4x4]; +// PseudoMotion[1] = RefSlice->listX[LIST_0][0]->mv_info[y_block4x4+PseudoMotion[0].mv[LIST_0].mv_y/BLOCK_SIZE/4][x_block4x4+PseudoMotion[0].mv[LIST_0].mv_x/BLOCK_SIZE/4]; +// +// scale = (double)(PseudoMotion[0].mv[LIST_0].mv_y) / (double)(PseudoMotion[1].mv[LIST_0].mv_y); +// returnVector.mv_y = (double)(PseudoMotion[0].mv[LIST_0].mv_y) * scale; +// +// scale = (double)(PseudoMotion[0].mv[LIST_0].mv_x) / (double)(PseudoMotion[1].mv[LIST_0].mv_x); +// returnVector.mv_x = (double)(PseudoMotion[0].mv[LIST_0].mv_x) * scale; +// +// return returnVector; +//} +// +// +//static int ConcealmentOptimization( int ConcealmentMethod, StorablePicture *IntraRefFrame, StorablePicture *InterRefFrame, +// StorablePicture *Disparity, MotionVector **Disparity2D_mv, +// int y_block4x4, int x_block4x4) +//{ +// +// +//} diff --git a/ldecod/src/ferc/ferc_ismid.c b/ldecod/src/ferc/ferc_ismid.c new file mode 100644 index 0000000..87cce9f --- /dev/null +++ b/ldecod/src/ferc/ferc_ismid.c @@ -0,0 +1,657 @@ +/*! +************************************************************************ +* \file ferc_ismid.c +* +* \brief +* Internal function for ferc API +* Include a reference method based on disparity information +* +* \author +* - Joao Carreira +* +************************************************************************ +*/ + +#include + +#include "ferc_api.h" +#include "ferc_internals.h" + +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_mvc.h" +#include "memalloc.h" +#include "image.h" +#include "mc_prediction.h" +#include "macroblock.h" +#include "block.h" +#include "mbuffer_common.h" +#include "ifunctions.h" +#include "ferc_opencv_api.h" + +#define DISP_SHIFT 128 + +int CLOSER_NEIHGHBORS[][2] = {{0,-1},{-1,0},{0,1},{1,0}}; + +static double AverageIntensityDifference( int ***Intensity, int BlockSize, int size_x, int size_y, int x, int y) +{ + int xx, yy, x_i, x_f, y_i, y_f, count = 0; + + unsigned long int sum = 0; + + x_i = imax(0,x-BlockSize/2); + x_f = imin(size_x-1, x+BlockSize/2); + + y_i = imax(0,y-BlockSize/2); + y_f = imin(size_y-1, y+BlockSize/2); + + for(yy=y_i; yy<=y_f; yy++) + { + for(xx=x_i; xx<=x_f; xx++) + { + if( Intensity[0][yy][xx] != INT_MAX ) + { + sum += iabs( Intensity[0][yy][xx] ); + count++; + } + } + } + if( count ) + return( sum / (double)(count)); + else + return -1; +} + +/*! +************************************************************************ +* \brief +* Compute the block based disparity for each pixel using a square block +* for a symmetric window +* +* The Disparity are normalized between +* [-WindowsSize, WindowsSize] +* Disp = Disp + GlobalWindowsSize + LocalWindowsSize; +************************************************************************ +*/ +static void BlockBasedDisparityEstimation( StorablePicture *Ref, StorablePicture *NonRef, + int WindowsSize, int BlockSize, StorablePicture *Disparity) +{ + + int x, y, xx, yy, d, disp, count; + int size_x = Ref->size_x, size_y = Ref->size_y; + double sad, min_sad; + int LowWindow, HighWindow; + + for(y=0; yRef->size_x ? Ref->size_x-x-1 : +WindowsSize; + + for(d=-LowWindow; d>=-HighWindow; d--) + { + sad = 0; + count = 0; + if( y-BlockSize/2<0 || y+BlockSize/2>=size_y || x-BlockSize/2-d<0 || x+BlockSize/2-d>=size_x ) + { + for(yy=-(BlockSize/2); yy<=(BlockSize/2); yy++) + { + for(xx=-(BlockSize/2); xx<=(BlockSize/2); xx++) + { + if( y+yy<0 || y+yy>=size_y || x+xx-d<0 || x+xx-d>=size_x ) + continue; + + sad += iabs( Ref->imgY[y+yy][x+xx] - NonRef->imgY[y+yy][x+xx-d]); + count++; + } + } + } + else + { + for(yy=-(BlockSize/2); yy<=(BlockSize/2); yy++) + { + for(xx=-(BlockSize/2); xx<=(BlockSize/2); xx+=1) + { + sad += iabs( Ref->imgY[y+yy][x+xx] - NonRef->imgY[y+yy][x+xx-d]); + count+=1; + } + } + } + sad = sad / (double)count; + if( sad < min_sad ) + { + min_sad = sad; + disp = d; + } + } + Disparity->imgY[y][x] = DISP_SHIFT + disp; + } + } + return; +} + +//static void MarkOclusionDectection( StorablePicture *Disparity, +// StorablePicture *OcclusionMap, int WindowSize ) +//{ +// int size_x = Disparity->size_x, size_y = Disparity->size_y; +// int x, y, w; +// +// for(y=0; yimgY[y][x] = 0; +// for(w=-WindowSize;w<=WindowSize;w++) +// { +// if( w != 0 && +// ( (short)(Disparity->imgY[y][x]) - DISP_SHIFT ) == +// ( ( (short)(Disparity->imgY[y][x+w]) - DISP_SHIFT) - w ) ) +// { +// OcclusionMap->imgY[y][x] = 255; +// } +// +// } +// } +// } +//} + +/*! +************************************************************************ +* \brief +* Diff to block and save to an image +* +************************************************************************ +*/ +void diffPredblockRegionYUV(int ***Dest_Diff, imgpel *predBlock_0, + imgpel *predBlock_1, int x, int y, int sum) +{ + int ii, jj; + int uv; + //! Y Matrix + for(ii=0;iiPicSlice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + Macroblock *currMB; + MotionVector **pelbasedMotionVectors; + imgpel *storeYUV[2], **tmp_block_pred; + int i,j, idx, y, x, yy, xx, x_base, x_new, y_new, y_pel, x_pel, mv[3], ii, jj, + y_block4x4, x_block4x4, mb_width, mb_height, pel_value, pel_value_u, pel_value_v; + int relation_y_c = p_Vid->width / p_Vid->width_cr, Temporal_Ref_idx[2] = {-1, -1}; + unsigned int idx_mb; + char ref_idx; + double average, average_average, count_average; + int loop, count; + double scale_factor, max_diff; + + StorablePicture *Frame_Base_T, *Frame_Base_Tminus1 = NULL, *Frame_Aux_Tminus1 = NULL; + StorablePicture *Disparity = NULL, *Disparity_Filtered; + StorablePicture *currReference = NULL; + StorablePicture *OcclusionMap = NULL; + + int ***IntensityDifference = NULL, ***IntensityDifference_Rec = NULL; + int **FlagConcealed = NULL; + fercCopyImg(p_Vid, Source, Dest); + + get_mem2Dpel(&tmp_block_pred, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + if (Source->chroma_format_idc != YUV400) + { + storeYUV[0] = (imgpel *) malloc ( (16 + (p_Vid->mb_cr_size_x*p_Vid->mb_cr_size_y)*2/16) * sizeof (imgpel)); + storeYUV[1] = (imgpel *) malloc ( (16 + (p_Vid->mb_cr_size_x*p_Vid->mb_cr_size_y)*2/16) * sizeof (imgpel)); + } + else + { + storeYUV[0] = (imgpel *) malloc (16 * sizeof (imgpel)); + storeYUV[1] = (imgpel *) malloc (16 * sizeof (imgpel)); + } + + //! Get pictures from the buffer + Frame_Base_T = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[BASE_VIEW_IDX], Dest->poc, BASE_VIEW_IDX, EXACT, 0, NULL); + Frame_Aux_Tminus1 = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[Dest->view_id], Dest->poc, Dest->view_id, CLOSEST_ALL, 0, NULL); + Frame_Base_Tminus1 = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[BASE_VIEW_IDX], Frame_Aux_Tminus1->poc, BASE_VIEW_IDX, EXACT, 0, NULL); + + Disparity = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + + +#if ( 0 ) + strcpy(p_Vid->p_Inp->DispLoadFileName,"Disparity.pgm"); + cvDisparity( p_Vid , Frame_Base_Tminus1, Frame_Aux_Tminus1, Disparity, LOAD, p_Vid->p_Inp->DisparityWindow, 0 ); +#else + BlockBasedDisparityEstimation( Frame_Aux_Tminus1, Frame_Base_Tminus1, 20, 17, Disparity); + saveStorablePicture(p_Vid,"Disparity.pgm",Disparity,0,0); +#endif + showStorablePicture(p_Vid, Disparity, 1, 0, "Disparity", 0); + + Disparity_Filtered = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + MedianFilter( Disparity->imgY, Disparity_Filtered->imgY, p_Vid->width, p_Vid->height, 7 ); + free_storable_picture( Disparity ); + Disparity = Disparity_Filtered; + + showStorablePicture(p_Vid, Disparity, 1, 0, "Disparity", 0); + + //! Initialization of reference list for base slice + baseSlice = malloc_slice(p_Vid->p_Inp, p_Vid); + baseSlice->p_Vid = p_Vid; + baseSlice->p_Dpb = p_Vid->p_Dpb_layer[Frame_Base_T->view_id]; + baseSlice->ThisPOC = Frame_Base_T->poc; + baseSlice->framepoc = Frame_Base_T->poc; + baseSlice->view_id = Frame_Base_T->view_id; + baseSlice->layer_id = Frame_Base_T->layer_id; + baseSlice->slice_type = Frame_Base_T->slice_type; + + //! LIST_0 + baseSlice->listXsize[LIST_0] = Frame_Base_T->Conc_listXsize[LIST_0]; + for( idx=0; idxlistXsize[LIST_0]; idx++) + { + baseSlice->listX[LIST_0][idx] = Frame_Base_T->Conc_listX[LIST_0][idx]; + if( !baseSlice->listX[LIST_0][idx] ) + { + printf("Cannot conceal missing frame! Exit \n"); + Dest->have_pic = 0; + return; + } + } + //! LIST_1 + baseSlice->listXsize[LIST_1] = Frame_Base_T->Conc_listXsize[LIST_1]; + for( idx=0; idxlistXsize[LIST_1]; idx++) + { + baseSlice->listX[LIST_1][idx] = Frame_Base_T->Conc_listX[LIST_1][idx]; + if( !baseSlice->listX[LIST_1][idx] ) + { + printf("Cant conceal!\n"); + Dest->have_pic = 0; + return; + } + } + dump_ref_lists(baseSlice); + + //! Initialization of reference list for lost slice + currSlice->p_Vid = p_Vid; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + currSlice->ThisPOC = Dest->poc; + currSlice->framepoc = Dest->poc; + currSlice->view_id = Dest->view_id; + currSlice->layer_id = Dest->layer_id; + currSlice->slice_type = Dest->slice_type; + + //! LIST_0 + currSlice->listXsize[LIST_0] = Frame_Base_T->Conc_listXsize[LIST_0]; + for( idx=0; idxlistXsize[LIST_0]; idx++) + { + currSlice->listX[LIST_0][idx] = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[Dest->layer_id], Frame_Base_T->Conc_listX[LIST_0][idx]->poc, 1, EXACT, 1, NULL); + if( !currSlice->listX[LIST_0][idx] ) + { + printf("Cannot conceal missing frame! Exit \n"); + Dest->have_pic = 0; + return; + } + } + //! LIST_1 + currSlice->listXsize[LIST_1] = Frame_Base_T->Conc_listXsize[LIST_1]; + for( idx=0; idxlistXsize[LIST_1]; idx++) + { + currSlice->listX[LIST_1][idx] = fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[Dest->layer_id], Frame_Base_T->Conc_listX[LIST_1][idx]->poc, 1, EXACT, 1, NULL); + if( !currSlice->listX[LIST_1][idx] ) + { + printf("Cant conceal!\n"); + Dest->have_pic = 0; + return; + } + } + //dump_ref_lists(currSlice); + + + + //! Alloc auxiliary information to conceal + get_mem2Dint( &FlagConcealed, p_Vid->height, p_Vid->width); + get_mem3Dint( &IntensityDifference , 3, p_Vid->height, p_Vid->width); + get_mem3Dint( &IntensityDifference_Rec , 3, p_Vid->height, p_Vid->width); + get_mem2Dmv( &pelbasedMotionVectors, p_Vid->height, p_Vid->width); + + OcclusionMap = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + + //!! Initialize the value of pixels + for(y=0;yheight;y++) + { + for(x=0;xwidth;x++) + { + FlagConcealed[y][x] = 0; + IntensityDifference_Rec[0][y][x] = IntensityDifference[0][y][x] = INT_MAX; + pelbasedMotionVectors[y][x].mv_x = pelbasedMotionVectors[y][x].mv_y = SHRT_MAX; + Dest->imgY[y][x] = 255; + OcclusionMap->imgY[y][x] = 0; + } + } + + //MarkOclusionDectection( Disparity, OcclusionMap, 20 ); + // saveStorablePicture(p_Vid,"OcclusionMap.bmp",OcclusionMap, 1, 0); + showStorablePicture(p_Vid, OcclusionMap, 0, 0, "Occlusion", 0); + + mb_width = Dest->PicWidthInMbs; + mb_height = (Dest->PicSizeInMbs)/(Dest->PicWidthInMbs); + + //! Loop though all motion vectors in the Base view frame + for(loop=0;loop<2;loop++) + { + for( y_block4x4=0; y_block4x4 < mb_height * MB_BLOCK_SIZE/BLOCK_SIZE; y_block4x4++) + { + y = y_block4x4 * BLOCK_SIZE; //!< get y cordinates + for( x_block4x4=0; x_block4x4 < mb_width * MB_BLOCK_SIZE/BLOCK_SIZE; x_block4x4++) + { + x = x_block4x4 * BLOCK_SIZE; + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idx_mb] ); + // Update coordinates of the current concealed macroblock + currMB->mb.x = (short) (x/BLOCK_SIZE); + currMB->mb.y = (short) (y/BLOCK_SIZE); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y/4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x/4; + + mv[2] = ref_idx = Frame_Base_T->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0]; + + if( loop == 0 )//! Intra blocks + { + + if( ref_idx >= 0 ) + continue; + + mv[0] = 0; + mv[1] = 0; + mv[2] = 0; + + x_new = x; + y_new = y; + } + else//! Other ones + { + + if( ref_idx < 0 ) + continue; + + mv[0] = Frame_Base_T->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x; + mv[1] = Frame_Base_T->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y; + + currReference = currSlice->listX[LIST_0][mv[2]]; + + scale_factor = (double)( Frame_Base_T->poc - Frame_Base_Tminus1->poc ) / (double)( Frame_Base_T->poc - currReference->poc ); + + mv[0] = mv[0] * scale_factor; + mv[1] = mv[1] * scale_factor; + + //! pel based vector + //! look at bit in position 2 - if it is one the final vector will have one more position + mv[0] = (mv[0]>>2) + ((mv[0]&0x02)>>1); + mv[1] = (mv[1]>>2) + ((mv[1]&0x02)>>1); + + x_new = x + mv[0]; + y_new = y + mv[1]; + + //! Goes outside of the image + if( x_new < 0 || x_new > p_Vid->width-4 || y_new < 0 || y_new > p_Vid->height-4) + continue; + } + + for(i=0;iheight;y++) + { + for(x=0;xwidth;x++) + { + if( pelbasedMotionVectors[y][x].mv_y != SHRT_MAX ) + { + y_new = y + pelbasedMotionVectors[y][x].mv_y; + x_new = x + pelbasedMotionVectors[y][x].mv_x; + + IntensityDifference[0][y][x] = (int)(Frame_Base_T->imgY[y_new][x_new]) - (int)(Frame_Base_Tminus1->imgY[y][x]); + IntensityDifference[1][y/2][x/2] = (int)(Frame_Base_T->imgY[y_new/2][x_new/2]) - (int)(Frame_Base_Tminus1->imgY[y/2][x/2]); + IntensityDifference[2][y/2][x/2] = (int)(Frame_Base_T->imgY[y_new/2][x_new/2]) - (int)(Frame_Base_Tminus1->imgY[y/2][x/2]); + } + else + { + IntensityDifference[0][y][x] = INT_MAX; + IntensityDifference[1][y>>1][x>>1] = INT_MAX; + IntensityDifference[2][y>>1][x>>1] = INT_MAX; + } + } + } + + //! Loop though all pixels in Frame of the view 1 in the instant t-1* + for(y=0;yheight;y++) + { + for(x=0;xwidth;x++) + { + //! Check oclude pixels + if( OcclusionMap->imgY[y][x] > 0) + continue; + + x_base = x - ( (int)(Disparity->imgY[y][x]) - DISP_SHIFT ); + //x_base = iClip3( 0, p_Vid->width - 1, x_base ); + if( x_base < 0 || x_base >= p_Vid->width ) + continue; + + //! This pixel were not reached in previous loop + if( IntensityDifference[0][y][x_base] == INT_MAX ) + continue; + + y_new = y + pelbasedMotionVectors[y][x_base].mv_y; + x_new = x + pelbasedMotionVectors[y][x_base].mv_x; + + if( y_new < 0 || y_new >= p_Vid->height || x_new < 0 || x_new >= p_Vid->width ) + { + continue; + } + + pel_value = (int)(Frame_Aux_Tminus1->imgY[y][x]) + IntensityDifference[0][y][x_base]; + pel_value_u = (int)(Frame_Aux_Tminus1->imgUV[0][y>>1][x>>1]) + IntensityDifference[1][y>>1][x_base>>1]; + pel_value_v = (int)(Frame_Aux_Tminus1->imgUV[1][y>>1][x>>1]) + IntensityDifference[2][y>>1][x_base>>1]; + //if( pel_value > 255 ) + //{ + // continue; + //} + //else if( pel_value < 0 ) + //{ + // continue; + //} + Dest->imgY[y_new][x_new] = (imgpel)iClip3(0,255,pel_value); + Dest->imgUV[0][y_new>>1][x_new>>1] = (imgpel)iClip3(0,255,pel_value_u); + Dest->imgUV[1][y_new>>1][x_new>>1] = (imgpel)iClip3(0,255,pel_value_v); + + IntensityDifference_Rec[0][y_new][x_new] = IntensityDifference[0][y][x_base]; + FlagConcealed[y_new][x_new] = 1; + } + } + + showStorablePicture(p_Vid,Dest,0,0,"Concealed frame",0); + + { + int count_1 = 0, count_2 = 0; + average_average = 0; + count_average=0; + + //! Hole Filling in the lost picture + for(y=0;yheight;y++) + { + for(x=0;xwidth;x++) + { + if( FlagConcealed[y][x] ) + continue; + + average = AverageIntensityDifference( IntensityDifference_Rec, 5, p_Vid->width, p_Vid->height, x, y); + + if( average < 0 ) + continue; + + count_average += 1; + average_average = ( average_average * (count_average-1) + average ) / ( count_average); + + if( average < 5 ) + { + Dest->imgY[y][x] = Frame_Aux_Tminus1->imgY[y][x]; + count_1++; + FlagConcealed[y][x] = 1; + } + } + } + showStorablePicture(p_Vid,Dest,0,0,"Concealed frame",0); + + //! Hole Filling + for(y=0;yheight;y++) + { + for(x=0;xwidth;x++) + { + if( FlagConcealed[y][x] ) + continue; + + for(idx=0, count = 0, average = 0; idx<4; idx++) + { + if( y+CLOSER_NEIHGHBORS[idx][0] >= 0 && y+CLOSER_NEIHGHBORS[idx][0] < Dest->size_y ) + { + if( x+CLOSER_NEIHGHBORS[idx][1] >= 0 && x+CLOSER_NEIHGHBORS[idx][1] < Dest->size_x ) + { + if( FlagConcealed[y+CLOSER_NEIHGHBORS[idx][0]][x+CLOSER_NEIHGHBORS[idx][1]] ) + { + average += Dest->imgY[y+CLOSER_NEIHGHBORS[idx][0]][x+CLOSER_NEIHGHBORS[idx][1]]; + count++; + } + } + } + } + if( count == 0 ) + { + Dest->imgY[y][x] = Frame_Aux_Tminus1->imgY[y][x]; + FlagConcealed[y][x] = 1; + count_1++; + continue; + } + average = average / count; + + Dest->imgY[y][x] = average; + FlagConcealed[y][x] = 1; + count_2++; + } + } + + printf("1: %d || 2: %d\n", count_1, count_2 ); + printf("%5.5f\n", average_average ); + } + + //! Hole Filling + for(y=0;yheight;y++) + { + for(x=0;xwidth;x++) + { + if( FlagConcealed[y][x] == 0) + { + int a = 0; + } + } + } + + showStorablePicture(p_Vid,Dest,0,0,"Concealed frame",0); + + + + /* Loop though all motion vectors */ + for( y_block4x4=0; y_block4x4 < ((Dest->PicSizeInMbs)/(Dest->PicWidthInMbs)) * MB_BLOCK_SIZE/BLOCK_SIZE; y_block4x4++) + { + y = y_block4x4 * BLOCK_SIZE; //!< get y cordinates + for( x_block4x4=0; x_block4x4 < (Dest->PicWidthInMbs) * MB_BLOCK_SIZE/BLOCK_SIZE; x_block4x4++) + { + x = x_block4x4 * BLOCK_SIZE; + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idx_mb] ); + + // Update coordinates of the current concealed macroblock + currMB->mb.x = (short) (x/BLOCK_SIZE); + currMB->mb.y = (short) (y/BLOCK_SIZE); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y/4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x/4; + + // configure motion vector + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = Temporal_Ref_idx[LIST_0]; + + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_1] = Temporal_Ref_idx[LIST_1]; + } + } + + free_mem2Dpel( tmp_block_pred ); + free( storeYUV[0] ); + free( storeYUV[1] ); + free_mem2Dmv( pelbasedMotionVectors ); + + free_mem3Dint( IntensityDifference ); + free_mem3Dint( IntensityDifference_Rec ); + + + free_storable_picture( Disparity ); + + if( baseSlice ) + free_slice(baseSlice); +} diff --git a/ldecod/src/ferc/ferc_motion.c b/ldecod/src/ferc/ferc_motion.c new file mode 100644 index 0000000..20fb0d4 --- /dev/null +++ b/ldecod/src/ferc/ferc_motion.c @@ -0,0 +1,262 @@ +/*! + ************************************************************************ + * \file ferc_internals.c + * + * \brief + * Internal function for ferc API + * Include the concealment function using motion compensated concelament only + * + * \author + * - Jo�o Carreira + * + ************************************************************************ + */ + +#include "ferc_api.h" +#include "ferc_internals.h" + +#include "memalloc.h" +//#include "stream_parser.h" +//#include "image.h" +/*! + ************************************************************************ + * \brief + * Conceal using source reference motion vectors and references + ************************************************************************ + */ +void Conceal_by_MotionCopy_Ref (VideoParameters *p_Vid, StorablePicture *Source, StorablePicture *Dest) +{ + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + int ConcealmentMode = ZERO_MV; + /* Motion copy loop variables */ + int mb_height, mb_width; + //! Alloc a Slice associated with lost frame + Slice *currSlice = Dest->PicSlice; + StorablePicture *currRef; + Macroblock *currMB; + float scale_factor; + int List, x, y, y_block4x4, x_block4x4, idx_mb, iy_8x8, ix_8x8, mv[3]; + char used_list[2] = {0,0}; + int idx; + imgpel *predMB, *storeYUV_list[2], **tmp_block_pred; + + int n_concealed_mv = 0; + //int err = 0; + //T_FRAME *debugFrame; //= createFrame(p_Vid->width, p_Vid->height, &err); + + get_mem2Dpel(&tmp_block_pred, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + if (Source->chroma_format_idc != YUV400) + { + storeYUV_list[LIST_0] = (imgpel *) malloc ( (16 + (p_Vid->mb_cr_size_x*p_Vid->mb_cr_size_y)*2/16) * sizeof (imgpel)); + storeYUV_list[LIST_1] = (imgpel *) malloc ( (16 + (p_Vid->mb_cr_size_x*p_Vid->mb_cr_size_y)*2/16) * sizeof (imgpel)); + } + else + { + storeYUV_list[LIST_0] = (imgpel *) malloc (16 * sizeof (imgpel)); + storeYUV_list[LIST_1] = (imgpel *) malloc (16 * sizeof (imgpel)); + } + //remove this + p_Vid->erc_img = p_Vid; + + //! Initialization of reference list + currSlice->p_Vid = p_Vid; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + +#if MVC_EXTENSION_ENABLE + if( Dest->view_id != BASE_VIEW_IDX) + { + currSlice->ThisPOC = Dest->poc; + currSlice->framepoc = currSlice->ThisPOC; + currSlice->view_id = Dest->view_id; + currSlice->layer_id = Dest->layer_id; + + init_mvc_picture(currSlice); + } +#endif + + /* Initialization of references pic list */ + currSlice->ThisPOC = Source->poc; + currSlice->framepoc = Source->poc; + currSlice->view_id = Source->view_id; + currSlice->layer_id = Source->layer_id; + + currSlice->listXsize[LIST_0] = Source->Conc_listXsize[LIST_0]; + currSlice ->listXsize[LIST_1] = Source->Conc_listXsize[LIST_1]; + for( idx=0; idxlistXsize[LIST_0]; idx++) + { + currSlice->listX[LIST_0][idx] = Source->Conc_listX[LIST_0][idx]; + if( Source->Conc_listXInterviewPos[LIST_0] == idx ) + { + currSlice->listX[LIST_0][idx] = p_Dpb->fs_ilref[0]->frame; + } + } + + for( idx=0; idxlistXsize[LIST_1]; idx++) + { + currSlice->listX[LIST_1][idx] = Source->Conc_listX[LIST_1][idx]; + if( Source->Conc_listXInterviewPos[LIST_1] == idx ) + { + currSlice->listX[LIST_1][idx] = p_Dpb->fs_ilref[0]->frame; + } + } + // End of intialization + + dump_ref_lists( currSlice ); + + mb_width = Dest->PicWidthInMbs; + mb_height = (Dest->PicSizeInMbs)/(Dest->PicWidthInMbs); + + // dump_dpb(p_Vid->p_Dpb_layer[1]); + + //============================================================================ + //===================== Motion Concealment Loop ============================== + //============================================================================ + + /* Loop though all motion vectors */ + for( y_block4x4=0; y_block4x4 < mb_height * MB_BLOCK_SIZE/BLOCK_SIZE; y_block4x4++) + { + y = y_block4x4 * BLOCK_SIZE; + for( x_block4x4=0; x_block4x4 < mb_width * MB_BLOCK_SIZE/BLOCK_SIZE; x_block4x4++) + { + // Init variables + currRef = NULL; + + x = x_block4x4 * BLOCK_SIZE; + + // get block 8x8 cordinates within a MB + iy_8x8 = ( y % MB_BLOCK_SIZE ) / SMB_BLOCK_SIZE; + ix_8x8 = ( x % MB_BLOCK_SIZE ) / SMB_BLOCK_SIZE; + + ///* not exact - dont work for currSlice->mb_aff_frame_flag = 1 */ + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + + currMB = &( p_Vid->mb_data[idx_mb] ); + currMB->p_Slice = currSlice; + + // Update coordinates of the current concealed macroblock + currMB->mb.x = (short) (x/BLOCK_SIZE); + currMB->mb.y = (short) (y/BLOCK_SIZE); + currMB->block_y = currMB->mb.y * BLOCK_SIZE; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y/4; + currMB->block_x = currMB->mb.x * BLOCK_SIZE; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x/4; + + List = Source->slice_type == B_SLICE ? LIST_1 : LIST_0; + + for(; List >= LIST_0; List--) + { + /* Update mv information - Read Reference Values */ + mv[0] = Source->mv_info[y_block4x4][x_block4x4].mv[List].mv_x; + mv[1] = Source->mv_info[y_block4x4][x_block4x4].mv[List].mv_y; + mv[2] = Source->mv_info[y_block4x4][x_block4x4].ref_idx[List]; //Reference Frame + + /* INTRA Blocks */ + if( Source->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] < 0 && Source->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_1] < 0) + { + break; + } + else if( Source->mv_info[y_block4x4][x_block4x4].ref_idx[List] >= 0) + { + /* Disparity Vectors */ + if( currSlice->view_id != 0 && currSlice->listX[List][mv[2]]->poc == Dest->poc) + { + if( !( p_FrameConc->ConcealmentMode == MOTION_COPY_SPATIAL || p_FrameConc->ConcealmentMode == MOTION_COPY_TEMPORAL_SPATIAL) ) + { + continue; + } + } + /* Temporal vectors */ + else + { + /* Unuse Temporal motion vectors */ + if( !( p_FrameConc->ConcealmentMode == MOTION_COPY_TEMPORAL || p_FrameConc->ConcealmentMode == MOTION_COPY_TEMPORAL_SPATIAL) ) + { + continue; + } + } + + currRef = currSlice->listX[List][mv[2]]; + // Scale mv + scale_factor = (float)( Dest->poc - currRef->poc ) / (float)( Source->poc - currRef->poc ); + scale_factor = scale_factor ? scale_factor : 1; + mv[0] = (int)( (float)( mv[0] ) * scale_factor ); + mv[1] = (int)( (float)( mv[1] ) * scale_factor ); + + // copy motion vector + Dest->mv_info[y_block4x4][x_block4x4].mv[List].mv_x = mv[0]; + Dest->mv_info[y_block4x4][x_block4x4].mv[List].mv_y = mv[1]; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[List] = mv[2]; + + if( currRef == p_Vid->no_reference_picture ) + { + printf("Bad reference frame!!\n"); + continue; + } + used_list[List] = 1; + buildPredblockRegionYUV(p_Vid, currRef, currMB, mv, x, y, storeYUV_list[List], BLOCK_SIZE, tmp_block_pred, 1); + } + else + { + //! current List not chosen + } + } + List = 0; + switch( used_list[LIST_0] + (used_list[LIST_1]<<1) ) + { + case 0: + ConcealmentMode = ZERO_MV; + //None -> Need concealment + // Update mv information - Read Reference Values + //conceal motion vector + //ConcealMotionVector(p_Vid, Dest, currSlice, y_block4x4, x_block4x4, AVERAGE, LIST_0, mv, currSlice->listX[LIST_0][0]->poc == Dest->poc ? 1 : 0); + ConcealMotionVector(p_Vid, Dest, currSlice, y_block4x4, x_block4x4, ConcealmentMode, LIST_0, mv, currSlice->listX[LIST_0][0]->poc == Dest->poc ? 1 : 0); // r80 + + if( ConcealmentMode == ZERO_MV) + { + mv[2] = imin( mv[2], currSlice->listXsize[LIST_0] - 1 ); + currRef = currSlice->listX[LIST_0][mv[2]]; + } + // Scale mv + //Do not need scaling because the vectors have already been modified + //scale_factor = (float)( Source->poc - currRef->poc ) / (float)( Dest->poc - currRef->poc ); + scale_factor = 1; + mv[0] = (int)( (float)( mv[0] ) / scale_factor ); + mv[1] = (int)( (float)( mv[1] ) / scale_factor ); + // copy mv + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = mv[0]; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = mv[1]; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = mv[2]; + + buildPredblockRegionYUV(p_Vid, currRef, currMB, mv, x, y, storeYUV_list[LIST_0], BLOCK_SIZE, tmp_block_pred, 1); + n_concealed_mv++; + predMB = storeYUV_list[LIST_0]; + break; + case 1: + // List 0 + predMB = storeYUV_list[LIST_0]; + break; + case 2: + // List 1 + predMB = storeYUV_list[LIST_1]; + break; + case 3: + // Both List 0 and 1 + ferc_bi_prediction(storeYUV_list[LIST_0], storeYUV_list[LIST_0], 1, storeYUV_list[LIST_1], 1, BLOCK_SIZE, BLOCK_SIZE, 1); + predMB = storeYUV_list[LIST_0]; + break; + } + used_list[LIST_0] = 0; + used_list[LIST_1] = 0; + + copyPredblockRegionYUVDestination( Dest, predMB, x, y, BLOCK_SIZE); + } + } + + //! Debug reports + printf("[FERC] Number of Concealed mv %d\n", n_concealed_mv); + + free_mem2Dpel( tmp_block_pred ); + free(storeYUV_list[LIST_0]); + free(storeYUV_list[LIST_1]); +} diff --git a/ldecod/src/ferc/ferc_motion_estimation.c b/ldecod/src/ferc/ferc_motion_estimation.c new file mode 100644 index 0000000..dae9bab --- /dev/null +++ b/ldecod/src/ferc/ferc_motion_estimation.c @@ -0,0 +1,288 @@ +/*! +************************************************************************ +* \file +* ferc_motion_estimation.c +* +* \brief +* Internal function for ferc API +* Motion estimation for intra blocks +* +* \author +* - Jo�o Carreira +* +************************************************************************ +*/ + +//#define OPTIMAZATIONS + + +#ifdef OPTIMAZATIONS + +//! System function and defines +#include +#include + + + +#include +#include +#include + +//! JM functions and defines +#include "typedefs.h" + + +int blockMatch(const imgpel* refFrame, int stepBytesRF /*stride*/, const imgpel* curBlock, + int stepBytesCB /*stride*/, int* matchBlock /*results*/, int frameWidth, int frameHeight, int block_size) +{ + int i, j, k, l; + int lowSum = INT_MAX; + int temSum = 0; + int blockHeight = block_size; + int blockWidth = block_size; + const imgpel *pRef, *pCur; + for (i=0; i<=frameHeight-blockHeight; i++) + { + for (j=0; j<=frameWidth-blockWidth; j++) + { + temSum = 0; + pCur = curBlock; + pRef = refFrame+i*stepBytesRF+j; + for (k=0; ksize_x; + // int size_y = InterRefFrame->size_y; + // int stride = InterRefFrame->size_x + 2 * InterRefFrame->iLumaPadX; + // int64 tmp_time; + + // Block_Size = 16; + + // gettime (&(p_Vid->start_time)); + + // get_mem3Dint( &BaseViewMV, mb_height * (MB_BLOCK_SIZE/Block_Size), mb_width * (MB_BLOCK_SIZE/Block_Size), 2); // size x + + // currSourceRef = pSliceInterViewReference->listX[LIST_0][0]; + + // //showStorablePicture( p_Vid , InterRefFrame , 0 , 0 , "Ref Disparity", 1); + // //showStorablePicture( p_Vid , currSourceRef , 0 , 0 , "New Disparity", 0); + // //OpenCVCloseWindows( NULL ); + + + // //===================== Motion Concealment Loop 1 ============================== + // /* Loop though all motion vectors */ + // for( y_block4x4=0; y_block4x4 < mb_height * (MB_BLOCK_SIZE/Block_Size); y_block4x4++) + // { + // y = y_block4x4 * Block_Size; //!< get y cordinates + // for( x_block4x4=0; x_block4x4 < mb_width * (MB_BLOCK_SIZE/Block_Size); x_block4x4+=1) + // { + // x = x_block4x4 * Block_Size; + + // //blockMatch( *(currSourceRef->imgY), stride /*stride*/, &(InterRefFrame->imgY[y][x]), stride /*stride*/, match_block /*results*/, size_x, size_y, Block_Size); + // blockMatch16x16SSE4( currSourceRef->imgY[0], xStride /*stride*/, &(InterRefFrame->imgY[y][x]), xStride /*stride*/, match_block /*results*/, SizeX, SizeY, Block_Size); + // //blockMatch4x4SSE2( *(currSourceRef->imgY), stride /*stride*/, &(InterRefFrame->imgY[y][x]), stride /*stride*/, match_block /*results*/, size_x, size_y, Block_Size); + + // BaseViewMV[y_block4x4][x_block4x4][0] = match_block[0] - x; + // BaseViewMV[y_block4x4][x_block4x4][1] = match_block[1] - y; + + // //BaseViewMV[y_block4x4][x_block4x4+1][0] = match_block[2] - x + 4; + // //BaseViewMV[y_block4x4][x_block4x4+1][1] = match_block[3] - y; + + // //BaseViewMV[y_block4x4][x_block4x4+1][0] = match_block[4] - x + 8; + // //BaseViewMV[y_block4x4][x_block4x4+1][1] = match_block[5] - y; + + // //BaseViewMV[y_block4x4][x_block4x4+1][0] = match_block[6] - x + 12; + // //BaseViewMV[y_block4x4][x_block4x4+1][1] = match_block[7] - y; + + // } + // } + + // gettime (&(p_Vid->end_time)); // end time + // tmp_time = timediff(&(p_Vid->start_time), &(p_Vid->end_time)); + // p_Vid->tot_time += tmp_time; + // tmp_time = timenorm(tmp_time); + + // printf("Motion estimation in %d\n", (int)tmp_time); + //} + +#endif diff --git a/ldecod/src/ferc/ferc_opencv_api.c b/ldecod/src/ferc/ferc_opencv_api.c new file mode 100644 index 0000000..ec1de46 --- /dev/null +++ b/ldecod/src/ferc/ferc_opencv_api.c @@ -0,0 +1,485 @@ +/*! +************************************************************************************* +* \file fercOpenCVApi.c +* +* \brief +* Functions to use OpenCV library in JM Software +* +* \date +* 29.11.2011 +* +* \author +* Joao Carreira +* +************************************************************************************* +*/ + +#include "ferc_opencv_api.h" + +#define HAVE_OPENCV 0 + +#if( HAVE_OPENCV == 1 ) + +#define ORIGINAL_OPENCV 1 + +//! OpenCV +#include "opencv2/highgui/highgui_c.h" +#include "opencv2/imgproc/imgproc_c.h" +#include "opencv2/calib3d/calib3d.hpp" +#include "opencv2/contrib/contrib.hpp" + +#if( _DEBUG ) +#define SHOW_IMG_DEBUG(WindowName,Img) cvShowImage( WindowName, Img ); cvWaitKey(0); cvDestroyWindow(WindowName); +#else +#define SHOW_IMG_DEBUG(WindowName,Img) ; +#endif + +static void convStorablePicture2IplImage( VideoParameters *p_Vid, StorablePicture *p_StorablePicture, IplImage **p_IplImageRGB, int SymbolSize ) +{ + static const int SubWidthC [4]= { 1, 2, 2, 1}; + static const int SubHeightC [4]= { 1, 2, 1, 1}; + int crop_left, crop_right, crop_top, crop_bottom; + IplImage *pU, *pV,*pY,*pU_big, *pV_big, *pYUV; + int depth; + + switch(SymbolSize) + { + case 1: + depth = IPL_DEPTH_8U; + break; + case 2: + depth = IPL_DEPTH_16U; + break; + default: + depth = IPL_DEPTH_8U; + break; + } + + pY = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , depth, 1 ); + pU_big = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , depth, 1 ); + pV_big = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , depth, 1 ); + pYUV = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , depth, 3 ); + + *p_IplImageRGB = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , depth, 3 ); + + if( p_StorablePicture->frame_cropping_flag ) + { + crop_left = SubWidthC [p_StorablePicture->chroma_format_idc] * p_StorablePicture->frame_crop_left_offset; + crop_right = SubWidthC [p_StorablePicture->chroma_format_idc] * p_StorablePicture->frame_crop_right_offset; + crop_top = SubHeightC[p_StorablePicture->chroma_format_idc] * ( 2 - p_StorablePicture->frame_mbs_only_flag ) * p_StorablePicture->frame_crop_top_offset; + crop_bottom = SubHeightC[p_StorablePicture->chroma_format_idc] * ( 2 - p_StorablePicture->frame_mbs_only_flag ) * p_StorablePicture->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + p_Vid->img2buf (p_StorablePicture->imgY, (unsigned char *)pY->imageData, p_StorablePicture->size_x, p_StorablePicture->size_y, ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3), crop_left, crop_right, crop_top, crop_bottom, p_StorablePicture->size_x); + pY->imageDataOrigin = pY->imageData; + + pU = cvCreateImage ( cvSize( p_StorablePicture->size_x_cr , p_StorablePicture->size_y_cr ) , depth, 1 ); + pV = cvCreateImage ( cvSize( p_StorablePicture->size_x_cr , p_StorablePicture->size_y_cr ) , depth, 1 ); + + crop_left = p_StorablePicture->frame_crop_left_offset; + crop_right = p_StorablePicture->frame_crop_right_offset; + crop_top = ( 2 - p_StorablePicture->frame_mbs_only_flag ) * p_StorablePicture->frame_crop_top_offset; + crop_bottom = ( 2 - p_StorablePicture->frame_mbs_only_flag ) * p_StorablePicture->frame_crop_bottom_offset; + p_Vid->img2buf (p_StorablePicture->imgUV[0], (unsigned char *)pU->imageData, p_StorablePicture->size_x_cr, p_StorablePicture->size_y_cr, ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3), crop_left, crop_right, crop_top, crop_bottom, p_StorablePicture->size_x_cr); + p_Vid->img2buf (p_StorablePicture->imgUV[1], (unsigned char *)pV->imageData, p_StorablePicture->size_x_cr, p_StorablePicture->size_y_cr, ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3), crop_left, crop_right, crop_top, crop_bottom, p_StorablePicture->size_x_cr); + pU->imageDataOrigin = pU->imageData; + pV->imageDataOrigin = pV->imageData; + + cvResize(pU, pU_big, CV_INTER_LINEAR ); + cvResize(pV, pV_big, CV_INTER_LINEAR ); + + cvMerge(pY, pU_big, pV_big, NULL, pYUV); + + cvReleaseImage(&pU_big); + cvReleaseImage(&pV_big); + cvCvtColor(pYUV,*p_IplImageRGB,CV_YCrCb2RGB); + cvReleaseImage(&pYUV); +} + +static void convStorablePicture2IplImage_Y( VideoParameters *p_Vid, StorablePicture *p_StorablePicture, IplImage **p_IplImageY, int SymbolSize ) +{ + static const int SubWidthC [4]= { 1, 2, 2, 1}; + static const int SubHeightC [4]= { 1, 2, 1, 1}; + int crop_left, crop_right, crop_top, crop_bottom; + int depth; + + switch(SymbolSize) + { + case 1: + depth = IPL_DEPTH_8U; + break; + case 2: + depth = IPL_DEPTH_16U; + break; + default: + SymbolSize = 1; + depth = IPL_DEPTH_8U; + break; + } + + if( !(*p_IplImageY) ) + (*p_IplImageY) = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , depth, 1 ); + + if( p_StorablePicture->frame_cropping_flag ) + { + crop_left = SubWidthC [p_StorablePicture->chroma_format_idc] * p_StorablePicture->frame_crop_left_offset; + crop_right = SubWidthC [p_StorablePicture->chroma_format_idc] * p_StorablePicture->frame_crop_right_offset; + crop_top = SubHeightC[p_StorablePicture->chroma_format_idc] * ( 2 - p_StorablePicture->frame_mbs_only_flag ) * p_StorablePicture->frame_crop_top_offset; + crop_bottom = SubHeightC[p_StorablePicture->chroma_format_idc] * ( 2 - p_StorablePicture->frame_mbs_only_flag ) * p_StorablePicture->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + + p_Vid->img2buf (p_StorablePicture->imgY, (unsigned char *)(*p_IplImageY)->imageData, p_StorablePicture->size_x, p_StorablePicture->size_y, SymbolSize , crop_left, crop_right, crop_top, crop_bottom, p_StorablePicture->size_x*SymbolSize); + + (*p_IplImageY)->origin = 0; + (*p_IplImageY)->imageDataOrigin = (*p_IplImageY)->imageData; + +} + + +static void convIplImage_Y2StorablePicture( VideoParameters *p_Vid, IplImage *p_IplImage, StorablePicture *p_StorablePicture, int symbol_size_in_bytes ) +{ + int i, j; + int size_x = p_StorablePicture->size_x, size_y = p_StorablePicture->size_y; + unsigned char *buf; + imgpel *img_buf; + IplImage *p_IplImageY = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , IPL_DEPTH_8U, 1 ); + IplImage *p_IplImageU = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , IPL_DEPTH_8U, 1 ); + IplImage *p_IplImageV = cvCreateImage ( cvSize( p_StorablePicture->size_x , p_StorablePicture->size_y ) , IPL_DEPTH_8U, 1 ); + + IplImage *p_IplImageU_small = cvCreateImage ( cvSize( p_StorablePicture->size_x_cr , p_StorablePicture->size_y_cr ) , IPL_DEPTH_8U, 1 ); + IplImage *p_IplImageV_small = cvCreateImage ( cvSize( p_StorablePicture->size_x_cr , p_StorablePicture->size_y_cr ) , IPL_DEPTH_8U, 1 ); + + if( p_IplImage->nChannels == 1 ){ + cvSet(p_IplImageU_small , cvScalar( 0 , 0 , 0 , 0) , NULL ); + cvSet(p_IplImageV_small , cvScalar( 0 , 0 , 0 , 0) , NULL ); + p_IplImageY = p_IplImage; + } + else + { + cvSplit(p_IplImage,p_IplImageY,p_IplImageU,p_IplImageV,NULL); + cvResize( p_IplImageU_small , p_IplImageU , CV_INTER_NN ); + cvResize( p_IplImageV_small , p_IplImageV , CV_INTER_NN ); + } + + + buf = (unsigned char *)p_IplImage->imageData; + for (j=0; j < size_y; j++) + { + img_buf = p_StorablePicture->imgY[j]; + for (i=0; i < size_x; i++) + { + *(img_buf++)= (imgpel) *(buf++); + } + } + + if( p_IplImage->nChannels != 1 ) + cvReleaseImage(&p_IplImageY); + + cvReleaseImage(&p_IplImageU); + cvReleaseImage(&p_IplImageV); + cvReleaseImage(&p_IplImageU_small); + cvReleaseImage(&p_IplImageV_small); + +} + +#endif + +void OpenCVCloseWindows (char *WindowName) +{ +#if( HAVE_OPENCV == 1 ) + if( WindowName == NULL ) + cvDestroyAllWindows(); + else + cvDestroyWindow(WindowName); +#endif + return; +} + +void showStorablePicture(VideoParameters *p_Vid , StorablePicture *Pic, int SymbolSize, int show_uv, char * WindowName, int wait) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *p_cvRGB = NULL; + +#if( _DEBUG == 0 ) + return; +#endif + + SymbolSize = SymbolSize ? SymbolSize : ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3); + + if( show_uv ) + convStorablePicture2IplImage( p_Vid, Pic, &p_cvRGB, SymbolSize ); + else + convStorablePicture2IplImage_Y( p_Vid, Pic, &p_cvRGB, SymbolSize ); + + cvShowImage( WindowName, p_cvRGB); + cvWaitKey(wait); + + cvReleaseImage(&p_cvRGB); + + if( wait == 0) + cvDestroyWindow(WindowName); +#endif + return; +} + + +void cvResizeStorablePicture( VideoParameters *p_Vid , StorablePicture *p_Input, StorablePicture *p_Output ) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *p_cvImgIn = NULL, *p_cvImgOut = NULL; + + convStorablePicture2IplImage_Y( p_Vid, p_Input , &p_cvImgIn, 0 ); + convStorablePicture2IplImage_Y( p_Vid, p_Output , &p_cvImgOut,0 ); + + cvResize( p_cvImgIn , p_cvImgOut , CV_INTER_NN ); + + convIplImage_Y2StorablePicture( p_Vid , p_cvImgOut , p_Output, 1 ); + + cvReleaseImage(&p_cvImgIn); + cvReleaseImage(&p_cvImgOut); +#endif + return; +} + +void cvDisparity( VideoParameters *p_Vid , StorablePicture *Ref, StorablePicture *NonRef, StorablePicture *Disparity, int Method, int WindowRatio, int Direction ) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *p_cvImgLeft = NULL, *p_cvImgRight= NULL; + IplImage *p_cvImgDisp = NULL; + int numberOfDisparities; + + + + if( Method == LOAD ) + { + if( ( p_cvImgDisp = cvLoadImage(p_Vid->p_Inp->DispLoadFileName, CV_LOAD_IMAGE_UNCHANGED) ) != NULL ) + { + //SHOW_IMG_DEBUG( "Disp Debug ",p_cvImgDisp) + convIplImage_Y2StorablePicture( p_Vid , p_cvImgDisp , Disparity, 1 ); + cvReleaseImage(&p_cvImgDisp); + } + return; + } + + convStorablePicture2IplImage_Y( p_Vid, Ref , &p_cvImgLeft, 0 ); + convStorablePicture2IplImage_Y( p_Vid, NonRef , &p_cvImgRight, 0 ); + + //SHOW_IMG_DEBUG( "Left",p_cvImgLeft) + + //numberOfDisparities = ( ( cvGetSize(p_cvImgLeft).width/10 ) + 15 ) & -16; + numberOfDisparities = 256 / WindowRatio; + + if( Method == VAR) + { + p_cvImgDisp = cvCreateImage ( cvSize( Ref->size_x , Ref->size_y ) , IPL_DEPTH_8U, 1 ); +#if( ORIGINAL_OPENCV == 0 ) + CvStereoVARState *stateVAR = cvCreateStereoVARState( 0, numberOfDisparities, 1 ); + switch( Direction) + { + case 1: + stateVAR->minDisp = 0; + stateVAR->maxDisp = ( numberOfDisparities ); + break; + case -1: + stateVAR->minDisp = -( numberOfDisparities ); + stateVAR->maxDisp = 0; + break; + default: + return; + } + cvFindStereoCorrespondenceVAR( p_cvImgLeft , p_cvImgRight , &p_cvImgDisp, stateVAR ); + cvReleaseStereoVARState( &stateVAR ); +#endif + } + else if( Method == BM) + { + IplImage *p_cvImgDisp_16S = cvCreateImage ( cvSize( Ref->size_x , Ref->size_y ) , IPL_DEPTH_16S, 1 ); + CvStereoBMState *stateBM = cvCreateStereoBMState( CV_STEREO_BM_BASIC, numberOfDisparities ); + + stateBM->preFilterCap = 31; + stateBM->SADWindowSize = 17; + //stateBM->look_left = 1; //!< Not implemented + stateBM->minDisparity = 0; + stateBM->numberOfDisparities = numberOfDisparities; + stateBM->textureThreshold = 10; + stateBM->uniquenessRatio = 15; + stateBM->speckleWindowSize = 100; + stateBM->speckleRange = 32; + stateBM->disp12MaxDiff = 1; + + cvFindStereoCorrespondenceBM( p_cvImgLeft, p_cvImgRight, p_cvImgDisp_16S, stateBM ); + + p_cvImgDisp = cvCreateImage ( cvSize( Ref->size_x , Ref->size_y ) , IPL_DEPTH_8U, 1 ); + cvConvertScale( p_cvImgDisp_16S, p_cvImgDisp, 255/(numberOfDisparities*16.), 0); + + cvReleaseStereoBMState( &stateBM ); + cvReleaseImage(&p_cvImgDisp_16S); + } +// else if( Method == SGBM) +// { +// p_cvImgDisp = cvCreateImage ( cvSize( Ref->size_x , Ref->size_y ) , IPL_DEPTH_8U, 1 ); +// if( p_cvImgDisp == NULL ) +// { +// printf("Do not have disparity image\n"); +// } +// } + else + { + p_cvImgDisp = cvCreateImage ( cvSize( Ref->size_x , Ref->size_y ) , IPL_DEPTH_8U, 1 ); + printf("Do not have disparity image\n"); + } + + convIplImage_Y2StorablePicture( p_Vid , p_cvImgDisp , Disparity, 1 ); + + cvReleaseImage(&p_cvImgLeft); + cvReleaseImage(&p_cvImgRight); + cvReleaseImage(&p_cvImgDisp); + +#endif + + return; +} + +void saveStorablePicture( VideoParameters *p_Vid, char *filename , StorablePicture *Picture , int SymbolSize, int save_uv ) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *p_cvRGB = NULL; + +#if( _DEBUG == 0 ) + //return; +#endif + + SymbolSize = SymbolSize ? SymbolSize : ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3); + + if( save_uv ) + convStorablePicture2IplImage( p_Vid, Picture, &p_cvRGB, SymbolSize ); + else + convStorablePicture2IplImage_Y( p_Vid, Picture , &p_cvRGB, SymbolSize ); + + cvSaveImage( filename , p_cvRGB , 0 ); + + cvReleaseImage(&p_cvRGB); + + +#endif + return; +} + +void cvLoadStorablePicture( VideoParameters *p_Vid, char *filename , StorablePicture *Picture , int SymbolSize, int load_uv ) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *cvInputImage = NULL; + + //#if( _DEBUG == 0 ) + // return; + //#endif + // + SymbolSize = SymbolSize ? SymbolSize : ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3); + + if( ( cvInputImage = cvLoadImage(filename, CV_LOAD_IMAGE_UNCHANGED) ) != NULL ) + { + SHOW_IMG_DEBUG( "IMG DEBUG",cvInputImage) + convIplImage_Y2StorablePicture( p_Vid , cvInputImage , Picture, 1 ); + cvReleaseImage(&cvInputImage); + } + +#endif + return; +} + +void cvImageFilter( VideoParameters *p_Vid , StorablePicture *InputImage, StorablePicture *OutputImage, CVFILTERTYPES Filter, int KernelSize ) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *cvInputImage = NULL, *cvOutputImage = NULL; + + /* + * Convert JM Storable picture to a OpenCV IplImage + * This function alloc the image struct so the pointer dont need to be allocated + */ + convStorablePicture2IplImage_Y( p_Vid, InputImage , &cvInputImage, 0 ); + + // Get image for contours with 8 bits depth and 1 channel (gray) + if( ( cvOutputImage = cvCreateImage ( cvSize( InputImage->size_x, InputImage->size_y) , IPL_DEPTH_8U, 1 ) ) == NULL) + { + printf("[OpenCV API] Cannot allocated memory for contours image - Returning a black image\n"); + cvReleaseImage(&cvInputImage); + return; + } + + SHOW_IMG_DEBUG( "Original Image", cvInputImage ); + + //! Apply the chosen filter + switch(Filter) + { + case MEAN_FILTER: + + cvSmooth( cvInputImage, cvOutputImage, CV_BLUR_NO_SCALE, KernelSize, KernelSize, 0, 0); + + break; + case MEDIAN_FILTER: + cvSmooth( cvInputImage, cvOutputImage, CV_MEDIAN , 5, 0, 0, 0); + break; + default: + return; + } + + SHOW_IMG_DEBUG( "Filtered Image", cvOutputImage ); + + //! Converts image + convIplImage_Y2StorablePicture( p_Vid , cvOutputImage , OutputImage, 1 ); + +#endif + return; +} + + +void cvFindImageContours( VideoParameters *p_Vid , StorablePicture *InputImage, StorablePicture *OutputContours ) +{ +#if( HAVE_OPENCV == 1 ) + IplImage *cvInputImage = NULL, *cvOutputContours = NULL; + int SobelOperatorKernel, lowerThresh, highTresh; + + /* + * Convert JM Storable picture to a OpenCV IplImage + * This function alloc the image struct so the pointer dont need to be allocated + */ + convStorablePicture2IplImage_Y( p_Vid, InputImage , &cvInputImage, 0 ); + + // Get image for contours with 8 bits depth and 1 channel (gray) + if( ( cvOutputContours = cvCreateImage ( cvSize( InputImage->size_x, InputImage->size_y) , IPL_DEPTH_8U, 1 ) ) == NULL) + { + printf("[OpenCV API] Cannot allocated memory for contours image - Returning a black image\n"); + cvReleaseImage(&cvInputImage); + return; + } + + //! Configure the edge detector variables + lowerThresh = 0; + highTresh = 9; + SobelOperatorKernel = 3; + + // Run the edge detector on grayscale + cvCanny( cvInputImage, cvOutputContours, lowerThresh, highTresh, SobelOperatorKernel); + + // Converts image + convIplImage_Y2StorablePicture( p_Vid , cvOutputContours , OutputContours, 1 ); +#endif + return; +} + + +int CheckOpenCVUsage(void) +{ +#if( HAVE_OPENCV == 1 ) + return 1; +#else + return 0; +#endif +} diff --git a/ldecod/src/ferc/ferc_proposed.c b/ldecod/src/ferc/ferc_proposed.c new file mode 100644 index 0000000..5b1096e --- /dev/null +++ b/ldecod/src/ferc/ferc_proposed.c @@ -0,0 +1,3693 @@ +/*! + ************************************************************************ + * \file ferc_proposed.c + * + * \brief + * Internal function for ferc API + * Include the proposed concealment method for the paper VCIP 2012 + * Proposed iterative concealment method + * + * \version + * 3.0 + * + * \author + * - Joao Carreira + * + ************************************************************************ + */ + +#include "ferc_api.h" +#include "ferc_internals.h" +#include "ferc_proposed.h" + +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_mvc.h" +#include "memalloc.h" +#include "image.h" +#include "ferc_opencv_api.h" +#include "stream_parser.h" + +#undef BLOCK_SIZE +#define BLOCK_SIZE 4 + +enum direction +{ + LEFT = -1, RIGHT = 1, +}; + +enum mv_types +{ + MV_INTRA = 0, MV_INTER = 1, +}; + +enum diff_types +{ + TEMPORAL_DIFF = 0, SPATIAL_DIFF = 1, +}; + +enum motion_disparity +{ + MOTION = 0, DISPARITY = 1, +}; + +typedef struct inter_intra_concealment +{ + VideoParameters *p_Vid; + + StorablePicture *Destination; + StorablePicture *BlockConcealmentState; + + /*! Slices for the reference frames*/ + Slice *SliceDestiantion; + Slice *SliceIntraViewReference; + Slice *SliceInterViewReference; + Slice *SliceInterViewMinus1Reference; + + StorablePicture *IntraRefFrame; + StorablePicture *InterRefFrame; + StorablePicture *InterRefFrameMinus1; + + int IntraMapList[2][MAX_LIST_SIZE]; + MotionPropInfo IntraMVCandidates; + int MVExtrapolationRefIdx[2]; + + int InterMapList[2][MAX_LIST_SIZE]; + MotionPropInfo InterMVCandidates; + + MotionPropInfo InterIntraMVCandidates; + + /* Disparity Maps*/ + int DisparityMethod; + int DisparityDirection; + int DisparityWindow; + int DisparityReference; + StorablePicture *DisparityAuxMinus1; + StorablePicture *DisparityBaseMinus1; + StorablePicture *DisparityBase; + StorablePicture *DisparityAux; + + StorablePicture *DisparityBlockwiseBase; + StorablePicture *DisparityBlockwiseAux; + int MeanDisparityValue; + + StorablePicture *DisparityBlockwiseAuxMinus1; + + StorablePicture *TemporalDifference; + StorablePicture *SpatialDifference; + int DifferenceThresholds[2]; + + imgpel ***storeYUV, ***storeSeparatedYUV; + imgpel **tmp_storeYUV; + + int BlockSize; +} INTER_INTRA_CONC_T; + +const int BLOCK_IDX_MB[16][2] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 }, { 2, 0 }, { 3, 0 }, { 2, 1 }, { 3, 1 }, { 0, 2 }, { 1, 2 }, { 0, 3 }, { 1, 3 }, + { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; +const int CLUSTER[16] = { 16, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, 4, 1, 1, 1 }; + +/*! + ************************************************************************ + * \brief + * Sort functions + ************************************************************************ + */ + +int sort_by_uint16_up( const void *arg1, const void *arg2 ) +{ + int32 n_0 = *( (uint16 *) arg1 ); + int32 n_1 = *( (uint16 *) arg2 ); + return ( n_0 - n_1 ); +} + +static int sort_imgpel_up( const void *arg1, const void *arg2 ) +{ + return (imgpel) ( *(imgpel *) arg1 ) - (imgpel) ( *(imgpel *) arg2 ); +} + +static void allocIntraInterConcData( VideoParameters *p_Vid, INTER_INTRA_CONC_T **pIntraInterConc, StorablePicture *Destination ) +{ + INTER_INTRA_CONC_T *IntraInterConc; + int i, j; + + IntraInterConc = ( *pIntraInterConc ) = (INTER_INTRA_CONC_T *) malloc( sizeof(INTER_INTRA_CONC_T) ); + + memset( IntraInterConc, 0, sizeof(INTER_INTRA_CONC_T) ); + + IntraInterConc->p_Vid = p_Vid; + IntraInterConc->Destination = Destination; + + IntraInterConc->BlockConcealmentState = alloc_storable_picture( p_Vid, FRAME, p_Vid->width / BLOCK_SIZE, p_Vid->height / BLOCK_SIZE, 0, 0, 1 ); + for( i = -p_Vid->iLumaPadX; i < p_Vid->width / BLOCK_SIZE + p_Vid->iLumaPadX; i++ ) + for( j = -p_Vid->iLumaPadY; j < ( p_Vid->height / BLOCK_SIZE + p_Vid->iLumaPadY ); j++ ) + IntraInterConc->BlockConcealmentState->imgY[j][i] = 0; + + IntraInterConc->TemporalDifference = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, 0, 0, 1 ); + IntraInterConc->SpatialDifference = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, 0, 0, 1 ); + + if( Destination->chroma_format_idc != YUV400 ) + get_mem3Dpel( &( IntraInterConc->storeYUV ), 2, 2, ( ( MB_BLOCK_SIZE * MB_BLOCK_SIZE ) + ( p_Vid->mb_cr_size_x * p_Vid->mb_cr_size_y ) * 2 / 16 ) ); + else + get_mem3Dpel( &( IntraInterConc->storeYUV ), 2, 2, MB_BLOCK_SIZE * MB_BLOCK_SIZE ); + + if( Destination->chroma_format_idc != YUV400 ) + get_mem3Dpel( &( IntraInterConc->storeSeparatedYUV ), 3, MB_BLOCK_SIZE, MB_BLOCK_SIZE ); + else + get_mem3Dpel( &( IntraInterConc->storeSeparatedYUV ), 1, MB_BLOCK_SIZE, MB_BLOCK_SIZE ); + + get_mem2Dpel( &( IntraInterConc->tmp_storeYUV ), MB_BLOCK_SIZE, MB_BLOCK_SIZE ); + + IntraInterConc->IntraMVCandidates.mv_info = NULL; + IntraInterConc->IntraMVCandidates.mv_info_count = NULL; + + IntraInterConc->DisparityMethod = p_Vid->p_Inp->DisparityMethod; + IntraInterConc->DisparityWindow = p_Vid->p_Inp->DisparityWindow; + IntraInterConc->DisparityDirection = p_Vid->p_Inp->DisparityDirection; + IntraInterConc->DisparityReference = p_Vid->p_Inp->DisparityReference; + +} + +static void freeIntraInterConcData( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc ) +{ + free_storable_picture( IntraInterConc->BlockConcealmentState ); + free_storable_picture( IntraInterConc->TemporalDifference ); + free_storable_picture( IntraInterConc->SpatialDifference ); + free_storable_picture( IntraInterConc->DisparityBlockwiseBase ); + free_storable_picture( IntraInterConc->DisparityBlockwiseAux ); + + if( IntraInterConc->DisparityAuxMinus1 ) + free_storable_picture( IntraInterConc->DisparityAuxMinus1 ); + + if( IntraInterConc->DisparityBaseMinus1 ) + free_storable_picture( IntraInterConc->DisparityBaseMinus1 ); + + if( IntraInterConc->DisparityBase ) + free_storable_picture( IntraInterConc->DisparityBase ); + + if( IntraInterConc->DisparityAux ) + free_storable_picture( IntraInterConc->DisparityAux ); + + if( IntraInterConc->IntraMVCandidates.mv_info ) + free_mem3Dmp( IntraInterConc->IntraMVCandidates.mv_info ); + if( IntraInterConc->IntraMVCandidates.mv_info_count ) + free_mem2Dint( IntraInterConc->IntraMVCandidates.mv_info_count ); + + if( IntraInterConc->InterMVCandidates.mv_info ) + free_mem3Dmp( IntraInterConc->InterMVCandidates.mv_info ); + if( IntraInterConc->InterMVCandidates.mv_info_count_lists ) + free_mem3Dint( IntraInterConc->InterMVCandidates.mv_info_count_lists ); + + free_mem3Dpel( IntraInterConc->storeYUV ); + free_mem3Dpel( IntraInterConc->storeSeparatedYUV ); + + free_mem2Dpel( IntraInterConc->tmp_storeYUV ); + + free_slice( IntraInterConc->SliceInterViewReference ); + free_slice( IntraInterConc->SliceIntraViewReference ); + free_slice( IntraInterConc->SliceInterViewMinus1Reference ); + + free( IntraInterConc ); +} + +static void initInterIntraReferenceLists( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, StorablePicture *Destination ) +{ + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[Destination->view_id]; + Slice *pSliceIntraViewReference, *pSliceInterViewReference, *pSliceInterViewMinus1Reference; + StorablePicture *IntraRefFrame, *InterRefFrame, *InterRefFrameMinus1; + Slice *pSliceDestiantion = Destination->PicSlice; + + StorablePicture *temp_frame; + int idx, idx1, dest_idx, list, find; + + IntraRefFrame = IntraInterConc->IntraRefFrame; + InterRefFrame = IntraInterConc->InterRefFrame; + InterRefFrameMinus1 = IntraInterConc->InterRefFrameMinus1; + + //! Initialization of reference list for Intra-View Reference + pSliceIntraViewReference = IntraInterConc->SliceIntraViewReference = malloc_slice( p_Vid->p_Inp, p_Vid ); + + pSliceIntraViewReference->p_Vid = p_Vid; + pSliceIntraViewReference->p_Dpb = p_Vid->p_Dpb_layer[IntraRefFrame->view_id]; + + pSliceIntraViewReference->ThisPOC = IntraRefFrame->poc; + pSliceIntraViewReference->framepoc = IntraRefFrame->poc; + pSliceIntraViewReference->view_id = IntraRefFrame->view_id; + pSliceIntraViewReference->layer_id = IntraRefFrame->layer_id; + pSliceIntraViewReference->slice_type = IntraRefFrame->slice_type; + + pSliceIntraViewReference->listXsize[LIST_0] = IntraRefFrame->Conc_listXsize[LIST_0]; + pSliceIntraViewReference->listXsize[LIST_1] = IntraRefFrame->Conc_listXsize[LIST_1]; + + for( idx = 0; idx < pSliceIntraViewReference->listXsize[LIST_0]; idx++ ) + { + pSliceIntraViewReference->listX[LIST_0][idx] = IntraRefFrame->Conc_listX[LIST_0][idx]; + if( IntraRefFrame->Conc_listXInterviewPos[LIST_0] == idx ) + { + pSliceIntraViewReference->listX[LIST_0][idx] = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[0], IntraRefFrame->poc, 0, EXACT, 1, NULL ); + if( !pSliceIntraViewReference->listX[LIST_0][idx] ) + pSliceIntraViewReference->listX[LIST_0][idx] = p_Vid->no_reference_picture; + } + } + for( idx = 0; idx < pSliceIntraViewReference->listXsize[LIST_1]; idx++ ) + { + pSliceIntraViewReference->listX[LIST_1][idx] = IntraRefFrame->Conc_listX[LIST_1][idx]; + if( IntraRefFrame->Conc_listXInterviewPos[LIST_1] == idx ) + { + pSliceIntraViewReference->listX[LIST_1][idx] = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[0], IntraRefFrame->poc, 0, EXACT, 1, NULL ); + if( !pSliceIntraViewReference->listX[LIST_0][idx] ) + pSliceIntraViewReference->listX[LIST_0][idx] = p_Vid->no_reference_picture; + } + } + printf( "[FERC] Reference list for the Intra-view reference frame" ); + dump_ref_lists( pSliceIntraViewReference ); +#if PRINTREFLIST_JC + printf( "[FERC] Reference list for the Intra-view reference frame"); + dump_ref_lists( pSliceIntraViewReference); +#endif + if( InterRefFrame ) + { + //! Initialization of reference list for Inter-View Reference + pSliceInterViewReference = IntraInterConc->SliceInterViewReference = malloc_slice( p_Vid->p_Inp, p_Vid ); + + pSliceInterViewReference->p_Vid = p_Vid; + pSliceInterViewReference->p_Dpb = p_Vid->p_Dpb_layer[Destination->view_id]; + pSliceInterViewReference->ThisPOC = InterRefFrame->poc; + pSliceInterViewReference->framepoc = InterRefFrame->poc; + pSliceInterViewReference->view_id = InterRefFrame->view_id; + pSliceInterViewReference->layer_id = InterRefFrame->layer_id; + pSliceInterViewReference->slice_type = InterRefFrame->slice_type; + + pSliceInterViewReference->listXsize[LIST_0] = InterRefFrame->Conc_listXsize[LIST_0]; + pSliceInterViewReference->listXsize[LIST_1] = InterRefFrame->Conc_listXsize[LIST_1]; + + for( idx = 0; idx < pSliceInterViewReference->listXsize[LIST_0]; idx++ ) + { + pSliceInterViewReference->listX[LIST_0][idx] = InterRefFrame->Conc_listX[LIST_0][idx]; + } + for( idx = 0; idx < pSliceInterViewReference->listXsize[LIST_1]; idx++ ) + { + pSliceInterViewReference->listX[LIST_1][idx] = InterRefFrame->Conc_listX[LIST_1][idx]; + } + printf( "[FERC] Reference list for the Inter-view reference frame" ); + dump_ref_lists( pSliceInterViewReference ); +#if PRINTREFLIST_JC + printf( "[FERC] Reference list for the Inter-view reference frame"); + dump_ref_lists( pSliceInterViewReference); +#endif + } + + //! Initialization of reference list for Destination + pSliceDestiantion = IntraInterConc->SliceDestiantion = Destination->PicSlice; + + pSliceDestiantion->p_Vid = p_Vid; + pSliceDestiantion->p_Dpb = p_Vid->p_Dpb_layer[Destination->view_id]; + pSliceDestiantion->ThisPOC = Destination->poc; + pSliceDestiantion->framepoc = Destination->poc; + pSliceDestiantion->view_id = Destination->view_id; + pSliceDestiantion->layer_id = Destination->layer_id; + pSliceDestiantion->slice_type = IntraRefFrame->slice_type; + + pSliceDestiantion->listXsize[LIST_0] = pSliceDestiantion->listXsize[LIST_1] = 0; + +#if MVC_EXTENSION_ENABLE + if( InterRefFrame && Destination->view_id != BASE_VIEW_IDX ) + { + init_mvc_picture( pSliceDestiantion ); + } +#endif + + IntraInterConc->MVExtrapolationRefIdx[0] = -1; + IntraInterConc->MVExtrapolationRefIdx[1] = -1; + + for( list = 0; list <= 1; list++ ) + { + //! Intra View Reference List + dest_idx = 0; + for( idx = 0; idx < pSliceIntraViewReference->listXsize[list]; dest_idx++ ) + { + pSliceDestiantion->listX[list][dest_idx] = pSliceIntraViewReference->listX[list][idx]; + if( IntraRefFrame->Conc_listXInterviewPos[list] == idx ) + { + if( InterRefFrame ) + pSliceDestiantion->listX[list][dest_idx] = p_Dpb->fs_ilref[0]->frame; + else + pSliceDestiantion->listX[list][dest_idx] = p_Vid->no_reference_picture; + IntraInterConc->MVExtrapolationRefIdx[1] = idx; + } + else if( IntraInterConc->MVExtrapolationRefIdx[0] == -1 ) + { + pSliceDestiantion->listX[list][dest_idx] = IntraRefFrame; + IntraInterConc->MVExtrapolationRefIdx[0] = dest_idx; + continue; + } + IntraInterConc->IntraMapList[list][idx] = dest_idx; + idx++; + } + pSliceDestiantion->listXsize[list] = dest_idx; + for( idx = 0; idx < pSliceInterViewReference->listXsize[list]; idx++ ) + { + // pSliceDestiantion->listX[LIST_0][idx] + temp_frame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[Destination->layer_id], InterRefFrame->Conc_listX[list][idx]->poc, Destination->layer_id, + EXACT, 1, NULL ); + for( idx1 = 0, find = 0; idx1 < pSliceDestiantion->listXsize[list]; idx1++ ) + { + if( pSliceDestiantion->listX[list][idx1] == temp_frame ) + { + IntraInterConc->InterMapList[list][idx] = idx1; + find = 1; + break; + } + } + if( !find ) + { + IntraInterConc->InterMapList[list][idx] = dest_idx; + pSliceDestiantion->listX[list][dest_idx++] = temp_frame; + } + } + pSliceDestiantion->listXsize[list] = dest_idx; + } + printf( "[FERC] Reference list for the Destination frame" ); + dump_ref_lists( pSliceDestiantion ); +#if PRINTREFLIST_JC + printf( "[FERC] Reference list for the Destination frame"); + dump_ref_lists( pSliceDestiantion); +#endif + + //! Initialization of reference list for Inter-View Minus 1 Reference + pSliceInterViewMinus1Reference = IntraInterConc->SliceInterViewMinus1Reference = malloc_slice( p_Vid->p_Inp, p_Vid ); + + pSliceInterViewMinus1Reference->p_Vid = p_Vid; + pSliceInterViewMinus1Reference->p_Dpb = p_Vid->p_Dpb_layer[IntraRefFrame->view_id]; + + pSliceInterViewMinus1Reference->ThisPOC = InterRefFrameMinus1->poc; + pSliceInterViewMinus1Reference->framepoc = InterRefFrameMinus1->poc; + pSliceInterViewMinus1Reference->view_id = InterRefFrameMinus1->view_id; + pSliceInterViewMinus1Reference->layer_id = InterRefFrameMinus1->layer_id; + pSliceInterViewMinus1Reference->slice_type = InterRefFrameMinus1->slice_type; + + pSliceInterViewMinus1Reference->listXsize[LIST_0] = InterRefFrameMinus1->Conc_listXsize[LIST_0]; + pSliceInterViewMinus1Reference->listXsize[LIST_1] = InterRefFrameMinus1->Conc_listXsize[LIST_1]; + + for( idx = 0; idx < pSliceInterViewMinus1Reference->listXsize[LIST_0]; idx++ ) + { + pSliceInterViewMinus1Reference->listX[LIST_0][idx] = InterRefFrameMinus1->Conc_listX[LIST_0][idx]; + } + for( idx = 0; idx < pSliceInterViewMinus1Reference->listXsize[LIST_1]; idx++ ) + { + pSliceInterViewMinus1Reference->listX[LIST_1][idx] = InterRefFrameMinus1->Conc_listX[LIST_1][idx]; + } + printf( "[FERC] Reference list for the Inter-view reference minus 1 frame" ); + dump_ref_lists( pSliceInterViewMinus1Reference ); +#if PRINTREFLIST_JC + printf( "[FERC] Reference list for the Inter-view reference minus 1 frame"); + dump_ref_lists( pSliceInterViewMinus1Reference); +#endif +} + +static int findBlock_Overlap( int x_pel, int y_pel, int x_block, int y_block, int block_size ) +{ + int x_block_start, y_block_start, x_block_end, y_block_end, i, j, overlap; + + x_block_start = x_block * block_size; + x_block_end = ( x_block + 1 ) * block_size - 1; + + y_block_start = y_block * block_size; + y_block_end = ( y_block + 1 ) * block_size - 1; + + for( overlap = 0, i = 0; i < block_size; i++ ) + { + for( j = 0; j < block_size; j++ ) + { + if( ( y_pel + i ) >= y_block_start && ( y_pel + i ) <= y_block_end ) + if( ( x_pel + j ) >= x_block_start && ( x_pel + j ) <= x_block_end ) + overlap++; + } + } + return overlap; +} + +static int findBlock_Quadrant( int x_pel, int y_pel, int x_block, int y_block, int block_size ) +{ + int x_block_start, y_block_start, x_block_end, y_block_end, quadrant; + + x_block_start = x_block * block_size; + x_block_end = ( x_block + 1 ) * block_size - 1; + + y_block_start = y_block * block_size; + y_block_end = ( y_block + 1 ) * block_size - 1; + + if( x_pel < x_block_start || x_pel > x_block_end || y_pel < y_block_start || y_pel > y_block_end ) + { + printf( "[FERC] Pixel (%d,%d) do not belong to the block (%d,%d)\n", x_pel, y_pel, x_block, y_block ); + return 0; + } + + quadrant = 1; + if( x_pel > x_block_end - ( block_size / 2 ) ) + quadrant += 1; + + if( y_pel > y_block_end - ( block_size / 2 ) ) + quadrant += 2; + + return quadrant; +} + +/*! + *********************************************************************** + * \brief + * Get the MV candidates for the different concealment strategies + *********************************************************************** + */ +void getINTERMotionVectorCandidates( VideoParameters *p_Vid, StorablePicture *Source, Slice *SourceSlice, StorablePicture *Destination, + StorablePicture *Disparity4x4, MotionPropInfo *Matrix_MV_Info, int Choose_Method ) +{ + const int Max_Candidates = 10; + + PicMotionParams ***mv_info; + int searched_mv[2], ***mv_info_count, ***mv_info_overlap; + int mv_info_count_i; + int Disparity; + StorablePicture *currRef; + int y_block, x_block, y, x, y_final_block, x_final_block, y_final, x_final; + int y_pos, x_pos; + int StartList, List, mv[3]; + float scale_factor; + StorablePicture *RefFrameMotionSearch; + + int DispDir = p_Vid->p_Inp->DisparityDirection; + + Matrix_MV_Info->mv_info_count = 0; + + get_mem3Dmp( &( mv_info ), ( Source->size_y >> BLOCK_SHIFT ), ( Source->size_x >> BLOCK_SHIFT ), Max_Candidates ); + get_mem3Dint( &mv_info_overlap, ( Source->size_y >> BLOCK_SHIFT ), ( Source->size_x >> BLOCK_SHIFT ), Max_Candidates ); + + get_mem3Dint( &mv_info_count, ( Source->size_y >> BLOCK_SHIFT ), ( Source->size_x >> BLOCK_SHIFT ), 2 ); + + memset( mv_info_count[0][0], -1, sizeof(int) * 2 * ( Source->size_y >> BLOCK_SHIFT ) * ( Source->size_x >> BLOCK_SHIFT ) ); + + StartList = SourceSlice->slice_type == B_SLICE ? LIST_1 : LIST_0; + + // StartList = LIST_0; + + //showStorablePicture(p_Vid, RefFrameMotionSearch, 0, 0, "Reference for search", 1); + //showStorablePicture(p_Vid, Source, 0, 0, "Source", 0); + + for( List = StartList; List >= LIST_0; List-- ) + { + memset( mv_info_overlap[0][0], 0, sizeof(int) * ( Source->size_y >> BLOCK_SHIFT ) * ( Source->size_x >> BLOCK_SHIFT ) * Max_Candidates ); + /* Loop though all block 4x4 in source */ + for( y_block = 0; y_block < ( Source->PicSizeInMbs / Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + if( Source->mv_info[y_block][x_block].ref_idx[List] >= 0 ) + { + /* Update mv information - Read Reference Values */ + mv[0] = Source->mv_info[y_block][x_block].mv[List].mv_x; + mv[1] = Source->mv_info[y_block][x_block].mv[List].mv_y; + mv[2] = Source->mv_info[y_block][x_block].ref_idx[List]; + + currRef = SourceSlice->listX[List][mv[2]]; + + /* Project the Temporal vectors to the other view (auxiliary view) */ + //! Pixel destination in auxiliary view + Disparity = Disparity4x4->imgY[y_block][x_block]; + //x_final = iClip3(0, Source->size_x - 1, ( x + DispDir * Disparity ) ); + x_final = x + DispDir * Disparity; + if( x_final < 0 ) + continue; + + y_final = y; + + //! Ajustments to cope with negative values + x_final_block = x_final < 0 ? ( x_final + 1 ) / 4 : x_final / 4; + y_final_block = y_final < 0 ? ( y_final + 1 ) / 4 : y_final / 4; + + y_final_block = y_final < 0 ? y_final_block - 1 : y_final_block; + x_final_block = x_final < 0 ? x_final_block - 1 : x_final_block; + + //! Check the Quadrant + switch( findBlock_Quadrant( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ) ) + { + case 0: + continue; + case 1: + break; + case 2: + x_final_block += 1; + break; + case 3: + y_final_block += 1; + break; + case 4: + y_final_block += 1; + x_final_block += 1; + break; + default: + continue; + } + + //! Check the image boundaries + if( y_final_block < 0 || y_final_block >= ( Source->PicSizeInMbs / Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + if( x_final_block < 0 || x_final_block >= ( Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + + //! Check for previous vectors associated with the current final block + if( mv_info_count[y_final_block][x_final_block][List] == -1 ) + mv_info_count[y_final_block][x_final_block][List] = 0; + + mv_info_count_i = mv_info_count[y_final_block][x_final_block][List]; + + if( mv_info_count_i >= 10 ) + continue; + + //! Associate the vector to the block + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[List].mv_x = mv[0]; + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[List].mv_y = mv[1]; + mv_info[y_final_block][x_final_block][mv_info_count_i].ref_idx[List] = mv[2]; + + //! Find block overlap + mv_info_overlap[y_final_block][x_final_block][mv_info_count_i] = findBlock_Overlap( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ); + + mv_info_count[y_final_block][x_final_block][List]++; + } + } + } + + /* Loop though all block 4x4 in destination to choose the best */ + for( y_block = 0; y_block < ( Source->PicSizeInMbs / Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + mv_info_count_i = mv_info_count[y_block][x_block][List]; + if( mv_info_count_i >= 0 ) + { + if( Choose_Method == 1 ) + { + //Most overlapped + mv_info_count_i = i_max_position( mv_info_overlap[y_block][x_block], mv_info_count_i, NULL, NULL ); + mv_info_count[y_block][x_block][List] = mv_info_count_i; + } + } + } + } + } + free_mem3Dint( mv_info_overlap ); + + ( *Matrix_MV_Info ).mv_info = mv_info; + ( *Matrix_MV_Info ).mv_info_count_lists = mv_info_count; + + return; +} + +void getINTRAMotionVectorCandidates( VideoParameters *p_Vid, StorablePicture *Source, Slice *SourceSlice, StorablePicture *Destination, + MotionPropInfo *Matrix_MV_Info, StorablePicture *MotionPicture, int Choose_Method, int UseDisparity ) +{ + const int Max_Candidates = 10; + + PicMotionParams ***mv_info; + int searched_mv[2], **mv_info_count, ***mv_info_overlap; + int mv_info_count_i, i; + + StorablePicture *currRef; + int y_block, x_block, y, x, y_final_block, x_final_block, y_final, x_final; + int y_pos, x_pos; + int StartList, List, mv[3]; + float scale_factor; + StorablePicture *RefFrameMotionSearch; + + Matrix_MV_Info->mv_info_count_lists = 0; + + get_mem3Dmp( &( mv_info ), ( Source->size_y >> BLOCK_SHIFT ), ( Source->size_x >> BLOCK_SHIFT ), Max_Candidates ); + get_mem3Dint( &mv_info_overlap, ( Source->size_y >> BLOCK_SHIFT ), ( Source->size_x >> BLOCK_SHIFT ), Max_Candidates ); + + mv_info_count = new_mem2Dint( ( Source->size_y >> BLOCK_SHIFT ), ( Source->size_x >> BLOCK_SHIFT ) ); + + memset( &( mv_info_count[0][0] ), -1, sizeof(int) * ( Source->size_y >> BLOCK_SHIFT ) * ( Source->size_x >> BLOCK_SHIFT ) ); + + StartList = SourceSlice->slice_type == B_SLICE ? LIST_1 : LIST_0; + + for( i = 0; i < SourceSlice->listXsize[LIST_0]; i++ ) + { + if( SourceSlice->listX[LIST_0][i]->view_id == Source->view_id ) + { + RefFrameMotionSearch = SourceSlice->listX[LIST_0][i]; + break; + } + } + + //showStorablePicture(p_Vid, RefFrameMotionSearch, 0, 0, "Reference for search", 1); + //showStorablePicture(p_Vid, Source, 0, 0, "Source", 0); + + /* Loop though all block 4x4 in source */ + for( y_block = 0; y_block < ( Source->PicSizeInMbs / Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + for( List = StartList; List >= LIST_0; List-- ) + { + if( Source->mv_info[y_block][x_block].ref_idx[List] >= 0 ) + { + /* Update mv information - Read Reference Values */ + mv[0] = Source->mv_info[y_block][x_block].mv[List].mv_x; + mv[1] = Source->mv_info[y_block][x_block].mv[List].mv_y; + mv[2] = Source->mv_info[y_block][x_block].ref_idx[List]; + + currRef = SourceSlice->listX[List][mv[2]]; + /* Disparity Vectors */ + if( SourceSlice->view_id != 0 && currRef->poc == Source->poc ) + { + if( !UseDisparity ) + continue; + + //! Pixel destination + x_final = x; + y_final = y; + + //x_pos = imax( x - 6, 0 ); + //y_pos = imax( y - 6, 0 ); + + //MotionSearchDynamic( RefFrameMotionSearch->imgY[0], RefFrameMotionSearch->size_x, &(Source->imgY[y_pos][x_pos]), Source->size_x, searched_mv, x_pos, y_pos, Source->size_x, Source->size_y, 16, 32); + ////blockMatch16x16SSE4( RefFrameMotionSearch->imgY[0], RefFrameMotionSearch->size_x, &(Source->imgY[y_pos][x_pos]), Source->size_x, searched_mv, Source->size_x, Source->size_y, 16); + + ////! vector = pos_final - pos_inicial + //searched_mv[0] = searched_mv[0] - x_pos; + //searched_mv[1] = searched_mv[1] - y_pos; + + //if( searched_mv[0] == 16 || searched_mv[1] == 16 ) + //{ + // searched_mv[0] = searched_mv[1] = 0; + //} + + ////!Pixel destination + //x_final = ( x - searched_mv[0] ); + //y_final = ( y - searched_mv[1] ); + + mv[2] = 1; + + } + /* Temporal vectors */ + else + { + // Scale mv + scale_factor = (double) ( Destination->poc - Source->poc ) / (double) ( Source->poc - currRef->poc ); + mv[0] = (int) ( (float) ( mv[0] ) * scale_factor ); + mv[1] = (int) ( (float) ( mv[1] ) * scale_factor ); + + //! Quarter pixel destination + x_final = ( x * 4 - mv[0] ); + y_final = ( y * 4 - mv[1] ); + + //! Pixel destination +#define FINAL_PIXEL 2 +#if( FINAL_PIXEL == 1 ) + x_final = x_final/4 + ((x_final&0x03) && (x_final&0x01)); + y_final = y_final/4 + ((y_final&0x03) && (y_final&0x01)); +#endif +#if( FINAL_PIXEL == 2 ) + x_final = x_final / 4 + ( ( x_final & 0x02 ) >> 1 ); + y_final = y_final / 4 + ( ( y_final & 0x02 ) >> 1 ); +#endif +#if( FINAL_PIXEL == 3 ) + x_final = x_final/4; + y_final = y_final/4; +#endif + + mv[2] = 0; + } + + //! Ajustments to cope with negative values + x_final_block = x_final < 0 ? ( x_final + 1 ) / 4 : x_final / 4; + y_final_block = y_final < 0 ? ( y_final + 1 ) / 4 : y_final / 4; + + y_final_block = y_final < 0 ? y_final_block - 1 : y_final_block; + x_final_block = x_final < 0 ? x_final_block - 1 : x_final_block; + + switch( findBlock_Quadrant( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ) ) + { + case 0: + continue; + case 1: + break; + case 2: + x_final_block += 1; + break; + case 3: + y_final_block += 1; + break; + case 4: + y_final_block += 1; + x_final_block += 1; + break; + default: + continue; + } + + if( y_final_block < 0 || y_final_block >= ( Source->PicSizeInMbs / Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + if( x_final_block < 0 || x_final_block >= ( Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + + if( mv_info_count[y_final_block][x_final_block] == -1 ) + mv_info_count[y_final_block][x_final_block] = 0; + + mv_info_count_i = mv_info_count[y_final_block][x_final_block]; + + if( mv_info_count_i >= 10 ) + continue; + + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[LIST_0].mv_x = mv[0]; + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[LIST_0].mv_y = mv[1]; + mv_info[y_final_block][x_final_block][mv_info_count_i].ref_idx[LIST_0] = mv[2]; + + mv_info_overlap[y_final_block][x_final_block][mv_info_count_i] = findBlock_Overlap( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ); + + mv_info_count[y_final_block][x_final_block]++; + } + } + } + } + + /* Loop though all block 4x4 in destination to choose the best */ + for( y_block = 0; y_block < ( Source->PicSizeInMbs / Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( Source->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + mv_info_count_i = mv_info_count[y_block][x_block]; + + if( mv_info_count_i >= 0 ) + { + if( mv_info_count_i > 1 ) + { + if( Choose_Method == 1 ) + { + //Most overlaped + mv_info_count_i = i_max_position( mv_info_overlap[y_block][x_block], mv_info_count_i, NULL, NULL ); + mv_info_count[y_block][x_block] = mv_info_count_i; + } + else if( Choose_Method == 2 ) + { + double sum_x = 0, sum_y = 0, sum_over = 0; + int ref_flag; + if( mv_info_count_i == 1 ) + { + ref_flag = mv_info[y_block][x_block][0].ref_idx[LIST_0]; + sum_x += (double) mv_info[y_block][x_block][0].mv[LIST_0].mv_x; + sum_y += (double) mv_info[y_block][x_block][0].mv[LIST_0].mv_y; + } + else + { + ref_flag = 0; + for( i = 0; i < mv_info_count_i; i++ ) + { + if( ref_flag == mv_info[y_block][x_block][0].ref_idx[LIST_0] ) + { + //sum_x += (double)mv_info[y_block][x_block][i].mv[LIST_0].mv_x * (double)mv_info_overlap[y_block][x_block][i]; + //sum_y += (double)mv_info[y_block][x_block][i].mv[LIST_0].mv_y * (double)mv_info_overlap[y_block][x_block][i]; + //sum_over += (double)(mv_info_overlap[y_block][x_block][i]); + if( mv_info[y_block][x_block][i].mv[LIST_0].mv_x == 0 && mv_info[y_block][x_block][i].mv[LIST_0].mv_y == 0 ) + continue; + + sum_x += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_x; + sum_y += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_y; + sum_over += (double) ( 1 ); + + } + } + } + sum_over = sum_over ? sum_over : 1; + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( sum_x / sum_over ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( sum_y / sum_over ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = ref_flag; + + mv_info_count_i = 0; + mv_info_count[y_block][x_block] = mv_info_count_i; + } + // Motion vector average + else if( Choose_Method == 3 ) + { + double sum_x = 0, sum_y = 0, sum_over = 0; + int disp_flag = mv_info[y_block][x_block][0].ref_idx[LIST_0] == 1; + for( i = 0; i < mv_info_count_i; i++ ) + { + if( mv_info[y_block][x_block][0].ref_idx[LIST_0] == disp_flag ) + { + sum_x += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_x * (double) mv_info_overlap[y_block][x_block][i]; + sum_y += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_y * (double) mv_info_overlap[y_block][x_block][i]; + sum_over += (double) ( mv_info_overlap[y_block][x_block][i] ); + } + } + sum_over = sum_over ? sum_over : 1; + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( sum_x / sum_over ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( sum_y / sum_over ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = disp_flag; + + mv_info_count_i = 0; + } + // Motion vector weighted average using the predominant prediction + else if( Choose_Method == 4 ) + { + double sum_x = 0, sum_y = 0, sum_over = 0; + int disp_flag = 0; + for( i = 0; i < mv_info_count_i; i++ ) + { + if( mv_info[y_block][x_block][0].ref_idx[LIST_0] == 1 ) + { + disp_flag++; + } + else + { + disp_flag--; + } + } + disp_flag = disp_flag > 0 ? 1 : 0; + for( i = 0; i < mv_info_count_i; i++ ) + { + if( mv_info[y_block][x_block][0].ref_idx[LIST_0] == disp_flag ) + { + sum_x += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_x * (double) mv_info_overlap[y_block][x_block][i]; + sum_y += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_y * (double) mv_info_overlap[y_block][x_block][i]; + sum_over += (double) ( mv_info_overlap[y_block][x_block][i] ); + } + } + sum_over = sum_over ? sum_over : 1; + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( sum_x / sum_over ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( sum_y / sum_over ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = disp_flag; + + mv_info_count_i = 0; + mv_info_count[y_block][x_block] = mv_info_count_i; + } + //! 1. use the non-zero vectors; 2. Disparity vectors; 3. Zero vectors; + else if( Choose_Method == 5 ) + { + double sum_x = 0, sum_y = 0, sum_over = 0; + int disp_idx = 0; + + for( i = 0; i < mv_info_count_i; i++ ) + { + if( mv_info[y_block][x_block][i].ref_idx[LIST_0] == 0 ) + { + if( mv_info[y_block][x_block][i].mv[LIST_0].mv_x == 0 && mv_info[y_block][x_block][i].mv[LIST_0].mv_y == 0 ) + continue; + + sum_x += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_x; + sum_y += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_y; + sum_over += (double) ( 1 ); + } + } + if( sum_over ) + { + sum_x = sum_x / sum_over; + sum_y = sum_y / sum_over; + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( sum_x ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( sum_y ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = 0; + mv_info_count_i = 0; + continue; + } + + for( i = 0; i < mv_info_count_i; i++ ) + { + if( mv_info[y_block][x_block][0].ref_idx[LIST_0] == 1 ) + { + if( mv_info[y_block][x_block][i].mv[LIST_0].mv_x == 0 && mv_info[y_block][x_block][i].mv[LIST_0].mv_y == 0 ) + continue; + + sum_x += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_x; + sum_y += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_y; + sum_over += (double) ( 1 ); + } + } + if( sum_over ) + { + sum_x = sum_x / sum_over; + sum_y = sum_y / sum_over; + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( sum_x ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( sum_y ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = 1; + mv_info_count_i = 0; + continue; + } + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( 0 ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( 0 ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = 0; + mv_info_count_i = 0; + continue; + } + else + { + mv_info_count_i = 0; + } + } + else + { + mv_info_count_i = 0; + } + } + mv_info_count[y_block][x_block] = mv_info_count_i; + } + } + + free_mem3Dint( mv_info_overlap ); + + ( *Matrix_MV_Info ).mv_info = mv_info; + ( *Matrix_MV_Info ).mv_info_count = mv_info_count; + + return; +} + +void getINTERINTRAMotionVectorCandidates( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, MotionPropInfo *Matrix_MV_Info ) +{ + const int Max_Candidates = 10; + + PicMotionParams ***mv_info; + int searched_mv[2], **mv_info_count, ***mv_info_overlap; + int mv_info_count_i, i; + int UseDisparity = 1; + StorablePicture *currRef; + int y_block, x_block, y, x, y_final_block, x_final_block, y_final, x_final; + int y_pos, x_pos; + int StartList, List, mv[3]; + float scale_factor; + StorablePicture *RefFrameMotionSearch; + StorablePicture *Disparity4x4 = IntraInterConc->DisparityBlockwiseAuxMinus1; + int Disparity; + int Choose_Method = 1; + + StorablePicture *INTERViewReference = IntraInterConc->InterRefFrame; + StorablePicture *Destination = IntraInterConc->Destination; + Slice *SourceSliceAux = IntraInterConc->SliceIntraViewReference; + Slice *SourceSliceBase = IntraInterConc->SliceInterViewMinus1Reference; + StorablePicture *SourceAux = IntraInterConc->IntraRefFrame; + StorablePicture *SourceBase; + int DispDir = p_Vid->p_Inp->DisparityDirection; + + Matrix_MV_Info->mv_info_count_lists = 0; + + SourceBase = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[INTERViewReference->view_id], SourceAux->poc, INTERViewReference->view_id, EXACT, 0, NULL ); + + get_mem3Dmp( &( mv_info ), ( SourceAux->size_y >> BLOCK_SHIFT ), ( SourceAux->size_x >> BLOCK_SHIFT ), Max_Candidates ); + get_mem3Dint( &mv_info_overlap, ( SourceAux->size_y >> BLOCK_SHIFT ), ( SourceAux->size_x >> BLOCK_SHIFT ), Max_Candidates ); + + mv_info_count = new_mem2Dint( ( SourceAux->size_y >> BLOCK_SHIFT ), ( SourceAux->size_x >> BLOCK_SHIFT ) ); + + memset( &( mv_info_count[0][0] ), -1, sizeof(int) * ( SourceAux->size_y >> BLOCK_SHIFT ) * ( SourceAux->size_x >> BLOCK_SHIFT ) ); + + StartList = SourceSliceAux->slice_type == B_SLICE ? LIST_1 : LIST_0; + + for( i = 0; i < SourceSliceAux->listXsize[LIST_0]; i++ ) + { + if( SourceSliceAux->listX[LIST_0][i]->view_id == SourceAux->view_id ) + { + RefFrameMotionSearch = SourceSliceAux->listX[LIST_0][i]; + break; + } + } + + // INTRA motion vector candidates + /* Loop though all block 4x4 in source */ + for( y_block = 0; y_block < ( SourceAux->PicSizeInMbs / SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + for( List = StartList; List >= LIST_0; List-- ) + { + if( SourceAux->mv_info[y_block][x_block].ref_idx[List] >= 0 ) + { + /* Update mv information - Read Reference Values */ + mv[0] = SourceAux->mv_info[y_block][x_block].mv[List].mv_x; + mv[1] = SourceAux->mv_info[y_block][x_block].mv[List].mv_y; + mv[2] = SourceAux->mv_info[y_block][x_block].ref_idx[List]; + + currRef = SourceSliceAux->listX[List][mv[2]]; + /* Disparity Vectors */ + if( SourceSliceAux->view_id != 0 && currRef->poc == SourceAux->poc ) + { + if( !UseDisparity ) + continue; + + //! Pixel destination + x_final = x; + y_final = y; + + mv[2] = 1; + + } + /* Temporal vectors */ + else + { + // Scale mv + scale_factor = (double) ( Destination->poc - SourceAux->poc ) / (double) ( SourceAux->poc - currRef->poc ); + mv[0] = (int) ( (float) ( mv[0] ) * scale_factor ); + mv[1] = (int) ( (float) ( mv[1] ) * scale_factor ); + + //! Quarter pixel destination + x_final = ( x * 4 - mv[0] ); + y_final = ( y * 4 - mv[1] ); + + //! Pixel destination +#define FINAL_PIXEL 2 +#if( FINAL_PIXEL == 1 ) + x_final = x_final/4 + ((x_final&0x03) && (x_final&0x01)); + y_final = y_final/4 + ((y_final&0x03) && (y_final&0x01)); +#endif +#if( FINAL_PIXEL == 2 ) + x_final = x_final / 4 + ( ( x_final & 0x02 ) >> 1 ); + y_final = y_final / 4 + ( ( y_final & 0x02 ) >> 1 ); +#endif +#if( FINAL_PIXEL == 3 ) + x_final = x_final/4; + y_final = y_final/4; +#endif + + mv[2] = 0; + } + + //! Ajustments to cope with negative values + x_final_block = x_final < 0 ? ( x_final + 1 ) / 4 : x_final / 4; + y_final_block = y_final < 0 ? ( y_final + 1 ) / 4 : y_final / 4; + + y_final_block = y_final < 0 ? y_final_block - 1 : y_final_block; + x_final_block = x_final < 0 ? x_final_block - 1 : x_final_block; + + switch( findBlock_Quadrant( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ) ) + { + case 0: + continue; + case 1: + break; + case 2: + x_final_block += 1; + break; + case 3: + y_final_block += 1; + break; + case 4: + y_final_block += 1; + x_final_block += 1; + break; + default: + continue; + } + + if( y_final_block < 0 || y_final_block >= ( SourceAux->PicSizeInMbs / SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + if( x_final_block < 0 || x_final_block >= ( SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + + if( mv_info_count[y_final_block][x_final_block] != -1 ) + continue; + + if( mv_info_count[y_final_block][x_final_block] == -1 ) + mv_info_count[y_final_block][x_final_block] = 0; + + mv_info_count_i = mv_info_count[y_final_block][x_final_block]; + + if( mv_info_count_i >= 10 ) + continue; + + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[LIST_0].mv_x = mv[0]; + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[LIST_0].mv_y = mv[1]; + mv_info[y_final_block][x_final_block][mv_info_count_i].ref_idx[LIST_0] = mv[2]; + + mv_info_overlap[y_final_block][x_final_block][mv_info_count_i] = findBlock_Overlap( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ); + + mv_info_count[y_final_block][x_final_block]++; + } + } + } + } + + // Get INTER candidates + for( List = StartList; List >= LIST_0; List-- ) + { + /* Loop though all block 4x4 in source */ + for( y_block = 0; y_block < ( SourceBase->PicSizeInMbs / SourceBase->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( SourceBase->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + Disparity = Disparity4x4->imgY[y_block][x_block]; + + x_final_block = x_block * BLOCK_SIZE + -1 * DispDir * Disparity; + x_final_block = x_final_block / BLOCK_SIZE; + + if( x_final_block < 0 || x_final_block > SourceBase->size_x / BLOCK_SIZE ) + continue; + + if( SourceBase->mv_info[y_block][x_final_block].ref_idx[List] >= 0 ) + { + /* Update mv information - Read Reference Values */ + mv[0] = SourceBase->mv_info[y_block][x_final_block].mv[List].mv_x; + mv[1] = SourceBase->mv_info[y_block][x_final_block].mv[List].mv_y; + mv[2] = SourceBase->mv_info[y_block][x_final_block].ref_idx[List]; + + currRef = SourceSliceBase->listX[List][mv[2]]; + + // Scale mv + scale_factor = (double) ( Destination->poc - SourceBase->poc ) / (double) ( SourceBase->poc - currRef->poc ); + mv[0] = (int) ( (float) ( mv[0] ) * scale_factor ); + mv[1] = (int) ( (float) ( mv[1] ) * scale_factor ); + + //! Quarter pixel destination + x_final = ( x * 4 - mv[0] ); + y_final = ( y * 4 - mv[1] ); + + //! Pixel destination +#define FINAL_PIXEL 2 +#if( FINAL_PIXEL == 1 ) + x_final = x_final/4 + ((x_final&0x03) && (x_final&0x01)); + y_final = y_final/4 + ((y_final&0x03) && (y_final&0x01)); +#endif +#if( FINAL_PIXEL == 2 ) + x_final = x_final / 4 + ( ( x_final & 0x02 ) >> 1 ); + y_final = y_final / 4 + ( ( y_final & 0x02 ) >> 1 ); +#endif +#if( FINAL_PIXEL == 3 ) + x_final = x_final/4; + y_final = y_final/4; +#endif + + mv[2] = 0; + + //! Ajustments to cope with negative values + x_final_block = x_final < 0 ? ( x_final + 1 ) / 4 : x_final / 4; + y_final_block = y_final < 0 ? ( y_final + 1 ) / 4 : y_final / 4; + + y_final_block = y_final < 0 ? y_final_block - 1 : y_final_block; + x_final_block = x_final < 0 ? x_final_block - 1 : x_final_block; + + switch( findBlock_Quadrant( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ) ) + { + case 0: + continue; + case 1: + break; + case 2: + x_final_block += 1; + break; + case 3: + y_final_block += 1; + break; + case 4: + y_final_block += 1; + x_final_block += 1; + break; + default: + continue; + } + + if( y_final_block < 0 || y_final_block >= ( SourceAux->PicSizeInMbs / SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + if( x_final_block < 0 || x_final_block >= ( SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ) ) + continue; + + if( mv_info_count[y_final_block][x_final_block] == -1 ) + mv_info_count[y_final_block][x_final_block] = 0; + + mv_info_count_i = mv_info_count[y_final_block][x_final_block]; + + if( mv_info_count_i >= Max_Candidates ) + continue; + + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[LIST_0].mv_x = mv[0]; + mv_info[y_final_block][x_final_block][mv_info_count_i].mv[LIST_0].mv_y = mv[1]; + mv_info[y_final_block][x_final_block][mv_info_count_i].ref_idx[LIST_0] = mv[2]; + + mv_info_overlap[y_final_block][x_final_block][mv_info_count_i] = findBlock_Overlap( x_final, y_final, x_final_block, y_final_block, BLOCK_SIZE ); + + mv_info_count[y_final_block][x_final_block]++; + + } + } + } + } + + Choose_Method = 2; + /* Loop though all block 4x4 in destination to choose the best */ + for( y_block = 0; y_block < ( SourceAux->PicSizeInMbs / SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); y_block++ ) + { + y = y_block * BLOCK_SIZE; + for( x_block = 0; x_block < ( SourceAux->PicWidthInMbs ) * ( MB_BLOCK_SIZE / BLOCK_SIZE ); x_block++ ) + { + x = x_block * BLOCK_SIZE; + + mv_info_count_i = mv_info_count[y_block][x_block]; + + if( mv_info_count_i >= 0 ) + { + if( mv_info_count_i > 1 ) + { + if( Choose_Method == 1 ) + { + //Most overlaped + mv_info_count_i = i_max_position( mv_info_overlap[y_block][x_block], mv_info_count_i, NULL, NULL ); + mv_info_count[y_block][x_block] = mv_info_count_i; + } + else if( Choose_Method == 2 ) + { + double sum_x = 0, sum_y = 0, sum_over = 0; + int ref_flag; + if( mv_info_count_i == 1 ) + { + ref_flag = mv_info[y_block][x_block][0].ref_idx[LIST_0]; + sum_x += (double) mv_info[y_block][x_block][0].mv[LIST_0].mv_x; + sum_y += (double) mv_info[y_block][x_block][0].mv[LIST_0].mv_y; + } + else + { + ref_flag = mv_info[y_block][x_block][0].ref_idx[LIST_0]; + for( i = 0; i < mv_info_count_i; i++ ) + { + if( ref_flag == mv_info[y_block][x_block][i].ref_idx[LIST_0] ) + { + //sum_x += (double)mv_info[y_block][x_block][i].mv[LIST_0].mv_x * (double)mv_info_overlap[y_block][x_block][i]; + //sum_y += (double)mv_info[y_block][x_block][i].mv[LIST_0].mv_y * (double)mv_info_overlap[y_block][x_block][i]; + //sum_over += (double)(mv_info_overlap[y_block][x_block][i]); + if( mv_info[y_block][x_block][i].mv[LIST_0].mv_x == 0 && mv_info[y_block][x_block][i].mv[LIST_0].mv_y == 0 ) + continue; + + sum_x += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_x; + sum_y += (double) mv_info[y_block][x_block][i].mv[LIST_0].mv_y; + sum_over += (double) ( 1 ); + + } + } + } + sum_over = sum_over ? sum_over : 1; + mv_info[y_block][x_block][0].mv[LIST_0].mv_x = (short) ( sum_x / sum_over ); + mv_info[y_block][x_block][0].mv[LIST_0].mv_y = (short) ( sum_y / sum_over ); + mv_info[y_block][x_block][0].ref_idx[LIST_0] = ref_flag; + + mv_info_count_i = 0; + mv_info_count[y_block][x_block] = mv_info_count_i; + } + } + else + { + mv_info_count_i = 0; + } + } + mv_info_count[y_block][x_block] = mv_info_count_i; + } + } + + free_mem3Dint( mv_info_overlap ); + + ( *Matrix_MV_Info ).mv_info = mv_info; + ( *Matrix_MV_Info ).mv_info_count = mv_info_count; + + return; +} + +static int GetBest4x4Disparity( VideoParameters *p_Vid, StorablePicture *p_Input, StorablePicture *p_Output, double MeanDisparity, unsigned int y_block4x4, + unsigned int x_block4x4, int out_block_size, int disp_block_size ) +{ + imgpel *img_pel = (imgpel *) malloc( disp_block_size * disp_block_size * sizeof(imgpel) ); + int i, j, x_start, y_start, x_end, y_end, ii, n_elem; + unsigned int x, y; + double average_n; + + int return_value = 0; + //int max_disparity = 255 / p_Vid->p_Inp->DisparityWindow; + int max_disparity = 2 * MeanDisparity; + char MODE = 2; + + if( p_Output != NULL ) + { + if( MODE == 1 ) + { + cvResizeStorablePicture( p_Vid, p_Input, p_Output ); + } + else + { + for( y_block4x4 = 0; y_block4x4 < ( p_Input->PicSizeInMbs / p_Input->PicWidthInMbs ) * ( MB_BLOCK_SIZE / out_block_size ); y_block4x4++ ) + { + y = y_block4x4 * out_block_size; + for( x_block4x4 = 0; x_block4x4 < p_Input->PicWidthInMbs * ( MB_BLOCK_SIZE / out_block_size ); x_block4x4++ ) + { + x = x_block4x4 * out_block_size; + + x_start = iClip3( 0, p_Input->size_x - disp_block_size, x - ( ( disp_block_size - out_block_size ) / 2 ) ); + y_start = iClip3( 0, p_Input->size_y - disp_block_size, y - ( ( disp_block_size - out_block_size ) / 2 ) ); + + x_end = x_start + disp_block_size; + y_end = y_start + disp_block_size; + + ii = 0; + for( i = y_start; i < y_end; i++ ) + { + for( j = x_start; j < x_end; j++ ) + { + img_pel[ii++] = p_Input->imgY[i][j]; + } + } + + if( MODE == 2 ) + { + //! Average + for( ii = 0, n_elem = 0, average_n = 0; ii < disp_block_size * disp_block_size; ii++ ) + { + if( img_pel[ii] == 0 ) + continue; + if( img_pel[ii] >= max_disparity ) + continue; + + n_elem++; + average_n += img_pel[ii]; + } + if( n_elem ) + { + average_n = average_n / (double) ( n_elem ); + p_Output->imgY[y_block4x4][x_block4x4] = (imgpel) ( average_n ); + } + else + { + double d_1, d_2, d_3, d_a, d_n; + d_1 = d_2 = d_3 = d_a = d_n = 0; + if( y_block4x4 != 0 ) + { + d_1 = p_Output->imgY[y_block4x4 - 1][x_block4x4]; + d_n++; + } + if( x_block4x4 != 0 ) + { + d_2 = p_Output->imgY[y_block4x4][x_block4x4 - 1]; + d_n++; + } + if( y_block4x4 != 0 && x_block4x4 != 0 ) + { + d_3 = p_Output->imgY[y_block4x4][x_block4x4 - 1]; + d_n++; + } + if( d_n == 0 ) + { + p_Output->imgY[y_block4x4][x_block4x4] = MeanDisparity; + } + else + { + d_a = ( d_1 + d_2 + d_3 ) / 3.0; + p_Output->imgY[y_block4x4][x_block4x4] = d_a; + } + + } + } + else + { + //! Median + qsort( img_pel, disp_block_size * disp_block_size, sizeof(imgpel), sort_imgpel_up ); + p_Output->imgY[y_block4x4][x_block4x4] = ( img_pel[disp_block_size / 2] + img_pel[disp_block_size / 2 + 1] + 1 ) >> 1; + } + } + } + } + } + else + { + for( y = y_block4x4 * out_block_size, i = 0; y < ( y_block4x4 * out_block_size + out_block_size ); y++ ) + for( x = x_block4x4 * out_block_size; x < ( x_block4x4 * out_block_size + out_block_size ); x++ ) + img_pel[i++] = p_Input->imgY[y][x]; + + if( MODE == 2 ) + { + //! Average + for( ii = 0, n_elem = 0, average_n = 0; ii < out_block_size * out_block_size; ii++ ) + { + if( img_pel[ii] > THRESHOLD_DISP ) + continue; + + n_elem++; + average_n = average_n + ( ( img_pel[ii] - average_n ) / n_elem ); + } + return_value = (imgpel) ( average_n ); + } + else + { + //! Median + qsort( img_pel, out_block_size * out_block_size, sizeof(imgpel), sort_imgpel_up ); + return_value = ( img_pel[7] + img_pel[8] + 1 ) >> 1; + } + } + + free( img_pel ); + return return_value; +} + +int DisparityProjection( VideoParameters *p_Vid, StorablePicture *Ref_Disparity, StorablePicture *Ref_Picture, Slice *Ref_Slice, + StorablePicture **New_Disparity, int Block_Size, int ProjectedPOC, int method ) +{ + int y_block4x4, x_block4x4; + double scale_factor; + int mv[3], need_concealment = 1, mb_width, mb_height; + // Init variables + unsigned int y, x, idx_mb; + Macroblock *currMB; + imgpel *storeYUV, **tmp_block_pred; + int FinalList, List, N_mv_Concealment = 0; + + if( ( *New_Disparity ) == NULL ) + { + ( *New_Disparity ) = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + ( *New_Disparity )->PicSizeInMbs = Ref_Disparity->PicSizeInMbs; + ( *New_Disparity )->PicWidthInMbs = Ref_Disparity->PicWidthInMbs; + ( *New_Disparity )->poc = ProjectedPOC; + ( *New_Disparity )->chroma_format_idc = Ref_Disparity->chroma_format_idc; + ( *New_Disparity )->pixel_factor = Ref_Disparity->pixel_factor; + } + + //! Alloc memory for temp blocks + get_mem2Dpel( &tmp_block_pred, MB_BLOCK_SIZE, MB_BLOCK_SIZE ); + if( ( *New_Disparity )->chroma_format_idc != YUV400 ) + { + //int get_mem3Dpel(imgpel ****array3D, int dim0, int dim1, int dim2) + get_mem1Dpel( &storeYUV, ( ( Block_Size * Block_Size ) + ( p_Vid->mb_cr_size_x * p_Vid->mb_cr_size_y ) * 2 / 16 ) ); + } + else + { + get_mem1Dpel( &storeYUV, Block_Size * Block_Size ); + } + + mb_width = ( *New_Disparity )->PicWidthInMbs; + mb_height = ( ( *New_Disparity )->PicSizeInMbs ) / ( ( *New_Disparity )->PicWidthInMbs ); + + if( method == 1 ) + { + /* Loop though all motion vectors */ + for( y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / Block_Size; y_block4x4++ ) + { + y = y_block4x4 * Block_Size; + for( x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / Block_Size; x_block4x4++ ) + { + need_concealment = 1; + + x = x_block4x4 * Block_Size; + + //! get MB - not exact - dont work for currSlice->mb_aff_frame_flag = 1 + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idx_mb] ); + + currMB->p_Slice = Ref_Slice; + + // Update coordinates of the current concealed macroblock + currMB->mb.x = (short) ( x / Block_Size ); + currMB->mb.y = (short) ( y / Block_Size ); + currMB->block_y = currMB->mb.y * Block_Size; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y / 4; + currMB->block_x = currMB->mb.x * Block_Size; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x / 4; + + FinalList = Ref_Picture->slice_type == B_SLICE ? LIST_1 : LIST_0; + + for( List = LIST_0; List <= FinalList; List++ ) + { + mv[0] = Ref_Picture->mv_info[y_block4x4][x_block4x4].mv[List].mv_x; + mv[1] = Ref_Picture->mv_info[y_block4x4][x_block4x4].mv[List].mv_y; + mv[2] = Ref_Picture->mv_info[y_block4x4][x_block4x4].ref_idx[List]; //Reference Frame + + if( Ref_Picture->mv_info[y_block4x4][x_block4x4].ref_idx[List] >= 0 ) + { + scale_factor = (float) ( Ref_Picture->poc - Ref_Disparity->poc ) / (float) ( Ref_Picture->poc - Ref_Slice->listX[List][mv[2]]->poc ); + scale_factor = scale_factor ? scale_factor : 1; + mv[0] = (int) ( (float) ( mv[0] ) * scale_factor ); + mv[1] = (int) ( (float) ( mv[1] ) * scale_factor ); + + buildPredblockRegionYUV( p_Vid, Ref_Disparity, currMB, mv, x, y, storeYUV, Block_Size, tmp_block_pred, 1 ); + + ( *New_Disparity )->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = mv[0]; + ( *New_Disparity )->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = mv[1]; + ( *New_Disparity )->mv_info[y_block4x4][x_block4x4].ref_idx[List] = mv[2]; + + need_concealment = 0; + break; + } + } + if( need_concealment ) + { + N_mv_Concealment++; + //conceal motion vector + ConcealMotionVector( p_Vid, ( *New_Disparity ), Ref_Slice, y_block4x4, x_block4x4, AVERAGE, LIST_0, mv, 0 ); + // Scale mv + //Dont need scalling because the vectors have already been modified + //scale_factor = (float)( Source->poc - currRef->poc ) / (float)( Dest->poc - currRef->poc ); + scale_factor = 1; + mv[0] = (int) ( (float) ( mv[0] ) * scale_factor ); + mv[1] = (int) ( (float) ( mv[1] ) * scale_factor ); + + buildPredblockRegionYUV( p_Vid, Ref_Disparity, currMB, mv, x, y, storeYUV, Block_Size, tmp_block_pred, 1 ); + } + copyPredblockRegionYUVDestination( ( *New_Disparity ), storeYUV, x, y, BLOCK_SIZE ); + } + } + } + else if( method == 2 ) + { + MotionPropInfo Matrix_MV_Info; + int mv_info_count_i; + int temporal_ref_idx = -1; + + getINTRAMotionVectorCandidates( p_Vid, Ref_Picture, Ref_Slice, ( *New_Disparity ), &Matrix_MV_Info, NULL, 2, 0 ); + + for( y_block4x4 = 0; y_block4x4 < Ref_Slice->listXsize[LIST_0]; y_block4x4++ ) + { + if( Ref_Slice->listX[LIST_0][y_block4x4]->poc == Ref_Picture->poc ) + { + temporal_ref_idx = y_block4x4; + break; + } + } + + /* Loop though all motion vectors */ + for( y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / Block_Size; y_block4x4++ ) + { + y = y_block4x4 * Block_Size; + for( x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / Block_Size; x_block4x4++ ) + { + x = x_block4x4 * Block_Size; + + //! get MB - not exact - dont work for currSlice->mb_aff_frame_flag = 1 + idx_mb = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idx_mb] ); + + currMB->p_Slice = Ref_Slice; + + // Update coordinates of the current concealed macroblock + currMB->mb.x = (short) ( x / Block_Size ); + currMB->mb.y = (short) ( y / Block_Size ); + currMB->block_y = currMB->mb.y * Block_Size; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y / 4; + currMB->block_x = currMB->mb.x * Block_Size; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x / 4; + + mv_info_count_i = Matrix_MV_Info.mv_info_count[y_block4x4][x_block4x4]; + + //get motion vector + if( mv_info_count_i >= 0 ) + { + //! improve this + mv[0] = Matrix_MV_Info.mv_info[y_block4x4][x_block4x4][mv_info_count_i].mv[LIST_0].mv_x; + mv[1] = Matrix_MV_Info.mv_info[y_block4x4][x_block4x4][mv_info_count_i].mv[LIST_0].mv_y; + + mv[2] = temporal_ref_idx; + } + else + { + N_mv_Concealment++; + //conceal motion vector + ConcealMotionVector( p_Vid, ( *New_Disparity ), Ref_Slice, y_block4x4, x_block4x4, ZERO_MV, LIST_0, mv, temporal_ref_idx ); + //Dont need scalling because the vectors have already been modified + } + // memset(storeYUV,0,((Block_Size*Block_Size) + (Block_Size*Block_Size/4)) * sizeof(imgpel)); + buildPredblockRegionYUV( p_Vid, Ref_Disparity, currMB, mv, x, y, storeYUV, Block_Size, tmp_block_pred, 1 ); + + ( *New_Disparity )->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = mv[0]; + ( *New_Disparity )->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = mv[1]; + ( *New_Disparity )->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = mv[2]; + + copyPredblockRegionYUVDestination( ( *New_Disparity ), storeYUV, x, y, BLOCK_SIZE ); + } + } + + if( Matrix_MV_Info.mv_info ) + free_mem3Dmp( Matrix_MV_Info.mv_info ); + + if( Matrix_MV_Info.mv_info ) + free_mem2Dint( Matrix_MV_Info.mv_info_count ); + + } + else + { + return 0; + } + //! Debug reports + printf( "[FERC] Number of Concealed mv %d for Disparity Projection\n", N_mv_Concealment ); + + free_mem2Dpel( tmp_block_pred ); + free_mem1Dpel( storeYUV ); + return 1; +} + +void getDisparityMap( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, StorablePicture *Reference, int SearchView, StorablePicture **ppDisparity ) +{ + StorablePicture *Dest = IntraInterConc->Destination; + StorablePicture *NonRefFrame; + StorablePicture *Disparity; + int DisparityDirection = 0; + int i, j, nElem; + double MeanDisp; + + if( ( *ppDisparity ) ) + { + return; + } + + NonRefFrame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[SearchView], Reference->poc, SearchView, EXACT, 0, NULL ); + + printf( "[FERC] Disparity measurement using frame %2d|%2d as reference\n", Reference->poc, Reference->view_id ); + + if( NonRefFrame->view_id > Reference->view_id ) + { + DisparityDirection = IntraInterConc->DisparityDirection; + } + else + { + DisparityDirection = ( -1 ) * IntraInterConc->DisparityDirection; + } + +#if( _DEBUG ) + //showStorablePicture( p_Vid , Reference , 0 , 0 , "Disparity Reference Frame", 0); + //showStorablePicture( p_Vid , NonRefFrame , 0 , 0 , "Disparity Non Reference Frame", 0); +#endif + + Disparity = ( *ppDisparity ) = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + + cvDisparity( p_Vid, Reference, NonRefFrame, Disparity, IntraInterConc->DisparityMethod, IntraInterConc->DisparityWindow, DisparityDirection ); + + // if (p_Vid->p_Inp->DisparityMethod != 0 && p_Vid->p_Inp->DispLoadFileName[0] != 0) + // { + // saveStorablePicture(p_Vid, p_Vid->p_Inp->DispLoadFileName, Disparity, 0, 0); + // } + + Disparity->PicSizeInMbs = Dest->PicSizeInMbs; + Disparity->PicWidthInMbs = Dest->PicWidthInMbs; + Disparity->poc = Reference->poc; + Disparity->chroma_format_idc = 0; + Disparity->pixel_factor = IntraInterConc->DisparityWindow; + + // Normalize the disparity map + nElem = 0; + MeanDisp = 0; + for( i = 0; i < Disparity->size_x; i++ ) + { + for( j = 0; j < Disparity->size_y; j++ ) + { + Disparity->imgY[j][i] = (imgpel) ( (double) ( Disparity->imgY[j][i] ) / (double) ( IntraInterConc->DisparityWindow ) ); + MeanDisp = (double) ( MeanDisp * nElem + (double) ( Disparity->imgY[j][i] ) ) / (double) ( nElem + 1 ); + nElem++; + } + } + Disparity->mean_value = MeanDisp; + return; +} + +void getDisparityINTERConcealment( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc ) +{ + StorablePicture *Dest = IntraInterConc->Destination; + StorablePicture *Disparity = NULL, *FinalDisparity = NULL, *DisparityBlockWise = NULL; + StorablePicture *RefProjFrame = NULL; + Slice *pSliceRefProjFrame = NULL; + int DisparityReference = IntraInterConc->DisparityReference; + + DisparityBlockWise = alloc_storable_picture( p_Vid, FRAME, p_Vid->width / BLOCK_SIZE, p_Vid->height / BLOCK_SIZE, p_Vid->width_cr / BLOCK_SIZE, + p_Vid->height_cr / BLOCK_SIZE, 1 ); + + if( DisparityReference == 0 ) + { + getDisparityMap( p_Vid, IntraInterConc, IntraInterConc->InterRefFrameMinus1, Dest->view_id, &( IntraInterConc->DisparityBaseMinus1 ) ); + Disparity = IntraInterConc->DisparityBaseMinus1; + RefProjFrame = IntraInterConc->InterRefFrame; + pSliceRefProjFrame = IntraInterConc->SliceInterViewReference; + IntraInterConc->DisparityBlockwiseBase = DisparityBlockWise; + } + else + { + getDisparityMap( p_Vid, IntraInterConc, IntraInterConc->IntraRefFrame, IntraInterConc->InterRefFrame->view_id, &( IntraInterConc->DisparityAuxMinus1 ) ); + Disparity = IntraInterConc->DisparityAuxMinus1; + RefProjFrame = IntraInterConc->IntraRefFrame; + pSliceRefProjFrame = IntraInterConc->SliceIntraViewReference; + IntraInterConc->DisparityBlockwiseAux = DisparityBlockWise; + } + + DisparityProjection( p_Vid, Disparity, RefProjFrame, pSliceRefProjFrame, &FinalDisparity, BLOCK_SIZE, Dest->poc, DisparityReference == 0 ? 1 : 2 ); + //showStorablePicture(p_Vid, IntraInterConc->InterRefFrame, 0, 0, "InterRefFrame", 0); + //GetBest4x4Disparity(p_Vid, Disparity, DisparityBlockWise, Disparity->mean_value, 0, 0, BLOCK_SIZE, p_Vid->p_Inp->Disparity4x4BlockSize); + GetBest4x4Disparity( p_Vid, FinalDisparity, DisparityBlockWise, Disparity->mean_value, 0, 0, BLOCK_SIZE, p_Vid->p_Inp->Disparity4x4BlockSize ); + + //showStorablePicture(p_Vid, Disparity, 0, 0, "Disparity", 0); + + free_storable_picture( FinalDisparity ); + + //cvLoadStorablePicture(p_Vid, "DisparityBlock.pgm", IntraInterConc->DisparityBlockwiseBase, 0, 0); + //showStorablePicture(p_Vid,IntraInterConc->DisparityBlockwiseBase,0,0,"DisparityBlock",0); + +} + +void getMVIntra( INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int *MV ) +{ + int intra_mv_cnt; + //! check INTRA mv candidate + if( ( intra_mv_cnt = IntraInterConc->IntraMVCandidates.mv_info_count[y_block][x_block] ) >= 0 ) + { + MV[0] = IntraInterConc->IntraMVCandidates.mv_info[y_block][x_block][intra_mv_cnt].mv[LIST_0].mv_x; + MV[1] = IntraInterConc->IntraMVCandidates.mv_info[y_block][x_block][intra_mv_cnt].mv[LIST_0].mv_y; + MV[2] = IntraInterConc->IntraMVCandidates.mv_info[y_block][x_block][intra_mv_cnt].ref_idx[LIST_0]; + MV[2] = IntraInterConc->MVExtrapolationRefIdx[MV[2]]; + } + else + { + MV[0] = MV[1] = 0; + MV[2] = -1; + } +} + +void getMVInterview( INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int *MV ) +{ + StorablePicture *Dest = IntraInterConc->Destination; + StorablePicture *DisparityBlockwise = IntraInterConc->DisparityBlockwiseAux; + int DisparityDirection = IntraInterConc->DisparityDirection; + int x, y; + + MV[0] = MV[1] = 0; + MV[2] = -1; + + if( list == LIST_1 ) + return; + + x = x_block * BLOCK_SIZE; + y = y_block * BLOCK_SIZE; + + if( x + ( -1 * DisparityDirection ) * (int) ( DisparityBlockwise->imgY[y_block][x_block] ) + != iClip3( 0, Dest->size_x - 1, x + ( -1 * DisparityDirection ) * (int) ( DisparityBlockwise->imgY[y_block][x_block] ) ) ) + { + return; + } + else + { + MV[0] = ( ( -1 * DisparityDirection ) * (int) ( DisparityBlockwise->imgY[y_block][x_block] ) ) * 4; + MV[1] = 0; + } + MV[2] = IntraInterConc->MVExtrapolationRefIdx[1]; + +} + +void getMVENHANCEDMVE( INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int *MV ) +{ + int intra_mv_cnt; + //! check INTRA mv candidate + if( ( intra_mv_cnt = IntraInterConc->InterIntraMVCandidates.mv_info_count[y_block][x_block] ) >= 0 ) + { + MV[0] = IntraInterConc->InterIntraMVCandidates.mv_info[y_block][x_block][intra_mv_cnt].mv[LIST_0].mv_x; + MV[1] = IntraInterConc->InterIntraMVCandidates.mv_info[y_block][x_block][intra_mv_cnt].mv[LIST_0].mv_y; + MV[2] = IntraInterConc->InterIntraMVCandidates.mv_info[y_block][x_block][intra_mv_cnt].ref_idx[LIST_0]; + MV[2] = IntraInterConc->MVExtrapolationRefIdx[MV[2]]; + } + else + { + MV[0] = MV[1] = 0; + MV[2] = -1; + } +} + +void getMVInter( INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int *MV ) +{ + StorablePicture *Disp = NULL; + StorablePicture *InterRefFrame = IntraInterConc->InterRefFrame; + MotionPropInfo InterMVCandidates = IntraInterConc->InterMVCandidates; + int DispDir = -1 * IntraInterConc->DisparityDirection; + int Width = IntraInterConc->p_Vid->width; + int inter_src_block, inter_mv_cnt; + + MV[0] = MV[1] = 0; + MV[2] = -1; + + switch( IntraInterConc->DisparityReference ) + { + case 0: + Disp = IntraInterConc->DisparityBlockwiseBase; + if( ( inter_mv_cnt = InterMVCandidates.mv_info_count_lists[y_block][x_block][list] ) >= 0 ) + { + MV[0] = InterMVCandidates.mv_info[y_block][x_block][inter_mv_cnt].mv[list].mv_x; + MV[1] = InterMVCandidates.mv_info[y_block][x_block][inter_mv_cnt].mv[list].mv_y; + MV[2] = InterMVCandidates.mv_info[y_block][x_block][inter_mv_cnt].ref_idx[list]; + MV[2] = MV[2] < 0 ? MV[2] : IntraInterConc->InterMapList[list][MV[2]]; + } + break; + case 1: + Disp = IntraInterConc->DisparityBlockwiseAux; + //! Get source base block based on pixel position and then + inter_src_block = iClip3( 0, Width, x_block * BLOCK_SIZE + DispDir * (int) ( Disp->imgY[y_block][x_block] ) ); + inter_src_block = inter_src_block / BLOCK_SIZE; // + (((inter_src_block%BLOCK_SIZE)&0x2)>>1); + + MV[0] = InterRefFrame->mv_info[y_block][inter_src_block].mv[list].mv_x; + MV[1] = InterRefFrame->mv_info[y_block][inter_src_block].mv[list].mv_y; + MV[2] = InterRefFrame->mv_info[y_block][inter_src_block].ref_idx[list]; + MV[2] = MV[2] < 0 ? MV[2] : IntraInterConc->InterMapList[list][MV[2]]; + break; + } +} + +static inline int target_cluster( int n ) +{ + switch( n ) + { + case 0: + return 1; + case 4: + return 4; + case 8: + return 16; + default: + return 0; + } +} + +int MotionSearchDynamic( imgpel* refFrame, int stepBytesRF /*stride*/, imgpel* curBlock, int stepBytesCB /*stride*/, int* matchBlock /*results*/, int x_pos, + int y_pos, int frameWidth, int frameHeight, int block_size, int search_window ) +{ + int i, j, k, l; + int lowSum = INT_MAX; + int temSum = 0; + int blockHeight = block_size; + int blockWidth = block_size; + const imgpel *pRef, *pCur; + int x_start, y_start, x_limit, y_limit; + + x_start = imax( 0, x_pos - search_window ); + x_limit = imin( frameWidth - blockWidth, x_pos + search_window ); + + y_start = imax( 0, y_pos - search_window ); + y_limit = imin( frameHeight - blockHeight, y_pos + search_window ); + + for( i = y_start; i <= y_limit; i++ ) + { + for( j = x_start; j <= x_limit; j++ ) + { + temSum = 0; + pCur = curBlock; + pRef = refFrame + i * stepBytesRF + j; + for( k = 0; k < blockHeight; k++ ) + { + for( l = 0; l < blockWidth; l++ ) + { + temSum += abs( *pRef - *pCur ); + pCur++; + pRef++; + } + pCur += stepBytesCB - blockWidth; + pRef += stepBytesRF - blockWidth; + } + if( temSum < lowSum ) + { + lowSum = temSum; + *matchBlock = j; + *( matchBlock + 1 ) = i; + } + } + } + return 0; +} + +//static void DisparityCompensation( VideoParameters *p_Vid, StorablePicture *Ref, StorablePicture *Output, StorablePicture *Disparity, int Direction ) +//{ +// int i, j; +// int disp = 0; +// for( i = 0; i < p_Vid->width; i++ ) +// { +// for( j = 0; j < p_Vid->height; j++ ) +// { +// disp = Direction * (int) ( Disparity->imgY[j][i] / Disparity->pixel_factor ); +// Output->imgY[j][i] = Ref->imgY[j][i + disp]; +// } +// } +// return; +//} + +void getDisparityMapForLostFrame( VideoParameters *p_Vid, StorablePicture *Dest, StorablePicture *IntraRefFrame, StorablePicture *RefProjFrame, + Slice *pSliceRefProjFrame, StorablePicture **ppDisparity, StorablePicture **ppDisparity4x4, int DisparityReference, int DisparityDirection, + int DisparityProjectionFlag ) +{ + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + StorablePicture *AuxRefFrame, *BaseRefFrame; + StorablePicture *Ref_Disparity, *Final_Disparity; + StorablePicture *Disparity4x4; + int iRet, i, j; + int nElem; + double MeanDisp; + AuxRefFrame = IntraRefFrame; + //fercGetPictureForConcealFromDpb(p_Vid->p_Dpb_layer[1], Dest->poc, 1, CLOSEST_FUTURE, 0, NULL); + BaseRefFrame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[0], AuxRefFrame->poc, 0, EXACT, 0, NULL ); + + Final_Disparity = ( *ppDisparity ) = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + + //if( !AuxRefFrame->disparity ) + { +#if( _DEBUG ) + //showStorablePicture( p_Vid , BaseRefFrame , 0 , 0 , "Base", 0); + //showStorablePicture( p_Vid , AuxRefFrame , 0 , 0 , "Auxiliary", 0); +#endif + + if( DisparityReference == 0 ) + { + if( BaseRefFrame->disparity ) + { + Ref_Disparity = BaseRefFrame->disparity; + } + else + { + printf( "[FERC] Disparity measurement using frame %2d|%2d as reference\n", BaseRefFrame->poc, BaseRefFrame->view_id ); + + Ref_Disparity = BaseRefFrame->disparity = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + cvDisparity( p_Vid, BaseRefFrame, AuxRefFrame, Ref_Disparity, p_Vid->p_Inp->DisparityMethod, p_Vid->p_Inp->DisparityWindow, + p_Vid->p_Inp->DisparityDirection ); + } + } + else if( DisparityReference == 1 ) + { + if( BaseRefFrame->disparity ) + { + Ref_Disparity = AuxRefFrame->disparity; + } + else + { + printf( "[FERC] Disparity measurement using frame %2d|%2d as reference\n", AuxRefFrame->poc, AuxRefFrame->view_id ); + Ref_Disparity = AuxRefFrame->disparity = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1 ); + cvDisparity( p_Vid, AuxRefFrame, BaseRefFrame, Ref_Disparity, p_Vid->p_Inp->DisparityMethod, p_Vid->p_Inp->DisparityWindow, DisparityDirection ); + } + } + + if( p_Vid->p_Inp->DisparityMethod != 0 && p_Vid->p_Inp->DispLoadFileName[0] != 0 ) + { + saveStorablePicture( p_Vid, p_Vid->p_Inp->DispLoadFileName, Ref_Disparity, 0, 0 ); + } + //#if( _DEBUG ) + //showStorablePicture( p_Vid , Ref_Disparity , 0 , 0 , "Original Disparity", 0); + //saveStorablePicture( p_Vid , "Disparity_Original.pgm", Ref_Disparity , 0 , 0 ); + //#endif + Ref_Disparity->PicSizeInMbs = Dest->PicSizeInMbs; + Ref_Disparity->PicWidthInMbs = Dest->PicWidthInMbs; + Ref_Disparity->poc = AuxRefFrame->poc; + Ref_Disparity->chroma_format_idc = 0; + Ref_Disparity->pixel_factor = p_Vid->p_Inp->DisparityWindow; + + // Normalize the disparity map + nElem = 0; + MeanDisp = 0; + for( i = 0; i < Ref_Disparity->size_x; i++ ) + for( j = 0; j < Ref_Disparity->size_y; j++ ) + { + Ref_Disparity->imgY[j][i] = (imgpel) ( (double) ( Ref_Disparity->imgY[j][i] ) / (double) ( p_Vid->p_Inp->DisparityWindow ) ); + MeanDisp = (double) ( MeanDisp * nElem + (double) ( Ref_Disparity->imgY[j][i] ) ) / (double) ( nElem + 1 ); + nElem++; + } +#if( _DEBUG ) + // showStorablePicture( p_Vid , Ref_Disparity , 0 , 0 , "Normalized Disparity", 0); +#endif + } + + Final_Disparity->PicSizeInMbs = Ref_Disparity->PicSizeInMbs; + Final_Disparity->PicWidthInMbs = Ref_Disparity->PicWidthInMbs; + Final_Disparity->chroma_format_idc = Ref_Disparity->chroma_format_idc; + Final_Disparity->pixel_factor = Ref_Disparity->pixel_factor; + Final_Disparity->poc = Dest->poc; + + iRet = 1; + if( DisparityProjectionFlag ) // p_Vid->p_Inp->DisparityProjection + { + iRet = DisparityProjection( p_Vid, Ref_Disparity, RefProjFrame, pSliceRefProjFrame, &Final_Disparity, Final_Disparity->poc, BLOCK_SIZE, + DisparityReference == 0 ? 1 : 2 ); + } + if( DisparityProjectionFlag == 0 || iRet == 0 ) + { + fercCopyImg( p_Vid, Ref_Disparity, Final_Disparity ); + } + + //#if( _DEBUG ) + // showStorablePicture( p_Vid , Final_Disparity , 0 , 0 , "Projected Disparity", 0); + // saveStorablePicture( p_Vid , "Disparity_Projected.pgm", Final_Disparity , 0 , 0 ); + //#endif + + *( ppDisparity4x4 ) = alloc_storable_picture( p_Vid, FRAME, p_Vid->width / BLOCK_SIZE, p_Vid->height / BLOCK_SIZE, p_Vid->width_cr / BLOCK_SIZE, + p_Vid->height_cr / BLOCK_SIZE, 1 ); + Disparity4x4 = *( ppDisparity4x4 ); + GetBest4x4Disparity( p_Vid, Final_Disparity, Disparity4x4, MeanDisp, 0, 0, BLOCK_SIZE, p_Vid->p_Inp->Disparity4x4BlockSize ); + + //#if( _DEBUG ) + // showStorablePicture( p_Vid , Final_Disparity , 0 , 0 , "Projected Disparity", 0); + // saveStorablePicture( p_Vid , "Disparity_Projected.pgm", Final_Disparity , 0 , 0 ); + // showStorablePicture( p_Vid , Disparity4x4 , 0 , 0 , "Disparity4x4", 0); + // saveStorablePicture( p_Vid , "Disparity_4x4.pgm", Disparity4x4 , 0 , 0 ); + //#endif + + free_storable_picture( Ref_Disparity ); + Ref_Disparity = BaseRefFrame->disparity = AuxRefFrame->disparity = NULL; + + return; +} + +/*! + ************************************************************************ + * \brief + * Update Macroblock information + ************************************************************************ + */ +static inline void updateMBData( VideoParameters *p_Vid, Slice *slice, int mb_idx, int x, int y, int blocksize ) +{ + Macroblock *currMB = &( p_Vid->mb_data[mb_idx] ); + + currMB->mb.x = (short) ( x / blocksize ); + currMB->mb.y = (short) ( y / blocksize ); + currMB->block_y = currMB->mb.y * blocksize; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y / 4; + currMB->block_x = currMB->mb.x * blocksize; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x / 4; + currMB->p_Slice = slice; +} + +/*! + ************************************************************************ + * \brief + * Copy a block to a bigger block in separate components + ************************************************************************ + */ +void copyPredblockRegionYUVSeparated( imgpel ***Destination, imgpel *predBlock, int x, int y, int BlockSize ) +{ + int ii, jj; + int uv; + + //! Y Matrix + for( ii = 0; ii < BlockSize; ii++ ) + for( jj = 0; jj < BlockSize; jj++ ) + Destination[0][y + ii][x + jj] = predBlock[ii * ( BlockSize ) + jj]; + + predBlock = predBlock + ( BlockSize * BlockSize ); + + for( uv = 1; uv <= 2; uv++ ) + { + for( ii = 0; ii < ( BlockSize / 2 ); ii++ ) + for( jj = 0; jj < ( BlockSize / 2 ); jj++ ) + Destination[uv][y / 2 + ii][x / 2 + jj] = predBlock[ii * ( BlockSize / 2 ) + jj]; + + predBlock = predBlock + ( BlockSize * BlockSize / 4 ); + } +} + +void copyPredblockRegionYUVSeparatedDestination( StorablePicture *Destination, imgpel ***Source, int x, int y, int BlockSize ) +{ + int ii, jj; + + //! Y Matrix + for( ii = 0; ii < BlockSize; ii++ ) + for( jj = 0; jj < BlockSize; jj++ ) + Destination->imgY[y + ii][x + jj] = Source[0][ii][jj]; + + //! UV Matrix + if( Destination->chroma_format_idc != YUV400 ) + { + int uv; + for( uv = 0; uv < 2; uv++ ) + { + for( ii = 0; ii < ( BlockSize / 2 ); ii++ ) + for( jj = 0; jj < ( BlockSize / 2 ); jj++ ) + Destination->imgUV[uv][y / 2 + ii][x / 2 + jj] = Source[uv + 1][ii][jj]; + } + } +} + +double compareBlockMSE( imgpel **storeYUV, int Block_Size ) +{ + unsigned long int Error = 0; + double MSE = 0; + int uv, y, x; + imgpel *A = storeYUV[MV_INTER], *B = storeYUV[MV_INTRA]; + + for( y = 0; y < Block_Size; y++ ) + { + for( x = 0; x < Block_Size; x++ ) + { + Error += iabs2( (int) ( *A ) - (int) ( *B ) ); + A++; + B++; + } + } + //for(uv=0; uv<2; uv++) + //{ + // for( y=0; yBlockConcealmentState; + double SAD_Value; + unsigned int SAD_Count; + int xb, yb, x, y; + int x_block, y_block; + int x_limit = Destination->size_x; + int y_limit = Destination->size_y; + + dst_x_pos = dst_x_pos - ( TotalSize - BlockSize ) / 2; + dst_y_pos = dst_y_pos - ( TotalSize - BlockSize ) / 2; + + if( src_x_pos != iClip3( 0, x_limit - 1, src_x_pos ) || src_y_pos != iClip3( 0, y_limit - 1, src_y_pos ) ) + return INT_MAX; + + src_x_pos = src_x_pos - ( TotalSize - BlockSize ) / 2; + src_y_pos = src_y_pos - ( TotalSize - BlockSize ) / 2; + + y_block = dst_y_pos / BLOCK_SIZE; + x_block = dst_x_pos / BLOCK_SIZE; + + SAD_Value = 0; + SAD_Count = 0; + for( yb = 0; yb < TotalSize / BLOCK_SIZE; yb++ ) + { + for( xb = 0; xb < TotalSize / BLOCK_SIZE; xb++ ) + { + if( y_block + yb >= 0 && x_block + xb >= 0 && y_block + yb < y_limit / BLOCK_SIZE && x_block + xb < x_limit / BLOCK_SIZE + && BlockConcealmentState->imgY[y_block + yb][x_block + xb] > 0 ) + { + for( x = 0; x < BLOCK_SIZE; x++ ) + { + for( y = 0; y < BLOCK_SIZE; y++ ) + { + if( dst_y_pos + yb * BLOCK_SIZE + y < 0 || dst_x_pos + xb * BLOCK_SIZE + x < 0 ) + continue; + if( dst_y_pos + yb * BLOCK_SIZE + y >= x_limit || dst_x_pos + xb * BLOCK_SIZE + x >= x_limit ) + continue; + if( src_y_pos + yb * BLOCK_SIZE + y < 0 || src_x_pos + xb * BLOCK_SIZE + x < 0 ) + continue; + if( src_y_pos + yb * BLOCK_SIZE + y >= y_limit || src_x_pos + xb * BLOCK_SIZE + x >= x_limit ) + continue; + SAD_Value += iabs( + (int) ( Destination->imgY[dst_y_pos + yb * BLOCK_SIZE + y][dst_x_pos + xb * BLOCK_SIZE + x] ) + - (int) ( Source->imgY[src_y_pos + yb * BLOCK_SIZE + y][src_x_pos + xb * BLOCK_SIZE + x] ) ); + SAD_Count += 1; + } + } + } + } + } + SAD_Value = SAD_Value / ( (double) SAD_Count ); + return SAD_Value; + +} +static void PrintDebugPGM( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, StorablePicture *Image, char *Name ) +{ + StorablePicture *Dest = IntraInterConc->Destination; + char out_ViewFileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + + strcpy( chBuf, p_Vid->p_Inp->outfile ); + pch = strrchr( chBuf, '.' ); + if( pch ) + *pch = '\0'; + if( !strcmp( "nul", chBuf ) ) + return; + sprintf( out_ViewFileName, "%s_%s_F%d_V%1d.pgm", chBuf, Name, Dest->poc, Dest->view_id ); + saveStorablePicture( p_Vid, out_ViewFileName, Image, 0, 0 ); +} + +static int GetThresholdHistogramBased( StorablePicture *Image, double SamplesThresh ) +{ +#define N_BINS 256 + int Threshold = 0; + int nSamples, y, x; + double count, Samples[N_BINS]; + + memset( Samples, 0, sizeof( Samples ) ); + + nSamples = Image->size_y * Image->size_x; + + for( y = 0; y < Image->size_y; y++ ) + for( x = 0; x < Image->size_x; x++ ) + Samples[Image->imgY[y][x]]++; + + for( x = 0; x < N_BINS; x++ ) + Samples[x] = Samples[x] / (double) nSamples; + + for( x = 0, count = 0; x < N_BINS && count < SamplesThresh; x++ ) + count += Samples[x]; + + Threshold = x - 1; + + Threshold = Threshold ? Threshold : 1; + + return Threshold; +} + +static void GetTemporalDifferenceFrame( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int ApplyFilter, double Threshold ) +{ + StorablePicture *TemporalDifference = IntraInterConc->TemporalDifference; + StorablePicture *TemporalDifferenceUnfiltred = NULL; + StorablePicture *IntraRefFrame = IntraInterConc->IntraRefFrame; + StorablePicture *IntraRefFrame_L0 = IntraInterConc->SliceIntraViewReference->listX[LIST_0][1]; + Slice *SliceIntraViewReference = IntraInterConc->SliceIntraViewReference; + StorablePicture *currRef; + int y, x, yf, xf, i; + int diff, mv[3], mvf[3] = { 0, 0, 0 }; + double scale_factor; + double mean_value = 0, n_samples = 0; + + if( ApplyFilter != NONE_FILTER ) + TemporalDifferenceUnfiltred = alloc_storable_picture( p_Vid, FRAME, p_Vid->width, p_Vid->height, 0, 0, 1 ); + else + TemporalDifferenceUnfiltred = TemporalDifference; + + for( i = 0; i < IntraInterConc->SliceIntraViewReference->listXsize[LIST_0]; i++ ) + { + if( IntraInterConc->SliceIntraViewReference->listX[LIST_0][i]->view_id == IntraRefFrame->view_id ) + { + IntraRefFrame_L0 = IntraInterConc->SliceIntraViewReference->listX[LIST_0][i]; + break; + } + } + + for( y = 0; y < p_Vid->height; y++ ) + { + mvf[0] = mvf[1] = 0; + for( x = 0; x < p_Vid->width; x++ ) + { + /* Update mv information - Read Reference Values */ + mv[0] = IntraRefFrame->mv_info[y >> 2][x >> 2].mv[LIST_0].mv_x; + mv[1] = IntraRefFrame->mv_info[y >> 2][x >> 2].mv[LIST_0].mv_y; + mv[2] = IntraRefFrame->mv_info[y >> 2][x >> 2].ref_idx[LIST_0]; + + if( mv[2] >= 0 ) + { + currRef = SliceIntraViewReference->listX[LIST_0][mv[2]]; + /* Disparity Vectors */ + if( !( SliceIntraViewReference->view_id != 0 && currRef->poc == IntraRefFrame->poc ) ) + { + // Scale mv + scale_factor = (double) ( IntraRefFrame->poc - IntraRefFrame_L0->poc ) / (double) ( IntraRefFrame->poc - currRef->poc ); + mv[0] = (int) ( (float) ( mv[0] ) * scale_factor ); + mv[1] = (int) ( (float) ( mv[1] ) * scale_factor ); + + mvf[0] = mv[0] >> 2; + mvf[1] = mv[1] >> 2; + } + + } + + xf = iClip3( 0, IntraRefFrame->size_x, x + mvf[0] ); + yf = iClip3( 0, IntraRefFrame->size_y, y + mvf[1] ); + + diff = iabs( (int) ( IntraRefFrame->imgY[y][x] ) - (int) ( IntraRefFrame_L0->imgY[yf][xf] ) ); + /*if( diff < -127 || diff > 127 ) + { + int a = 0; + }*/ + + diff = iClip3( -127, 127, diff ); + + TemporalDifferenceUnfiltred->imgY[y][x] = diff; + + mean_value = ( mean_value * n_samples + (double) ( diff ) ); + n_samples += 1; + mean_value /= n_samples; + + } + } + + TemporalDifferenceUnfiltred->mean_value = mean_value; + + if( ApplyFilter != NONE_FILTER ) + { + //! Filtering the temporal difference + cvImageFilter( p_Vid, TemporalDifferenceUnfiltred, TemporalDifference, MEDIAN_FILTER, 9 ); + free_storable_picture( TemporalDifferenceUnfiltred ); + } + + IntraInterConc->DifferenceThresholds[TEMPORAL_DIFF] = GetThresholdHistogramBased( TemporalDifference, Threshold ); + + printf( "[FERC] Temporal Diff Threshold: %d\n", IntraInterConc->DifferenceThresholds[TEMPORAL_DIFF] ); + + //showStorablePicture(p_Vid, TemporalDifference, 0, 0, "TemporalDifference", 0); + + PrintDebugPGM( p_Vid, IntraInterConc, TemporalDifference, "TemporalDifference" ); + +} + +static void GetSpatialDifferenceFrame( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int ApplyFilter, double Threshold ) +{ + StorablePicture *IntraRefFrame = IntraInterConc->IntraRefFrame; + StorablePicture *IntraRefFrameDisp = NULL; + StorablePicture *SpatialDifference = IntraInterConc->SpatialDifference; + StorablePicture *IntraRefFrame_D0; + int DisparityDirection = IntraInterConc->DisparityDirection; + int y, x; + int n, disp, diff; + double mean_disp = 0; + double mean_value = 0, n_samples = 0; + + IntraRefFrame_D0 = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[IntraInterConc->InterRefFrame->view_id], IntraRefFrame->poc, + IntraInterConc->InterRefFrame->view_id, EXACT, 0, NULL ); + + getDisparityMap( p_Vid, IntraInterConc, IntraRefFrame, IntraRefFrame_D0->view_id, &( IntraInterConc->DisparityAuxMinus1 ) ); + + IntraRefFrameDisp = IntraInterConc->DisparityAuxMinus1; + + //showStorablePicture(p_Vid, IntraRefFrameDisp, 1, 0, "[FERC] Test Dispartiy", 0); + + for( x = 0, n = 0; x < p_Vid->width; x++ ) + { + for( y = 0; y < p_Vid->height; y++ ) + { + disp = IntraRefFrameDisp->imgY[y][x]; + + disp = ( -1 * DisparityDirection ) * disp; + + //! In loop average value measurement + mean_disp = (double) ( mean_disp * n + disp ) / (double) ( n + 1 ); + n++; + + diff = iabs( (int) ( IntraRefFrame->imgY[y][x] ) - (int) ( IntraRefFrame_D0->imgY[y][x + disp] ) ); + /*if( diff < -127 || diff > 127 ) + { + int a = 0; + }*/ + + diff = iClip3( -127, 127, diff ); + + SpatialDifference->imgY[y][x] = diff; + + mean_value = ( mean_value * n_samples + (double) ( diff ) ); + n_samples += 1; + mean_value /= n_samples; + + } + } + + SpatialDifference->mean_value = mean_value; + + //! Lost of information, although not relevance for this studyMcDonalds loc: + IntraInterConc->MeanDisparityValue = mean_disp; + + IntraInterConc->DifferenceThresholds[SPATIAL_DIFF] = GetThresholdHistogramBased( SpatialDifference, Threshold ); + + printf( "[FERC] Spatial Diff Threshold: %d\n", IntraInterConc->DifferenceThresholds[SPATIAL_DIFF] ); + + //showStorablePicture(p_Vid, SpatialDifference, 0, 0, "Spatial Difference", 0); + + PrintDebugPGM( p_Vid, IntraInterConc, SpatialDifference, "SpatialDifference" ); +} + +static void ShowStageDebug( VideoParameters *p_Vid, StorablePicture *Dest, int Stage, char *StageName ) +{ + char Name[50]; + //return; + sprintf( Name, "Concealed Frame Stage %1d %s ", Stage, StageName ); + showStorablePicture( p_Vid, Dest, 0, 1, Name, 0 ); + sprintf( Name, "Concealed_Frame_Stage_%1d_%s.pgm", Stage, StageName ); + // saveStorablePicture(p_Vid, Name, Dest, 0, 0); +} + +/*! + ************************************************************************ + * \brief + * Definition of each Iteration and Main function + ************************************************************************ + */ + +/*! + ************************************************************************ + * \brief + * Conceal missing frame block MSE Based: + * Conceal if difference between predictors is lower than a specified threshold + ************************************************************************ + */ +static inline void ConcealCurrentClusterMSEBased( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_MB, int y_MB, int block_idx, + int *block_size, double MSEDiffThreshold ) +{ + StorablePicture *Dest = IntraInterConc->Destination; + imgpel ***storeYUV = IntraInterConc->storeYUV; + double tmp_MSE; + int cur_idx, max_clust, x_block, y_block; + int mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 }; + int idxMB = y_MB / MB_BLOCK_SIZE * Dest->PicWidthInMbs + x_MB / MB_BLOCK_SIZE; + int test_idx = 0; + + *block_size = 0; + cur_idx = block_idx; + + max_clust = CLUSTER[block_idx]; + max_clust += block_idx; + + cur_idx = block_idx; + while( cur_idx < max_clust ) + { + do + { + y_block = ( y_MB * MB_BLOCK_SIZE / BLOCK_SIZE ) + BLOCK_IDX_MB[cur_idx][1]; + x_block = ( x_MB * MB_BLOCK_SIZE / BLOCK_SIZE ) + BLOCK_IDX_MB[cur_idx][0]; + + if( IntraInterConc->BlockConcealmentState->imgY[y_block][x_block] > 0 ) + return; //!< Stop clustering + + getMVIntra( IntraInterConc, LIST_0, y_block, x_block, mv_intra ); + getMVInter( IntraInterConc, LIST_0, y_block, x_block, mv_inter ); + + if( mv_inter[2] < 0 || mv_intra[2] < 0 ) + return; //!< Stop clustering + + EnhancedbuildPredblock4x4YUV( p_Vid, mv_inter, x_block * BLOCK_SIZE, y_block * BLOCK_SIZE, storeYUV[LIST_0][MV_INTER], LIST_0, idxMB, + IntraInterConc->tmp_storeYUV ); + EnhancedbuildPredblock4x4YUV( p_Vid, mv_intra, x_block * BLOCK_SIZE, y_block * BLOCK_SIZE, storeYUV[LIST_0][MV_INTRA], LIST_0, idxMB, + IntraInterConc->tmp_storeYUV ); + + if( ( tmp_MSE = compareBlockMSE( storeYUV[LIST_0], BLOCK_SIZE ) ) <= MSEDiffThreshold ) + { + //ferc_bi_prediction( storeYUV[LIST_0][MV_INTER], storeYUV[LIST_0][MV_INTER], 1, storeYUV[LIST_0][MV_INTRA], 1, BLOCK_SIZE, BLOCK_SIZE, 1); + copyPredblockRegionYUVSeparated( IntraInterConc->storeSeparatedYUV, storeYUV[LIST_0][MV_INTER], BLOCK_IDX_MB[test_idx][0] * BLOCK_SIZE, + BLOCK_IDX_MB[test_idx][1] * BLOCK_SIZE, BLOCK_SIZE ); + + // set motion vector in the concealed picture + Dest->mv_info[y_block][x_block].mv[LIST_0].mv_x = mv_inter[0]; + Dest->mv_info[y_block][x_block].mv[LIST_0].mv_y = mv_inter[1]; + Dest->mv_info[y_block][x_block].ref_idx[LIST_0] = mv_inter[2]; + + test_idx++; + cur_idx++; + continue; + } + + return; + } while( cur_idx < block_idx + target_cluster( *block_size ) ); + ( *block_size ) = ( *block_size ) ? ( *block_size ) * 2 : BLOCK_SIZE; + } + return; +} +static int MSEBasedConcealmentStage( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc ) +{ + Slice *SliceDestiantion = IntraInterConc->SliceDestiantion; + StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState; + StorablePicture *Dest = IntraInterConc->Destination; + double BlockRatio, MSE_Threshold; + unsigned int MaxBlockNumber = ( p_Vid->width * p_Vid->height / iabs2( BLOCK_SIZE ) ); + int BlockSize, iBlock, y4x4, x4x4, y, x, iyMB, ixMB, idxMB, y_block4x4, x_block4x4, Iterations, BlockSizeThreshold, prev_nConcealed, nConcealed, mb_height, + mb_width; + + mb_width = Dest->PicWidthInMbs; + mb_height = ( Dest->PicSizeInMbs ) / ( Dest->PicWidthInMbs ); + nConcealed = 0; + BlockSizeThreshold = 16; + prev_nConcealed = 1; + BlockSize = 0; + + /* + * Loop through all Macroblocks and conceal the one based on the MSE value between the different prediction (INTRA and INTER) + */ + BlockRatio = 0.8; + while( BlockSizeThreshold >= 16 ) + { + for( Iterations = 0; /*((double) (nConcealed) < (double) (MaxBlockNumber) * BlockRatio ) && ( prev_nConcealed != nConcealed ) && */( Iterations < 5 ); + Iterations++ ) + { + MSE_Threshold = 1 * Iterations; + prev_nConcealed = nConcealed; + + for( iyMB = 0; iyMB < mb_height; iyMB++ ) + { + y = iyMB * MB_BLOCK_SIZE; + + for( ixMB = 0; ixMB < mb_width; ixMB++ ) + { + x = ixMB * MB_BLOCK_SIZE; + idxMB = iyMB * Dest->PicWidthInMbs + ixMB; + updateMBData( p_Vid, SliceDestiantion, idxMB, x, y, BLOCK_SIZE ); + + iBlock = 0; + while( iBlock < iabs2( MB_BLOCK_SIZE ) / iabs2( BLOCK_SIZE ) ) + { + x = ixMB * MB_BLOCK_SIZE + BLOCK_IDX_MB[iBlock][0] * BLOCK_SIZE; + y = iyMB * MB_BLOCK_SIZE + BLOCK_IDX_MB[iBlock][1] * BLOCK_SIZE; + + y_block4x4 = y / BLOCK_SIZE; + x_block4x4 = x / BLOCK_SIZE; + + ConcealCurrentClusterMSEBased( p_Vid, IntraInterConc, ixMB, iyMB, iBlock, &BlockSize, MSE_Threshold ); + + if( BlockSize >= BlockSizeThreshold ) + { + for( y4x4 = 0; y4x4 < BlockSize / BLOCK_SIZE; y4x4++ ) + for( x4x4 = 0; x4x4 < BlockSize / BLOCK_SIZE; x4x4++ ) + BlockConcealmentState->imgY[y_block4x4 + y4x4][x_block4x4 + x4x4] = 1; + + copyPredblockRegionYUVSeparatedDestination( Dest, IntraInterConc->storeSeparatedYUV, x, y, BlockSize ); + nConcealed += iabs2( BlockSize / BLOCK_SIZE ); + iBlock += iabs2( BlockSize / BLOCK_SIZE ); + } + else + { + iBlock += 1; + } + } + } + } //for (iyMB = 0; iyMB < mb_height; iyMB++) + + } + BlockSizeThreshold = BlockSizeThreshold / 2; + BlockRatio += 0.06; + } + BlockRatio = (double) nConcealed / (double) MaxBlockNumber; + + return nConcealed; +} + +static int ConcealBasedOnDifference( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int DifferenceThreshold, int x_block4x4, int y_block4x4, + int BLockWindow, int DiffType ) +{ + StorablePicture *DifferenceMap; + StorablePicture *TemporalDifference = IntraInterConc->TemporalDifference; + StorablePicture *SpatialDifference = IntraInterConc->SpatialDifference; + imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; + double CurrentDiff = 0; + int CountThreshHigher, MV[3], iRet = 0, curr_mb_idx, diff = 0, y, x, count = 0; + double currSAD, MinSAD = ULONG_MAX; + curr_mb_idx = y_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + x_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE; + + MinSAD = INT_MAX; + //DiffType=SPATIAL_DIFF; + //DiffType = TEMPORAL_DIFF; + //for (; DiffType >= imin(TEMPORAL_DIFF, SPATIAL_DIFF) && DiffType <= imax(TEMPORAL_DIFF, SPATIAL_DIFF); DiffType++) + { + // if (DifferenceThreshold > IntraInterConc->DifferenceThresholds[DiffType]) + // return iRet; + + switch( DiffType ) + { + case TEMPORAL_DIFF: + //getMVIntra(IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV); + getMVInter( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + DifferenceMap = TemporalDifference; + // if( MV[2] < 0) + // { + // getMVIntra(IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV); + // } + break; + case SPATIAL_DIFF: + getMVInterview( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + DifferenceMap = SpatialDifference; + break; + default: + return iRet; + } + + if( MV[2] < 0 ) + return iRet; + + CountThreshHigher = 0; + for( y = imax( 0, y_block4x4 - BLockWindow ) * BLOCK_SIZE; y < imin( DifferenceMap->size_y / BLOCK_SIZE, y_block4x4 + BLockWindow + 1 ) * BLOCK_SIZE; y++ ) + { + for( x = imax( 0, x_block4x4 - BLockWindow ) * BLOCK_SIZE; x < imin( DifferenceMap->size_x / BLOCK_SIZE, x_block4x4 + BLockWindow + 1 ) * BLOCK_SIZE; + x++ ) + { + if( y >= 0 && y < DifferenceMap->size_y && x >= 0 && x < DifferenceMap->size_x ) + { + diff = (int) ( DifferenceMap->imgY[y][x] ); + CurrentDiff = ( (double) ( CurrentDiff * count + diff ) ) / ( (double) count + 1 ); + count++; + if( diff > DifferenceThreshold ) + CountThreshHigher++; + } + } + } + if( CountThreshHigher > MB_BLOCK_SIZE * MB_BLOCK_SIZE ) + return iRet; + + if( CurrentDiff <= (double) ( DifferenceThreshold ) ) + { + currSAD = computeSADOverlap( IntraInterConc, IntraInterConc->Destination, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, + IntraInterConc->SliceDestiantion->listX[LIST_0][MV[2]], x_block4x4 * BLOCK_SIZE + MV[0] / 4, y_block4x4 * BLOCK_SIZE + MV[1] / 4, BLOCK_SIZE, + BLOCK_SIZE + 2 * BLOCK_SIZE ); + + if( currSAD <= MinSAD ) + { + MinSAD = currSAD; + + EnhancedbuildPredblock4x4YUV( p_Vid, MV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, + IntraInterConc->tmp_storeYUV ); + copyPredblockRegionYUVDestination( IntraInterConc->Destination, storeYUV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BLOCK_SIZE ); + IntraInterConc->BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; + + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = MV[0]; + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = MV[1]; + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = MV[2]; + iRet = 1; + } + } + } + return iRet; +} + +//static int ConcealBasedOnTemporalDifference(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int DifferenceThreshold, int x_block4x4, int y_block4x4, +// int BLockWindow) +//{ +// void +// (*getMV)(INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int MV[3]); +// StorablePicture *DifferenceMap; +// StorablePicture *TemporalDifference = IntraInterConc->TemporalDifference; +// StorablePicture *SpatialDifference = IntraInterConc->SpatialDifference; +// imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; +// double CurrentDiff = 0; +// int CountThreshHigher, MV[3], DiffType, iRet = 0, curr_mb_idx, diff = 0, y, x, count = 0; +// double currSAD, MinSAD = ULONG_MAX; +// curr_mb_idx = y_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + x_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE; +// +// MinSAD = INT_MAX; +// //DiffType=SPATIAL_DIFF; +// DiffType = TEMPORAL_DIFF; +// +// if (DifferenceThreshold > IntraInterConc->DifferenceThresholds[DiffType]) +// return iRet; +// +// DifferenceMap = TemporalDifference; +// +// getMVInter(IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV); +// +// // if (MV[2] < 0) +// // { +// // getMVIntra(IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV); +// // +// // } +// +// if (MV[2] < 0) +// return iRet; +// +// CountThreshHigher = 0; +// for (y = imax(0, y_block4x4 - BLockWindow) * BLOCK_SIZE; y < imin(DifferenceMap->size_y / BLOCK_SIZE, y_block4x4 + BLockWindow + 1) * BLOCK_SIZE; y++) +// { +// for (x = imax(0, x_block4x4 - BLockWindow) * BLOCK_SIZE; x < imin(DifferenceMap->size_x / BLOCK_SIZE, x_block4x4 + BLockWindow + 1) * BLOCK_SIZE; x++) +// { +// if (y >= 0 && y < DifferenceMap->size_y && x >= 0 && x < DifferenceMap->size_x) +// { +// diff = (int) (DifferenceMap->imgY[y][x]); +// CurrentDiff = ((double) (CurrentDiff * count + diff)) / ((double) count + 1); +// count++; +// if (diff > DifferenceThreshold) +// CountThreshHigher++; +// } +// } +// } +// if (CountThreshHigher > MB_BLOCK_SIZE * MB_BLOCK_SIZE) +// return iRet; +// +// if (CurrentDiff <= (double) (DifferenceThreshold)) +// { +// currSAD = computeSADOverlap(IntraInterConc, IntraInterConc->Destination, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, +// IntraInterConc->SliceDestiantion->listX[LIST_0][MV[2]], x_block4x4 * BLOCK_SIZE + MV[0] / 4, y_block4x4 * BLOCK_SIZE + MV[1] / 4, BLOCK_SIZE, +// BLOCK_SIZE + 2 * BLOCK_SIZE); +// +// if (currSAD <= MinSAD) +// { +// MinSAD = currSAD; +// +// EnhancedbuildPredblock4x4YUV(p_Vid, MV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV); +// copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BLOCK_SIZE); +// IntraInterConc->BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; +// +// IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = MV[0]; +// IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = MV[1]; +// IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = MV[2]; +// iRet = 1; +// } +// } +// return iRet; +//} + +//static int ConcealBasedOnINTRADisparity(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_block4x4, int y_block4x4) +//{ +// void +// (*getMV)(INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int MV[3]); +// StorablePicture *DifferenceMap; +// StorablePicture *TemporalDifference = IntraInterConc->TemporalDifference; +// StorablePicture *DisparityMap = IntraInterConc->DisparityBlockwiseAux; +// imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; +// double CurrentDiff = 0; +// int MV[3], DiffType, iRet = 0, curr_mb_idx, diff = 0, y, x, count = 0; +// unsigned long int currSAD, MinSAD; +// unsigned int Disparity; +// +// curr_mb_idx = y_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + x_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE; +// +// getMVIntra(IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV); +// if (MV[2] != IntraInterConc->MVExtrapolationRefIdx[1]) +// return iRet; +// +// Disparity = DisparityMap->imgY[y_block4x4][x_block4x4] * 4; +// +// EnhancedbuildPredblock4x4YUV(p_Vid, MV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV); +// copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BLOCK_SIZE); +// IntraInterConc->BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; +// +// IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = MV[0]; +// IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = MV[1]; +// IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = MV[2]; +// iRet = 1; +// +// return iRet; +//} + +static int ConcealBasedOnINTRAandZeroMV( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_block4x4, int y_block4x4 ) +{ + void + (*getMV)( INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int MV[3] ); + StorablePicture *DifferenceMap; + StorablePicture *TemporalDifference = IntraInterConc->TemporalDifference; + StorablePicture *DisparityMap = IntraInterConc->DisparityBlockwiseAux; + imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; + double CurrentDiff = 0; + int MV[3], DiffType, iRet = 0, curr_mb_idx, diff = 0, y, x, count = 0; + unsigned long int currSAD, MinSAD; + unsigned int Disparity; + + curr_mb_idx = y_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + x_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE; + + getMVIntra( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + if( MV[2] < 0 ) + { + MV[0] = MV[1] = 0; + MV[2] = IntraInterConc->MVExtrapolationRefIdx[0]; + } + EnhancedbuildPredblock4x4YUV( p_Vid, MV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV ); + copyPredblockRegionYUVDestination( IntraInterConc->Destination, storeYUV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BLOCK_SIZE ); + IntraInterConc->BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; + + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = MV[0]; + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = MV[1]; + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = MV[2]; + iRet = 1; + + return iRet; +} + +static int ConcealBasedOnDisparityOrMotion( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_block4x4, int y_block4x4, +//void (*getMV)(INTER_INTRA_CONC_T *, int, int, int, int *)) + int MotionDispFlag ) +{ + imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; + int MV[3], iRet = 0, curr_mb_idx; + + switch( MotionDispFlag ) + { + case MOTION: + getMVInter( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + if( MV[2] >= 0 ) + break; + getMVIntra( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + break; + case DISPARITY: + getMVIntra( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + if( MV[2] != IntraInterConc->MVExtrapolationRefIdx[1] ) + { + getMVInterview( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + } + break; + } + + if( MV[2] < 0 ) + return iRet; + + curr_mb_idx = y_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + x_block4x4 * BLOCK_SIZE / MB_BLOCK_SIZE; + + EnhancedbuildPredblock4x4YUV( p_Vid, MV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV ); + copyPredblockRegionYUVDestination( IntraInterConc->Destination, storeYUV, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BLOCK_SIZE ); + IntraInterConc->BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; + + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = MV[0]; + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = MV[1]; + IntraInterConc->Destination->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = MV[2]; + iRet = 1; + + return iRet; +} + +/*! + ************************************************************************ + * \brief + * Definition of each Stage and Main function + ************************************************************************ + */ + +#define CONCEALMENT_STAGES 6 + +// MVE +const int MOTION_INTRAVIEW_STAGES[] = { MOTION_INTRAVIEW, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV }; +// BASE_MC +const int MOTION_INTERVIEW_STAGES[] = { MOTION_INTERVIEW, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV }; +// INTERVIEW_COPY +const int INTERVIEW_COPY_STAGES[] = { INTERVIEW_COPY, MOTION_INTRAVIEW, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV }; +// COMB_MC +const int MOTION_INTERVIEW_FIRST_STAGES[] = { MOTION_INTERVIEW, MOTION_INTRAVIEW, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV }; +// COMB_MC_DISP +const int MOTION_INTERVIEW_MVE_INTERCOPY_STAGES[] = { MOTION_INTERVIEW, INTERVIEW_COPY, MOTION_INTRAVIEW, CONCEALMV, CONCEALMV, CONCEALMV }; +// Enhanced MVE +const int ENHANCED_MVE_STAGES[] = { ENHANCED_MVE, CONCEALMV, CONCEALMV, CONCEALMV, CONCEALMV }; +//TEST +const int MOTION_INTERVIEW_DISP_INTERCOPY_MVE_STAGES[] = { MOTION_INTERVIEW, MOTION_INTRAVIEW_DISP, INTERVIEW_COPY, MOTION_INTRAVIEW, ZERO_MV_CONC, CONCEALMV }; + +const int MOTION_ITERATIONS_METHODS[] = { MOTION_INTERVIEW, MOTION_INTRAVIEW, INTERVIEW_COPY, CONCEALMV, CONCEALMV, CONCEALMV }; +const int MOTION_ITERATIONS_STAGES[] = { MSE_BASED, SPAT_TEMP_DIFF, MOTION_INTERVIEW, MOTION_DISP_FRAME, MOTION_INTRAVIEW, CONCEALMV }; + +static inline int GetCurrentConcealmentMethodFrame( INTER_INTRA_CONC_T *IntraInterConc, int ConcealmentMethod, int Stage ) +{ + int CurrentConcealmentMethod; + CurrentConcealmentMethod = CONCEALMV; + switch( ConcealmentMethod ) + { + case MOTION_INTRAVIEW: + CurrentConcealmentMethod = MOTION_INTRAVIEW_STAGES[Stage - 1]; + break; + case MOTION_INTERVIEW: + CurrentConcealmentMethod = MOTION_INTERVIEW_STAGES[Stage - 1]; + break; + case INTERVIEW_COPY: + CurrentConcealmentMethod = INTERVIEW_COPY_STAGES[Stage - 1]; + break; + case MOTION_INTERVIEW_FIRST: + CurrentConcealmentMethod = MOTION_INTERVIEW_FIRST_STAGES[Stage - 1]; + break; + case MOTION_INTERVIEW_MVE_INTERCOPY: + CurrentConcealmentMethod = MOTION_INTERVIEW_MVE_INTERCOPY_STAGES[Stage - 1]; + break; + case ENHANCED_MVE: + CurrentConcealmentMethod = ENHANCED_MVE_STAGES[Stage - 1]; + break; + case MOTION_ITERATIONS: + CurrentConcealmentMethod = MOTION_ITERATIONS_STAGES[Stage - 1]; + if( CurrentConcealmentMethod == MOTION_DISP_FRAME ) + { + if( IntraInterConc->SpatialDifference->mean_value > IntraInterConc->TemporalDifference->mean_value ) + { + printf( "[FERC] Using Motion in Stage %d\n", Stage ); + CurrentConcealmentMethod = MOTION_INTRAVIEW; + } + else + { + printf( "[FERC] Using Disparity in Stage %d\n", Stage ); + CurrentConcealmentMethod = INTERVIEW_COPY; + } + } + break; + } + return CurrentConcealmentMethod; +} + +static int SpatioTemporalDecision( INTER_INTRA_CONC_T *IntraInterConc, int x_block4x4, int y_block4x4, int BLockWindow ) +{ + + StorablePicture *DifferenceMap; + StorablePicture *TemporalDifference = IntraInterConc->TemporalDifference; + StorablePicture *SpatialDifference = IntraInterConc->SpatialDifference; + int Max_Count, count, diff, CountThreshHigher, x, y; + double CurrentDiffAverage; + int MV[3]; + int DiffType, DifferenceThreshold; + + Max_Count = ( BLockWindow + 1 ) * ( BLockWindow + 1 ) * BLOCK_SIZE * BLOCK_SIZE; + + for( DiffType = imin( TEMPORAL_DIFF, SPATIAL_DIFF ); DiffType <= imax( TEMPORAL_DIFF, SPATIAL_DIFF ); DiffType++ ) + { + switch( DiffType ) + { + case TEMPORAL_DIFF: + getMVInter( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + DifferenceMap = TemporalDifference; + break; + case SPATIAL_DIFF: + getMVIntra( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + if( MV[2] != IntraInterConc->MVExtrapolationRefIdx[1] ) + { + getMVInterview( IntraInterConc, LIST_0, y_block4x4, x_block4x4, MV ); + } + DifferenceMap = SpatialDifference; + break; + } + + if( MV[2] < 0 ) + return NONE_CONCEAL; + + CountThreshHigher = 0; + count = 0; + DifferenceThreshold = IntraInterConc->DifferenceThresholds[DiffType]; + //DifferenceThreshold = 256; + + for( y = imax( 0, y_block4x4 - BLockWindow ) * BLOCK_SIZE; y < imin( DifferenceMap->size_y / BLOCK_SIZE, y_block4x4 + BLockWindow + 1 ) * BLOCK_SIZE; y++ ) + { + for( x = imax( 0, x_block4x4 - BLockWindow ) * BLOCK_SIZE; x < imin( DifferenceMap->size_x / BLOCK_SIZE, x_block4x4 + BLockWindow + 1 ) * BLOCK_SIZE; + x++ ) + { + //if( y >= 0 && y < DifferenceMap->size_y && x >= 0 && x < DifferenceMap->size_x ) + //{ + diff = (int) ( DifferenceMap->imgY[y][x] ); + CurrentDiffAverage = ( (double) ( CurrentDiffAverage * count + diff ) ) / ( (double) count + 1 ); + count++; + if( diff > DifferenceThreshold ) + CountThreshHigher++; + //} + } + } + + if( CountThreshHigher > ( Max_Count / 2 ) ) + continue; + + switch( DiffType ) + { + case TEMPORAL_DIFF: + return MOTION_INTERVIEW; + break; + case SPATIAL_DIFF: + return INTERVIEW_COPY; + break; + } + + } + return NONE_CONCEAL; +} + +static inline int GetCurrentConcealmentMethodBlockBased( INTER_INTRA_CONC_T *IntraInterConc, int ConcealmentMethod, int y_block, int x_block ) +{ + int CurrentConcealmentMethod; + int mv_intra[3], mv_inter[3]; + CurrentConcealmentMethod = ConcealmentMethod; + + if( ConcealmentMethod != MSE_BASED && ConcealmentMethod != SPAT_TEMP_DIFF ) + return CurrentConcealmentMethod; + + if( ConcealmentMethod == MSE_BASED ) + { + CurrentConcealmentMethod = NONE_CONCEAL; + getMVIntra( IntraInterConc, LIST_0, y_block, x_block, mv_intra ); + getMVInter( IntraInterConc, LIST_0, y_block, x_block, mv_inter ); + if( mv_inter[2] >= 0 && mv_intra[2] >= 0 ) + if( mv_inter[0] == mv_intra[0] ) + if( mv_inter[1] == mv_intra[1] ) + if( mv_inter[2] == mv_intra[2] ) + CurrentConcealmentMethod = MOTION_INTERVIEW; + } + if( ConcealmentMethod == SPAT_TEMP_DIFF ) + { + CurrentConcealmentMethod = SpatioTemporalDecision( IntraInterConc, x_block, y_block, 2 ); + } + + return CurrentConcealmentMethod; +} + +static int UseThisMotion( int ConcealmentMethod, int MotionSource ) +{ + const int *MethodStages; + int i; + + switch( ConcealmentMethod ) + { + case MOTION_INTRAVIEW: + MethodStages = MOTION_INTRAVIEW_STAGES; + break; + case MOTION_INTERVIEW: + MethodStages = MOTION_INTERVIEW_STAGES; + break; + case INTERVIEW_COPY: + MethodStages = INTERVIEW_COPY_STAGES; + break; + case MOTION_INTERVIEW_FIRST: + MethodStages = MOTION_INTERVIEW_FIRST_STAGES; + break; + case MOTION_INTERVIEW_MVE_INTERCOPY: + MethodStages = MOTION_INTERVIEW_MVE_INTERCOPY_STAGES; + break; + case ENHANCED_MVE: + MethodStages = ENHANCED_MVE_STAGES; + break; + case MOTION_ITERATIONS: + MethodStages = MOTION_ITERATIONS_METHODS; + break; + } + for( i = 0; i < CONCEALMENT_STAGES; i++ ) + { + if( MethodStages[i] == MotionSource ) + return 1; + } + return 0; +} + +void Conceal_by_Stages( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, StorablePicture *Dest, int ConcealmentMethod ) +{ + + //! Reference frames + StorablePicture *InterRefFrame = IntraInterConc->InterRefFrame; + //! Storable picture to save the disparity maps + Slice *pSliceDestiantion = Dest->PicSlice; + + StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState; //!< State of the lost image blocks + + //! Motion concealment loop variables +#define NCONCEALMENTMETHODS 3 + imgpel *predMB[NCONCEALMENTMETHODS]; + unsigned int SAD_Values[NCONCEALMENTMETHODS]; + Macroblock *currMB; + int usedList[2], idxMB, List; + int Stage = 0, mb_height, mb_width; + int x_block4x4, y_block4x4, y, x; + imgpel ***storeYUV = IntraInterConc->storeYUV; + int BlockSize, MV[3]; + StorablePicture *currRef; + int CurrentConcealmentMethodFrame, CurrentConcealmentMethod; + double PerStageConcealmentRatio = 0; + + //! Initialize the variables + BlockSize = 4; //!< Define the Block Size + mb_width = Dest->PicWidthInMbs; + mb_height = ( Dest->PicSizeInMbs ) / ( Dest->PicWidthInMbs ); + + for( Stage = 1; Stage <= CONCEALMENT_STAGES; Stage++ ) + { + PerStageConcealmentRatio = 0; + CurrentConcealmentMethodFrame = GetCurrentConcealmentMethodFrame( IntraInterConc, ConcealmentMethod, Stage ); + + for( y_block4x4 = 0; y_block4x4 < mb_height * ( MB_BLOCK_SIZE / BlockSize ); y_block4x4++ ) + { + y = y_block4x4 * BlockSize; //!< get y cordinates + for( x_block4x4 = 0; x_block4x4 < mb_width * ( MB_BLOCK_SIZE / BlockSize ); x_block4x4++ ) + { + x = x_block4x4 * BlockSize; + + // Init variables + memset( SAD_Values, 0, NCONCEALMENTMETHODS * sizeof(int) ); + memset( predMB, 0, NCONCEALMENTMETHODS * sizeof(imgpel *) ); + usedList[LIST_0] = 0; + usedList[LIST_1] = 0; + + // Update coordinates of the current concealed macroblock + idxMB = ( y / MB_BLOCK_SIZE ) * mb_width + ( x / MB_BLOCK_SIZE ); + updateMBData( p_Vid, IntraInterConc->SliceDestiantion, idxMB, x, y, BLOCK_SIZE ); + currMB = &( p_Vid->mb_data[idxMB] ); + currMB->mb.x = (short) ( x / BlockSize ); + currMB->mb.y = (short) ( y / BlockSize ); + currMB->block_y = currMB->mb.y * BlockSize; + currMB->pix_c_y = currMB->mb.y * p_Vid->mb_cr_size_y / 4; + currMB->block_x = currMB->mb.x * BlockSize; + currMB->pix_c_x = currMB->mb.x * p_Vid->mb_cr_size_x / 4; + currMB->p_Slice = pSliceDestiantion; + + //Check if the current block have been already concealed + if( BlockConcealmentState->imgY[y_block4x4][x_block4x4] != 0 ) + continue; + + CurrentConcealmentMethod = GetCurrentConcealmentMethodBlockBased( IntraInterConc, CurrentConcealmentMethodFrame, y_block4x4, x_block4x4 ); + + for( List = LIST_1; List >= LIST_0; List-- ) + { + if( CurrentConcealmentMethod == MOTION_INTRAVIEW ) + { + if( List == LIST_1 ) + continue; + getMVIntra( IntraInterConc, List, y_block4x4, x_block4x4, MV ); + if( MV[2] < 0 ) + continue; + } + else if( CurrentConcealmentMethod == MOTION_INTRAVIEW_DISP ) + { + if( List == LIST_1 ) + continue; + getMVIntra( IntraInterConc, List, y_block4x4, x_block4x4, MV ); + if( MV[2] < 0 ) + continue; + currRef = pSliceDestiantion->listX[List][MV[2]]; + if( currRef->view_id == Dest->view_id ) + continue; + } + else if( CurrentConcealmentMethod == MOTION_INTERVIEW ) + { + if( InterRefFrame->slice_type != B_SLICE && List == LIST_1 ) + continue; + getMVInter( IntraInterConc, List, y_block4x4, x_block4x4, MV ); + if( MV[2] < 0 ) + continue; + } + else if( CurrentConcealmentMethod == ENHANCED_MVE ) + { + if( List == LIST_1 ) + continue; + getMVENHANCEDMVE( IntraInterConc, List, y_block4x4, x_block4x4, MV ); + if( MV[2] < 0 ) + continue; + } + else if( CurrentConcealmentMethod == INTERVIEW_COPY ) + { + getMVInterview( IntraInterConc, List, y_block4x4, x_block4x4, MV ); + if( MV[2] < 0 ) + continue; + } + else if( CurrentConcealmentMethod == ZERO_MV_CONC ) + { + MV[0] = MV[1] = 0; + MV[2] = IntraInterConc->MVExtrapolationRefIdx[0]; + } + else if( CurrentConcealmentMethod == CONCEALMV ) + { + if( List == LIST_1 ) + continue; + + ConcealMotionVector( p_Vid, Dest, pSliceDestiantion, y_block4x4, x_block4x4, p_Vid->p_Inp->MVConcealmentMode, LIST_0, MV, + IntraInterConc->MVExtrapolationRefIdx[0] ); + //Dont need scalling because the vectors have already been modified + + BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; + } + else if( CurrentConcealmentMethod == NONE_CONCEAL ) + { + continue; + } + else + { + continue; + } + + if( MV[2] >= 0 ) + { + usedList[List] = 1; + currRef = pSliceDestiantion->listX[List][MV[2]]; + + //copy motion vector + Dest->mv_info[y_block4x4][x_block4x4].mv[List].mv_x = MV[0]; + Dest->mv_info[y_block4x4][x_block4x4].mv[List].mv_y = MV[1]; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[List] = MV[2]; + + if( currRef == p_Vid->no_reference_picture ) + continue; + + usedList[List] = 1; + + buildPredblockRegionYUV( p_Vid, currRef, currMB, MV, x, y, storeYUV[0][List], BlockSize, IntraInterConc->tmp_storeYUV, 1 ); + + } + } + + switch( usedList[LIST_0] + usedList[LIST_1] ) + { + case 1: // List 0 or List 1 + predMB[0] = storeYUV[0][usedList[LIST_1]]; + break; + case 2: // Both List 0 and 1 + ferc_bi_prediction( storeYUV[0][LIST_0], storeYUV[0][LIST_0], 1, storeYUV[0][LIST_1], 1, BlockSize, BlockSize, 1 ); + predMB[0] = storeYUV[0][LIST_0]; + break; + default: + continue; + } + PerStageConcealmentRatio++; + //! Insert the block in the image + copyPredblockRegionYUVDestination( Dest, predMB[0], x, y, BLOCK_SIZE ); + BlockConcealmentState->imgY[y_block4x4][x_block4x4] = 1; + + } + } + PerStageConcealmentRatio = PerStageConcealmentRatio / (double) ( mb_height * ( MB_BLOCK_SIZE / BlockSize ) * mb_width * ( MB_BLOCK_SIZE / BlockSize ) ); + printf( "[FERC] Stage %d : %4.2f\n", Stage, PerStageConcealmentRatio ); + ShowStageDebug( p_Vid, Dest, Stage, "Debug" ); + fflush( stdout ); + + } + +} + +/***************************************************************************************************************** + * Function to conceal the missing frame using the motion vector from base and auxiliary view + * using multiple iterations + *****************************************************************************************************************/ +void Conceal_by_Iterations( VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, StorablePicture *Dest, int ConcealmentMethod ) +{ + void (*getMV)( INTER_INTRA_CONC_T *, int, int, int, int * ); + //! Reference frames + //! Storable picture to save the disparity maps + StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState; //!< State of the lost image blocks + + //! Motion concealment loop variables + int Stage = 0, mb_height, mb_width; + int x_block4x4, y_block4x4; + int nConcealed, DiffType, DifferenceThreshold; + unsigned int MaxBlockNumber = ( p_Vid->width * p_Vid->height / iabs2( BLOCK_SIZE ) ); + int MotionDispFlag = MOTION; + //! Initialize the variables + mb_width = Dest->PicWidthInMbs; + mb_height = ( Dest->PicSizeInMbs ) / ( Dest->PicWidthInMbs ); + + //! Get temporal and spatial difference + GetTemporalDifferenceFrame( p_Vid, IntraInterConc, 0, (double) ( p_Vid->p_Inp->TemporalThreshold ) / 100 ); + GetSpatialDifferenceFrame( p_Vid, IntraInterConc, 0, (double) ( p_Vid->p_Inp->SpatialThreshold ) / 100 ); + //IntraInterConc->DifferenceThresholds[TEMPORAL_DIFF] = 256; + // IntraInterConc->DifferenceThresholds[SPATIAL_DIFF] = 5; + + //! Alloc memory for temp blocks + BlockConcealmentState = IntraInterConc->BlockConcealmentState; + + //! Initialize the variables + mb_width = Dest->PicWidthInMbs; + mb_height = ( Dest->PicSizeInMbs ) / ( Dest->PicWidthInMbs ); + nConcealed = 0; + + nConcealed = MSEBasedConcealmentStage( p_Vid, IntraInterConc ); + ShowStageDebug( p_Vid, Dest, Stage, "MSEBased" ); + printf( "[FERC] Stage %d : %4.2f\n", Stage++, (double) ( nConcealed ) / (double) ( MaxBlockNumber ) ); + + // nConcealed = 0; + // //! Loop Through Spatial and Temporal Differences - Temporal First + // for (DiffType = imin(TEMPORAL_DIFF, SPATIAL_DIFF); DiffType <= imax(TEMPORAL_DIFF, SPATIAL_DIFF); DiffType++) + // { + // nConcealed = 0; + // DifferenceThreshold = IntraInterConc->DifferenceThresholds[DiffType]; + // DifferenceThreshold = 255; + // for (y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++) + // { + // for (x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++) + // { + // if (BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0) + // { + // nConcealed += ConcealBasedOnDifference(p_Vid, IntraInterConc, DifferenceThreshold, x_block4x4, y_block4x4, 3, DiffType); + // } + // } + // } + // if (DiffType == TEMPORAL_DIFF) + // { + // ShowStageDebug(p_Vid, Dest, Stage, "TemporalDiff"); + // PrintDebugPGM( p_Vid, IntraInterConc, Dest, "TemporalDiff"); + // printf("[FERC] Stage %d : %4.2f\n", Stage++, (double) (nConcealed) / (double) (MaxBlockNumber)); + // + // } + // if (DiffType == SPATIAL_DIFF) + // { + // ShowStageDebug(p_Vid, Dest, Stage, "SpatialDiff"); + // PrintDebugPGM( p_Vid, IntraInterConc, Dest, "SpatialDiff"); + // printf("[FERC] Stage %d : %4.2f\n", Stage++, (double) (nConcealed) / (double) (MaxBlockNumber)); + // } + // } + + nConcealed = 0; + DifferenceThreshold = 255; + for( y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++ ) + { + for( x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++ ) + { + if( BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0 ) + { + nConcealed += ConcealBasedOnDifference( p_Vid, IntraInterConc, DifferenceThreshold, x_block4x4, y_block4x4, 4, TEMPORAL_DIFF ); + } + } + } + ShowStageDebug( p_Vid, Dest, Stage, "TemporalDiff2" ); + printf( "[FERC] Stage %d : %4.2f\n", Stage++, (double) ( nConcealed ) / (double) ( MaxBlockNumber ) ); + + //nConcealed = 0; + // //! Only use the disparity vectors of the INTRA reference frame + // DifferenceThreshold = 20; + // for (y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++) + // { + // for (x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++) + // { + // if (BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0) + // { + // nConcealed += ConcealBasedOnINTRADisparity(p_Vid, IntraInterConc, x_block4x4, y_block4x4); + // } + // } + // } + // ShowStageDebug(p_Vid, Dest, Stage, "TemporalDiffDispOnly"); + // printf("[FERC] Stage %d : %4.2f\n", Stage++, (double) (nConcealed) / (double) (MaxBlockNumber)); + + nConcealed = 0; + if( IntraInterConc->SpatialDifference->mean_value > IntraInterConc->TemporalDifference->mean_value ) + { + printf( "[FERC] Using Motion in Stage %d\n", Stage ); + getMV = getMVIntra; + MotionDispFlag = MOTION; + } + else + { + printf( "[FERC] Using Disparity in Stage %d\n", Stage ); + getMV = getMVInterview; + MotionDispFlag = DISPARITY; + } + + for( y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++ ) + { + for( x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++ ) + { + if( BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0 ) + { + nConcealed += ConcealBasedOnDisparityOrMotion( p_Vid, IntraInterConc, x_block4x4, y_block4x4, MotionDispFlag ); + } + } + } + ShowStageDebug( p_Vid, Dest, Stage, "Disparity or Motion" ); + printf( "[FERC] Stage %d : %4.2f\n", Stage++, (double) ( nConcealed ) / (double) ( MaxBlockNumber ) ); + + nConcealed = 0; + for( y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++ ) + { + for( x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++ ) + { + if( BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0 ) + { + nConcealed += ConcealBasedOnINTRAandZeroMV( p_Vid, IntraInterConc, x_block4x4, y_block4x4 ); + } + } + } + ShowStageDebug( p_Vid, Dest, Stage, "INTRA or ZeroMV" ); + printf( "[FERC] Stage %d : %4.2f\n", Stage++, (double) ( nConcealed ) / (double) ( MaxBlockNumber ) ); + + // MeanDisparityValue = IntraInterConc->DisparityAux->mean_value; + + // for (Iterations = 0; nConcealed < MaxBlockNumber && Iterations <= 5; Iterations++) + // { + // BlockSizeThreshold = 128; + // for (BlockSizeThreshold = 32; BlockSizeThreshold >= 4; BlockSizeThreshold -= BLOCK_SIZE) + // { + // for (y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++) + // { + // for (x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++) + // { + // if (BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0 && x_block4x4 * BLOCK_SIZE > MeanDisparityValue) + // { + // getCurrentCluster(p_Vid, IntraInterConc,/*Same Condition=0*/ + // 0, x_block4x4, y_block4x4, &BlockSize); + // //if( BlockSize == 0 || BlockSize > BlockSizeThreshold) + // if (BlockSize != BlockSizeThreshold) + // continue; + // + // nConcealed += ConcealCurrentClusterDisparitySearch(p_Vid, IntraInterConc, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BlockSize, 32, 1, 1); + // } + // } + // } + // } + // } + // ShowStageDebug(p_Vid, Dest, Stage++, "DisparitySearch"); + + // BlockSizeThreshold = 32; + // for (Iterations = 0; nConcealed < MaxBlockNumber && Iterations <= 5; Iterations++) + // { + // for (y_block4x4 = 0; y_block4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; y_block4x4++) + // { + // for (x_block4x4 = 0; x_block4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; x_block4x4++) + // { + // if (BlockConcealmentState->imgY[y_block4x4][x_block4x4] == 0) + // { + // getCurrentCluster(p_Vid, IntraInterConc,/*Same Condition=0*/ + // 0, x_block4x4, y_block4x4, &BlockSize); + // if (BlockSize == 0) + // continue; + // if (BlockSize > BlockSizeThreshold) + // BlockSize = BlockSizeThreshold; + // + // nConcealed += ConcealCurrentClusterMotionSearch(p_Vid, IntraInterConc, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BlockSize, 64); + // } + // } + // } + // } + // ShowStageDebug(p_Vid, Dest, Stage++, "MotionSearch"); + +} + +void Conceal_by_IntraInterMotionCopy_V2( VideoParameters *p_Vid, StorablePicture *Source/*Ignored*/, StorablePicture *Dest ) +{ + //! Base concealment variables + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[Dest->view_id]; + ConcealParameters *p_FrameConc = p_Vid->p_FrameConc; + INTER_INTRA_CONC_T *IntraInterConc = NULL; + StorablePicture *IntraRefFrame, *InterRefFrame, *InterRefFrameMinus1; + + int BlockSize, mb_height, mb_width, x_block4x4, y_block4x4; + + //! Temporally pointers to predicted blocks + double MotionRatio = 0; + int ConcealmentMethod = p_FrameConc->ConcealmentMode; + + // Reference Slices - Store the information about pseudo Slices + // corresponding to the reference Frames + Slice *pSliceInterViewReference = NULL, *pSliceIntraViewReference = NULL, *pSliceDestiantion = Dest->PicSlice; + + //! Alloc Data structures + allocIntraInterConcData( p_Vid, &IntraInterConc, Dest ); + + //! Get concealment references + IntraRefFrame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[Dest->view_id], Dest->poc, Dest->view_id, CLOSEST_FUTURE, 0, NULL ); + + if( p_Vid->active_subset_sps->num_views_minus1 > 1 ) + { + int iLayer, currView, bestRefLayer, BestDeltaView = 99; + currView = GetViewIdx( p_Vid, Dest->view_id ); + for( iLayer = Dest->view_id - 1; iLayer >= 0; iLayer-- ) + { + InterRefFrame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[iLayer], Dest->poc, iLayer, EXACT, 1, NULL ); + + if( !InterRefFrame->concealed_pic ) + { + if( iabs( currView - GetViewIdx( p_Vid, iLayer ) ) < BestDeltaView ) + { + BestDeltaView = iabs( currView - GetViewIdx( p_Vid, iLayer ) ); + bestRefLayer = iLayer; + } + } + } + InterRefFrame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[bestRefLayer], Dest->poc, bestRefLayer, EXACT, 1, NULL ); + } + else + { //! Stereo video + InterRefFrame = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[BASE_VIEW_IDX], Dest->poc, BASE_VIEW_IDX, EXACT, 1, NULL ); + } + + InterRefFrameMinus1 = fercGetPictureForConcealFromDpb( p_Vid->p_Dpb_layer[InterRefFrame->view_id], IntraRefFrame->poc, InterRefFrame->view_id, EXACT, 1, + NULL ); + + IntraInterConc->IntraRefFrame = IntraRefFrame; + IntraInterConc->InterRefFrame = InterRefFrame; + IntraInterConc->InterRefFrameMinus1 = InterRefFrameMinus1; + + if( !IntraRefFrame && !InterRefFrame ) + { + printf( "Error: Cannot conceal missing frame! Exit\n" ); + Dest->have_pic = 0; + return; + } + + initInterIntraReferenceLists( p_Vid, IntraInterConc, Dest ); + + pSliceIntraViewReference = IntraInterConc->SliceIntraViewReference; + pSliceInterViewReference = IntraInterConc->SliceInterViewReference; + pSliceDestiantion = IntraInterConc->SliceDestiantion; + + if( ConcealmentMethod == MOTION_ITERATIONS ) + { + //! Get temporal and spatial difference + GetTemporalDifferenceFrame( p_Vid, IntraInterConc, 0, (double) ( p_Vid->p_Inp->TemporalThreshold ) / 100 ); + GetSpatialDifferenceFrame( p_Vid, IntraInterConc, 0, (double) ( p_Vid->p_Inp->SpatialThreshold ) / 100 ); + } + + //! Get motion information of the base view frame + if( ConcealmentMethod == MOTION_SMART_MOTION_BASED ) + { + printf( "[FERC] Parsing base view MV values \n" ); + parse_mv_values( p_Vid, pSliceInterViewReference, InterRefFrame, 0 ); + + MotionRatio = ( (double) ( p_Vid->IntraBlocks ) - 15.0 ) * 0.6 + ( (double) ( p_Vid->NoZeroMVsCount ) - 9 ) * 0.4; + + if( MotionRatio >= 0 ) + ConcealmentMethod = MOTION_INTERVIEW_MVE_INTERCOPY; + else + ConcealmentMethod = MOTION_INTERVIEW_FIRST; + + printf( "[FERC] MotionRatio: %2.1f Using method %d.\n", MotionRatio, ConcealmentMethod ); + } + + //! Project the Motion Vectors + IntraInterConc->IntraMVCandidates.mv_info = NULL; + IntraInterConc->IntraMVCandidates.mv_info_count = NULL; + + if( UseThisMotion( ConcealmentMethod, MOTION_INTRAVIEW ) ) + { + printf( "[FERC] Using frame %2d|%2d for Concealment Reference \n", IntraRefFrame->poc, IntraRefFrame->view_id ); + getINTRAMotionVectorCandidates( p_Vid, IntraRefFrame, pSliceIntraViewReference, Dest, &( IntraInterConc->IntraMVCandidates ), NULL, + p_Vid->p_Inp->MotionVectorCandidates, 1 ); + + } + + if( UseThisMotion( ConcealmentMethod, MOTION_INTERVIEW ) ) + { + printf( "[FERC] Using frame %2d|%2d for Concealment Reference \n", InterRefFrame->poc, InterRefFrame->view_id ); + getDisparityINTERConcealment( p_Vid, IntraInterConc ); + if( p_Vid->p_Inp->DisparityReference == 0 ) + { + getINTERMotionVectorCandidates( p_Vid, InterRefFrame, pSliceInterViewReference, Dest, IntraInterConc->DisparityBlockwiseBase, + &( IntraInterConc->InterMVCandidates ), 1 ); + } + } + + if( UseThisMotion( ConcealmentMethod, ENHANCED_MVE ) ) + { + getDisparityMap( p_Vid, IntraInterConc, IntraInterConc->IntraRefFrame, IntraInterConc->InterRefFrame->view_id, &( IntraInterConc->DisparityAuxMinus1 ) ); + + IntraInterConc->DisparityBlockwiseAuxMinus1 = alloc_storable_picture( p_Vid, FRAME, p_Vid->width / BLOCK_SIZE, p_Vid->height / BLOCK_SIZE, + p_Vid->width_cr / BLOCK_SIZE, p_Vid->height_cr / BLOCK_SIZE, 1 ); + + GetBest4x4Disparity( p_Vid, IntraInterConc->DisparityAuxMinus1, IntraInterConc->DisparityBlockwiseAuxMinus1, IntraInterConc->DisparityAuxMinus1->mean_value, + 0, 0, BLOCK_SIZE, p_Vid->p_Inp->Disparity4x4BlockSize ); + + //showStorablePicture(p_Vid, IntraInterConc->DisparityAuxMinus1, 0, 0, "Disparity Aux T-1", 0); + + getINTERINTRAMotionVectorCandidates( p_Vid, IntraInterConc, &( IntraInterConc->InterIntraMVCandidates ) ); + + } + + if( UseThisMotion( ConcealmentMethod, INTERVIEW_COPY ) ) + { + int aux = IntraInterConc->DisparityReference; + IntraInterConc->DisparityReference = 1; + getDisparityINTERConcealment( p_Vid, IntraInterConc ); + IntraInterConc->DisparityReference = aux; + } + + BlockSize = 4; + mb_width = Dest->PicWidthInMbs; + mb_height = ( Dest->PicSizeInMbs ) / ( Dest->PicWidthInMbs ); + for( y_block4x4 = 0; y_block4x4 < mb_height * ( MB_BLOCK_SIZE / BlockSize ); y_block4x4++ ) + { + for( x_block4x4 = 0; x_block4x4 < mb_width * ( MB_BLOCK_SIZE / BlockSize ); x_block4x4++ ) + { + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_0].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_0] = -1; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_x = 0; + Dest->mv_info[y_block4x4][x_block4x4].mv[LIST_1].mv_y = 0; + Dest->mv_info[y_block4x4][x_block4x4].ref_idx[LIST_1] = -1; + } + } + + //if (ConcealmentMethod == MOTION_ITERATIONS) + //Conceal_by_Iterations(p_Vid, IntraInterConc, Dest, ConcealmentMethod); + //else + Conceal_by_Stages( p_Vid, IntraInterConc, Dest, ConcealmentMethod ); + + //parse_mv_prediction( p_Vid, pSliceDestiantion, Dest ); + parse_mv_values( p_Vid, pSliceDestiantion, Dest, 1 ); + + fercSaveListsInfo( p_Vid, pSliceDestiantion ); + free_storable_picture( IntraInterConc->DisparityBase ); + free_storable_picture( IntraInterConc->DisparityAux ); + + freeIntraInterConcData( p_Vid, IntraInterConc ); + + Dest->have_pic = 1; + + return; +} + +//for( Iterations=0; nConcealed < MaxBlockNumber && Iterations <= 5; Iterations++ ) +//{ +// for( BlockSizeThreshold=BLOCK_SIZE; BlockSizeThreshold<=8; BlockSizeThreshold+=BLOCK_SIZE ) +// { +// for(y_block4x4=0;y_block4x4imgY[y_block4x4][x_block4x4] == 0 && x_block4x4 * BLOCK_SIZE > MeanDisparityValue ) +// { +// BlockSize = BLOCK_SIZE; +// //getCurrentCluster ( p_Vid, IntraInterConc,/*Same Condition=0*/0, x_block4x4, y_block4x4, &BlockSize ); +// //if( BlockSize == 0 || BlockSize > BlockSizeThreshold) +// // continue; +// nConcealed += ConcealCurrentClusterDisparitySearch ( p_Vid, IntraInterConc, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BlockSize, 16, 1 ); +// //showStorablePicture( p_Vid , Dest , 0 , 1 , "Concealed Frame", 0); +// } +// } +// } +// //showStorablePicture( p_Vid , Dest , 0 , 1 , "Concealed Frame", 0); +// } +//} +//ShowStageDebug( p_Vid, Dest, Stage++, "DisparitySearch2" ); + +//BlockSizeThreshold = MB_BLOCK_SIZE; +//while( BlockSizeThreshold <= MB_BLOCK_SIZE ) +//{ +// for(y_block4x4=0;y_block4x4 BlockSizeThreshold) +// continue; + +// nConcealed += ConcealCurrentClusterOnePredictor ( p_Vid, IntraInterConc, x_block4x4 * BLOCK_SIZE, y_block4x4 * BLOCK_SIZE, BlockSize ); +// } +// } +// BlockSizeThreshold *= 2; +//} + +//for( iyMB=0; iyMBPicWidthInMbs + ixMB; + +// updateMBData( p_Vid, pSliceDestiantion, idx_mb, x, y, BLOCK_SIZE ); + +// iBlock = 0; +// while( iBlock < iabs2(MB_BLOCK_SIZE)/iabs2(BLOCK_SIZE) ) +// { +// x = ixMB * MB_BLOCK_SIZE + BLOCK_IDX_MB[iBlock][0] * BLOCK_SIZE; +// y = iyMB * MB_BLOCK_SIZE + BLOCK_IDX_MB[iBlock][1] * BLOCK_SIZE; + +// y_block4x4 = y / BLOCK_SIZE; +// x_block4x4 = x / BLOCK_SIZE; + +// getCurrentClusterSafer( p_Vid, IntraInterConc, ixMB, iyMB, iBlock, &BlockSize, MSE_Threshold, MV); + +// currRef = pSliceDestiantion->listX[LIST_0][MV[2]]; + +// if( BlockSize >= BlockSizeThreshold ) +// { +// for(y4x4=0; y4x4imgY[y_block4x4+y4x4][x_block4x4+x4x4] == 1 ) +// { +// int a = 0; +// } +// EnhancedbuildPredblock4x4YUV( p_Vid, MV, x + x4x4*BLOCK_SIZE , y + y4x4*BLOCK_SIZE, storeYUV[LIST_0][0], LIST_0, idx_mb, IntraInterConc->tmp_storeYUV); +// copyPredblockRegionYUVDestination(Dest, storeYUV[LIST_0][0], x + x4x4*BLOCK_SIZE, y + y4x4*BLOCK_SIZE, BLOCK_SIZE); +// BlockConcealmentState->imgY[y_block4x4+y4x4][x_block4x4+x4x4] = 1; +// nConcealed++; +// } +// } +// iBlock += iabs2( BlockSize/BLOCK_SIZE ); +// } +// else +// { +// iBlock += 1; +// } +// } +// } +//} +//showStorablePicture( p_Vid , Dest , 0 , 1 , "Concealed Frame", 0); + diff --git a/ldecod/src/ferc/ferc_used_code.txt b/ldecod/src/ferc/ferc_used_code.txt new file mode 100644 index 0000000..ab128cf --- /dev/null +++ b/ldecod/src/ferc/ferc_used_code.txt @@ -0,0 +1,734 @@ + +/*! + ************************************************************************ + * \file ferc_proposed.c + * + * \brief + * Unused code + * + * \author + * - Joao Carreira + * + ************************************************************************ + */ + +static int computeSADNeighborsWithoutEdges(StorablePicture *Destination, StorablePicture *BlockState, int x, int y, int Block_Size) +{ + int ii, jj; + int sad = 0; + int yBlock4x4 = y / Block_Size, xBlock4x4 = x / Block_Size; + int discard; + + // ***** ***** + // ***** * * + // ***** * * + // ***** ***** + + //! Left Neighbor + if (xBlock4x4 != 0 && BlockState->imgY[yBlock4x4][xBlock4x4 - 1] != 0) + { + for (ii = 0; ii < Block_Size; ii++) + { + sad += iabs(Destination->imgY[y + ii][x - 1] - Destination->imgY[y + ii][x]); + } + } + //! Right Neighbor + if ((x + BLOCK_SIZE) != Destination->size_x && BlockState->imgY[yBlock4x4][xBlock4x4 + 1] != 0) + { + for (ii = 0; ii < BLOCK_SIZE; ii++) + { + sad += iabs(Destination->imgY[y + ii][x + BLOCK_SIZE - 1] - Destination->imgY[y + ii][x + BLOCK_SIZE]); + } + } + + // ***** + // ***** + // ***** + // ***** + // ***** + // * * + // * * + // ***** + + //! Top Neighbor + if (y != 0 && BlockState->imgY[yBlock4x4 - 1][xBlock4x4] != 0) + { + for (jj = 0; jj < Block_Size; jj++) + { + sad += iabs(Destination->imgY[y - 1][x + jj] - Destination->imgY[y][x + jj]); + } + } + //! Bottom Neighbor + if ((y + BLOCK_SIZE) != Destination->size_y && BlockState->imgY[yBlock4x4 + 1][xBlock4x4] != 0) + { + for (jj = 0; jj < BLOCK_SIZE; jj++) + { + sad += iabs(Destination->imgY[y + BLOCK_SIZE][x + jj] - Destination->imgY[y + BLOCK_SIZE - 1][x + jj]); + } + } + + if (sad == 0) + { + int a = 0; + } + return sad; +} + +static int computeSADNeighborsWithEdges(StorablePicture *Destination, StorablePicture *BlockState, int x, int y, int Block_Size, StorablePicture *Edges) +{ + int ii, jj; + int sad = 0; + int yBlock4x4 = y / Block_Size, xBlock4x4 = x / Block_Size; + int discard; + + // ***** ***** + // ***** * * + // ***** * * + // ***** ***** + + //! Left Neighbor + if (xBlock4x4 != 0 && BlockState->imgY[yBlock4x4][xBlock4x4 - 1] != 0) + { + for (ii = 0; ii < Block_Size; ii++) + { + //! Check the egdes + discard = 0; + for (jj = -Block_Size / 2; jj <= Block_Size / 2; jj++) + { + if (Edges->imgY[y + ii][x + jj] >= 128) + { + discard = 1; + break; + } + } + if (discard) + continue; + sad += iabs(Destination->imgY[y + ii][x - 1] - Destination->imgY[y + ii][x]); + } + } + //! Right Neighbor + if ((x + BLOCK_SIZE) != Destination->size_x && BlockState->imgY[yBlock4x4][xBlock4x4 + 1] != 0) + { + for (ii = 0; ii < BLOCK_SIZE; ii++) + { + //! Check the egdes + discard = 0; + for (jj = -Block_Size / 2; jj <= Block_Size / 2; jj++) + { + if (Edges->imgY[y + ii][x + BLOCK_SIZE + jj] >= 128) + { + discard = 1; + break; + } + } + if (discard) + continue; + sad += iabs(Destination->imgY[y + ii][x + BLOCK_SIZE - 1] - Destination->imgY[y + ii][x + BLOCK_SIZE]); + } + } + + // ***** + // ***** + // ***** + // ***** + // ***** + // * * + // * * + // ***** + + //! Top Neighbor + if (y != 0 && BlockState->imgY[yBlock4x4 - 1][xBlock4x4] != 0) + { + for (jj = 0; jj < Block_Size; jj++) + { + //! Check the egdes + discard = 0; + for (ii = -Block_Size / 2; ii <= Block_Size / 2; ii++) + { + if (Edges->imgY[y + ii][x + jj] >= 128) + { + discard = 1; + break; + } + } + if (discard) + continue; + sad += iabs(Destination->imgY[y - 1][x + jj] - Destination->imgY[y][x + jj]); + } + } + //! Bottom Neighbor + if ((y + BLOCK_SIZE) != Destination->size_y && BlockState->imgY[yBlock4x4 + 1][xBlock4x4] != 0) + { + for (jj = 0; jj < BLOCK_SIZE; jj++) + { + //! Check the egdes + discard = 0; + for (ii = -Block_Size / 2; ii <= Block_Size / 2; ii++) + { + if (Edges->imgY[y + BLOCK_SIZE + ii][x + jj] >= 128) + { + discard = 1; + break; + } + } + if (discard) + continue; + sad += iabs(Destination->imgY[y + BLOCK_SIZE][x + jj] - Destination->imgY[y + BLOCK_SIZE - 1][x + jj]); + } + } + return sad; +} + +static double BlockVariance(StorablePicture *Picture, int BlockSize, int xPel, int yPel) +{ + int i, j; + double n_elem, average_n, average_n_minus1, variance_n; + imgpel **ImgY = Picture->imgY; + + if (xPel + BlockSize > Picture->size_x || yPel + BlockSize > Picture->size_y) + return INT_MAX; + + n_elem = 0.0; + average_n = 0; + variance_n = 0; + + for (i = yPel; i < yPel + BlockSize; i++) + { + for (j = xPel; j < xPel + BlockSize; j++) + { + /* On-line average and population variation */ + n_elem++; + average_n_minus1 = average_n; + average_n = average_n_minus1 + ((ImgY[i][j] - average_n_minus1) / n_elem); + variance_n = (n_elem - 1) * variance_n + (ImgY[i][j] - average_n) * (ImgY[i][j] - average_n_minus1); + variance_n = variance_n / n_elem; + } + } + return variance_n; +} + +static int ConcealmentDecision(VideoParameters *p_Vid, int ConcealmentMethod, StorablePicture *IntraRefFrame, StorablePicture *InterRefFrame, + StorablePicture *Disparity, StorablePicture *Disparity_4x4, MotionPropInfo Matrix_MV_Info, int y_block4x4, int x_block4x4, int Block_Size) +{ + int use_IntraMotionCopy = 1, use_InterMotionCopy = 1; + int mv_info_count, src_mv_y, src_mv_x; + int DispDir = p_Vid->p_Inp->DisparityDirection; + + if (ConcealmentMethod != MOTION_INTERVIEW_FIRST && ConcealmentMethod != MOTION_INTRA_INTER_SAD) + return ConcealmentMethod; + + src_mv_y = y_block4x4; + src_mv_x = x_block4x4; + + //! Check wich concealment strategies are valid + if ((mv_info_count = Matrix_MV_Info.mv_info_count[y_block4x4][x_block4x4]) < 0) + { + use_IntraMotionCopy = 0; + } + + src_mv_y = y_block4x4; + src_mv_x = i_min_max(x_block4x4 * Block_Size + DispDir * (int) (Disparity_4x4->imgY[y_block4x4][x_block4x4]), 0, p_Vid->width - 1); + src_mv_x = src_mv_x / Block_Size + (((src_mv_x % Block_Size) & 0x2) >> 1); + + if (InterRefFrame->mv_info[src_mv_y][src_mv_x].ref_idx[LIST_0] < 0 + && (InterRefFrame->slice_type != B_SLICE || InterRefFrame->mv_info[src_mv_y][src_mv_x].ref_idx[LIST_1] < 0)) + use_InterMotionCopy = 0; + + if ((use_IntraMotionCopy + use_InterMotionCopy) == 0) + { + //return MOTION_INTERVIEW_COPY; + return CONCEALMV; + } + else if ((use_IntraMotionCopy + use_InterMotionCopy) == 1) + { + if (use_IntraMotionCopy) + return MOTION_INTRAVIEW; + else + return MOTION_INTERVIEW; + } + else + { + if (ConcealmentMethod == MOTION_INTERVIEW_FIRST) + return MOTION_INTERVIEW; + + if (InterRefFrame->mv_info[src_mv_y][src_mv_x].mv[LIST_0].mv_x == Matrix_MV_Info.mv_info[y_block4x4][x_block4x4][mv_info_count].mv[LIST_0].mv_x + && InterRefFrame->mv_info[src_mv_y][src_mv_x].mv[LIST_0].mv_y == Matrix_MV_Info.mv_info[y_block4x4][x_block4x4][mv_info_count].mv[LIST_0].mv_y + && InterRefFrame->mv_info[src_mv_y][src_mv_x].ref_idx[LIST_0]) + { + //Same vectors + return MOTION_INTERVIEW; + } + + return (MOTION_INTRAVIEW + MOTION_INTERVIEW); + + } +} + +static int ConcealCurrentClusterDisparitySearch(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_pos, int y_pos, int BlockSize, + int SearchRange, int Inter_NotIntra, int BLockWindow) +{ + StorablePicture *Disparity = IntraInterConc->DisparityBlockwiseAux; + StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState; + StorablePicture *InterRefFrame = IntraInterConc->InterRefFrame; + StorablePicture *Destination = IntraInterConc->Destination; + StorablePicture *DifferenceMap = IntraInterConc->SpatialDifference; + imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; + int count, y, x, diff, curr_mb_idx, d, x_block, y_block, xx_b, yy_b, num, disp; + double SAD, MinSAD = 999; + int iRet = 0, MV[3], xFinalDisp; + double CurrentDiff; + int DifferenceThreshold; + + x_block = x_pos / BLOCK_SIZE; + y_block = y_pos / BLOCK_SIZE; + + disp = 0; + num = 0; + for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++) + { + for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++) + { + disp += Disparity->imgY[yy_b][xx_b]; + if (disp == 255) + return 0; + num++; + } + } + disp /= num; + + CurrentDiff = 0; + count = 0; + for (y = imax(0, y_block - BLockWindow) * BLOCK_SIZE; y < imin(DifferenceMap->size_y / BLOCK_SIZE, y_block + BLockWindow + 1) * BLOCK_SIZE; y++) + { + for (x = imax(0, x_block - BLockWindow) * BLOCK_SIZE; x < imin(DifferenceMap->size_x / BLOCK_SIZE, x_block + BLockWindow + 1) * BLOCK_SIZE; x++) + { + if (y >= 0 && y < DifferenceMap->size_y && x >= 0 && x < DifferenceMap->size_x) + { + diff = (int) (DifferenceMap->imgY[y][x]); + CurrentDiff = ((double) (CurrentDiff * count + diff)) / ((double) count + 1); + count++; + } + } + } + + xFinalDisp = disp; + //if( CurrentDiff > IntraInterConc->DifferenceThresholds[SPATIAL_DIFF] ) + { + MinSAD = INT_MAX; + for (d = -SearchRange; d <= SearchRange; d++) + { + if ((x_pos - (disp + d)) < 0 || (x_pos - (disp + d)) >= Destination->size_x) + continue; + SAD = computeSADOverlap(IntraInterConc, Destination, x_pos, y_pos, InterRefFrame, x_pos - (disp + d), y_pos, BlockSize, BlockSize + 4 * BLOCK_SIZE); + if (SAD <= MinSAD) + { + MinSAD = SAD; + xFinalDisp = disp + d; + } + } + } + + if (Inter_NotIntra) + { + MV[0] = (-xFinalDisp) * 4; + MV[1] = 0; + MV[2] = 0; + } + else + { + //xFinalDisp /= /BLOCK_SIZE; + //! For 4x4 blocks + xFinalDisp = xFinalDisp / BLOCK_SIZE + (((xFinalDisp % BLOCK_SIZE) & 0x2) >> 1); + } + + for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++) + { + for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++) + { + curr_mb_idx = yy_b * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + xx_b * BLOCK_SIZE / MB_BLOCK_SIZE; + + if (!Inter_NotIntra) + { + getMVInter(IntraInterConc, LIST_0, y_block, x_block - xFinalDisp, MV); + if (MV[2] < 0) + continue; + } + + EnhancedbuildPredblock4x4YUV(p_Vid, MV, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV); + copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, BLOCK_SIZE); + + // set motion vector in the concealed picture + IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_x = MV[0]; + IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_y = MV[1]; + IntraInterConc->Destination->mv_info[yy_b][xx_b].ref_idx[LIST_0] = MV[2]; + + IntraInterConc->BlockConcealmentState->imgY[yy_b][xx_b] = 1; + iRet++; + } + } + return iRet; +} + +static int ConcealCurrentClusterMotionSearch(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_pos, int y_pos, int BlockSize, int SearchRange) +{ + StorablePicture *Disparity = IntraInterConc->DisparityBlockwiseAux; + StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState; + StorablePicture *IntraRefFrame = IntraInterConc->IntraRefFrame; + StorablePicture *Destination = IntraInterConc->Destination; + imgpel *storeYUV = IntraInterConc->storeYUV[LIST_0][0]; + int curr_mb_idx, i, d, x_block, y_block, xx_b, yy_b, num, disp; + double SAD, MinSAD; + int y_final, x_final; + int iRet = 0, MVCandidate[2], MV[3], MVFinal[3]; + + x_block = x_pos / BLOCK_SIZE; + y_block = y_pos / BLOCK_SIZE; + + disp = 0; + num = 0; + for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++) + { + for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++) + { + disp += Disparity->imgY[yy_b][xx_b]; + num++; + } + } + disp /= num; + + MVCandidate[0] = 0; + MVCandidate[1] = 0; + num = 0; + getMVInter(IntraInterConc, LIST_0, y_block, x_block - disp / BLOCK_SIZE, MV); + if (MV[2] >= 0) + { + MVCandidate[0] += MV[0]; + MVCandidate[1] += MV[1]; + num++; + } + getMVIntra(IntraInterConc, LIST_0, y_block, x_block, MV); + if (MV[2] >= 0) + { + MVCandidate[0] += MV[0]; + MVCandidate[1] += MV[1]; + num++; + } + num = num ? num : 1; + MVCandidate[0] = MV[0] / num; + MVCandidate[1] = MV[1] / num; + + MinSAD = INT_MAX; + for (MV[1] = -SearchRange; MV[1] <= SearchRange; MV[1]++) + { + for (MV[0] = -SearchRange; MV[0] <= SearchRange; MV[0]++) + { + // if( x_pos + MVCandidate[0] + MV[0] ) + SAD = computeSADOverlap(IntraInterConc, Destination, x_pos, y_pos, IntraRefFrame, x_pos + MVCandidate[0] + MV[0], y_pos + MVCandidate[1] + MV[1], + BlockSize, BlockSize + 4 * BLOCK_SIZE); + if (SAD < MinSAD) + { + MinSAD = SAD; + MVFinal[0] = MVCandidate[0] + MV[0]; + MVFinal[1] = MVCandidate[1] + MV[1]; + } + } + } + MVFinal[0] *= 4; + MVFinal[1] *= 4; + MVFinal[2] = IntraInterConc->MVExtrapolationRefIdx[0]; + + for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++) + { + for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++) + { + curr_mb_idx = yy_b * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + xx_b * BLOCK_SIZE / MB_BLOCK_SIZE; + + EnhancedbuildPredblock4x4YUV(p_Vid, MVFinal, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, storeYUV, LIST_0, curr_mb_idx, IntraInterConc->tmp_storeYUV); + copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, BLOCK_SIZE); + + // set motion vector in the concealed picture + IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_x = MVFinal[0]; + IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_y = MVFinal[1]; + IntraInterConc->Destination->mv_info[yy_b][xx_b].ref_idx[LIST_0] = MVFinal[2]; + + IntraInterConc->BlockConcealmentState->imgY[yy_b][xx_b] = 1; + iRet++; + } + } + return iRet; +} + +static void getCurrentCluster(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int SameCondition, int x_block, int y_block, int *BlockSize) +{ + StorablePicture *BlockConcealmentState = IntraInterConc->BlockConcealmentState; + int i, j; + int Stop, currBlockSize = 1; + int *curr_mv, mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 }; + int prev_condition = -1, condition; + + *BlockSize = 0; + //! Find the first block to conceal + if (BlockConcealmentState->imgY[y_block][x_block] == 0 && (x_block == 0 || BlockConcealmentState->imgY[y_block][x_block - 1] != 0) + && (y_block == 0 || BlockConcealmentState->imgY[y_block - 1][x_block] != 0)) + { + Stop = 0; + currBlockSize = 0; + while (1) + { + //! Check Vertical side + for (i = 0; i < currBlockSize + 1; i++) + { + if (y_block + i >= BlockConcealmentState->size_y || x_block + currBlockSize >= BlockConcealmentState->size_x + || BlockConcealmentState->imgY[y_block + i][x_block + currBlockSize] == 1) + { + Stop = 1; + break; + } + + if (SameCondition) + { + getMVIntra(IntraInterConc, LIST_0, y_block + i, x_block + currBlockSize, mv_intra); + getMVInter(IntraInterConc, LIST_0, y_block + i, x_block + currBlockSize, mv_inter); + condition = (mv_intra[2] > 0) + (mv_inter[2] > 0) * 10; + if (prev_condition != -1 && condition != prev_condition) + { + Stop = 1; + break; + } + prev_condition = condition; + } + } + //! Check Horizontal side + for (i = 0; i < currBlockSize + 1; i++) + { + if (y_block + currBlockSize >= BlockConcealmentState->size_y || x_block + i >= BlockConcealmentState->size_x + || BlockConcealmentState->imgY[y_block + currBlockSize][x_block + i] == 1) + { + Stop = 1; + break; + } + + if (SameCondition) + { + getMVIntra(IntraInterConc, LIST_0, y_block + currBlockSize, x_block + i, mv_intra); + getMVInter(IntraInterConc, LIST_0, y_block + currBlockSize, x_block + i, mv_inter); + condition = (mv_intra[2] > 0) + (mv_inter[2] > 0) * 10; + if (prev_condition != -1 && condition != prev_condition) + { + Stop = 1; + break; + } + prev_condition = condition; + } + } + if (Stop) + break; + + currBlockSize++; + } + currBlockSize *= BLOCK_SIZE; + *BlockSize = currBlockSize; + return; + } +} + +static int ConcealCurrentClusterOnePredictor(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_pos, int y_pos, int BlockSize) +{ + imgpel ***storeYUV = IntraInterConc->storeYUV; + int *curr_mv, mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 }; + int curr_mb_idx, x_block, y_block, xx_b, yy_b; + int prev_case_metric = -1, case_metric; + int iRet = 0; + void + (*getMV)(INTER_INTRA_CONC_T *IntraInterConc, int list, int y_block, int x_block, int MV[3]); + + x_block = x_pos / BLOCK_SIZE; + y_block = y_pos / BLOCK_SIZE; + + for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++) + { + for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++) + { + getMVIntra(IntraInterConc, LIST_0, yy_b, xx_b, mv_intra); + getMVInter(IntraInterConc, LIST_0, yy_b, xx_b, mv_inter); + + case_metric = (mv_intra[2] > 0) + (mv_inter[2] > 0) * 10; + + if (prev_case_metric != -1 && case_metric != prev_case_metric) + { + return iRet; + } + prev_case_metric = case_metric; + } + } + + switch (case_metric) + { + case 0: // nothing + return iRet; + case 1: // only INTRA + getMV = getMVIntra; + break; + case 10: // only INTER + getMV = getMVInter; + break; + case 11: // both + //getMV = getMVInter; + return iRet; + break; + default: + case_metric = 0; + return iRet; + } + + for (xx_b = x_block; xx_b < x_block + BlockSize / BLOCK_SIZE; xx_b++) + { + for (yy_b = y_block; yy_b < y_block + BlockSize / BLOCK_SIZE; yy_b++) + { + getMV(IntraInterConc, LIST_0, yy_b, xx_b, mv_inter); + + curr_mb_idx = yy_b * BLOCK_SIZE / MB_BLOCK_SIZE * IntraInterConc->Destination->PicWidthInMbs + xx_b * BLOCK_SIZE / MB_BLOCK_SIZE; + + EnhancedbuildPredblock4x4YUV(p_Vid, mv_inter, xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, storeYUV[LIST_0][0], LIST_0, curr_mb_idx, + IntraInterConc->tmp_storeYUV); + copyPredblockRegionYUVDestination(IntraInterConc->Destination, storeYUV[LIST_0][0], xx_b * BLOCK_SIZE, yy_b * BLOCK_SIZE, BLOCK_SIZE); + + // set motion vector in the concealed picture + IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_x = mv_inter[0]; + IntraInterConc->Destination->mv_info[yy_b][xx_b].mv[LIST_0].mv_y = mv_inter[1]; + IntraInterConc->Destination->mv_info[yy_b][xx_b].ref_idx[LIST_0] = mv_inter[2]; + + IntraInterConc->BlockConcealmentState->imgY[yy_b][xx_b] = 1; + iRet++; + } + } + return iRet; +} + +static void getImageEdges(VideoParameters *p_Vid, StorablePicture *BaseviewFrame, StorablePicture *Disparity, StorablePicture *EdgesAuxView) +{ + StorablePicture *EdgesBaseView = NULL; + + EdgesBaseView = alloc_storable_picture(p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + + cvFindImageContours(p_Vid, BaseviewFrame, EdgesBaseView); + + DisparityCompensation(p_Vid, EdgesBaseView, EdgesAuxView, Disparity, LEFT); + + //showStorablePicture( p_Vid, EdgesBaseView, 0, 0, "Edges Base", 0 ); + //saveStorablePicture( p_Vid , "EdgesBaseView.bmp" , EdgesBaseView , 0 , 0 ); + //showStorablePicture( p_Vid, EdgesAuxView, 0, 0, "Edges Aux", 0 ); + //saveStorablePicture( p_Vid , "EdgesAuxView.bmp" , EdgesAuxView , 0 , 0 ); + + free_storable_picture(EdgesBaseView); + + return; +} + + +static void getCurrentClusterSafer(VideoParameters *p_Vid, INTER_INTRA_CONC_T *IntraInterConc, int x_MB, int y_MB, int block_idx, int *block_size, + double MSEThreshold, int MV[3]) +{ + int cur_idx, max_clust, x_block, y_block, inter_src_block, intra_mv_cnt, tmp_block_size = BLOCK_SIZE; + int mv_intra[3] = { 0, 0, 0 }, mv_inter[3] = { 0, 0, 0 }; + + MV[0] = MV[1] = 0; + MV[2] = -1; + + *block_size = 0; + cur_idx = block_idx; + + max_clust = CLUSTER[block_idx]; + max_clust += block_idx; + + cur_idx = block_idx; + while (cur_idx < max_clust) + { + do + { + y_block = (y_MB * MB_BLOCK_SIZE / BLOCK_SIZE) + BLOCK_IDX_MB[cur_idx][1]; + x_block = (x_MB * MB_BLOCK_SIZE / BLOCK_SIZE) + BLOCK_IDX_MB[cur_idx][0]; + + getMVIntra(IntraInterConc, LIST_0, y_block, x_block, mv_intra); + + getMVInter(IntraInterConc, LIST_0, y_block, x_block, mv_inter); + + if (mv_inter[2] < 0 || mv_intra[2] < 0) + { + return; //!< Cannot conceal anymore + } + + //! Compare mv candidates + //! If MSE Threshold is equal to zero we do not need to compare MSE, just the prediction + if (mv_intra[0] == mv_inter[0] && mv_intra[1] == mv_inter[1]) + { + //! Check reference frames to confirm + if (mv_intra[2] == mv_inter[2]) + { + if ((*block_size) == 0 || (mv_intra[0] == MV[0] && mv_intra[1] == MV[1] && mv_intra[2] == MV[2])) + { + MV[0] = mv_intra[0]; + MV[1] = mv_intra[1]; + MV[2] = mv_intra[2]; + cur_idx++; + continue; + } + } + } + + return; + } while (cur_idx < block_idx + target_cluster(*block_size)); + (*block_size) = (*block_size) ? (*block_size) * 2 : BLOCK_SIZE; + } + return; +} + + +/*! + ************************************************************************ + * \brief + * Compute the block based disparity for each pixel using a square block + * for a symmetric window + * + * The Disparity are normalized between + * [-WindowsSize, WindowsSize] + * Disp = Disp + GlobalWindowsSize + LocalWindowsSize; + ************************************************************************ + */ +static void FullSearchMotionEstimation(imgpel **currImg, imgpel**refImg, int size_x, int size_y, int window, int block_size, int pos_x, int pos_y, + MotionVector *curr_mv) +{ + int x, y, xx, yy, count; + int x_min, x_max, y_min, y_max; + uint16 sad, **sad_vector; + + get_mem2Duint16(&sad_vector, window * 2, window * 2); + + x_min = imax(0, pos_x - window); + y_max = imin(size_y - block_size, pos_y + window); + + y_min = imax(0, pos_y - window); + x_max = imin(size_x - block_size, pos_x + window); + + count = 0; + for (y = y_min; y < y_max; y++) + { + for (x = x_min; x < x_max; x++) + { + + // SAD between the current block and a possible ref block + for (yy = 0; yy <= block_size; yy++) + { + for (xx = 0; xx <= block_size; xx++) + { + sad += iabs(currImg[y + yy][x + xx] - refImg[y + yy][x + xx]); + } + } + (*sad_vector)[count++] = sad; + } + } + qsort(sad_vector, count, sizeof(uint16), sort_by_uint16_up); + // uint16_min_position( sad_vector, unsigned int n_elem, uint16 *min_value, unsigned int *min_pos) + free_mem2Duint16(sad_vector); + return; +} \ No newline at end of file diff --git a/ldecod/src/filehandle.c b/ldecod/src/filehandle.c new file mode 100644 index 0000000..2b5ff2b --- /dev/null +++ b/ldecod/src/filehandle.c @@ -0,0 +1,177 @@ + +/*! + ************************************************************************************** + * \file + * filehandle.c + * \brief + * Trace file handling and standard error handling function. + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + *************************************************************************************** + */ + +#include "contributors.h" +#include "global.h" +#include "mbuffer.h" + + +#if TRACE + +#include + +/*! +************************************************************************ +* \brief +* decrement trace p_Dec->bitcounter (used for special case in mb aff) +************************************************************************ +*/ +void dectracebitcnt(int count) +{ + p_Dec->bitcounter -= count; +} + +/*! + ************************************************************************ + * \brief + * Tracing bitpatterns for symbols + * A code word has the following format: 0 Xn...0 X2 0 X1 0 X0 1 + ************************************************************************ + */ +void tracebits( + const char *trace_str, //!< tracing information, char array describing the symbol + int len, //!< length of syntax element in bits + int info, //!< infoword of syntax element + int value1) +{ + int i, chars; + // int outint = 1; + + if(len>=64) + { + snprintf(errortext, ET_SIZE, "Length argument to put too long for trace to work"); + error (errortext, 600); + } + + putc('@', p_Dec->p_trace); + chars = fprintf(p_Dec->p_trace, "%i", p_Dec->bitcounter); + while(chars++ < 5) + putc(' ',p_Dec->p_trace); + + chars += fprintf(p_Dec->p_trace, " %s", trace_str); + while(chars++ < 55) + putc(' ',p_Dec->p_trace); + + // Align bitpattern + if(len<15) + { + for(i=0 ; i<15-len ; i++) + fputc(' ', p_Dec->p_trace); + } + + // Print bitpattern + for(i=0 ; ip_trace); + } + // put 1 + fprintf(p_Dec->p_trace, "1"); + + // Print bitpattern + for(i=0 ; i> ((len/2-i)-1))) + fputc('1', p_Dec->p_trace); + else + fputc('0', p_Dec->p_trace); + } + + fprintf(p_Dec->p_trace, " (%3d) \n", value1); + p_Dec->bitcounter += len; + + fflush (p_Dec->p_trace); +} + +/*! + ************************************************************************ + * \brief + * Tracing bitpatterns + ************************************************************************ + */ +void tracebits2( + const char *trace_str, //!< tracing information, char array describing the symbol + int len, //!< length of syntax element in bits + int info) +{ + + int i, chars; + // int outint = 1; + + if(len>=64) + { + snprintf(errortext, ET_SIZE, "Length argument to put too long for trace to work"); + error (errortext, 600); + } + + putc('@', p_Dec->p_trace); + chars = fprintf(p_Dec->p_trace, "%i", p_Dec->bitcounter); + + while(chars++ < 5) + putc(' ',p_Dec->p_trace); + + chars += fprintf(p_Dec->p_trace, " %s", trace_str); + + while(chars++ < 55) + putc(' ',p_Dec->p_trace); + + // Align bitpattern + if(len < 15) + { + for(i = 0; i < 15 - len; i++) + fputc(' ', p_Dec->p_trace); + } + + p_Dec->bitcounter += len; + while (len >= 32) + { + for(i = 0; i < 8; i++) + { + fputc('0', p_Dec->p_trace); + } + len -= 8; + } + + // Print bitpattern + for(i=0 ; i> (len-i-1))) + fputc('1', p_Dec->p_trace); + else + fputc('0', p_Dec->p_trace); + } + + fprintf(p_Dec->p_trace, " (%3d) \n", info); + + fflush (p_Dec->p_trace); +} + +/*! + ************************************************************************ + * \brief + * Tracing information such as motion/ref_idx etc + ************************************************************************ + */ +void trace_info( + SyntaxElement *currSE, //!< syntax element to update + const char *description_str, //!< tracing information, char array describing the symbol + int value1 //!< value to be recorded +) + +{ + char tstring[20]; + sprintf( tstring, "%s%d", description_str, value1); + strncpy(currSE->tracestring, tstring, TRACESTRING_SIZE); +} + +#endif + diff --git a/ldecod/src/fmo.c b/ldecod/src/fmo.c new file mode 100644 index 0000000..d531723 --- /dev/null +++ b/ldecod/src/fmo.c @@ -0,0 +1,555 @@ + +/*! + ***************************************************************************** + * + * \file fmo.c + * + * \brief + * Support for Flexible Macroblock Ordering (FMO) + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger stewe@cs.tu-berlin.de + * - Karsten Suehring + ****************************************************************************** + */ + +#include "global.h" +#include "elements.h" +#include "defines.h" +#include "header.h" +#include "fmo.h" +#include "fast_memory.h" + +//#define PRINT_FMO_MAPS + +static void FmoGenerateType0MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ); +static void FmoGenerateType1MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ); +static void FmoGenerateType2MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ); +static void FmoGenerateType3MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice ); +static void FmoGenerateType4MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice ); +static void FmoGenerateType5MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice ); +static void FmoGenerateType6MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ); + + +/*! + ************************************************************************ + * \brief + * Generates p_Vid->MapUnitToSliceGroupMap + * Has to be called every time a new Picture Parameter Set is used + * + * \param p_Vid + * video encoding parameters for current picture + * + ************************************************************************ + */ +static int FmoGenerateMapUnitToSliceGroupMap (VideoParameters *p_Vid, Slice *currSlice) +{ + seq_parameter_set_rbsp_t* sps = p_Vid->active_sps; + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + + unsigned int NumSliceGroupMapUnits; + + NumSliceGroupMapUnits = (sps->pic_height_in_map_units_minus1+1)* (sps->pic_width_in_mbs_minus1+1); + + if (pps->slice_group_map_type == 6) + { + if ((pps->pic_size_in_map_units_minus1 + 1) != NumSliceGroupMapUnits) + { + error ("wrong pps->pic_size_in_map_units_minus1 for used SPS and FMO type 6", 500); + } + } + + // allocate memory for p_Vid->MapUnitToSliceGroupMap + if (p_Vid->MapUnitToSliceGroupMap) + free (p_Vid->MapUnitToSliceGroupMap); + if ((p_Vid->MapUnitToSliceGroupMap = malloc ((NumSliceGroupMapUnits) * sizeof (int))) == NULL) + { + printf ("cannot allocated %d bytes for p_Vid->MapUnitToSliceGroupMap, exit\n", (int) ( (pps->pic_size_in_map_units_minus1+1) * sizeof (int))); + exit (-1); + } + + if (pps->num_slice_groups_minus1 == 0) // only one slice group + { + fast_memset (p_Vid->MapUnitToSliceGroupMap, 0, NumSliceGroupMapUnits * sizeof (int)); + return 0; + } + + switch (pps->slice_group_map_type) + { + case 0: + FmoGenerateType0MapUnitMap (p_Vid, NumSliceGroupMapUnits); + break; + case 1: + FmoGenerateType1MapUnitMap (p_Vid, NumSliceGroupMapUnits); + break; + case 2: + FmoGenerateType2MapUnitMap (p_Vid, NumSliceGroupMapUnits); + break; + case 3: + FmoGenerateType3MapUnitMap (p_Vid, NumSliceGroupMapUnits, currSlice); + break; + case 4: + FmoGenerateType4MapUnitMap (p_Vid, NumSliceGroupMapUnits, currSlice); + break; + case 5: + FmoGenerateType5MapUnitMap (p_Vid, NumSliceGroupMapUnits, currSlice); + break; + case 6: + FmoGenerateType6MapUnitMap (p_Vid, NumSliceGroupMapUnits); + break; + default: + printf ("Illegal slice_group_map_type %d , exit \n", (int) pps->slice_group_map_type); + exit (-1); + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * Generates p_Vid->MbToSliceGroupMap from p_Vid->MapUnitToSliceGroupMap + * + * \param p_Vid + * video encoding parameters for current picture + * + ************************************************************************ + */ +static int FmoGenerateMbToSliceGroupMap (VideoParameters *p_Vid, Slice *pSlice) +{ + seq_parameter_set_rbsp_t* sps = p_Vid->active_sps; + + unsigned i; + + // allocate memory for p_Vid->MbToSliceGroupMap + if (p_Vid->MbToSliceGroupMap) + free (p_Vid->MbToSliceGroupMap); + + if ((p_Vid->MbToSliceGroupMap = malloc ((p_Vid->PicSizeInMbs) * sizeof (int))) == NULL) + { + printf ("cannot allocate %d bytes for p_Vid->MbToSliceGroupMap, exit\n", (int) ((p_Vid->PicSizeInMbs) * sizeof (int))); + exit (-1); + } + + + if ((sps->frame_mbs_only_flag)|| pSlice->field_pic_flag) + { + int *MbToSliceGroupMap = p_Vid->MbToSliceGroupMap; + int *MapUnitToSliceGroupMap = p_Vid->MapUnitToSliceGroupMap; + for (i=0; iPicSizeInMbs; i++) + { + *MbToSliceGroupMap++ = *MapUnitToSliceGroupMap++; + } + } + else + if (sps->mb_adaptive_frame_field_flag && (!pSlice->field_pic_flag)) + { + for (i=0; iPicSizeInMbs; i++) + { + p_Vid->MbToSliceGroupMap[i] = p_Vid->MapUnitToSliceGroupMap[i/2]; + } + } + else + { + for (i=0; iPicSizeInMbs; i++) + { + p_Vid->MbToSliceGroupMap[i] = p_Vid->MapUnitToSliceGroupMap[(i/(2*p_Vid->PicWidthInMbs))*p_Vid->PicWidthInMbs+(i%p_Vid->PicWidthInMbs)]; + } + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * FMO initialization: Generates p_Vid->MapUnitToSliceGroupMap and p_Vid->MbToSliceGroupMap. + * + * \param p_Vid + * video encoding parameters for current picture + ************************************************************************ + */ +int fmo_init(VideoParameters *p_Vid, Slice *pSlice) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + +#ifdef PRINT_FMO_MAPS + unsigned i,j; +#endif + + FmoGenerateMapUnitToSliceGroupMap(p_Vid, pSlice); + FmoGenerateMbToSliceGroupMap(p_Vid, pSlice); + + p_Vid->NumberOfSliceGroups = pps->num_slice_groups_minus1 + 1; + +#ifdef PRINT_FMO_MAPS + printf("\n"); + printf("FMO Map (Units):\n"); + + for (j=0; jPicHeightInMapUnits; j++) + { + for (i=0; iPicWidthInMbs; i++) + { + printf("%c",48+p_Vid->MapUnitToSliceGroupMap[i+j*p_Vid->PicWidthInMbs]); + } + printf("\n"); + } + printf("\n"); + printf("FMO Map (Mb):\n"); + + for (j=0; jPicHeightInMbs; j++) + { + for (i=0; iPicWidthInMbs; i++) + { + printf("%c",48 + p_Vid->MbToSliceGroupMap[i + j * p_Vid->PicWidthInMbs]); + } + printf("\n"); + } + printf("\n"); + +#endif + + return 0; +} + + +/*! + ************************************************************************ + * \brief + * Free memory allocated by FMO functions + ************************************************************************ + */ +int FmoFinit(VideoParameters *p_Vid) +{ + if (p_Vid->MbToSliceGroupMap) + { + free (p_Vid->MbToSliceGroupMap); + p_Vid->MbToSliceGroupMap = NULL; + } + if (p_Vid->MapUnitToSliceGroupMap) + { + free (p_Vid->MapUnitToSliceGroupMap); + p_Vid->MapUnitToSliceGroupMap = NULL; + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * FmoGetNumberOfSliceGroup(p_Vid) + * + * \par p_Vid: + * VideoParameters + ************************************************************************ + */ +int FmoGetNumberOfSliceGroup(VideoParameters *p_Vid) +{ + return p_Vid->NumberOfSliceGroups; +} + + +/*! + ************************************************************************ + * \brief + * FmoGetLastMBOfPicture(p_Vid) + * returns the macroblock number of the last MB in a picture. This + * mb happens to be the last macroblock of the picture if there is only + * one slice group + * + * \par Input: + * None + ************************************************************************ + */ +int FmoGetLastMBOfPicture(VideoParameters *p_Vid) +{ + return FmoGetLastMBInSliceGroup (p_Vid, FmoGetNumberOfSliceGroup(p_Vid)-1); +} + + +/*! + ************************************************************************ + * \brief + * FmoGetLastMBInSliceGroup: Returns MB number of last MB in SG + * + * \par Input: + * SliceGroupID (0 to 7) + ************************************************************************ + */ + +int FmoGetLastMBInSliceGroup (VideoParameters *p_Vid, int SliceGroup) +{ + int i; + + for (i=p_Vid->PicSizeInMbs-1; i>=0; i--) + if (FmoGetSliceGroupId (p_Vid, i) == SliceGroup) + return i; + return -1; + +} + + +/*! + ************************************************************************ + * \brief + * Returns SliceGroupID for a given MB + * + * \param p_Vid + * video encoding parameters for current picture + * \param mb + * Macroblock number (in scan order) + ************************************************************************ + */ +int FmoGetSliceGroupId (VideoParameters *p_Vid, int mb) +{ + assert (mb < (int) p_Vid->PicSizeInMbs); + assert (p_Vid->MbToSliceGroupMap != NULL); + return p_Vid->MbToSliceGroupMap[mb]; +} + + +/*! + ************************************************************************ + * \brief + * FmoGetNextMBBr: Returns the MB-Nr (in scan order) of the next + * MB in the (scattered) Slice, -1 if the slice is finished + * \param p_Vid + * video encoding parameters for current picture + * + * \param CurrentMbNr + * number of the current macroblock + ************************************************************************ + */ +int FmoGetNextMBNr (VideoParameters *p_Vid, int CurrentMbNr) +{ + int SliceGroup = FmoGetSliceGroupId (p_Vid, CurrentMbNr); + + while (++CurrentMbNr<(int)p_Vid->PicSizeInMbs && p_Vid->MbToSliceGroupMap [CurrentMbNr] != SliceGroup) + ; + + if (CurrentMbNr >= (int)p_Vid->PicSizeInMbs) + return -1; // No further MB in this slice (could be end of picture) + else + return CurrentMbNr; +} + + +/*! + ************************************************************************ + * \brief + * Generate interleaved slice group map type MapUnit map (type 0) + * + ************************************************************************ + */ +static void FmoGenerateType0MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + unsigned iGroup, j; + unsigned i = 0; + do + { + for( iGroup = 0; + (iGroup <= pps->num_slice_groups_minus1) && (i < PicSizeInMapUnits); + i += pps->run_length_minus1[iGroup++] + 1 ) + { + for( j = 0; j <= pps->run_length_minus1[ iGroup ] && i + j < PicSizeInMapUnits; j++ ) + p_Vid->MapUnitToSliceGroupMap[i+j] = iGroup; + } + } + while( i < PicSizeInMapUnits ); +} + + +/*! + ************************************************************************ + * \brief + * Generate dispersed slice group map type MapUnit map (type 1) + * + ************************************************************************ + */ +static void FmoGenerateType1MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + unsigned i; + for( i = 0; i < PicSizeInMapUnits; i++ ) + { + p_Vid->MapUnitToSliceGroupMap[i] = ((i%p_Vid->PicWidthInMbs)+(((i/p_Vid->PicWidthInMbs)*(pps->num_slice_groups_minus1+1))/2)) + %(pps->num_slice_groups_minus1+1); + } +} + +/*! + ************************************************************************ + * \brief + * Generate foreground with left-over slice group map type MapUnit map (type 2) + * + ************************************************************************ + */ +static void FmoGenerateType2MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + int iGroup; + unsigned i, x, y; + unsigned yTopLeft, xTopLeft, yBottomRight, xBottomRight; + + for( i = 0; i < PicSizeInMapUnits; i++ ) + p_Vid->MapUnitToSliceGroupMap[ i ] = pps->num_slice_groups_minus1; + + for( iGroup = pps->num_slice_groups_minus1 - 1 ; iGroup >= 0; iGroup-- ) + { + yTopLeft = pps->top_left[ iGroup ] / p_Vid->PicWidthInMbs; + xTopLeft = pps->top_left[ iGroup ] % p_Vid->PicWidthInMbs; + yBottomRight = pps->bottom_right[ iGroup ] / p_Vid->PicWidthInMbs; + xBottomRight = pps->bottom_right[ iGroup ] % p_Vid->PicWidthInMbs; + for( y = yTopLeft; y <= yBottomRight; y++ ) + for( x = xTopLeft; x <= xBottomRight; x++ ) + p_Vid->MapUnitToSliceGroupMap[ y * p_Vid->PicWidthInMbs + x ] = iGroup; + } +} + + +/*! + ************************************************************************ + * \brief + * Generate box-out slice group map type MapUnit map (type 3) + * + ************************************************************************ + */ +static void FmoGenerateType3MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + unsigned i, k; + int leftBound, topBound, rightBound, bottomBound; + int x, y, xDir, yDir; + int mapUnitVacant; + + unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * currSlice->slice_group_change_cycle, PicSizeInMapUnits); + + for( i = 0; i < PicSizeInMapUnits; i++ ) + p_Vid->MapUnitToSliceGroupMap[ i ] = 2; + + x = ( p_Vid->PicWidthInMbs - pps->slice_group_change_direction_flag ) / 2; + y = ( p_Vid->PicHeightInMapUnits - pps->slice_group_change_direction_flag ) / 2; + + leftBound = x; + topBound = y; + rightBound = x; + bottomBound = y; + + xDir = pps->slice_group_change_direction_flag - 1; + yDir = pps->slice_group_change_direction_flag; + + for( k = 0; k < PicSizeInMapUnits; k += mapUnitVacant ) + { + mapUnitVacant = ( p_Vid->MapUnitToSliceGroupMap[ y * p_Vid->PicWidthInMbs + x ] == 2 ); + if( mapUnitVacant ) + p_Vid->MapUnitToSliceGroupMap[ y * p_Vid->PicWidthInMbs + x ] = ( k >= mapUnitsInSliceGroup0 ); + + if( xDir == -1 && x == leftBound ) + { + leftBound = imax( leftBound - 1, 0 ); + x = leftBound; + xDir = 0; + yDir = 2 * pps->slice_group_change_direction_flag - 1; + } + else + if( xDir == 1 && x == rightBound ) + { + rightBound = imin( rightBound + 1, (int)p_Vid->PicWidthInMbs - 1 ); + x = rightBound; + xDir = 0; + yDir = 1 - 2 * pps->slice_group_change_direction_flag; + } + else + if( yDir == -1 && y == topBound ) + { + topBound = imax( topBound - 1, 0 ); + y = topBound; + xDir = 1 - 2 * pps->slice_group_change_direction_flag; + yDir = 0; + } + else + if( yDir == 1 && y == bottomBound ) + { + bottomBound = imin( bottomBound + 1, (int)p_Vid->PicHeightInMapUnits - 1 ); + y = bottomBound; + xDir = 2 * pps->slice_group_change_direction_flag - 1; + yDir = 0; + } + else + { + x = x + xDir; + y = y + yDir; + } + } + +} + +/*! + ************************************************************************ + * \brief + * Generate raster scan slice group map type MapUnit map (type 4) + * + ************************************************************************ + */ +static void FmoGenerateType4MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + + unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * currSlice->slice_group_change_cycle, PicSizeInMapUnits); + unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0; + + unsigned i; + + for( i = 0; i < PicSizeInMapUnits; i++ ) + if( i < sizeOfUpperLeftGroup ) + p_Vid->MapUnitToSliceGroupMap[ i ] = pps->slice_group_change_direction_flag; + else + p_Vid->MapUnitToSliceGroupMap[ i ] = 1 - pps->slice_group_change_direction_flag; + +} + +/*! + ************************************************************************ + * \brief + * Generate wipe slice group map type MapUnit map (type 5) + * + ************************************************************************ + */ +static void FmoGenerateType5MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits, Slice *currSlice ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + + unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * currSlice->slice_group_change_cycle, PicSizeInMapUnits); + unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0; + + unsigned i,j, k = 0; + + for( j = 0; j < p_Vid->PicWidthInMbs; j++ ) + for( i = 0; i < p_Vid->PicHeightInMapUnits; i++ ) + if( k++ < sizeOfUpperLeftGroup ) + p_Vid->MapUnitToSliceGroupMap[ i * p_Vid->PicWidthInMbs + j ] = pps->slice_group_change_direction_flag; + else + p_Vid->MapUnitToSliceGroupMap[ i * p_Vid->PicWidthInMbs + j ] = 1 - pps->slice_group_change_direction_flag; + +} + +/*! + ************************************************************************ + * \brief + * Generate explicit slice group map type MapUnit map (type 6) + * + ************************************************************************ + */ +static void FmoGenerateType6MapUnitMap (VideoParameters *p_Vid, unsigned PicSizeInMapUnits ) +{ + pic_parameter_set_rbsp_t* pps = p_Vid->active_pps; + unsigned i; + for (i=0; iMapUnitToSliceGroupMap[i] = pps->slice_group_id[i]; + } +} + diff --git a/ldecod/src/header.c b/ldecod/src/header.c new file mode 100644 index 0000000..aa20857 --- /dev/null +++ b/ldecod/src/header.c @@ -0,0 +1,995 @@ + +/*! + ************************************************************************************* + * \file header.c + * + * \brief + * H.264 Slice headers + * + ************************************************************************************* + */ + +#include "global.h" +#include "elements.h" +#include "defines.h" +#include "fmo.h" +#include "vlc.h" +#include "mbuffer.h" +#include "header.h" + +#include "ctx_tables.h" + + +#if TRACE +#define SYMTRACESTRING(s) strncpy(sym.tracestring,s,TRACESTRING_SIZE) +#else +#define SYMTRACESTRING(s) // do nothing +#endif + +static void ref_pic_list_reordering(Slice *currSlice); +static void pred_weight_table(Slice *currSlice); +#if (MVC_EXTENSION_ENABLE) +static void ref_pic_list_mvc_modification(Slice *currSlice); +#endif + + +/*! + ************************************************************************ + * \brief + * calculate Ceil(Log2(uiVal)) + ************************************************************************ + */ +unsigned CeilLog2( unsigned uiVal) +{ + unsigned uiTmp = uiVal-1; + unsigned uiRet = 0; + + while( uiTmp != 0 ) + { + uiTmp >>= 1; + uiRet++; + } + return uiRet; +} + +unsigned CeilLog2_sf( unsigned uiVal) +{ + unsigned uiTmp = uiVal-1; + unsigned uiRet = 0; + + while( uiTmp > 0 ) + { + uiTmp >>= 1; + uiRet++; + } + return uiRet; +} + +/*! + ************************************************************************ + * \brief + * read the first part of the header (only the pic_parameter_set_id) + * \return + * Length of the first part of the slice header (in bits) + ************************************************************************ + */ +int FirstPartOfSliceHeader(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + byte dP_nr = assignSE2partition[currSlice->dp_mode][SE_HEADER]; + DataPartition *partition = &(currSlice->partArr[dP_nr]); + Bitstream *currStream = partition->bitstream; + int tmp; + + p_Dec->UsedBits= partition->bitstream->frame_bitoffset; // was hardcoded to 31 for previous start-code. This is better. + + // Get first_mb_in_slice + currSlice->start_mb_nr = read_ue_v ("SH: first_mb_in_slice", currStream, &p_Dec->UsedBits); + + tmp = read_ue_v ("SH: slice_type", currStream, &p_Dec->UsedBits); + + if (tmp > 4) tmp -= 5; + + p_Vid->type = currSlice->slice_type = (SliceType) tmp; + + currSlice->pic_parameter_set_id = read_ue_v ("SH: pic_parameter_set_id", currStream, &p_Dec->UsedBits); + + if( p_Vid->separate_colour_plane_flag ) + currSlice->colour_plane_id = read_u_v (2, "SH: colour_plane_id", currStream, &p_Dec->UsedBits); + else + currSlice->colour_plane_id = PLANE_Y; + + return p_Dec->UsedBits; +} + +/*! + ************************************************************************ + * \brief + * read the scond part of the header (without the pic_parameter_set_id + * \return + * Length of the second part of the Slice header in bits + ************************************************************************ + */ +int RestOfSliceHeader(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + byte dP_nr = assignSE2partition[currSlice->dp_mode][SE_HEADER]; + DataPartition *partition = &(currSlice->partArr[dP_nr]); + Bitstream *currStream = partition->bitstream; + + int val, len; + + currSlice->frame_num = read_u_v (active_sps->log2_max_frame_num_minus4 + 4, "SH: frame_num", currStream, &p_Dec->UsedBits); + + /* Tian Dong: frame_num gap processing, if found */ + if(currSlice->idr_flag) //if (p_Vid->idr_flag) + { +//#if (MVC_EXTENSION_ENABLE) +// int i; +// for(i=1;ipre_frame_num[i] = -1; +// p_Vid->last_ref_pic_poc[i] = 0; +// } +// p_Vid->pre_frame_num[0] = 0; +// p_Vid->last_ref_pic_poc[currSlice->view_id] = 0; +//#else +// p_Vid->last_ref_pic_poc = 0; +// p_Vid->pre_frame_num = currSlice->frame_num; +//#endif +// // picture error concealment +// + assert(currSlice->frame_num == 0); + } + + if (active_sps->frame_mbs_only_flag) + { + p_Vid->structure = FRAME; + currSlice->field_pic_flag=0; + } + else + { + // field_pic_flag u(1) + currSlice->field_pic_flag = read_u_1("SH: field_pic_flag", currStream, &p_Dec->UsedBits); + if (currSlice->field_pic_flag) + { + // bottom_field_flag u(1) + currSlice->bottom_field_flag = (byte) read_u_1("SH: bottom_field_flag", currStream, &p_Dec->UsedBits); + p_Vid->structure = currSlice->bottom_field_flag ? BOTTOM_FIELD : TOP_FIELD; + } + else + { + p_Vid->structure = FRAME; + currSlice->bottom_field_flag = FALSE; + } + } + + currSlice->structure = (PictureStructure) p_Vid->structure; + + currSlice->mb_aff_frame_flag = (active_sps->mb_adaptive_frame_field_flag && (currSlice->field_pic_flag==0)); + //currSlice->mb_aff_frame_flag = p_Vid->mb_aff_frame_flag; + + if (p_Vid->structure == FRAME ) + assert (currSlice->field_pic_flag == 0); + if (p_Vid->structure == TOP_FIELD ) + assert (currSlice->field_pic_flag == 1 && (currSlice->bottom_field_flag == FALSE)); + if (p_Vid->structure == BOTTOM_FIELD) + assert (currSlice->field_pic_flag == 1 && (currSlice->bottom_field_flag == TRUE )); + + if (currSlice->idr_flag) + { + currSlice->idr_pic_id = read_ue_v("SH: idr_pic_id", currStream, &p_Dec->UsedBits); + } +#if (MVC_EXTENSION_ENABLE) + else if ( currSlice->svc_extension_flag == 0 && currSlice->NaluHeaderMVCExt.non_idr_flag == 0 ) + { + currSlice->idr_pic_id = read_ue_v("SH: idr_pic_id", currStream, &p_Dec->UsedBits); + } +#endif + + if (active_sps->pic_order_cnt_type == 0) + { + currSlice->pic_order_cnt_lsb = read_u_v(active_sps->log2_max_pic_order_cnt_lsb_minus4 + 4, "SH: pic_order_cnt_lsb", currStream, &p_Dec->UsedBits); + if( p_Vid->active_pps->bottom_field_pic_order_in_frame_present_flag == 1 && !currSlice->field_pic_flag ) + currSlice->delta_pic_order_cnt_bottom = read_se_v("SH: delta_pic_order_cnt_bottom", currStream, &p_Dec->UsedBits); + else + currSlice->delta_pic_order_cnt_bottom = 0; + } + if( active_sps->pic_order_cnt_type == 1 ) + { + if ( !active_sps->delta_pic_order_always_zero_flag ) + { + currSlice->delta_pic_order_cnt[ 0 ] = read_se_v("SH: delta_pic_order_cnt[0]", currStream, &p_Dec->UsedBits); + if( p_Vid->active_pps->bottom_field_pic_order_in_frame_present_flag == 1 && !currSlice->field_pic_flag ) + currSlice->delta_pic_order_cnt[ 1 ] = read_se_v("SH: delta_pic_order_cnt[1]", currStream, &p_Dec->UsedBits); + else + currSlice->delta_pic_order_cnt[ 1 ] = 0; // set to zero if not in stream + } + else + { + currSlice->delta_pic_order_cnt[ 0 ] = 0; + currSlice->delta_pic_order_cnt[ 1 ] = 0; + } + } + + //! redundant_pic_cnt is missing here + if (p_Vid->active_pps->redundant_pic_cnt_present_flag) + { + currSlice->redundant_pic_cnt = read_ue_v ("SH: redundant_pic_cnt", currStream, &p_Dec->UsedBits); + } + + if(currSlice->slice_type == B_SLICE) + { + currSlice->direct_spatial_mv_pred_flag = read_u_1 ("SH: direct_spatial_mv_pred_flag", currStream, &p_Dec->UsedBits); + } + + currSlice->num_ref_idx_active[LIST_0] = p_Vid->active_pps->num_ref_idx_l0_default_active_minus1 + 1; + currSlice->num_ref_idx_active[LIST_1] = p_Vid->active_pps->num_ref_idx_l1_default_active_minus1 + 1; + + if(currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE || currSlice->slice_type == B_SLICE) + { + val = read_u_1 ("SH: num_ref_idx_override_flag", currStream, &p_Dec->UsedBits); + if (val) + { + currSlice->num_ref_idx_active[LIST_0] = 1 + read_ue_v ("SH: num_ref_idx_l0_active_minus1", currStream, &p_Dec->UsedBits); + + if(currSlice->slice_type == B_SLICE) + { + currSlice->num_ref_idx_active[LIST_1] = 1 + read_ue_v ("SH: num_ref_idx_l1_active_minus1", currStream, &p_Dec->UsedBits); + } + } + } + if (currSlice->slice_type!=B_SLICE) + { + currSlice->num_ref_idx_active[LIST_1] = 0; + } + +#if (MVC_EXTENSION_ENABLE) + if (currSlice->svc_extension_flag == 0 || currSlice->svc_extension_flag == 1) + ref_pic_list_mvc_modification(currSlice); + else + ref_pic_list_reordering(currSlice); +#else + ref_pic_list_reordering(currSlice); +#endif + + currSlice->weighted_pred_flag = (unsigned short) ((currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE) + ? p_Vid->active_pps->weighted_pred_flag + : (currSlice->slice_type == B_SLICE && p_Vid->active_pps->weighted_bipred_idc == 1)); + currSlice->weighted_bipred_idc = (unsigned short) (currSlice->slice_type == B_SLICE && p_Vid->active_pps->weighted_bipred_idc > 0); + + if ((p_Vid->active_pps->weighted_pred_flag&&(currSlice->slice_type == P_SLICE|| currSlice->slice_type == SP_SLICE))|| + (p_Vid->active_pps->weighted_bipred_idc==1 && (currSlice->slice_type == B_SLICE))) + { + pred_weight_table(currSlice); + } + + if (currSlice->nal_reference_idc) + dec_ref_pic_marking(p_Vid, currStream, currSlice); + + if (p_Vid->active_pps->entropy_coding_mode_flag && currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + currSlice->model_number = read_ue_v("SH: cabac_init_idc", currStream, &p_Dec->UsedBits); + } + else + { + currSlice->model_number = 0; + } + + currSlice->slice_qp_delta = val = read_se_v("SH: slice_qp_delta", currStream, &p_Dec->UsedBits); + //currSlice->qp = p_Vid->qp = 26 + p_Vid->active_pps->pic_init_qp_minus26 + val; + currSlice->qp = 26 + p_Vid->active_pps->pic_init_qp_minus26 + val; + + if ((currSlice->qp < -p_Vid->bitdepth_luma_qp_scale) || (currSlice->qp > 51)) + error ("slice_qp_delta makes slice_qp_y out of range", 500); + + if(currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + if(currSlice->slice_type==SP_SLICE) + { + currSlice->sp_switch = read_u_1 ("SH: sp_for_switch_flag", currStream, &p_Dec->UsedBits); + } + currSlice->slice_qs_delta = val = read_se_v("SH: slice_qs_delta", currStream, &p_Dec->UsedBits); + currSlice->qs = 26 + p_Vid->active_pps->pic_init_qs_minus26 + val; + if ((currSlice->qs < 0) || (currSlice->qs > 51)) + error ("slice_qs_delta makes slice_qs_y out of range", 500); + } + + if ( !HI_intra_only_profile(active_sps->profile_idc, active_sps->constrained_set3_flag) || (p_Inp->intra_profile_deblocking == 1) ) + //then read flags and parameters from bistream + { +#if DPF_PARAM_DISP + printf("deblocking_filter_control_present_flag:%d\n", p_Vid->active_pps->deblocking_filter_control_present_flag); +#endif + if (p_Vid->active_pps->deblocking_filter_control_present_flag) + { + currSlice->DFDisableIdc = (short) read_ue_v ("SH: disable_deblocking_filter_idc", currStream, &p_Dec->UsedBits); + + if (currSlice->DFDisableIdc!=1) + { + currSlice->DFAlphaC0Offset = (short) (2 * read_se_v("SH: slice_alpha_c0_offset_div2", currStream, &p_Dec->UsedBits)); + currSlice->DFBetaOffset = (short) (2 * read_se_v("SH: slice_beta_offset_div2", currStream, &p_Dec->UsedBits)); + } + else + { + currSlice->DFAlphaC0Offset = currSlice->DFBetaOffset = 0; + } + } + else + { + currSlice->DFDisableIdc = currSlice->DFAlphaC0Offset = currSlice->DFBetaOffset = 0; + } +#if DPF_PARAM_DISP + printf("Slice:%d, DFParameters:(%d,%d,%d)\n\n", currSlice->current_slice_nr, currSlice->DFDisableIdc, currSlice->DFAlphaC0Offset, currSlice->DFBetaOffset); +#endif + } + else //By default the Loop Filter is Off + { //444_TEMP_NOTE: change made below. 08/07/07 + //still need to parse the SEs (read flags and parameters from bistream) but will ignore + if (p_Vid->active_pps->deblocking_filter_control_present_flag) + { + currSlice->DFDisableIdc = (short) read_ue_v ("SH: disable_deblocking_filter_idc", currStream, &p_Dec->UsedBits); + + if (currSlice->DFDisableIdc!=1) + { + currSlice->DFAlphaC0Offset = (short) (2 * read_se_v("SH: slice_alpha_c0_offset_div2", currStream, &p_Dec->UsedBits)); + currSlice->DFBetaOffset = (short) (2 * read_se_v("SH: slice_beta_offset_div2", currStream, &p_Dec->UsedBits)); + } + }//444_TEMP_NOTE. the end of change. 08/07/07 + //Ignore the SEs, by default the Loop Filter is Off + currSlice->DFDisableIdc =1; + currSlice->DFAlphaC0Offset = currSlice->DFBetaOffset = 0; + } + + + if (p_Vid->active_pps->num_slice_groups_minus1>0 && p_Vid->active_pps->slice_group_map_type>=3 && + p_Vid->active_pps->slice_group_map_type<=5) + { + len = (active_sps->pic_height_in_map_units_minus1+1)*(active_sps->pic_width_in_mbs_minus1+1)/ + (p_Vid->active_pps->slice_group_change_rate_minus1+1); + if (((active_sps->pic_height_in_map_units_minus1+1)*(active_sps->pic_width_in_mbs_minus1+1))% + (p_Vid->active_pps->slice_group_change_rate_minus1+1)) + len +=1; + + len = CeilLog2(len+1); + + currSlice->slice_group_change_cycle = read_u_v (len, "SH: slice_group_change_cycle", currStream, &p_Dec->UsedBits); + } + p_Vid->PicHeightInMbs = p_Vid->FrameHeightInMbs / ( 1 + currSlice->field_pic_flag ); + p_Vid->PicSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->PicHeightInMbs; + p_Vid->FrameSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->FrameHeightInMbs; + + return p_Dec->UsedBits; +} + + +/*! + ************************************************************************ + * \brief + * read the reference picture reordering information + ************************************************************************ + */ +static void ref_pic_list_reordering(Slice *currSlice) +{ + //VideoParameters *p_Vid = currSlice->p_Vid; + byte dP_nr = assignSE2partition[currSlice->dp_mode][SE_HEADER]; + DataPartition *partition = &(currSlice->partArr[dP_nr]); + Bitstream *currStream = partition->bitstream; + int i, val; + + alloc_ref_pic_list_reordering_buffer(currSlice); + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + val = currSlice->ref_pic_list_reordering_flag[LIST_0] = read_u_1 ("SH: ref_pic_list_reordering_flag_l0", currStream, &p_Dec->UsedBits); + + if (val) + { + i=0; + do + { + val = currSlice->modification_of_pic_nums_idc[LIST_0][i] = read_ue_v("SH: modification_of_pic_nums_idc_l0", currStream, &p_Dec->UsedBits); + if (val==0 || val==1) + { + currSlice->abs_diff_pic_num_minus1[LIST_0][i] = read_ue_v("SH: abs_diff_pic_num_minus1_l0", currStream, &p_Dec->UsedBits); + } + else + { + if (val==2) + { + currSlice->long_term_pic_idx[LIST_0][i] = read_ue_v("SH: long_term_pic_idx_l0", currStream, &p_Dec->UsedBits); + } + } + i++; + // assert (i>currSlice->num_ref_idx_active[LIST_0]); + } while (val != 3); + } + } + + if (currSlice->slice_type == B_SLICE) + { + val = currSlice->ref_pic_list_reordering_flag[LIST_1] = read_u_1 ("SH: ref_pic_list_reordering_flag_l1", currStream, &p_Dec->UsedBits); + + if (val) + { + i=0; + do + { + val = currSlice->modification_of_pic_nums_idc[LIST_1][i] = read_ue_v("SH: modification_of_pic_nums_idc_l1", currStream, &p_Dec->UsedBits); + if (val==0 || val==1) + { + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = read_ue_v("SH: abs_diff_pic_num_minus1_l1", currStream, &p_Dec->UsedBits); + } + else + { + if (val==2) + { + currSlice->long_term_pic_idx[LIST_1][i] = read_ue_v("SH: long_term_pic_idx_l1", currStream, &p_Dec->UsedBits); + } + } + i++; + // assert (i>currSlice->num_ref_idx_active[LIST_1]); + } while (val != 3); + } + } + + // set reference index of redundant slices. + if(currSlice->redundant_pic_cnt && (currSlice->slice_type != I_SLICE) ) + { + currSlice->redundant_slice_ref_idx = currSlice->abs_diff_pic_num_minus1[LIST_0][0] + 1; + } +} + +/*! + ************************************************************************ + * \brief + * read the MVC reference picture reordering information + ************************************************************************ + */ +#if (MVC_EXTENSION_ENABLE) +static void ref_pic_list_mvc_modification(Slice *currSlice) +{ + //VideoParameters *p_Vid = currSlice->p_Vid; + byte dP_nr = assignSE2partition[currSlice->dp_mode][SE_HEADER]; + DataPartition *partition = &(currSlice->partArr[dP_nr]); + Bitstream *currStream = partition->bitstream; + int i, val; + + alloc_ref_pic_list_reordering_buffer(currSlice); + + if ((currSlice->slice_type % 5) != I_SLICE && (currSlice->slice_type % 5) != SI_SLICE) + { + val = currSlice->ref_pic_list_reordering_flag[LIST_0] = read_u_1 ("SH: ref_pic_list_modification_flag_l0", currStream, &p_Dec->UsedBits); + + if (val) + { + i=0; + do + { + val = currSlice->modification_of_pic_nums_idc[LIST_0][i] = read_ue_v("SH: modification_of_pic_nums_idc_l0", currStream, &p_Dec->UsedBits); + if (val==0 || val==1) + { + currSlice->abs_diff_pic_num_minus1[LIST_0][i] = read_ue_v("SH: abs_diff_pic_num_minus1_l0", currStream, &p_Dec->UsedBits); + } + else + { + if (val==2) + { + currSlice->long_term_pic_idx[LIST_0][i] = read_ue_v("SH: long_term_pic_idx_l0", currStream, &p_Dec->UsedBits); + } + else if (val==4 || val==5) + { + currSlice->abs_diff_view_idx_minus1[LIST_0][i] = read_ue_v("SH: abs_diff_view_idx_minus1_l0", currStream, &p_Dec->UsedBits); + } + } + i++; + // assert (i>img->num_ref_idx_l0_active); + } while (val != 3); + } + } + + if ((currSlice->slice_type % 5) == B_SLICE) + { + val = currSlice->ref_pic_list_reordering_flag[LIST_1] = read_u_1 ("SH: ref_pic_list_reordering_flag_l1", currStream, &p_Dec->UsedBits); + + if (val) + { + i=0; + do + { + val = currSlice->modification_of_pic_nums_idc[LIST_1][i] = read_ue_v("SH: modification_of_pic_nums_idc_l1", currStream, &p_Dec->UsedBits); + if (val==0 || val==1) + { + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = read_ue_v("SH: abs_diff_pic_num_minus1_l1", currStream, &p_Dec->UsedBits); + } + else + { + if (val==2) + { + currSlice->long_term_pic_idx[LIST_1][i] = read_ue_v("SH: long_term_pic_idx_l1", currStream, &p_Dec->UsedBits); + } + else if (val==4 || val==5) + { + currSlice->abs_diff_view_idx_minus1[LIST_1][i] = read_ue_v("SH: abs_diff_view_idx_minus1_l1", currStream, &p_Dec->UsedBits); + } + } + i++; + // assert (i>img->num_ref_idx_l1_active); + } while (val != 3); + } + } + + // set reference index of redundant slices. + if(currSlice->redundant_pic_cnt && (currSlice->slice_type != I_SLICE) ) + { + currSlice->redundant_slice_ref_idx = currSlice->abs_diff_pic_num_minus1[LIST_0][0] + 1; + } +} +#endif + +static void reset_wp_params(Slice *currSlice) +{ + int i,comp; + int log_weight_denom; + + for (i=0; iluma_log2_weight_denom : currSlice->chroma_log2_weight_denom; + currSlice->wp_weight[0][i][comp] = 1 << log_weight_denom; + currSlice->wp_weight[1][i][comp] = 1 << log_weight_denom; + } + } +} + +/*! + ************************************************************************ + * \brief + * read the weighted prediction tables + ************************************************************************ + */ +static void pred_weight_table(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + byte dP_nr = assignSE2partition[currSlice->dp_mode][SE_HEADER]; + DataPartition *partition = &(currSlice->partArr[dP_nr]); + Bitstream *currStream = partition->bitstream; + int luma_weight_flag_l0, luma_weight_flag_l1, chroma_weight_flag_l0, chroma_weight_flag_l1; + int i,j; + + currSlice->luma_log2_weight_denom = (unsigned short) read_ue_v ("SH: luma_log2_weight_denom", currStream, &p_Dec->UsedBits); + currSlice->wp_round_luma = currSlice->luma_log2_weight_denom ? 1<<(currSlice->luma_log2_weight_denom - 1): 0; + + if ( 0 != active_sps->chroma_format_idc) + { + currSlice->chroma_log2_weight_denom = (unsigned short) read_ue_v ("SH: chroma_log2_weight_denom", currStream, &p_Dec->UsedBits); + currSlice->wp_round_chroma = currSlice->chroma_log2_weight_denom ? 1<<(currSlice->chroma_log2_weight_denom - 1): 0; + } + + reset_wp_params(currSlice); + + for (i=0; inum_ref_idx_active[LIST_0]; i++) + { + luma_weight_flag_l0 = read_u_1("SH: luma_weight_flag_l0", currStream, &p_Dec->UsedBits); + + if (luma_weight_flag_l0) + { + currSlice->wp_weight[LIST_0][i][0] = read_se_v ("SH: luma_weight_l0", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_0][i][0] = read_se_v ("SH: luma_offset_l0", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_0][i][0] = currSlice->wp_offset[LIST_0][i][0]<<(p_Vid->bitdepth_luma - 8); + } + else + { + currSlice->wp_weight[LIST_0][i][0] = 1 << currSlice->luma_log2_weight_denom; + currSlice->wp_offset[LIST_0][i][0] = 0; + } + + if (active_sps->chroma_format_idc != 0) + { + chroma_weight_flag_l0 = read_u_1 ("SH: chroma_weight_flag_l0", currStream, &p_Dec->UsedBits); + + for (j=1; j<3; j++) + { + if (chroma_weight_flag_l0) + { + currSlice->wp_weight[LIST_0][i][j] = read_se_v("SH: chroma_weight_l0", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_0][i][j] = read_se_v("SH: chroma_offset_l0", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_0][i][j] = currSlice->wp_offset[LIST_0][i][j]<<(p_Vid->bitdepth_chroma-8); + } + else + { + currSlice->wp_weight[LIST_0][i][j] = 1<chroma_log2_weight_denom; + currSlice->wp_offset[LIST_0][i][j] = 0; + } + } + } + } + if ((currSlice->slice_type == B_SLICE) && p_Vid->active_pps->weighted_bipred_idc == 1) + { + for (i=0; inum_ref_idx_active[LIST_1]; i++) + { + luma_weight_flag_l1 = read_u_1("SH: luma_weight_flag_l1", currStream, &p_Dec->UsedBits); + + if (luma_weight_flag_l1) + { + currSlice->wp_weight[LIST_1][i][0] = read_se_v ("SH: luma_weight_l1", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_1][i][0] = read_se_v ("SH: luma_offset_l1", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_1][i][0] = currSlice->wp_offset[LIST_1][i][0]<<(p_Vid->bitdepth_luma-8); + } + else + { + currSlice->wp_weight[LIST_1][i][0] = 1<luma_log2_weight_denom; + currSlice->wp_offset[LIST_1][i][0] = 0; + } + + if (active_sps->chroma_format_idc != 0) + { + chroma_weight_flag_l1 = read_u_1 ("SH: chroma_weight_flag_l1", currStream, &p_Dec->UsedBits); + + for (j=1; j<3; j++) + { + if (chroma_weight_flag_l1) + { + currSlice->wp_weight[LIST_1][i][j] = read_se_v("SH: chroma_weight_l1", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_1][i][j] = read_se_v("SH: chroma_offset_l1", currStream, &p_Dec->UsedBits); + currSlice->wp_offset[LIST_1][i][j] = currSlice->wp_offset[LIST_1][i][j]<<(p_Vid->bitdepth_chroma-8); + } + else + { + currSlice->wp_weight[LIST_1][i][j] = 1<chroma_log2_weight_denom; + currSlice->wp_offset[LIST_1][i][j] = 0; + } + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * read the memory control operations + ************************************************************************ + */ +void dec_ref_pic_marking(VideoParameters *p_Vid, Bitstream *currStream, Slice *pSlice) +{ + int val; + + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2; + + // free old buffer content + while (pSlice->dec_ref_pic_marking_buffer) + { + tmp_drpm=pSlice->dec_ref_pic_marking_buffer; + + pSlice->dec_ref_pic_marking_buffer=tmp_drpm->Next; + free (tmp_drpm); + } + +#if (MVC_EXTENSION_ENABLE) + if ( pSlice->idr_flag || (pSlice->svc_extension_flag == 0 && pSlice->NaluHeaderMVCExt.non_idr_flag == 0) ) +#else + if (pSlice->idr_flag) +#endif + { + pSlice->no_output_of_prior_pics_flag = read_u_1("SH: no_output_of_prior_pics_flag", currStream, &p_Dec->UsedBits); + p_Vid->no_output_of_prior_pics_flag = pSlice->no_output_of_prior_pics_flag; + pSlice->long_term_reference_flag = read_u_1("SH: long_term_reference_flag", currStream, &p_Dec->UsedBits); + } + else + { + pSlice->adaptive_ref_pic_buffering_flag = read_u_1("SH: adaptive_ref_pic_buffering_flag", currStream, &p_Dec->UsedBits); + if (pSlice->adaptive_ref_pic_buffering_flag) + { + // read Memory Management Control Operation + do + { + tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)); + tmp_drpm->Next=NULL; + + val = tmp_drpm->memory_management_control_operation = read_ue_v("SH: memory_management_control_operation", currStream, &p_Dec->UsedBits); + + if ((val==1)||(val==3)) + { + tmp_drpm->difference_of_pic_nums_minus1 = read_ue_v("SH: difference_of_pic_nums_minus1", currStream, &p_Dec->UsedBits); + } + if (val==2) + { + tmp_drpm->long_term_pic_num = read_ue_v("SH: long_term_pic_num", currStream, &p_Dec->UsedBits); + } + + if ((val==3)||(val==6)) + { + tmp_drpm->long_term_frame_idx = read_ue_v("SH: long_term_frame_idx", currStream, &p_Dec->UsedBits); + } + if (val==4) + { + tmp_drpm->max_long_term_frame_idx_plus1 = read_ue_v("SH: max_long_term_pic_idx_plus1", currStream, &p_Dec->UsedBits); + } + + // add command + if (pSlice->dec_ref_pic_marking_buffer==NULL) + { + pSlice->dec_ref_pic_marking_buffer=tmp_drpm; + } + else + { + tmp_drpm2=pSlice->dec_ref_pic_marking_buffer; + while (tmp_drpm2->Next!=NULL) tmp_drpm2=tmp_drpm2->Next; + tmp_drpm2->Next=tmp_drpm; + } + + } + while (val != 0); + } + } +} + +/*! + ************************************************************************ + * \brief + * To calculate the poc values + * based upon JVT-F100d2 + * POC200301: Until Jan 2003, this function will calculate the correct POC + * values, but the management of POCs in buffered pictures may need more work. + * \return + * none + ************************************************************************ + */ +void decode_poc(VideoParameters *p_Vid, Slice *pSlice) +{ + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + int i; + // for POC mode 0: + unsigned int MaxPicOrderCntLsb = (1<<(active_sps->log2_max_pic_order_cnt_lsb_minus4+4)); + + switch ( active_sps->pic_order_cnt_type ) + { + case 0: // POC MODE 0 + // 1st + if(pSlice->idr_flag) + { + p_Vid->PrevPicOrderCntMsb = 0; + p_Vid->PrevPicOrderCntLsb = 0; + } + else + { + if (p_Vid->last_has_mmco_5) + { + if (p_Vid->last_pic_bottom_field) + { + p_Vid->PrevPicOrderCntMsb = 0; + p_Vid->PrevPicOrderCntLsb = 0; + } + else + { + p_Vid->PrevPicOrderCntMsb = 0; + p_Vid->PrevPicOrderCntLsb = pSlice->toppoc; + } + } + } + // Calculate the MSBs of current picture + if( pSlice->pic_order_cnt_lsb < p_Vid->PrevPicOrderCntLsb && + ( p_Vid->PrevPicOrderCntLsb - pSlice->pic_order_cnt_lsb ) >= ( MaxPicOrderCntLsb / 2 ) ) + pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb + MaxPicOrderCntLsb; + else if ( pSlice->pic_order_cnt_lsb > p_Vid->PrevPicOrderCntLsb && + ( pSlice->pic_order_cnt_lsb - p_Vid->PrevPicOrderCntLsb ) > ( MaxPicOrderCntLsb / 2 ) ) + pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb - MaxPicOrderCntLsb; + else + pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb; + + // 2nd + + if(pSlice->field_pic_flag==0) + { //frame pix + pSlice->toppoc = pSlice->PicOrderCntMsb + pSlice->pic_order_cnt_lsb; + pSlice->bottompoc = pSlice->toppoc + pSlice->delta_pic_order_cnt_bottom; + pSlice->ThisPOC = pSlice->framepoc = (pSlice->toppoc < pSlice->bottompoc)? pSlice->toppoc : pSlice->bottompoc; // POC200301 + } + else if (pSlice->bottom_field_flag == FALSE) + { //top field + pSlice->ThisPOC= pSlice->toppoc = pSlice->PicOrderCntMsb + pSlice->pic_order_cnt_lsb; + } + else + { //bottom field + pSlice->ThisPOC= pSlice->bottompoc = pSlice->PicOrderCntMsb + pSlice->pic_order_cnt_lsb; + } + pSlice->framepoc = pSlice->ThisPOC; + + p_Vid->ThisPOC = pSlice->ThisPOC; + + //if ( pSlice->frame_num != p_Vid->PreviousFrameNum) //Seems redundant + p_Vid->PreviousFrameNum = pSlice->frame_num; + + if(pSlice->nal_reference_idc) + { + p_Vid->PrevPicOrderCntLsb = pSlice->pic_order_cnt_lsb; + p_Vid->PrevPicOrderCntMsb = pSlice->PicOrderCntMsb; + } + + break; + + case 1: // POC MODE 1 + // 1st + if(pSlice->idr_flag) + { + p_Vid->FrameNumOffset=0; // first pix of IDRGOP, + if(pSlice->frame_num) + error("frame_num not equal to zero in IDR picture", -1020); + } + else + { + if (p_Vid->last_has_mmco_5) + { + p_Vid->PreviousFrameNumOffset = 0; + p_Vid->PreviousFrameNum = 0; + } + if (pSlice->frame_numPreviousFrameNum) + { //not first pix of IDRGOP + p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset + p_Vid->max_frame_num; + } + else + { + p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset; + } + } + + // 2nd + if(active_sps->num_ref_frames_in_pic_order_cnt_cycle) + pSlice->AbsFrameNum = p_Vid->FrameNumOffset+pSlice->frame_num; + else + pSlice->AbsFrameNum=0; + if( (!pSlice->nal_reference_idc) && pSlice->AbsFrameNum > 0) + pSlice->AbsFrameNum--; + + // 3rd + p_Vid->ExpectedDeltaPerPicOrderCntCycle=0; + + if(active_sps->num_ref_frames_in_pic_order_cnt_cycle) + for(i=0;i<(int) active_sps->num_ref_frames_in_pic_order_cnt_cycle;i++) + p_Vid->ExpectedDeltaPerPicOrderCntCycle += active_sps->offset_for_ref_frame[i]; + + if(pSlice->AbsFrameNum) + { + p_Vid->PicOrderCntCycleCnt = (pSlice->AbsFrameNum-1)/active_sps->num_ref_frames_in_pic_order_cnt_cycle; + p_Vid->FrameNumInPicOrderCntCycle = (pSlice->AbsFrameNum-1)%active_sps->num_ref_frames_in_pic_order_cnt_cycle; + p_Vid->ExpectedPicOrderCnt = p_Vid->PicOrderCntCycleCnt*p_Vid->ExpectedDeltaPerPicOrderCntCycle; + for(i=0;i<=(int)p_Vid->FrameNumInPicOrderCntCycle;i++) + p_Vid->ExpectedPicOrderCnt += active_sps->offset_for_ref_frame[i]; + } + else + p_Vid->ExpectedPicOrderCnt=0; + + if(!pSlice->nal_reference_idc) + p_Vid->ExpectedPicOrderCnt += active_sps->offset_for_non_ref_pic; + + if(pSlice->field_pic_flag==0) + { //frame pix + pSlice->toppoc = p_Vid->ExpectedPicOrderCnt + pSlice->delta_pic_order_cnt[0]; + pSlice->bottompoc = pSlice->toppoc + active_sps->offset_for_top_to_bottom_field + pSlice->delta_pic_order_cnt[1]; + pSlice->ThisPOC = pSlice->framepoc = (pSlice->toppoc < pSlice->bottompoc)? pSlice->toppoc : pSlice->bottompoc; // POC200301 + } + else if (pSlice->bottom_field_flag == FALSE) + { //top field + pSlice->ThisPOC = pSlice->toppoc = p_Vid->ExpectedPicOrderCnt + pSlice->delta_pic_order_cnt[0]; + } + else + { //bottom field + pSlice->ThisPOC = pSlice->bottompoc = p_Vid->ExpectedPicOrderCnt + active_sps->offset_for_top_to_bottom_field + pSlice->delta_pic_order_cnt[0]; + } + pSlice->framepoc=pSlice->ThisPOC; + + p_Vid->PreviousFrameNum=pSlice->frame_num; + p_Vid->PreviousFrameNumOffset=p_Vid->FrameNumOffset; + + break; + + + case 2: // POC MODE 2 + if(pSlice->idr_flag) // IDR picture + { + p_Vid->FrameNumOffset=0; // first pix of IDRGOP, + pSlice->ThisPOC = pSlice->framepoc = pSlice->toppoc = pSlice->bottompoc = 0; + if(pSlice->frame_num) + error("frame_num not equal to zero in IDR picture", -1020); + } + else + { + if (p_Vid->last_has_mmco_5) + { + p_Vid->PreviousFrameNum = 0; + p_Vid->PreviousFrameNumOffset = 0; + } + if (pSlice->frame_numPreviousFrameNum) + p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset + p_Vid->max_frame_num; + else + p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset; + + + pSlice->AbsFrameNum = p_Vid->FrameNumOffset+pSlice->frame_num; + if(!pSlice->nal_reference_idc) + pSlice->ThisPOC = (2*pSlice->AbsFrameNum - 1); + else + pSlice->ThisPOC = (2*pSlice->AbsFrameNum); + + if (pSlice->field_pic_flag==0) + pSlice->toppoc = pSlice->bottompoc = pSlice->framepoc = pSlice->ThisPOC; + else if (pSlice->bottom_field_flag == FALSE) + pSlice->toppoc = pSlice->framepoc = pSlice->ThisPOC; + else + pSlice->bottompoc = pSlice->framepoc = pSlice->ThisPOC; + } + + p_Vid->PreviousFrameNum=pSlice->frame_num; + p_Vid->PreviousFrameNumOffset=p_Vid->FrameNumOffset; + break; + + + default: + //error must occurs + assert( 1==0 ); + break; + } +} + +/*! + ************************************************************************ + * \brief + * A little helper for the debugging of POC code + * \return + * none + ************************************************************************ + */ +int dumppoc(VideoParameters *p_Vid) +{ + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + printf ("\nPOC locals...\n"); + printf ("toppoc %d\n", (int) p_Vid->ppSliceList[0]->toppoc); + printf ("bottompoc %d\n", (int) p_Vid->ppSliceList[0]->bottompoc); + printf ("frame_num %d\n", (int) p_Vid->ppSliceList[0]->frame_num); + printf ("field_pic_flag %d\n", (int) p_Vid->ppSliceList[0]->field_pic_flag); + printf ("bottom_field_flag %d\n", (int) p_Vid->ppSliceList[0]->bottom_field_flag); + printf ("POC SPS\n"); + printf ("log2_max_frame_num_minus4 %d\n", (int) active_sps->log2_max_frame_num_minus4); // POC200301 + printf ("log2_max_pic_order_cnt_lsb_minus4 %d\n", (int) active_sps->log2_max_pic_order_cnt_lsb_minus4); + printf ("pic_order_cnt_type %d\n", (int) active_sps->pic_order_cnt_type); + printf ("num_ref_frames_in_pic_order_cnt_cycle %d\n", (int) active_sps->num_ref_frames_in_pic_order_cnt_cycle); + printf ("delta_pic_order_always_zero_flag %d\n", (int) active_sps->delta_pic_order_always_zero_flag); + printf ("offset_for_non_ref_pic %d\n", (int) active_sps->offset_for_non_ref_pic); + printf ("offset_for_top_to_bottom_field %d\n", (int) active_sps->offset_for_top_to_bottom_field); + printf ("offset_for_ref_frame[0] %d\n", (int) active_sps->offset_for_ref_frame[0]); + printf ("offset_for_ref_frame[1] %d\n", (int) active_sps->offset_for_ref_frame[1]); + printf ("POC in SLice Header\n"); + printf ("bottom_field_pic_order_in_frame_present_flag %d\n", (int) p_Vid->active_pps->bottom_field_pic_order_in_frame_present_flag); + printf ("delta_pic_order_cnt[0] %d\n", (int) p_Vid->ppSliceList[0]->delta_pic_order_cnt[0]); + printf ("delta_pic_order_cnt[1] %d\n", (int) p_Vid->ppSliceList[0]->delta_pic_order_cnt[1]); + printf ("idr_flag %d\n", (int) p_Vid->ppSliceList[0]->idr_flag); + printf ("max_frame_num %d\n", (int) p_Vid->max_frame_num); + + return 0; +} + +/*! + ************************************************************************ + * \brief + * return the poc of p_Vid as per (8-1) JVT-F100d2 + * POC200301 + ************************************************************************ + */ +int picture_order( Slice *pSlice ) +{ + if (pSlice->field_pic_flag==0) // is a frame + return pSlice->framepoc; + else if (pSlice->bottom_field_flag == FALSE) // top field + return pSlice->toppoc; + else // bottom field + return pSlice->bottompoc; +} + diff --git a/ldecod/src/image.c b/ldecod/src/image.c new file mode 100644 index 0000000..fa6279b --- /dev/null +++ b/ldecod/src/image.c @@ -0,0 +1,2785 @@ +/*! + *********************************************************************** + * \file image.c + * + * \brief + * Decode a Slice + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langoy + * - Rickard Sjoberg + * - Jani Lainema + * - Sebastian Purreiter + * - Byeong-Moon Jeon + * - Thomas Wedi + * - Gabi Blaettermann + * - Ye-Kui Wang + * - Antti Hallapuro + * - Alexis Tourapis + * - Jill Boyce + * - Saurav K Bandyopadhyay + * - Zhenyu Wu + * + *********************************************************************** + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "image.h" +#include "fmo.h" +#include "annexb.h" +#include "nalu.h" +#include "parset.h" +#include "header.h" + +#include "sei.h" +#include "output.h" +#include "mb_access.h" +#include "memalloc.h" +#include "macroblock.h" + +#include "loopfilter.h" + +#include "biaridecod.h" +#include "context_ini.h" +#include "cabac.h" +#include "vlc.h" +#include "quant.h" + +#include "errorconcealment.h" +#include "erc_api.h" + +/* Edited by Joao Carreira */ +#include "transcode_dec.h" +#include "ferc_api.h" +#include "ferc_opencv_api.h" + +#include "mbuffer_common.h" +#include "mbuffer_mvc.h" +#include "fast_memory.h" + +#include "mc_prediction.h" + +#include "stream_parser.h" + +extern int testEndian( void); +void reorder_lists( Slice *currSlice); + +static inline void reset_mbs( Macroblock *currMB) +{ + currMB->slice_nr = -1; + currMB->ei_flag = 1; + currMB->dpl_flag = 0; + currMB->is_decoded = 0; +} + +static void setup_buffers( VideoParameters *p_Vid, int layer_id) +{ + CodingParameters *cps = p_Vid->p_EncodePar[layer_id]; + int i; + + if( p_Vid->last_dec_layer_id != layer_id ) + { + p_Vid->imgY_ref = cps->imgY_ref; + p_Vid->imgUV_ref = cps->imgUV_ref; + if( cps->separate_colour_plane_flag ) + { + for( i = 0; i < MAX_PLANE; i++ ) + { + p_Vid->mb_data_JV[i] = cps->mb_data_JV[i]; + p_Vid->intra_block_JV[i] = cps->intra_block_JV[i]; + p_Vid->ipredmode_JV[i] = cps->ipredmode_JV[i]; + p_Vid->siblock_JV[i] = cps->siblock_JV[i]; + } + p_Vid->mb_data = NULL; + p_Vid->intra_block = NULL; + p_Vid->ipredmode = NULL; + p_Vid->siblock = NULL; + } + else + { + p_Vid->mb_data = cps->mb_data; + p_Vid->intra_block = cps->intra_block; + p_Vid->ipredmode = cps->ipredmode; + p_Vid->siblock = cps->siblock; + } + p_Vid->PicPos = cps->PicPos; + p_Vid->nz_coeff = cps->nz_coeff; + p_Vid->qp_per_matrix = cps->qp_per_matrix; + p_Vid->qp_rem_matrix = cps->qp_rem_matrix; + p_Vid->oldFrameSizeInMbs = cps->oldFrameSizeInMbs; + p_Vid->img2buf = cps->img2buf; + p_Vid->last_dec_layer_id = layer_id; + } +} + +#if MVC_EXTENSION_ENABLE +void init_mvc_picture( Slice *currSlice) +{ + int l, i, v, find; + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[0]; + // Edited by Joao Carreira + int max_view_num = p_Vid->active_subset_sps->num_views_minus1 + 1; + int curr_view_id = currSlice->view_id; + + StorablePicture *p_pic[MAX_NUM_DPB_LAYERS - 1]; + int find_refs = 0; + + memset( p_pic, NULL, (MAX_NUM_DPB_LAYERS - 1) * sizeof(StorablePicture *)); + + // find BL reconstructed picture + if( currSlice->structure == FRAME ) + { + for( l = 0; l < p_Vid->active_subset_sps->num_views_minus1 + 1; l++ ) + { + p_Dpb = p_Vid->p_Dpb_layer[l]; + for( i = 0; i < (int) p_Dpb->used_size/*size*/; i++ ) + { + FrameStore *fs = p_Dpb->fs[i]; + if( (fs->frame->view_id != currSlice->view_id) && (fs->frame->frame_poc == currSlice->framepoc) ) + { + p_pic[find_refs++] = fs->frame; + //break; + } + } + } + } + else if( currSlice->structure == TOP_FIELD ) + { + for( l = 0; l < p_Vid->active_subset_sps->num_views_minus1 + 1; l++ ) + { + p_Dpb = p_Vid->p_Dpb_layer[l]; + for( i = 0; i < (int) p_Dpb->used_size/*size*/; i++ ) + { + FrameStore *fs = p_Dpb->fs[i]; + if( (fs->top_field->view_id != currSlice->view_id) && (fs->top_field->top_poc == currSlice->toppoc) ) + { + p_pic[find_refs++] = fs->top_field; + //break; + } + } + } + } + else + { + for( l = 0; l < p_Vid->active_subset_sps->num_views_minus1 + 1; l++ ) + { + p_Dpb = p_Vid->p_Dpb_layer[l]; + for( i = 0; i < (int) p_Dpb->used_size/*size*/; i++ ) + { + FrameStore *fs = p_Dpb->fs[i]; + if( (fs->bottom_field->view_id != currSlice->view_id) && (fs->bottom_field->bottom_poc == currSlice->bottompoc) ) + { + p_pic[find_refs++] = fs->bottom_field; + //break; + } + } + } + } + + //picture error concealment - only works for stereo video + if( !p_pic[0] ) + { + p_Dpb = p_Vid->p_Dpb_layer[0]; + fercConcealLostInterviewRefFrames( p_Dpb, &p_pic[0], currSlice, 0); + find_refs++; + } + + //picture error concealment - multi-view coding scenario + for( v = 0; v < curr_view_id; v++ ) + { + find = 0; + for( i = 0; i < find_refs; i++ ) + { + if( p_pic[i]->view_id == v ) + { + find = 1; + break; + } + } + if( !find ) + { + p_Dpb = p_Vid->p_Dpb_layer[v]; + fercConcealLostInterviewRefFrames( p_Vid->p_Dpb_layer[v], &p_pic[find_refs], currSlice, v); + find_refs++; + } + } + + if( !p_pic[0] ) + { + p_Vid->bFrameInit = 0; + } + else + { + int i; + check_for_previous_interview_frames( currSlice->p_Dpb, p_pic[0]); + i = 0; + for( i = 0; i < find_refs; i++ ) + { + process_picture_in_dpb_s( p_Vid, p_pic[i]); + store_proc_picture_in_dpb( currSlice->p_Dpb, clone_storable_picture( p_Vid, p_pic[i])); + } + } +} +#endif + +/*! + ************************************************************************ + * \brief + * Initializes the parameters for a new picture + ************************************************************************ + */ +static void init_picture( VideoParameters *p_Vid, Slice *currSlice, InputParameters *p_Inp) +{ + int i; + int nplane; + StorablePicture *dec_picture = NULL; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + p_Vid->PicHeightInMbs = p_Vid->FrameHeightInMbs / (1 + currSlice->field_pic_flag); + p_Vid->PicSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->PicHeightInMbs; + p_Vid->FrameSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->FrameHeightInMbs; + + p_Vid->bFrameInit = 1; + if( p_Vid->dec_picture ) // && p_Vid->num_dec_mb == p_Vid->PicSizeInMbs) + { + // this may only happen on slice loss + exit_picture( p_Vid, &p_Vid->dec_picture); + } + p_Vid->dpb_layer_id = currSlice->layer_id; + //set buffers; + setup_buffers( p_Vid, currSlice->layer_id); + + if( p_Vid->recovery_point ) + p_Vid->recovery_frame_num = (currSlice->frame_num + p_Vid->recovery_frame_cnt) % p_Vid->max_frame_num; + + if( currSlice->idr_flag ) + { +#if (MVC_EXTENSION_ENABLE) + p_Vid->pre_frame_num[currSlice->view_id] = 0; +#else + p_Vid->pre_frame_num = 0; +#endif + p_Vid->recovery_frame_num = currSlice->frame_num; + } + +#if (MVC_EXTENSION_ENABLE) + if( (currSlice->layer_id > 0) && (currSlice->svc_extension_flag == 0 && currSlice->NaluHeaderMVCExt.non_idr_flag == 0) ) + { + p_Vid->pre_frame_num[currSlice->view_id] = 0; + } +#endif + +#if ( MVC_EXTENSION_ENABLE ) + /* Edit by Joao Carreira */ + if( p_Vid->recovery_point == 0 && currSlice->frame_num != p_Vid->pre_frame_num[currSlice->view_id] + && currSlice->frame_num != (p_Vid->pre_frame_num[currSlice->view_id] + 1) % p_Vid->max_frame_num ) + { +#else + if (p_Vid->recovery_point == 0 && + currSlice->frame_num != p_Vid->pre_frame_num && + currSlice->frame_num != (p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num) + { +#endif + //if (active_sps->gaps_in_frame_num_value_allowed_flag == 0) + if( 0 == 0 ) + { + // picture error concealment + if( p_Inp->conceal_mode != 0 ) + { +#if ( MVC_EXTENSION_ENABLE ) + if( ((currSlice->frame_num) < ((p_Vid->pre_frame_num[currSlice->view_id] + 1) % p_Vid->max_frame_num)) /* && currSlice->view_id != BASE_VIEW_IDX */) +#else + if((currSlice->frame_num) < ((p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num)) +#endif + { + fercConcealLostRefFrames( p_Dpb, currSlice, 1); + } + else + { + fercConcealLostRefFrames( p_Dpb, currSlice, 0); + } + } + else + { /* Advanced Error Concealment would be called here to combat unintentional loss of pictures. */ + error( "An unintentional loss of pictures occurs! Exit\n", 100); + } + } + if( p_Vid->conceal_mode == 0 ) + fill_frame_num_gap( p_Vid, currSlice); + } + + if( currSlice->nal_reference_idc ) + { +#if(MVC_EXTENSION_ENABLE) + p_Vid->pre_frame_num[currSlice->view_id] = currSlice->frame_num; +#else + p_Vid->pre_frame_num = currSlice->frame_num; +#endif + } + + //p_Vid->num_dec_mb = 0; + + //calculate POC + decode_poc( p_Vid, currSlice); + + if( p_Vid->recovery_frame_num == (int) currSlice->frame_num && p_Vid->recovery_poc == 0x7fffffff ) + p_Vid->recovery_poc = currSlice->framepoc; + + if( currSlice->nal_reference_idc ) +#if ( MVC_EXTENSION_ENABLE ) + p_Vid->last_ref_pic_poc[currSlice->view_id] = currSlice->framepoc; + if( ( (currSlice->framepoc/p_Inp->poc_scale)%p_Vid->p_Inp->GOP_Size ) == 0 ) + p_Vid->last_ref_hier0_poc[currSlice->view_id] = currSlice->framepoc; +#else + p_Vid->last_ref_pic_poc = currSlice->framepoc; +#endif + + // dumppoc (p_Vid); + + if( currSlice->structure == FRAME || currSlice->structure == TOP_FIELD ) + { + gettime( &(p_Vid->start_time)); // start time + } + + dec_picture = p_Vid->dec_picture = alloc_storable_picture( p_Vid, currSlice->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + dec_picture->top_poc = currSlice->toppoc; + dec_picture->bottom_poc = currSlice->bottompoc; + dec_picture->frame_poc = currSlice->framepoc; + dec_picture->qp = currSlice->qp; + dec_picture->slice_qp_delta = currSlice->slice_qp_delta; + dec_picture->chroma_qp_offset[0] = p_Vid->active_pps->chroma_qp_index_offset; + dec_picture->chroma_qp_offset[1] = p_Vid->active_pps->second_chroma_qp_index_offset; + dec_picture->iCodingType = currSlice->structure == FRAME ? (currSlice->mb_aff_frame_flag ? FRAME_MB_PAIR_CODING : FRAME_CODING) : FIELD_CODING; //currSlice->slice_type; + dec_picture->layer_id = currSlice->layer_id; +#if (MVC_EXTENSION_ENABLE) + dec_picture->view_id = currSlice->view_id; + dec_picture->inter_view_flag = currSlice->inter_view_flag; + dec_picture->anchor_pic_flag = currSlice->anchor_pic_flag; + if( dec_picture->view_id >= 1 ) + { + if( (p_Vid->profile_idc == MVC_HIGH) || (p_Vid->profile_idc == STEREO_HIGH) ) + init_mvc_picture( currSlice); + } +#endif + + fercFillCurrPicture(p_Vid, dec_picture); + + // reset all variables of the error concealment instance before decoding of every frame. + // here the third parameter should, if perfectly, be equal to the number of slices per frame. + // using little value is ok, the code will allocate more memory if the slice number is larger +#if (DISABLE_ERC == 0) + ercReset(p_Vid->erc_errorVar, p_Vid->PicSizeInMbs, p_Vid->PicSizeInMbs, dec_picture->size_x); +#endif + p_Vid->erc_mvperMB = 0; + + switch( currSlice->structure ) + { + case TOP_FIELD: + { + dec_picture->poc = currSlice->toppoc; + p_Vid->number *= 2; + break; + } + case BOTTOM_FIELD: + { + dec_picture->poc = currSlice->bottompoc; + p_Vid->number = p_Vid->number * 2 + 1; + break; + } + case FRAME: + { + dec_picture->poc = currSlice->framepoc; + break; + } + default: + error( "p_Vid->structure not initialized", 235); + } + + //p_Vid->current_slice_nr=0; + + if( p_Vid->type > SI_SLICE ) + { + set_ec_flag( p_Vid, SE_PTYPE); + p_Vid->type = P_SLICE; // concealed element + } + + // CAVLC init + if( p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC ) + { + memset( p_Vid->nz_coeff[0][0][0], -1, p_Vid->PicSizeInMbs * 48 * sizeof(byte)); // 3 * 4 * 4 + } + + // Set the slice_nr member of each MB to -1, to ensure correct when packet loss occurs + // TO set Macroblock Map (mark all MBs as 'have to be concealed') + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + for( nplane = 0; nplane < MAX_PLANE; ++nplane ) + { + Macroblock *currMB = p_Vid->mb_data_JV[nplane]; + char *intra_block = p_Vid->intra_block_JV[nplane]; + for( i = 0; i < (int) p_Vid->PicSizeInMbs; ++i ) + { + reset_mbs( currMB++); + } + fast_memset( p_Vid->ipredmode_JV[nplane][0], DC_PRED, 16 * p_Vid->FrameHeightInMbs * p_Vid->PicWidthInMbs * sizeof(char)); + if( p_Vid->active_pps->constrained_intra_pred_flag ) + { + for( i = 0; i < (int) p_Vid->PicSizeInMbs; ++i ) + { + intra_block[i] = 1; + } + } + } + } + else + { +#if 0 //defined(OPENMP) +#pragma omp parallel for + for(i=0; i<(int)p_Vid->PicSizeInMbs; ++i) + reset_mbs(&p_Vid->mb_data[i]); +#else + Macroblock *currMB = p_Vid->mb_data; + for( i = 0; i < (int) p_Vid->PicSizeInMbs; ++i ) + reset_mbs( currMB++); +#endif + if( p_Vid->active_pps->constrained_intra_pred_flag ) + { + for( i = 0; i < (int) p_Vid->PicSizeInMbs; ++i ) + { + p_Vid->intra_block[i] = 1; + } + } + fast_memset( p_Vid->ipredmode[0], DC_PRED, 16 * p_Vid->FrameHeightInMbs * p_Vid->PicWidthInMbs * sizeof(char)); + } + + dec_picture->slice_type = p_Vid->type; + dec_picture->used_for_reference = (currSlice->nal_reference_idc != 0); + dec_picture->idr_flag = currSlice->idr_flag; + dec_picture->no_output_of_prior_pics_flag = currSlice->no_output_of_prior_pics_flag; + dec_picture->long_term_reference_flag = currSlice->long_term_reference_flag; + dec_picture->adaptive_ref_pic_buffering_flag = currSlice->adaptive_ref_pic_buffering_flag; + + dec_picture->dec_ref_pic_marking_buffer = currSlice->dec_ref_pic_marking_buffer; + currSlice->dec_ref_pic_marking_buffer = NULL; + + dec_picture->mb_aff_frame_flag = currSlice->mb_aff_frame_flag; + dec_picture->PicWidthInMbs = p_Vid->PicWidthInMbs; + + p_Vid->get_mb_block_pos = dec_picture->mb_aff_frame_flag ? get_mb_block_pos_mbaff : get_mb_block_pos_normal; + p_Vid->getNeighbour = dec_picture->mb_aff_frame_flag ? getAffNeighbour : getNonAffNeighbour; + + dec_picture->pic_num = currSlice->frame_num; + dec_picture->frame_num = currSlice->frame_num; + + dec_picture->recovery_frame = (unsigned int) ((int) currSlice->frame_num == p_Vid->recovery_frame_num); + + dec_picture->coded_frame = (currSlice->structure == FRAME); + + dec_picture->chroma_format_idc = active_sps->chroma_format_idc; + + dec_picture->frame_mbs_only_flag = active_sps->frame_mbs_only_flag; + dec_picture->frame_cropping_flag = active_sps->frame_cropping_flag; + + if( dec_picture->frame_cropping_flag ) + { + dec_picture->frame_crop_left_offset = active_sps->frame_crop_left_offset; + dec_picture->frame_crop_right_offset = active_sps->frame_crop_right_offset; + dec_picture->frame_crop_top_offset = active_sps->frame_crop_top_offset; + dec_picture->frame_crop_bottom_offset = active_sps->frame_crop_bottom_offset; + } + +#if (ENABLE_OUTPUT_TONEMAPPING) + // store the necessary tone mapping sei into StorablePicture structure + if( p_Vid->seiToneMapping->seiHasTone_mapping ) + { + int coded_data_bit_max = (1 << p_Vid->seiToneMapping->coded_data_bit_depth); + dec_picture->seiHasTone_mapping = 1; + dec_picture->tone_mapping_model_id = p_Vid->seiToneMapping->model_id; + dec_picture->tonemapped_bit_depth = p_Vid->seiToneMapping->sei_bit_depth; + dec_picture->tone_mapping_lut = malloc( coded_data_bit_max * sizeof(int)); + if( NULL == dec_picture->tone_mapping_lut ) + { + no_mem_exit( "init_picture: tone_mapping_lut"); + } + memcpy( dec_picture->tone_mapping_lut, p_Vid->seiToneMapping->lut, sizeof(imgpel) * coded_data_bit_max); + update_tone_mapping_sei( p_Vid->seiToneMapping); + } + else + dec_picture->seiHasTone_mapping = 0; +#endif + + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + p_Vid->dec_picture_JV[0] = p_Vid->dec_picture; + p_Vid->dec_picture_JV[1] = alloc_storable_picture( p_Vid, (PictureStructure) currSlice->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, + p_Vid->height_cr, 1); + copy_dec_picture_JV( p_Vid, p_Vid->dec_picture_JV[1], p_Vid->dec_picture_JV[0]); + p_Vid->dec_picture_JV[2] = alloc_storable_picture( p_Vid, (PictureStructure) currSlice->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, + p_Vid->height_cr, 1); + copy_dec_picture_JV( p_Vid, p_Vid->dec_picture_JV[2], p_Vid->dec_picture_JV[0]); + } +} + +static void update_mbaff_macroblock_data( imgpel **cur_img, imgpel (*temp)[16], int x0, int width, int height) +{ + imgpel (*temp_evn)[16] = temp; + imgpel (*temp_odd)[16] = temp + height; + imgpel **temp_img = cur_img; + int y; + + for( y = 0; y < 2 * height; ++y ) + memcpy( *temp++, (*temp_img++ + x0), width * sizeof(imgpel)); + + for( y = 0; y < height; ++y ) + { + memcpy( (*cur_img++ + x0), *temp_evn++, width * sizeof(imgpel)); + memcpy( (*cur_img++ + x0), *temp_odd++, width * sizeof(imgpel)); + } +} + +static void MbAffPostProc( VideoParameters *p_Vid) +{ + + imgpel temp_buffer[32][16]; + + StorablePicture *dec_picture = p_Vid->dec_picture; + imgpel ** imgY = dec_picture->imgY; + imgpel ***imgUV = dec_picture->imgUV; + + short i, x0, y0; + + for( i = 0; i < (int) dec_picture->PicSizeInMbs; i += 2 ) + { + if( dec_picture->motion.mb_field[i] ) + { + get_mb_pos( p_Vid, i, p_Vid->mb_size[IS_LUMA], &x0, &y0); + update_mbaff_macroblock_data( imgY + y0, temp_buffer, x0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + if( dec_picture->chroma_format_idc != YUV400 ) + { + x0 = (short) ((x0 * p_Vid->mb_cr_size_x) >> 4); + y0 = (short) ((y0 * p_Vid->mb_cr_size_y) >> 4); + + update_mbaff_macroblock_data( imgUV[0] + y0, temp_buffer, x0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + update_mbaff_macroblock_data( imgUV[1] + y0, temp_buffer, x0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + } + } +} + +static void fill_wp_params( Slice *currSlice) +{ + if( currSlice->slice_type == B_SLICE ) + { + int i, j, k; + int comp; + int log_weight_denom; + int tb, td; + int tx, DistScaleFactor; + + int max_l0_ref = currSlice->num_ref_idx_active[LIST_0]; + int max_l1_ref = currSlice->num_ref_idx_active[LIST_1]; + + if( currSlice->active_pps->weighted_bipred_idc == 2 ) + { + currSlice->luma_log2_weight_denom = 5; + currSlice->chroma_log2_weight_denom = 5; + currSlice->wp_round_luma = 16; + currSlice->wp_round_chroma = 16; + + for( i = 0; i < MAX_REFERENCE_PICTURES; ++i ) + { + for( comp = 0; comp < 3; ++comp ) + { + log_weight_denom = (comp == 0) ? currSlice->luma_log2_weight_denom : currSlice->chroma_log2_weight_denom; + currSlice->wp_weight[0][i][comp] = 1 << log_weight_denom; + currSlice->wp_weight[1][i][comp] = 1 << log_weight_denom; + currSlice->wp_offset[0][i][comp] = 0; + currSlice->wp_offset[1][i][comp] = 0; + } + } + } + + for( i = 0; i < max_l0_ref; ++i ) + { + for( j = 0; j < max_l1_ref; ++j ) + { + for( comp = 0; comp < 3; ++comp ) + { + log_weight_denom = (comp == 0) ? currSlice->luma_log2_weight_denom : currSlice->chroma_log2_weight_denom; + if( currSlice->active_pps->weighted_bipred_idc == 1 ) + { + currSlice->wbp_weight[0][i][j][comp] = currSlice->wp_weight[0][i][comp]; + currSlice->wbp_weight[1][i][j][comp] = currSlice->wp_weight[1][j][comp]; + } + else if( currSlice->active_pps->weighted_bipred_idc == 2 ) + { + td = iClip3( -128, 127, currSlice->listX[LIST_1][j]->poc - currSlice->listX[LIST_0][i]->poc); + if( td == 0 || currSlice->listX[LIST_1][j]->is_long_term || currSlice->listX[LIST_0][i]->is_long_term ) + { + currSlice->wbp_weight[0][i][j][comp] = 32; + currSlice->wbp_weight[1][i][j][comp] = 32; + } + else + { + tb = iClip3( -128, 127, currSlice->ThisPOC - currSlice->listX[LIST_0][i]->poc); + + tx = (16384 + iabs( td / 2)) / td; + DistScaleFactor = iClip3( -1024, 1023, (tx * tb + 32) >> 6); + + currSlice->wbp_weight[1][i][j][comp] = DistScaleFactor >> 2; + currSlice->wbp_weight[0][i][j][comp] = 64 - currSlice->wbp_weight[1][i][j][comp]; + if( currSlice->wbp_weight[1][i][j][comp] < -64 || currSlice->wbp_weight[1][i][j][comp] > 128 ) + { + currSlice->wbp_weight[0][i][j][comp] = 32; + currSlice->wbp_weight[1][i][j][comp] = 32; + currSlice->wp_offset[0][i][comp] = 0; + currSlice->wp_offset[1][j][comp] = 0; + } + } + } + } + } + } + + if( currSlice->mb_aff_frame_flag ) + { + for( i = 0; i < 2 * max_l0_ref; ++i ) + { + for( j = 0; j < 2 * max_l1_ref; ++j ) + { + for( comp = 0; comp < 3; ++comp ) + { + for( k = 2; k < 6; k += 2 ) + { + currSlice->wp_offset[k + 0][i][comp] = currSlice->wp_offset[0][i >> 1][comp]; + currSlice->wp_offset[k + 1][j][comp] = currSlice->wp_offset[1][j >> 1][comp]; + + log_weight_denom = (comp == 0) ? currSlice->luma_log2_weight_denom : currSlice->chroma_log2_weight_denom; + if( currSlice->active_pps->weighted_bipred_idc == 1 ) + { + currSlice->wbp_weight[k + 0][i][j][comp] = currSlice->wp_weight[0][i >> 1][comp]; + currSlice->wbp_weight[k + 1][i][j][comp] = currSlice->wp_weight[1][j >> 1][comp]; + } + else if( currSlice->active_pps->weighted_bipred_idc == 2 ) + { + td = iClip3( -128, 127, currSlice->listX[k + LIST_1][j]->poc - currSlice->listX[k + LIST_0][i]->poc); + if( td == 0 || currSlice->listX[k + LIST_1][j]->is_long_term || currSlice->listX[k + LIST_0][i]->is_long_term ) + { + currSlice->wbp_weight[k + 0][i][j][comp] = 32; + currSlice->wbp_weight[k + 1][i][j][comp] = 32; + } + else + { + tb = iClip3( -128, 127, ((k == 2) ? currSlice->toppoc : currSlice->bottompoc) - currSlice->listX[k + LIST_0][i]->poc); + + tx = (16384 + iabs( td / 2)) / td; + DistScaleFactor = iClip3( -1024, 1023, (tx * tb + 32) >> 6); + + currSlice->wbp_weight[k + 1][i][j][comp] = DistScaleFactor >> 2; + currSlice->wbp_weight[k + 0][i][j][comp] = 64 - currSlice->wbp_weight[k + 1][i][j][comp]; + if( currSlice->wbp_weight[k + 1][i][j][comp] < -64 || currSlice->wbp_weight[k + 1][i][j][comp] > 128 ) + { + currSlice->wbp_weight[k + 1][i][j][comp] = 32; + currSlice->wbp_weight[k + 0][i][j][comp] = 32; + currSlice->wp_offset[k + 0][i][comp] = 0; + currSlice->wp_offset[k + 1][j][comp] = 0; + } + } + } + } + } + } + } + } + } +} + +static void init_picture_decoding( VideoParameters *p_Vid) +{ + Slice *pSlice = p_Vid->ppSliceList[0]; + int j, i, iDeblockMode = 1; + + if( p_Vid->iSliceNumOfCurrPic >= MAX_NUM_SLICES ) + { + error( "Maximum number of supported slices exceeded. \nPlease recompile with increased value for MAX_NUM_SLICES", 200); + } + + if( p_Vid->pNextPPS->Valid && (int) p_Vid->pNextPPS->pic_parameter_set_id == pSlice->pic_parameter_set_id ) + { + pic_parameter_set_rbsp_t tmpPPS; + memcpy( &tmpPPS, &(p_Vid->PicParSet[pSlice->pic_parameter_set_id]), sizeof(pic_parameter_set_rbsp_t)); + (p_Vid->PicParSet[pSlice->pic_parameter_set_id]).slice_group_id = NULL; + MakePPSavailable( p_Vid, p_Vid->pNextPPS->pic_parameter_set_id, p_Vid->pNextPPS); + memcpy( p_Vid->pNextPPS, &tmpPPS, sizeof(pic_parameter_set_rbsp_t)); + tmpPPS.slice_group_id = NULL; + } + + UseParameterSet( pSlice); + if( pSlice->idr_flag ) + p_Vid->number = 0; + + p_Vid->PicHeightInMbs = p_Vid->FrameHeightInMbs / (1 + pSlice->field_pic_flag); + p_Vid->PicSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->PicHeightInMbs; + p_Vid->FrameSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->FrameHeightInMbs; + p_Vid->structure = pSlice->structure; + + fmo_init( p_Vid, pSlice); + +#if (MVC_EXTENSION_ENABLE) + //! Bugfix from previous versions of JM Encoder + //if(pSlice->frame_num==0 && pSlice->view_id>0 ) + //{ + // pSlice->NaluHeaderMVCExt.non_idr_flag=0; + //} + if( (pSlice->layer_id > 0) && (pSlice->svc_extension_flag == 0 && pSlice->NaluHeaderMVCExt.non_idr_flag == 0) ) + { + idr_memory_management( p_Vid->p_Dpb_layer[pSlice->layer_id], p_Vid->dec_picture); + } + update_ref_list( p_Vid->p_Dpb_layer[pSlice->view_id]); + update_ltref_list( p_Vid->p_Dpb_layer[pSlice->view_id]); + update_pic_num( pSlice); + i = pSlice->view_id; +#else + update_pic_num(pSlice); + i = 0; +#endif + init_Deblock( p_Vid, pSlice->mb_aff_frame_flag); + //init mb_data; + for( j = 0; j < p_Vid->iSliceNumOfCurrPic; j++ ) + { + if( p_Vid->ppSliceList[j]->DFDisableIdc != 1 ) + iDeblockMode = 0; +#if (MVC_EXTENSION_ENABLE) + assert( p_Vid->ppSliceList[j]->view_id == i); +#endif + } + p_Vid->iDeblockMode = iDeblockMode; + + //! Edited by Joao Carreira + if( p_Vid->p_Transcode == NULL ) + initTranscodeModule( p_Vid); + +} + +//!Edited by Joao Carreira +void check_concealed_references( Slice *currSlice) +{ + //VideoParameters *p_Vid = currSlice->p_Vid; + int idx_ref; + int view = currSlice->view_id; + + if( currSlice->slice_type == I_SLICE ) + { + currSlice->have_concealed_reference = 0; + return; + } + for( idx_ref = 0; idx_ref < currSlice->num_ref_idx_active[LIST_0]; idx_ref++ ) + { + if( currSlice->listX[LIST_0][idx_ref]->concealed_pic == 1 ) + { + currSlice->have_concealed_reference = 1; + } + } + for( idx_ref = 0; idx_ref < currSlice->num_ref_idx_active[LIST_0]; idx_ref++ ) + { + if( currSlice->listX[LIST_1][idx_ref]->concealed_pic == 1 ) + { + currSlice->have_concealed_reference = 1; + } + } +} + +void init_slice( VideoParameters *p_Vid, Slice *currSlice) +{ + int i; + + if( currSlice->framepoc == 6 ) + { + int a = 0; + } + + p_Vid->active_sps = currSlice->active_sps; + p_Vid->active_pps = currSlice->active_pps; + + currSlice->init_lists( currSlice); + + //dump_ref_lists(currSlice); + +#if (MVC_EXTENSION_ENABLE) + if( currSlice->svc_extension_flag == 0 || currSlice->svc_extension_flag == 1 ) + reorder_lists_mvc( currSlice, currSlice->ThisPOC); + else + reorder_lists( currSlice); + + if( currSlice->fs_listinterview0 ) + { + free( currSlice->fs_listinterview0); + currSlice->fs_listinterview0 = NULL; + } + if( currSlice->fs_listinterview1 ) + { + free( currSlice->fs_listinterview1); + currSlice->fs_listinterview1 = NULL; + } + + currSlice->have_concealed_reference = 0; + check_concealed_references( currSlice); + +#else + reorder_lists (currSlice); +#endif + +#if PRINTREFLIST_JC + dump_ref_lists(currSlice); +#endif + + if( currSlice->structure == FRAME ) + { + init_mbaff_lists( p_Vid, currSlice); + } + //p_Vid->recovery_point = 0; + + // update reference flags and set current p_Vid->ref_flag + if( !(currSlice->redundant_pic_cnt != 0 && p_Vid->previous_frame_num == currSlice->frame_num) ) + { + for( i = 16; i > 0; i-- ) + { + currSlice->ref_flag[i] = currSlice->ref_flag[i - 1]; + } + } + currSlice->ref_flag[0] = currSlice->redundant_pic_cnt == 0 ? p_Vid->Is_primary_correct : p_Vid->Is_redundant_correct; + //p_Vid->previous_frame_num = currSlice->frame_num; //p_Vid->frame_num; + + if( (currSlice->active_sps->chroma_format_idc == 0) || (currSlice->active_sps->chroma_format_idc == 3) ) + { + currSlice->linfo_cbp_intra = linfo_cbp_intra_other; + currSlice->linfo_cbp_inter = linfo_cbp_inter_other; + } + else + { + currSlice->linfo_cbp_intra = linfo_cbp_intra_normal; + currSlice->linfo_cbp_inter = linfo_cbp_inter_normal; + } +} + +void decode_slice( Slice *currSlice, int current_header) +{ + if( currSlice->active_pps->entropy_coding_mode_flag ) + { + init_contexts( currSlice); + cabac_new_slice( currSlice); + } + + if( (currSlice->active_pps->weighted_bipred_idc > 0 && (currSlice->slice_type == B_SLICE)) + || (currSlice->active_pps->weighted_pred_flag && currSlice->slice_type != I_SLICE) ) + fill_wp_params( currSlice); + + //printf("frame picture %d %d %d\n",currSlice->structure,currSlice->ThisPOC,currSlice->direct_spatial_mv_pred_flag); + + // decode main slice information + if( (current_header == SOP || current_header == SOS) && currSlice->ei_flag == 0 ) + decode_one_slice( currSlice); + + // setMB-Nr in case this slice was lost + // if(currSlice->ei_flag) + // p_Vid->current_mb_nr = currSlice->last_mb_nr + 1; + +} + +/*! + ************************************************************************ + * \brief + * Error tracking: if current frame is lost or any reference frame of + * current frame is lost, current frame is incorrect. + ************************************************************************ + */ +static void Error_tracking( VideoParameters *p_Vid, Slice *currSlice) +{ + int i; + + if( currSlice->redundant_pic_cnt == 0 ) + { + p_Vid->Is_primary_correct = p_Vid->Is_redundant_correct = 1; + } + + if( currSlice->redundant_pic_cnt == 0 && p_Vid->type != I_SLICE ) + { + for( i = 0; i < currSlice->num_ref_idx_active[LIST_0]; ++i ) + { + if( currSlice->ref_flag[i] == 0 ) // any reference of primary slice is incorrect + { + p_Vid->Is_primary_correct = 0; // primary slice is incorrect + } + } + } + else if( currSlice->redundant_pic_cnt != 0 && p_Vid->type != I_SLICE ) + { + if( currSlice->ref_flag[currSlice->redundant_slice_ref_idx] == 0 ) // reference of redundant slice is incorrect + { + p_Vid->Is_redundant_correct = 0; // redundant slice is incorrect + } + } +} + +static void CopyPOC( Slice *pSlice0, Slice *currSlice) +{ + currSlice->framepoc = pSlice0->framepoc; + currSlice->toppoc = pSlice0->toppoc; + currSlice->bottompoc = pSlice0->bottompoc; + currSlice->ThisPOC = pSlice0->ThisPOC; +} + +/*! + *********************************************************************** + * \brief + * decodes one I- or P-frame + * + *********************************************************************** + */ +int decode_one_frame( DecoderParams *pDecoder) +{ + VideoParameters *p_Vid = pDecoder->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int current_header, iRet; + Slice *currSlice; // = p_Vid->currentSlice; + Slice **ppSliceList = p_Vid->ppSliceList; + int iSliceNo; + + //read one picture first; + p_Vid->iSliceNumOfCurrPic = 0; + current_header = 0; + p_Vid->iNumOfSlicesDecoded = 0; + p_Vid->num_dec_mb = 0; + if( p_Vid->newframe ) + { + if( p_Vid->pNextPPS->Valid ) + { + //assert((int) p_Vid->pNextPPS->pic_parameter_set_id == p_Vid->pNextSlice->pic_parameter_set_id); + MakePPSavailable( p_Vid, p_Vid->pNextPPS->pic_parameter_set_id, p_Vid->pNextPPS); + p_Vid->pNextPPS->Valid = 0; + } + + //get the first slice from currentslice; + assert( ppSliceList[p_Vid->iSliceNumOfCurrPic]); + currSlice = ppSliceList[p_Vid->iSliceNumOfCurrPic]; + ppSliceList[p_Vid->iSliceNumOfCurrPic] = p_Vid->pNextSlice; + p_Vid->pNextSlice = currSlice; + assert( ppSliceList[p_Vid->iSliceNumOfCurrPic]->current_slice_nr == 0); + + currSlice = ppSliceList[p_Vid->iSliceNumOfCurrPic]; + + UseParameterSet( currSlice); + + init_picture( p_Vid, currSlice, p_Inp); + + p_Vid->iSliceNumOfCurrPic++; + current_header = SOS; + } + while( current_header != SOP && current_header != EOS ) + { + //no pending slices; + assert( p_Vid->iSliceNumOfCurrPic < p_Vid->iNumOfSlicesAllocated); + if( !ppSliceList[p_Vid->iSliceNumOfCurrPic] ) + { + ppSliceList[p_Vid->iSliceNumOfCurrPic] = malloc_slice( p_Inp, p_Vid); + } + currSlice = ppSliceList[p_Vid->iSliceNumOfCurrPic]; + + //p_Vid->currentSlice = currSlice; + currSlice->p_Vid = p_Vid; + currSlice->p_Inp = p_Inp; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[0]; //set default value; + currSlice->next_header = -8888; + currSlice->num_dec_mb = 0; + currSlice->coeff_ctr = -1; + currSlice->pos = 0; + currSlice->is_reset_coeff = FALSE; + currSlice->is_reset_coeff_cr = FALSE; + + current_header = read_new_slice( currSlice); + //init; + currSlice->current_header = current_header; + + // error tracking of primary and redundant slices. + Error_tracking( p_Vid, currSlice); + // If primary and redundant are received and primary is correct, discard the redundant + // else, primary slice will be replaced with redundant slice. + if( currSlice->frame_num == p_Vid->previous_frame_num && currSlice->redundant_pic_cnt != 0 && p_Vid->Is_primary_correct != 0 && current_header != EOS ) + { + continue; + } + + if( (current_header != SOP && current_header != EOS) || (p_Vid->iSliceNumOfCurrPic == 0 && current_header == SOP) ) + { + currSlice->current_slice_nr = (short) p_Vid->iSliceNumOfCurrPic; + p_Vid->dec_picture->max_slice_id = (short) imax( currSlice->current_slice_nr, p_Vid->dec_picture->max_slice_id); + if( p_Vid->iSliceNumOfCurrPic > 0 ) + { + CopyPOC( *ppSliceList, currSlice); + ppSliceList[p_Vid->iSliceNumOfCurrPic - 1]->end_mb_nr_plus1 = currSlice->start_mb_nr; + } + p_Vid->iSliceNumOfCurrPic++; + if( p_Vid->iSliceNumOfCurrPic >= p_Vid->iNumOfSlicesAllocated ) + { + Slice **tmpSliceList = (Slice **) realloc( p_Vid->ppSliceList, (p_Vid->iNumOfSlicesAllocated + MAX_NUM_DECSLICES) * sizeof(Slice*)); + if( !tmpSliceList ) + { + tmpSliceList = (Slice **) calloc( (p_Vid->iNumOfSlicesAllocated + MAX_NUM_DECSLICES), sizeof(Slice*)); + memcpy( tmpSliceList, p_Vid->ppSliceList, p_Vid->iSliceNumOfCurrPic * sizeof(Slice*)); + //free; + free( p_Vid->ppSliceList); + ppSliceList = p_Vid->ppSliceList = tmpSliceList; + } + else + { + //assert(tmpSliceList == p_Vid->ppSliceList); + ppSliceList = p_Vid->ppSliceList = tmpSliceList; + memset( p_Vid->ppSliceList + p_Vid->iSliceNumOfCurrPic, 0, sizeof(Slice*) * MAX_NUM_DECSLICES); + } + p_Vid->iNumOfSlicesAllocated += MAX_NUM_DECSLICES; + } + current_header = SOS; + } + else + { + if( ppSliceList[p_Vid->iSliceNumOfCurrPic - 1]->mb_aff_frame_flag ) + ppSliceList[p_Vid->iSliceNumOfCurrPic - 1]->end_mb_nr_plus1 = p_Vid->FrameSizeInMbs / 2; + else + ppSliceList[p_Vid->iSliceNumOfCurrPic - 1]->end_mb_nr_plus1 = p_Vid->FrameSizeInMbs / (1 + ppSliceList[p_Vid->iSliceNumOfCurrPic - 1]->field_pic_flag); + p_Vid->newframe = 1; + currSlice->current_slice_nr = 0; + //keep it in currentslice; + ppSliceList[p_Vid->iSliceNumOfCurrPic] = p_Vid->pNextSlice; + p_Vid->pNextSlice = currSlice; + } + + copy_slice_info( currSlice, p_Vid->old_slice); + } + iRet = current_header; + init_picture_decoding( p_Vid); + + calculate_frame_no( p_Vid, p_Vid->dec_picture); + + for( iSliceNo = 0; iSliceNo < p_Vid->iSliceNumOfCurrPic; iSliceNo++ ) + { + currSlice = ppSliceList[iSliceNo]; + current_header = currSlice->current_header; + //p_Vid->currentSlice = currSlice; + + assert( current_header != EOS); + assert( currSlice->current_slice_nr == iSliceNo); + + init_slice( p_Vid, currSlice); + decode_slice( currSlice, current_header); + + p_Vid->iNumOfSlicesDecoded++; + p_Vid->num_dec_mb += currSlice->num_dec_mb; + p_Vid->erc_mvperMB += currSlice->erc_mvperMB; + + if( currSlice->have_concealed_reference == 1 ) + p_Vid->dec_picture->have_concealed_reference = 1; + + } + +#if MVC_EXTENSION_ENABLE + p_Vid->last_dec_view_id = p_Vid->dec_picture->view_id; +#endif + if( p_Vid->dec_picture->structure == FRAME ) + p_Vid->last_dec_poc = p_Vid->dec_picture->frame_poc; + else if( p_Vid->dec_picture->structure == TOP_FIELD ) + p_Vid->last_dec_poc = p_Vid->dec_picture->top_poc; + else if( p_Vid->dec_picture->structure == BOTTOM_FIELD ) + p_Vid->last_dec_poc = p_Vid->dec_picture->bottom_poc; + exit_picture( p_Vid, &p_Vid->dec_picture); + p_Vid->previous_frame_num = ppSliceList[0]->frame_num; + return (iRet); +} + +/*! + ************************************************************************ + * \brief + * Convert file read buffer to source picture structure + * \param imgX + * Pointer to image plane + * \param buf + * Buffer for file output + * \param size_x + * horizontal image size in pixel + * \param size_y + * vertical image size in pixel + * \param symbol_size_in_bytes + * number of bytes used per pel + ************************************************************************ + */ +void buffer2img( imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes) +{ + int i, j; + + uint16 tmp16, ui16; + unsigned long tmp32, ui32; + + if( symbol_size_in_bytes > sizeof(imgpel) ) + { + error( "Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500); + } + + if( (sizeof(char) == sizeof(imgpel)) && (sizeof(char) == symbol_size_in_bytes) ) + { + // imgpel == pixel_in_file == 1 byte -> simple copy + fast_memcpy( &imgX[0][0], buf, size_x * size_y); + } + else + { + // sizeof (imgpel) > sizeof(char) + if( testEndian( ) ) + { + // big endian + switch( symbol_size_in_bytes ) + { + case 1: + { + for( j = 0; j < size_y; ++j ) + for( i = 0; i < size_x; ++i ) + { + imgX[j][i] = buf[i + j * size_x]; + } + break; + } + case 2: + { + for( j = 0; j < size_y; ++j ) + for( i = 0; i < size_x; ++i ) + { + memcpy( &tmp16, buf + ((i + j * size_x) * 2), 2); + ui16 = (uint16) ((tmp16 >> 8) | ((tmp16 & 0xFF) << 8)); + imgX[j][i] = (imgpel) ui16; + } + break; + } + case 4: + { + for( j = 0; j < size_y; ++j ) + for( i = 0; i < size_x; ++i ) + { + memcpy( &tmp32, buf + ((i + j * size_x) * 4), 4); + ui32 = ((tmp32 & 0xFF00) << 8) | ((tmp32 & 0xFF) << 24) | ((tmp32 & 0xFF0000) >> 8) | ((tmp32 & 0xFF000000) >> 24); + imgX[j][i] = (imgpel) ui32; + } + } + default: + { + error( "reading only from formats of 8, 16 or 32 bit allowed on big endian architecture", 500); + break; + } + } + + } + else + { + // little endian + if( symbol_size_in_bytes == 1 ) + { + for( j = 0; j < size_y; ++j ) + { + for( i = 0; i < size_x; ++i ) + { + imgX[j][i] = *(buf++); + } + } + } + else + { + for( j = 0; j < size_y; ++j ) + { + int jpos = j * size_x; + for( i = 0; i < size_x; ++i ) + { + imgX[j][i] = 0; + memcpy( &(imgX[j][i]), buf + ((i + jpos) * symbol_size_in_bytes), symbol_size_in_bytes); + } + } + } + + } + } +} + +/*! + *********************************************************************** + * \brief + * compute generic SSE + *********************************************************************** + */ +int64 compute_SSE( imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, int ySize, int xSize) +{ + int i, j; + imgpel *lineRef, *lineSrc; + int64 distortion = 0; + + for( j = 0; j < ySize; j++ ) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for( i = 0; i < xSize; i++ ) + { + distortion += iabs2( *lineRef++ - *lineSrc++); + } + } + return distortion; +} + +/*! + ************************************************************************ + * \brief + * Calculate the value of frame_no + * Edit by Joao Carreira + ************************************************************************ + */ +void calculate_frame_no( VideoParameters *p_Vid, StorablePicture *p) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int FrameSkip = p_Inp->FrameSkip; + // calculate frame number + int POC = p_Vid->active_sps->mb_adaptive_frame_field_flag ? p->poc / (p_Inp->poc_scale) : p->poc / (p_Inp->poc_scale); + + if( POC == 0 && p->idr_flag ) // && p_Vid->psnr_number) + { + p_Vid->idr_psnr_number = p_Vid->g_nFrame * p_Vid->ref_poc_gap / (p_Inp->poc_scale); + p_Vid->idr_psnr_number = p_Vid->p_Inp->IDR_Period * p_Vid->IDRframe_ctr; + + p_Vid->frame_no = p->frame_no = p_Vid->p_Inp->IDR_Period * p_Vid->IDRframe_ctr + FrameSkip; + } + else + { + p_Vid->frame_no = p->frame_no = p_Vid->frame_no_idr + POC + FrameSkip; + } + //p_Vid->psnr_number = imax(p_Vid->psnr_number, p_Vid->idr_psnr_number+psnrPOC); + + /* Edited by Joao Carreira */ + //p_Vid->frame_no = p_Vid->idr_psnr_number + psnrPOC; + //p_Vid->frame_no = p->frame_no = p_Vid->idr_psnr_number + psnrPOC + FrameSkip; +} + +/*! + ************************************************************************ + * \brief + * Find PSNR for all three components. + * Compare decoded frame with the original sequence. + * Read p_Inp->jumpd frames to reflect frame skipping. + * \param p_Vid + * video encoding parameters for current picture + * \param p + * picture to be compared + * \param p_ref + * file pointer piont to reference YUV reference file + ************************************************************************ + */ +void find_snr( VideoParameters *p_Vid, StorablePicture *p, int *p_ref) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + SNRParameters *snr = p_Vid->snr[p->view_id]; + + int k; + int ret; + int64 diff_comp[3] = + { 0 }; + int64 status; + int symbol_size_in_bytes = (p_Vid->pic_unit_bitsize_on_disk >> 3); + int comp_size_x[3], comp_size_y[3]; + int64 framesize_in_bytes; + + unsigned int max_pix_value_sqd[3]; + + Boolean rgb_output = (Boolean) (p_Vid->active_sps->vui_seq_parameters.matrix_coefficients == 0); + unsigned char *buf; + imgpel **cur_ref[3]; + imgpel **cur_comp[3]; + // picture error concealment + char yuv_types[4][6] = + { "4:0:0", "4:2:0", "4:2:2", "4:4:4" }; + + max_pix_value_sqd[0] = iabs2( p_Vid->max_pel_value_comp[0]); + max_pix_value_sqd[1] = iabs2( p_Vid->max_pel_value_comp[1]); + max_pix_value_sqd[2] = iabs2( p_Vid->max_pel_value_comp[2]); + + cur_ref[0] = p_Vid->imgY_ref; + cur_ref[1] = p->chroma_format_idc != YUV400 ? p_Vid->imgUV_ref[0] : NULL; + cur_ref[2] = p->chroma_format_idc != YUV400 ? p_Vid->imgUV_ref[1] : NULL; + + cur_comp[0] = p->imgY; + cur_comp[1] = p->chroma_format_idc != YUV400 ? p->imgUV[0] : NULL; + cur_comp[2] = p->chroma_format_idc != YUV400 ? p->imgUV[1] : NULL; + + comp_size_x[0] = p_Inp->source.width[0]; + comp_size_y[0] = p_Inp->source.height[0]; + comp_size_x[1] = comp_size_x[2] = p_Inp->source.width[1]; + comp_size_y[1] = comp_size_y[2] = p_Inp->source.height[1]; + + framesize_in_bytes = (((int64) comp_size_x[0] * comp_size_y[0]) + ((int64) comp_size_x[1] * comp_size_y[1]) * 2) * symbol_size_in_bytes; + + // KS: this buffer should actually be allocated only once, but this is still much faster than the previous version + buf = malloc( comp_size_x[0] * comp_size_y[0] * symbol_size_in_bytes); + + if( NULL == buf ) + { + no_mem_exit( "find_snr: buf"); + } + + status = lseek( *p_ref, framesize_in_bytes * p_Vid->frame_no, SEEK_SET); + if( status == -1 ) + { + fprintf( stdout, "Warning: Could not seek to frame number %d in reference file. Shown PSNR might be wrong.\n", p_Vid->frame_no); + free( buf); + return; + } + + if( rgb_output ) + lseek( *p_ref, framesize_in_bytes / 3, SEEK_CUR); + + for( k = 0; k < ((p->chroma_format_idc != YUV400) ? 3 : 1); ++k ) + { + + if( rgb_output && k == 2 ) + lseek( *p_ref, -framesize_in_bytes, SEEK_CUR); + + ret = read( *p_ref, buf, comp_size_x[k] * comp_size_y[k] * symbol_size_in_bytes); + if( ret != comp_size_x[k] * comp_size_y[k] * symbol_size_in_bytes ) + { + printf( "Warning: could not read from reconstructed file\n"); + fast_memset( buf, 0, comp_size_x[k] * comp_size_y[k] * symbol_size_in_bytes); + close( *p_ref); + *p_ref = -1; + break; + } + buffer2img( cur_ref[k], buf, comp_size_x[k], comp_size_y[k], symbol_size_in_bytes); + + // Compute SSE + diff_comp[k] = compute_SSE( cur_ref[k], cur_comp[k], 0, 0, comp_size_y[k], comp_size_x[k]); + + // Collecting SNR statistics + snr->snr[k] = psnr( max_pix_value_sqd[k], comp_size_x[k] * comp_size_y[k], (float) diff_comp[k]); + + if( snr->frame_ctr == 0 ) // first + { + snr->snra[k] = snr->snr[k]; // keep luma snr for first frame + } + else + { + snr->snra[k] = (float) (snr->snra[k] * (snr->frame_ctr) + snr->snr[k]) / (snr->frame_ctr + 1); // average snr chroma for all frames + } + } + + if( rgb_output ) + lseek( *p_ref, framesize_in_bytes * 2 / 3, SEEK_CUR); + + free( buf); +} + +void reorder_lists( Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + + if( (currSlice->slice_type != I_SLICE) && (currSlice->slice_type != SI_SLICE) ) + { + if( currSlice->ref_pic_list_reordering_flag[LIST_0] ) + { + reorder_ref_pic_list( currSlice, LIST_0); + } + if( p_Vid->no_reference_picture == currSlice->listX[0][currSlice->num_ref_idx_active[LIST_0] - 1] ) + { + if( p_Vid->non_conforming_stream ) + printf( "RefPicList0[ %d ] is equal to 'no reference picture'\n", currSlice->num_ref_idx_active[LIST_0] - 1); + else + error( "RefPicList0[ num_ref_idx_l0_active_minus1 ] is equal to 'no reference picture', invalid bitstream", 500); + } + // that's a definition + currSlice->listXsize[0] = (char) currSlice->num_ref_idx_active[LIST_0]; + } + + if( currSlice->slice_type == B_SLICE ) + { + if( currSlice->ref_pic_list_reordering_flag[LIST_1] ) + { + reorder_ref_pic_list( currSlice, LIST_1); + } + if( p_Vid->no_reference_picture == currSlice->listX[1][currSlice->num_ref_idx_active[LIST_1] - 1] ) + { + if( p_Vid->non_conforming_stream ) + printf( "RefPicList1[ %d ] is equal to 'no reference picture'\n", currSlice->num_ref_idx_active[LIST_1] - 1); + else + error( "RefPicList1[ num_ref_idx_l1_active_minus1 ] is equal to 'no reference picture', invalid bitstream", 500); + } + // that's a definition + currSlice->listXsize[1] = (char) currSlice->num_ref_idx_active[LIST_1]; + } + + free_ref_pic_list_reordering_buffer( currSlice); + + if( currSlice->slice_type == P_SLICE ) + { +#if PRINTREFLIST + unsigned int i; +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if( (p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr == 0 ) + { + if( currSlice->listXsize[0] > 0 ) + { + printf( "\n"); + printf( " ** (FinalViewID:%d) %s Ref Pic List 0 ****\n", currSlice->view_id, + currSlice->structure == FRAME ? "FRM" : (currSlice->structure == TOP_FIELD ? "TOP" : "BOT")); + for( i = 0; i < (unsigned int) (currSlice->listXsize[0]); i++ ) //ref list 0 + { + printf( " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, + currSlice->listX[0][i]->view_id); + } + } + } +#endif +#endif + } + else if( currSlice->slice_type == B_SLICE ) + { +#if PRINTREFLIST + unsigned int i; +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if( (p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr == 0 ) + { + if( (currSlice->listXsize[0] > 0) || (currSlice->listXsize[1] > 0) ) + printf( "\n"); + if( currSlice->listXsize[0] > 0 ) + { + printf( " ** (FinalViewID:%d) %s Ref Pic List 0 ****\n", currSlice->view_id, + currSlice->structure == FRAME ? "FRM" : (currSlice->structure == TOP_FIELD ? "TOP" : "BOT")); + for( i = 0; i < (unsigned int) (currSlice->listXsize[0]); i++ ) //ref list 0 + { + printf( " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, + currSlice->listX[0][i]->view_id); + } + } + if( currSlice->listXsize[1] > 0 ) + { + printf( " ** (FinalViewID:%d) %s Ref Pic List 1 ****\n", currSlice->view_id, + currSlice->structure == FRAME ? "FRM" : (currSlice->structure == TOP_FIELD ? "TOP" : "BOT")); + for( i = 0; i < (unsigned int) (currSlice->listXsize[1]); i++ ) //ref list 1 + { + printf( " %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[1][i]->poc, currSlice->listX[1][i]->pic_num, + currSlice->listX[1][i]->view_id); + } + } + } +#endif + +#endif + } +} + +/*! + ************************************************************************ + * \brief + * Reads new slice from bit_stream_dec + ************************************************************************ + */ +int read_new_slice( Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + NALU_t *nalu = p_Vid->nalu; + int current_header = 0; + int BitsUsedByHeader; + Bitstream *currStream = NULL; + + int slice_id_a, slice_id_b, slice_id_c; + + for( ;; ) + { +#if (MVC_EXTENSION_ENABLE) + currSlice->svc_extension_flag = -1; +#endif + if( 0 == read_next_nalu( p_Vid, nalu) ) + return EOS; + +#if (MVC_EXTENSION_ENABLE) + if( p_Inp->DecodeAllLayers == 1 && (nalu->nal_unit_type == NALU_TYPE_PREFIX || nalu->nal_unit_type == NALU_TYPE_SLC_EXT) ) + { + currStream = currSlice->partArr[0].bitstream; + currStream->ei_flag = 0; + currStream->frame_bitoffset = currStream->read_len = 0; + fast_memcpy( currStream->streamBuffer, &nalu->buf[1], nalu->len - 1); + currStream->code_len = currStream->bitstream_length = RBSPtoSODB( currStream->streamBuffer, nalu->len - 1); + + currSlice->svc_extension_flag = read_u_1( "svc_extension_flag", currStream, &p_Dec->UsedBits); + + if( currSlice->svc_extension_flag ) + { + nal_unit_header_svc_extension( ); + } + else + { + nal_unit_header_mvc_extension( &currSlice->NaluHeaderMVCExt, currStream); + currSlice->NaluHeaderMVCExt.iPrefixNALU = (nalu->nal_unit_type == NALU_TYPE_PREFIX); + } + + if( nalu->nal_unit_type == NALU_TYPE_SLC_EXT ) + { + if( currSlice->svc_extension_flag ) + { + //to be implemented for Annex G; + } + else + { + nalu->nal_unit_type = NALU_TYPE_SLICE; //currSlice->NaluHeaderMVCExt.non_idr_flag==0? NALU_TYPE_IDR: NALU_TYPE_SLICE; + } + } + } +#endif + + process_nalu: switch( nalu->nal_unit_type ) + { + case NALU_TYPE_SLICE: + case NALU_TYPE_IDR: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_SLICE\n"); +#endif + + if( p_Vid->recovery_point || nalu->nal_unit_type == NALU_TYPE_IDR ) + { + if( p_Vid->recovery_point_found == 0 ) + { + if( nalu->nal_unit_type != NALU_TYPE_IDR ) + { + printf( "Warning: Decoding does not start with an IDR picture.\n"); + p_Vid->non_conforming_stream = 1; + } + else + p_Vid->non_conforming_stream = 0; + } + p_Vid->recovery_point_found = 1; + } + + if( p_Vid->recovery_point_found == 0 ) + break; + + currSlice->idr_flag = (nalu->nal_unit_type == NALU_TYPE_IDR); + currSlice->nal_reference_idc = nalu->nal_reference_idc; + currSlice->dp_mode = PAR_DP_1; + currSlice->max_part_nr = 1; +#if (MVC_EXTENSION_ENABLE) + if( currSlice->svc_extension_flag != 0 ) + { + currStream = currSlice->partArr[0].bitstream; + currStream->ei_flag = 0; + currStream->frame_bitoffset = currStream->read_len = 0; + fast_memcpy( currStream->streamBuffer, &nalu->buf[1], nalu->len - 1); + currStream->code_len = currStream->bitstream_length = RBSPtoSODB( currStream->streamBuffer, nalu->len - 1); + } +#else + currStream = currSlice->partArr[0].bitstream; + currStream->ei_flag = 0; + currStream->frame_bitoffset = currStream->read_len = 0; + memcpy (currStream->streamBuffer, &nalu->buf[1], nalu->len-1); + currStream->code_len = currStream->bitstream_length = RBSPtoSODB(currStream->streamBuffer, nalu->len-1); +#endif + +#if (MVC_EXTENSION_ENABLE) + if( currSlice->svc_extension_flag == 0 ) + { //MVC + //if(is_MVC_profile(p_Vid->active_sps->profile_idc)) + //{ + currSlice->view_id = currSlice->NaluHeaderMVCExt.view_id; + currSlice->inter_view_flag = currSlice->NaluHeaderMVCExt.inter_view_flag; + currSlice->anchor_pic_flag = currSlice->NaluHeaderMVCExt.anchor_pic_flag; + //} + } + else if( currSlice->svc_extension_flag == -1 ) //SVC and the normal AVC; + { + if( p_Vid->active_subset_sps == NULL ) + { + currSlice->view_id = GetBaseViewId( p_Vid, &p_Vid->active_subset_sps); + if( currSlice->NaluHeaderMVCExt.iPrefixNALU > 0 ) + { + assert( currSlice->view_id == currSlice->NaluHeaderMVCExt.view_id); + currSlice->inter_view_flag = currSlice->NaluHeaderMVCExt.inter_view_flag; + currSlice->anchor_pic_flag = currSlice->NaluHeaderMVCExt.anchor_pic_flag; + } + else + { + currSlice->inter_view_flag = 1; + currSlice->anchor_pic_flag = currSlice->idr_flag; + } + } + else + { + assert( p_Vid->active_subset_sps->num_views_minus1 >=0); + // prefix NALU available + if( currSlice->NaluHeaderMVCExt.iPrefixNALU > 0 ) + { + currSlice->view_id = currSlice->NaluHeaderMVCExt.view_id; + currSlice->inter_view_flag = currSlice->NaluHeaderMVCExt.inter_view_flag; + currSlice->anchor_pic_flag = currSlice->NaluHeaderMVCExt.anchor_pic_flag; + } + else + { //no prefix NALU; + currSlice->view_id = p_Vid->active_subset_sps->view_id[0]; + currSlice->inter_view_flag = 1; + currSlice->anchor_pic_flag = currSlice->idr_flag; + } + } + } + //! Edited by Joao Carreira + currSlice->layer_id = currSlice->view_id = GetVOIdx( p_Vid, currSlice->view_id); + //currSlice->layer_id = GetVOIdx( p_Vid, currSlice->view_id ); + /* + if(currSlice->view_id >=0) + { + currSlice->p_Dpb = p_Vid->p_Dpb_layer[currSlice->view_id]; + currSlice->imgtype = currSlice->p_Dpb->imgtype; + } + */ +#endif + + // Some syntax of the Slice Header depends on the parameter set, which depends on + // the parameter set ID of the SLice header. Hence, read the pic_parameter_set_id + // of the slice header first, then setup the active parameter sets, and then read + // the rest of the slice header + BitsUsedByHeader = FirstPartOfSliceHeader( currSlice); + UseParameterSet( currSlice); + currSlice->active_sps = p_Vid->active_sps; + currSlice->active_pps = p_Vid->active_pps; + currSlice->Transform8x8Mode = p_Vid->active_pps->transform_8x8_mode_flag; + currSlice->chroma444_not_separate = (p_Vid->active_sps->chroma_format_idc == YUV444) && ((p_Vid->separate_colour_plane_flag == 0)); + + BitsUsedByHeader += RestOfSliceHeader( currSlice); +#if (MVC_EXTENSION_ENABLE) + if( currSlice->view_id >= 0 ) + { + currSlice->p_Dpb = p_Vid->p_Dpb_layer[currSlice->view_id]; + } +#endif + + assign_quant_params( currSlice); + + // if primary slice is replaced with redundant slice, set the correct image type + if( currSlice->redundant_pic_cnt && p_Vid->Is_primary_correct == 0 && p_Vid->Is_redundant_correct ) + { + p_Vid->dec_picture->slice_type = p_Vid->type; + } + + if( is_new_picture( p_Vid->dec_picture, currSlice, p_Vid->old_slice) ) + { + if( p_Vid->iSliceNumOfCurrPic == 0 ) + init_picture( p_Vid, currSlice, p_Inp); + + current_header = SOP; + //check zero_byte if it is also the first NAL unit in the access unit + CheckZeroByteVCL( p_Vid, nalu); + } + else + current_header = SOS; + + setup_slice_methods( currSlice); + + // From here on, p_Vid->active_sps, p_Vid->active_pps and the slice header are valid + if( currSlice->mb_aff_frame_flag ) + currSlice->current_mb_nr = currSlice->start_mb_nr << 1; + else + currSlice->current_mb_nr = currSlice->start_mb_nr; + + if( p_Vid->active_pps->entropy_coding_mode_flag ) + { + int ByteStartPosition = currStream->frame_bitoffset / 8; + if( currStream->frame_bitoffset % 8 != 0 ) + { + ++ByteStartPosition; + } + arideco_start_decoding( &currSlice->partArr[0].de_cabac, currStream->streamBuffer, ByteStartPosition, &currStream->read_len); + } + // printf ("read_new_slice: returning %s\n", current_header == SOP?"SOP":"SOS"); + //FreeNALU(nalu); + p_Vid->recovery_point = 0; + return current_header; + break; + case NALU_TYPE_DPA: + if( p_Vid->recovery_point_found == 0 ) + break; + + // read DP_A + currSlice->dpB_NotPresent = 1; + currSlice->dpC_NotPresent = 1; + + currSlice->idr_flag = FALSE; + currSlice->nal_reference_idc = nalu->nal_reference_idc; + currSlice->dp_mode = PAR_DP_3; + currSlice->max_part_nr = 3; + currSlice->ei_flag = 0; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[0]; + currStream = currSlice->partArr[0].bitstream; + currStream->ei_flag = 0; + currStream->frame_bitoffset = currStream->read_len = 0; + memcpy( currStream->streamBuffer, &nalu->buf[1], nalu->len - 1); + currStream->code_len = currStream->bitstream_length = RBSPtoSODB( currStream->streamBuffer, nalu->len - 1); +#if (MVC_EXTENSION_ENABLE) + currSlice->view_id = GetBaseViewId( p_Vid, &p_Vid->active_subset_sps); + currSlice->inter_view_flag = 1; + currSlice->layer_id = currSlice->view_id = GetVOIdx( p_Vid, currSlice->view_id); + //currSlice->layer_id = GetVOIdx( p_Vid, currSlice->view_id ); + currSlice->anchor_pic_flag = currSlice->idr_flag; +#endif + + BitsUsedByHeader = FirstPartOfSliceHeader( currSlice); + UseParameterSet( currSlice); + currSlice->active_sps = p_Vid->active_sps; + currSlice->active_pps = p_Vid->active_pps; + currSlice->Transform8x8Mode = p_Vid->active_pps->transform_8x8_mode_flag; + currSlice->chroma444_not_separate = (p_Vid->active_sps->chroma_format_idc == YUV444) && ((p_Vid->separate_colour_plane_flag == 0)); + + BitsUsedByHeader += RestOfSliceHeader( currSlice); +#if (MVC_EXTENSION_ENABLE) + currSlice->p_Dpb = p_Vid->p_Dpb_layer[currSlice->view_id]; +#else + currSlice->p_Dpb = p_Vid->p_Dpb_layer[0]; +#endif + assign_quant_params( currSlice); + + if( is_new_picture( p_Vid->dec_picture, currSlice, p_Vid->old_slice) ) + { + if( p_Vid->iSliceNumOfCurrPic == 0 ) + init_picture( p_Vid, currSlice, p_Inp); + + current_header = SOP; + //check zero_byte if it is also the first NAL unit in the access unit + CheckZeroByteVCL( p_Vid, nalu); + } + else + current_header = SOS; + + setup_slice_methods( currSlice); + + // From here on, p_Vid->active_sps, p_Vid->active_pps and the slice header are valid + if( currSlice->mb_aff_frame_flag ) + currSlice->current_mb_nr = currSlice->start_mb_nr << 1; + else + currSlice->current_mb_nr = currSlice->start_mb_nr; + + // Now I need to read the slice ID, which depends on the value of + // redundant_pic_cnt_present_flag + + slice_id_a = read_ue_v( "NALU: DP_A slice_id", currStream, &p_Dec->UsedBits); + + if( p_Vid->active_pps->entropy_coding_mode_flag ) + error( "received data partition with CABAC, this is not allowed", 500); + + // continue with reading next DP + if( 0 == read_next_nalu( p_Vid, nalu) ) + return current_header; + + if( NALU_TYPE_DPB == nalu->nal_unit_type ) + { + // we got a DPB + currStream = currSlice->partArr[1].bitstream; + currStream->ei_flag = 0; + currStream->frame_bitoffset = currStream->read_len = 0; + + memcpy( currStream->streamBuffer, &nalu->buf[1], nalu->len - 1); + currStream->code_len = currStream->bitstream_length = RBSPtoSODB( currStream->streamBuffer, nalu->len - 1); + + slice_id_b = read_ue_v( "NALU: DP_B slice_id", currStream, &p_Dec->UsedBits); + + currSlice->dpB_NotPresent = 0; + + if( (slice_id_b != slice_id_a) || (nalu->lost_packets) ) + { + printf( "Waning: got a data partition B which does not match DP_A (DP loss!)\n"); + currSlice->dpB_NotPresent = 1; + currSlice->dpC_NotPresent = 1; + } + else + { + if( p_Vid->active_pps->redundant_pic_cnt_present_flag ) + read_ue_v( "NALU: DP_B redundant_pic_cnt", currStream, &p_Dec->UsedBits); + + // we're finished with DP_B, so let's continue with next DP + if( 0 == read_next_nalu( p_Vid, nalu) ) + return current_header; + } + } + else + { + currSlice->dpB_NotPresent = 1; + } + + // check if we got DP_C + if( NALU_TYPE_DPC == nalu->nal_unit_type ) + { + currStream = currSlice->partArr[2].bitstream; + currStream->ei_flag = 0; + currStream->frame_bitoffset = currStream->read_len = 0; + + memcpy( currStream->streamBuffer, &nalu->buf[1], nalu->len - 1); + currStream->code_len = currStream->bitstream_length = RBSPtoSODB( currStream->streamBuffer, nalu->len - 1); + + currSlice->dpC_NotPresent = 0; + + slice_id_c = read_ue_v( "NALU: DP_C slice_id", currStream, &p_Dec->UsedBits); + if( (slice_id_c != slice_id_a) || (nalu->lost_packets) ) + { + printf( "Warning: got a data partition C which does not match DP_A(DP loss!)\n"); + //currSlice->dpB_NotPresent =1; + currSlice->dpC_NotPresent = 1; + } + + if( p_Vid->active_pps->redundant_pic_cnt_present_flag ) + read_ue_v( "NALU:SLICE_C redudand_pic_cnt", currStream, &p_Dec->UsedBits); + } + else + { + currSlice->dpC_NotPresent = 1; + } + + // check if we read anything else than the expected partitions + if( (nalu->nal_unit_type != NALU_TYPE_DPB) && (nalu->nal_unit_type != NALU_TYPE_DPC) ) + { + // we have a NALI that we can't process here, so restart processing + goto process_nalu; + // yes, "goto" should not be used, but it's really the best way here before we restructure the decoding loop + // (which should be taken care of anyway) + } + + //FreeNALU(nalu); + return current_header; + break; + case NALU_TYPE_DPB: + if( p_Inp->silent == FALSE ) + { + printf( "found data partition B without matching DP A, discarding\n"); + } + break; + case NALU_TYPE_DPC: + if( p_Inp->silent == FALSE ) + { + printf( "found data partition C without matching DP A, discarding\n"); + } + break; + case NALU_TYPE_SEI: +#if( FOUND_NALU ) + printf ("read_new_slice: Found NALU_TYPE_SEI, len %d\n", nalu->len); +#endif + InterpretSEIMessage( nalu->buf, nalu->len, p_Vid, currSlice); + break; + case NALU_TYPE_PPS: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_PPS\n"); +#endif + ProcessPPS( p_Vid, nalu); + break; + case NALU_TYPE_SPS: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_SPS\n"); +#endif + ProcessSPS( p_Vid, nalu); + break; + case NALU_TYPE_AUD: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_AUD\n"); + printf ("read_new_slice: Found 'Access Unit Delimiter' NAL unit, len %d, ignored\n", nalu->len); +#endif + + break; + case NALU_TYPE_EOSEQ: +#if( FOUND_NALU ) + printf ("read_new_slice: Found 'End of Sequence' NAL unit, len %d, ignored\n", nalu->len); +#endif + break; + case NALU_TYPE_EOSTREAM: +#if( FOUND_NALU ) + printf ("read_new_slice: Found 'End of Stream' NAL unit, len %d, ignored\n", nalu->len); +#endif + break; + case NALU_TYPE_FILL: + if( p_Inp->silent == FALSE ) + { + +#if( FOUND_NALU ) + printf ("read_new_slice: Found NALU_TYPE_FILL, len %d\n", (int) nalu->len); + printf ("Skipping these filling bits, proceeding w/ next NALU\n"); +#endif + } + break; +#if (MVC_EXTENSION_ENABLE) + case NALU_TYPE_VDRD: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_VDRD\n"); +#endif + // printf ("read_new_slice: Found 'View and Dependency Representation Delimiter' NAL unit, len %d, ignored\n", nalu->len); + break; + case NALU_TYPE_PREFIX: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_PREFIX\n"); +#endif + if( currSlice->svc_extension_flag == 1 ) + prefix_nal_unit_svc( ); + break; + case NALU_TYPE_SUB_SPS: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_SUB_SPS\n"); +#endif + if( p_Inp->DecodeAllLayers == 1 ) + { + ProcessSubsetSPS( p_Vid, nalu); + } + else + { + if( p_Inp->silent == FALSE ) + printf( "Found Subsequence SPS NALU. Ignoring.\n"); + } + break; + case NALU_TYPE_SLC_EXT: +#if( FOUND_NALU ) + printf ("Found NALU_TYPE_SLC_EXT\n"); +#endif + if( p_Inp->DecodeAllLayers == 0 && (p_Inp->silent == FALSE) ) + printf( "Found SVC extension NALU (%d). Ignoring.\n", (int) nalu->nal_unit_type); + break; +#endif + default: + { + if( p_Inp->silent == FALSE ) + printf( "Found NALU type %d, len %d undefined, ignore NALU, moving on\n", (int) nalu->nal_unit_type, (int) nalu->len); + } + break; + } + } +} + +void pad_buf( imgpel *pImgBuf, int iWidth, int iHeight, int iStride, int iPadX, int iPadY) +{ + int j; + imgpel *pLine0 = pImgBuf - iPadX, *pLine; +#if (IMGTYPE==0) + int pad_width = iPadX + iWidth; + fast_memset( pImgBuf - iPadX, *pImgBuf, iPadX * sizeof(imgpel)); + fast_memset( pImgBuf + iWidth, *(pImgBuf + iWidth - 1), iPadX * sizeof(imgpel)); + + pLine = pLine0 - iPadY * iStride; + + for( j = -iPadY; j < 0; j++ ) + { + fast_memcpy( pLine, pLine0, iStride * sizeof(imgpel)); + pLine += iStride; + } + + for( j = 1; j < iHeight; j++ ) + { + pLine += iStride; + fast_memset( pLine, *(pLine + iPadX), iPadX * sizeof(imgpel)); + fast_memset( pLine + pad_width, *(pLine + pad_width - 1), iPadX * sizeof(imgpel)); + } + + pLine0 = pLine + iStride; + + for( j = iHeight; j < iHeight + iPadY; j++ ) + { + fast_memcpy( pLine0, pLine, iStride * sizeof(imgpel)); + pLine0 += iStride; + } +#else + int i; + for(i=-iPadX; i<0; i++) + pImgBuf[i] = *pImgBuf; + for(i=0; iiLumaPadX; + int iPadY = p_Vid->iLumaPadY; + int iWidth = dec_picture->size_x; + int iHeight = dec_picture->size_y; + int iStride = dec_picture->iLumaStride; + + pad_buf( *dec_picture->imgY, iWidth, iHeight, iStride, iPadX, iPadY); + + if( dec_picture->chroma_format_idc != YUV400 ) + { + iPadX = p_Vid->iChromaPadX; + iPadY = p_Vid->iChromaPadY; + iWidth = dec_picture->size_x_cr; + iHeight = dec_picture->size_y_cr; + iStride = dec_picture->iChromaStride; + pad_buf( *dec_picture->imgUV[0], iWidth, iHeight, iStride, iPadX, iPadY); + pad_buf( *dec_picture->imgUV[1], iWidth, iHeight, iStride, iPadX, iPadY); + } +} + +/*! + ************************************************************************ + * \brief + * finish decoding of a picture, conceal errors and store it + * into the DPB + ************************************************************************ + */ +void exit_picture( VideoParameters *p_Vid, StorablePicture **dec_picture) +{ + InputParameters *p_Inp = p_Vid->p_Inp; +#if( MVC_EXTENSION_ENABLE) + SNRParameters *snr = p_Vid->snr[(*dec_picture)->view_id]; +#else + SNRParameters *snr = p_Vid->snr; +#endif + char yuv_types[4][6] = + { "4:0:0", "4:2:0", "4:2:2", "4:4:4" }; +#if (DISABLE_ERC == 0) + int ercStartMB; + int ercSegment; + frame recfr; +#endif + +#if(MVC_EXTENSION_ENABLE) + int view_id; +#endif + int structure, frame_poc, slice_type, refpic, qp, pic_num, chroma_format_idc, is_idr; + + int64 tmp_time; // time used by decoding the last frame + char yuvFormat[10]; + + // return if the last picture has already been finished + if( *dec_picture == NULL || p_Vid->num_dec_mb == 0 ) + //if (*dec_picture==NULL || (p_Vid->num_dec_mb != p_Vid->PicSizeInMbs && (p_Vid->yuv_format != YUV444 || !p_Vid->separate_colour_plane_flag))) + { + return; + } + + showStorablePicture( p_Vid , *dec_picture , 0 , 1 , "Decoded Frame", 0); + +//#define LOST_POC 8 +// if( (*dec_picture)->poc == LOST_POC ) +// { +// fercModLostRefFrames( p_Vid, (*dec_picture) ); +// } + + //! Save some information for error concealment + fercSaveListsInfo( p_Vid, p_Vid->ppSliceList[0]); + + saveTranscodingInfo( p_Vid, (*dec_picture)); + +#ifndef DISABLE_MB_DECODING + +#if (DISABLE_ERC == 0) + recfr.p_Vid = p_Vid; + recfr.yptr = &(*dec_picture)->imgY[0][0]; + if ((*dec_picture)->chroma_format_idc != YUV400) + { + recfr.uptr = &(*dec_picture)->imgUV[0][0][0]; + recfr.vptr = &(*dec_picture)->imgUV[1][0][0]; + } + + //! this is always true at the beginning of a picture + ercStartMB = 0; + ercSegment = 0; + + //! mark the start of the first segment + if (!(*dec_picture)->mb_aff_frame_flag) + { + unsigned int i; + ercStartSegment(0, ercSegment, 0 , p_Vid->erc_errorVar); + //! generate the segments according to the macroblock map + for(i = 1; i<(*dec_picture)->PicSizeInMbs; ++i) + { + if(p_Vid->mb_data[i].ei_flag != p_Vid->mb_data[i-1].ei_flag) + { + ercStopSegment(i-1, ercSegment, 0, p_Vid->erc_errorVar); //! stop current segment + + //! mark current segment as lost or OK + if(p_Vid->mb_data[i-1].ei_flag) + ercMarkCurrSegmentLost((*dec_picture)->size_x, p_Vid->erc_errorVar); + else + ercMarkCurrSegmentOK((*dec_picture)->size_x, p_Vid->erc_errorVar); + + ++ercSegment;//! next segment + ercStartSegment(i, ercSegment, 0 , p_Vid->erc_errorVar);//! start new segment + ercStartMB = i;//! save start MB for this segment + } + } + //! mark end of the last segment + ercStopSegment((*dec_picture)->PicSizeInMbs-1, ercSegment, 0, p_Vid->erc_errorVar); + if(p_Vid->mb_data[i-1].ei_flag) + ercMarkCurrSegmentLost((*dec_picture)->size_x, p_Vid->erc_errorVar); + else + ercMarkCurrSegmentOK((*dec_picture)->size_x, p_Vid->erc_errorVar); + + //! call the right error concealment function depending on the frame type. + p_Vid->erc_mvperMB /= (*dec_picture)->PicSizeInMbs; + + p_Vid->erc_img = p_Vid; + + if((*dec_picture)->slice_type == I_SLICE || (*dec_picture)->slice_type == SI_SLICE)// I-frame + ercConcealIntraFrame(p_Vid, &recfr, (*dec_picture)->size_x, (*dec_picture)->size_y, p_Vid->erc_errorVar); + else + ercConcealInterFrame(&recfr, p_Vid->erc_object_list, (*dec_picture)->size_x, (*dec_picture)->size_y, p_Vid->erc_errorVar, (*dec_picture)->chroma_format_idc); + } +#endif + + if( !p_Vid->iDeblockMode && (p_Vid->bDeblockEnable & (1 << (*dec_picture)->used_for_reference)) ) + { + //deblocking for frame or field + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + int nplane; + int colour_plane_id = p_Vid->ppSliceList[0]->colour_plane_id; + for( nplane = 0; nplane < MAX_PLANE; ++nplane ) + { + p_Vid->ppSliceList[0]->colour_plane_id = nplane; + change_plane_JV( p_Vid, nplane, NULL ); + DeblockPicture( p_Vid, *dec_picture); + } + p_Vid->ppSliceList[0]->colour_plane_id = colour_plane_id; + make_frame_picture_JV( p_Vid); + } + else + { + DeblockPicture( p_Vid, *dec_picture); + } + } + else + { + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + make_frame_picture_JV( p_Vid); + } + } +#endif + + if( (*dec_picture)->mb_aff_frame_flag ) + MbAffPostProc( p_Vid); + + if( p_Vid->structure == FRAME ) // buffer mgt. for frame mode + frame_postprocessing( p_Vid); + else + field_postprocessing( p_Vid); // reset all interlaced variables +#if (MVC_EXTENSION_ENABLE) + if( (*dec_picture)->used_for_reference || ((*dec_picture)->inter_view_flag == 1) ) + pad_dec_picture( p_Vid, *dec_picture); +#else + if((*dec_picture)->used_for_reference) + pad_dec_picture(p_Vid, *dec_picture); +#endif + structure = (*dec_picture)->structure; + slice_type = (*dec_picture)->slice_type; + frame_poc = (*dec_picture)->frame_poc; + refpic = (*dec_picture)->used_for_reference; + qp = (*dec_picture)->qp; + pic_num = (*dec_picture)->pic_num; + is_idr = (*dec_picture)->idr_flag; +#if(MVC_EXTENSION_ENABLE) + view_id = (*dec_picture)->view_id; +#endif + + chroma_format_idc = (*dec_picture)->chroma_format_idc; + +#if MVC_EXTENSION_ENABLE + store_picture_in_dpb( p_Vid->p_Dpb_layer[(*dec_picture)->view_id], *dec_picture); +#else + store_picture_in_dpb(p_Vid->p_Dpb_layer[0], *dec_picture); +#endif + + calculate_frame_no( p_Vid, (*dec_picture)); + + p_Vid->nFramesDecoded[view_id]++; + + /* Edit by Jo���o Carreira - Control de Number of IDR frames to control the frame_no */ + if( (*dec_picture)->idr_flag ) + { + p_Vid->IDRframe_ctr++; + p_Vid->frame_no_idr = p_Vid->frame_no; + } + +#if(MVC_EXTENSION_ENABLE) + if( p_Vid->p_ref_mvc[GetViewIdx( p_Vid, view_id)] != -1 ) + find_snr( p_Vid, (*dec_picture), &(p_Vid->p_ref_mvc[GetViewIdx( p_Vid, view_id)])); +#else + if( p_Vid->p_ref != -1) + find_snr( p_Vid, (*dec_picture) , &p_Vid->p_ref); +#endif + + if( p_Vid->last_has_mmco_5 ) + { +#if (MVC_EXTENSION_ENABLE) + // p_Vid->pre_frame_num[(*dec_picture)->view_id] = 0; +#else + // p_Vid->pre_frame_num = 0; +#endif + } + + *dec_picture = NULL; + + if( p_Inp->silent == FALSE ) + { + if( structure == TOP_FIELD || structure == FRAME ) + { + if( slice_type == I_SLICE && is_idr ) // IDR picture + strcpy( p_Vid->cslice_type, "IDR"); + else if( slice_type == I_SLICE ) // I picture + strcpy( p_Vid->cslice_type, " I "); + else if( slice_type == P_SLICE ) // P pictures + strcpy( p_Vid->cslice_type, " P "); + else if( slice_type == SP_SLICE ) // SP pictures + strcpy( p_Vid->cslice_type, "SP "); + else if( slice_type == SI_SLICE ) + strcpy( p_Vid->cslice_type, "SI "); + else if( refpic ) // stored B pictures + strcpy( p_Vid->cslice_type, " B "); + else + // B pictures + strcpy( p_Vid->cslice_type, " b "); + + if( structure == FRAME ) + { + strncat( p_Vid->cslice_type, ") ", 8 - strlen( p_Vid->cslice_type)); + } + } + else if( structure == BOTTOM_FIELD ) + { + if( slice_type == I_SLICE && is_idr ) // IDR picture + strncat( p_Vid->cslice_type, "|IDR)", 8 - strlen( p_Vid->cslice_type)); + else if( slice_type == I_SLICE ) // I picture + strncat( p_Vid->cslice_type, "| I )", 8 - strlen( p_Vid->cslice_type)); + else if( slice_type == P_SLICE ) // P pictures + strncat( p_Vid->cslice_type, "| P )", 8 - strlen( p_Vid->cslice_type)); + else if( slice_type == SP_SLICE ) // SP pictures + strncat( p_Vid->cslice_type, "|SP )", 8 - strlen( p_Vid->cslice_type)); + else if( slice_type == SI_SLICE ) + strncat( p_Vid->cslice_type, "|SI )", 8 - strlen( p_Vid->cslice_type)); + else if( refpic ) // stored B pictures + strncat( p_Vid->cslice_type, "| B )", 8 - strlen( p_Vid->cslice_type)); + else + // B pictures + strncat( p_Vid->cslice_type, "| b )", 8 - strlen( p_Vid->cslice_type)); + } + } + + if( (structure == FRAME) || structure == BOTTOM_FIELD ) + { + gettime( &(p_Vid->end_time)); // end time + + tmp_time = timediff( &(p_Vid->start_time), &(p_Vid->end_time)); + p_Vid->tot_time += tmp_time; + tmp_time = timenorm( tmp_time); + sprintf( yuvFormat, "%s", yuv_types[chroma_format_idc]); + + if( p_Inp->silent == FALSE ) + { +#if( MVC_EXTENSION_ENABLE) + SNRParameters *snr = p_Vid->snr[view_id]; + if( p_Vid->p_ref_mvc[view_id] != -1 ) + fprintf( stdout, "%05d(%s%3d|%2d %5d %5d %8.4f %8.4f %8.4f %s %7d\n", p_Vid->frame_no, p_Vid->cslice_type, frame_poc, GetViewIdx( p_Vid, view_id), + pic_num, qp, snr->snr[0], snr->snr[1], snr->snr[2], yuvFormat, (int) tmp_time); + else + fprintf( stdout, "%05d(%s%3d|%2d %5d %5d %s %7d\n", p_Vid->frame_no, p_Vid->cslice_type, frame_poc, + GetViewIdx( p_Vid, view_id), pic_num, qp, yuvFormat, (int) tmp_time); +#else + SNRParameters *snr = p_Vid->snr; + if (p_Vid->p_ref != -1) + fprintf(stdout,"%05d(%s%5d %5d %5d %8.4f %8.4f %8.4f %s %7d\n", + p_Vid->frame_no, p_Vid->cslice_type, frame_poc, pic_num, qp, snr->snr[0], snr->snr[1], snr->snr[2], yuvFormat, (int) tmp_time); + else + fprintf(stdout,"%05d(%s%5d %5d %5d %s %7d\n", + p_Vid->frame_no, p_Vid->cslice_type, frame_poc, pic_num, qp, yuvFormat, (int)tmp_time); +#endif + } + else + { + fprintf( stdout, "Completed Decoding frame %05d.\r", snr->frame_ctr); + } + fflush( stdout); + + if( slice_type == I_SLICE || slice_type == SI_SLICE || slice_type == P_SLICE || refpic ) // I or P pictures + { +#if (MVC_EXTENSION_ENABLE) + if( (p_Vid->ppSliceList[0])->view_id != 0 ) +#endif + ++(p_Vid->number); + } + else + ++(p_Vid->Bframe_ctr); // B pictures + ++(snr->frame_ctr); + +#if (MVC_EXTENSION_ENABLE) + if( (p_Vid->ppSliceList[0])->view_id != 0 ) +#endif + ++(p_Vid->g_nFrame); + } + + //p_Vid->currentSlice->current_mb_nr = -4712; // impossible value for debugging, StW + //p_Vid->currentSlice->current_slice_nr = 0; +} + +/*! + ************************************************************************ + * \brief + * set defaults for old_slice + * NAL unit of a picture" + ************************************************************************ + */ +void init_old_slice( OldSliceParams *p_old_slice) +{ + p_old_slice->field_pic_flag = 0; + p_old_slice->pps_id = INT_MAX; + p_old_slice->frame_num = INT_MAX; + p_old_slice->nal_ref_idc = INT_MAX; + p_old_slice->idr_flag = FALSE; + + p_old_slice->pic_oder_cnt_lsb = UINT_MAX; + p_old_slice->delta_pic_oder_cnt_bottom = INT_MAX; + + p_old_slice->delta_pic_order_cnt[0] = INT_MAX; + p_old_slice->delta_pic_order_cnt[1] = INT_MAX; +} + +void copy_slice_info( Slice *currSlice, OldSliceParams *p_old_slice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + + p_old_slice->pps_id = currSlice->pic_parameter_set_id; + p_old_slice->frame_num = currSlice->frame_num; //p_Vid->frame_num; + p_old_slice->field_pic_flag = currSlice->field_pic_flag; //p_Vid->field_pic_flag; + + if( currSlice->field_pic_flag ) + { + p_old_slice->bottom_field_flag = currSlice->bottom_field_flag; + } + + p_old_slice->nal_ref_idc = currSlice->nal_reference_idc; + p_old_slice->idr_flag = (byte) currSlice->idr_flag; + + if( currSlice->idr_flag ) + { + p_old_slice->idr_pic_id = currSlice->idr_pic_id; + } + + if( p_Vid->active_sps->pic_order_cnt_type == 0 ) + { + p_old_slice->pic_oder_cnt_lsb = currSlice->pic_order_cnt_lsb; + p_old_slice->delta_pic_oder_cnt_bottom = currSlice->delta_pic_order_cnt_bottom; + } + + if( p_Vid->active_sps->pic_order_cnt_type == 1 ) + { + p_old_slice->delta_pic_order_cnt[0] = currSlice->delta_pic_order_cnt[0]; + p_old_slice->delta_pic_order_cnt[1] = currSlice->delta_pic_order_cnt[1]; + } +#if (MVC_EXTENSION_ENABLE) + p_old_slice->view_id = currSlice->view_id; + p_old_slice->inter_view_flag = currSlice->inter_view_flag; + p_old_slice->anchor_pic_flag = currSlice->anchor_pic_flag; +#endif + p_old_slice->layer_id = currSlice->layer_id; +} + +/*! + ************************************************************************ + * \brief + * detect if current slice is "first VCL NAL unit of a picture" + ************************************************************************ + */ +int is_new_picture( StorablePicture *dec_picture, Slice *currSlice, OldSliceParams *p_old_slice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + + int result = 0; + + result |= (NULL == dec_picture); + + result |= (p_old_slice->pps_id != currSlice->pic_parameter_set_id); + + result |= (p_old_slice->frame_num != currSlice->frame_num); + + result |= (p_old_slice->field_pic_flag != currSlice->field_pic_flag); + + if( currSlice->field_pic_flag && p_old_slice->field_pic_flag ) + { + result |= (p_old_slice->bottom_field_flag != currSlice->bottom_field_flag); + } + + result |= (p_old_slice->nal_ref_idc != currSlice->nal_reference_idc) && ((p_old_slice->nal_ref_idc == 0) || (currSlice->nal_reference_idc == 0)); + result |= (p_old_slice->idr_flag != currSlice->idr_flag); + + if( currSlice->idr_flag && p_old_slice->idr_flag ) + { + result |= (p_old_slice->idr_pic_id != currSlice->idr_pic_id); + } + + if( p_Vid->active_sps->pic_order_cnt_type == 0 ) + { + result |= (p_old_slice->pic_oder_cnt_lsb != currSlice->pic_order_cnt_lsb); + if( p_Vid->active_pps->bottom_field_pic_order_in_frame_present_flag == 1 && !currSlice->field_pic_flag ) + { + result |= (p_old_slice->delta_pic_oder_cnt_bottom != currSlice->delta_pic_order_cnt_bottom); + } + } + + if( p_Vid->active_sps->pic_order_cnt_type == 1 ) + { + if( !p_Vid->active_sps->delta_pic_order_always_zero_flag ) + { + result |= (p_old_slice->delta_pic_order_cnt[0] != currSlice->delta_pic_order_cnt[0]); + if( p_Vid->active_pps->bottom_field_pic_order_in_frame_present_flag == 1 && !currSlice->field_pic_flag ) + { + result |= (p_old_slice->delta_pic_order_cnt[1] != currSlice->delta_pic_order_cnt[1]); + } + } + } + +#if (MVC_EXTENSION_ENABLE) + result |= (currSlice->view_id != p_old_slice->view_id); + result |= (currSlice->inter_view_flag != p_old_slice->inter_view_flag); + result |= (currSlice->anchor_pic_flag != p_old_slice->anchor_pic_flag); +#endif + result |= (currSlice->layer_id != p_old_slice->layer_id); + return result; +} + +/*! + ************************************************************************ + * \brief + * Prepare field and frame buffer after frame decoding + ************************************************************************ + */ +void frame_postprocessing( VideoParameters *p_Vid) +{ +} + +/*! + ************************************************************************ + * \brief + * Prepare field and frame buffer after field decoding + ************************************************************************ + */ +void field_postprocessing( VideoParameters *p_Vid) +{ + p_Vid->number /= 2; +} + +/*! + ************************************************************************ + * \brief + * copy StorablePicture *src -> StorablePicture *dst + * for 4:4:4 Independent mode + ************************************************************************ + */ +void copy_dec_picture_JV( VideoParameters *p_Vid, StorablePicture *dst, StorablePicture *src) +{ + dst->top_poc = src->top_poc; + dst->bottom_poc = src->bottom_poc; + dst->frame_poc = src->frame_poc; + dst->qp = src->qp; + dst->slice_qp_delta = src->slice_qp_delta; + dst->chroma_qp_offset[0] = src->chroma_qp_offset[0]; + dst->chroma_qp_offset[1] = src->chroma_qp_offset[1]; + + dst->poc = src->poc; + + dst->slice_type = src->slice_type; + dst->used_for_reference = src->used_for_reference; + dst->idr_flag = src->idr_flag; + dst->no_output_of_prior_pics_flag = src->no_output_of_prior_pics_flag; + dst->long_term_reference_flag = src->long_term_reference_flag; + dst->adaptive_ref_pic_buffering_flag = src->adaptive_ref_pic_buffering_flag; + + dst->dec_ref_pic_marking_buffer = src->dec_ref_pic_marking_buffer; + + dst->mb_aff_frame_flag = src->mb_aff_frame_flag; + dst->PicWidthInMbs = src->PicWidthInMbs; + dst->pic_num = src->pic_num; + dst->frame_num = src->frame_num; + dst->recovery_frame = src->recovery_frame; + dst->coded_frame = src->coded_frame; + + dst->chroma_format_idc = src->chroma_format_idc; + + dst->frame_mbs_only_flag = src->frame_mbs_only_flag; + dst->frame_cropping_flag = src->frame_cropping_flag; + + dst->frame_crop_left_offset = src->frame_crop_left_offset; + dst->frame_crop_right_offset = src->frame_crop_right_offset; + dst->frame_crop_top_offset = src->frame_crop_top_offset; + dst->frame_crop_bottom_offset = src->frame_crop_bottom_offset; + +#if (ENABLE_OUTPUT_TONEMAPPING) + // store the necessary tone mapping sei into StorablePicture structure + dst->seiHasTone_mapping = src->seiHasTone_mapping; + + dst->seiHasTone_mapping = src->seiHasTone_mapping; + dst->tone_mapping_model_id = src->tone_mapping_model_id; + dst->tonemapped_bit_depth = src->tonemapped_bit_depth; + if( src->tone_mapping_lut ) + { + int coded_data_bit_max = (1 << p_Vid->seiToneMapping->coded_data_bit_depth); + dst->tone_mapping_lut = malloc( sizeof(int) * coded_data_bit_max); + if( NULL == dst->tone_mapping_lut ) + { + no_mem_exit( "copy_dec_picture_JV: tone_mapping_lut"); + } + memcpy( dst->tone_mapping_lut, src->tone_mapping_lut, sizeof(imgpel) * coded_data_bit_max); + } +#endif +} + +// this is intended to make get_block_luma faster by doing this at a more appropriate level +// i.e. per slice rather than per MB +static void init_cur_imgy( Slice *currSlice, VideoParameters *p_Vid) +{ + int i, j; + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + StorablePicture *vidref = p_Vid->no_reference_picture; + int noref = (currSlice->framepoc < p_Vid->recovery_poc); + switch( currSlice->colour_plane_id ) + { + case 0: + for( j = 0; j < 6; j++ ) //for (j = 0; j < (currSlice->slice_type==B_SLICE?2:1); j++) { + { + for( i = 0; i < MAX_LIST_SIZE; i++ ) + { + StorablePicture *curr_ref = currSlice->listX[j][i]; + if( curr_ref ) + { + curr_ref->no_ref = noref && (curr_ref == vidref); + curr_ref->cur_imgY = curr_ref->imgY; + } + } + } + break; + } + } + else + { + StorablePicture *vidref = p_Vid->no_reference_picture; + int noref = (currSlice->framepoc < p_Vid->recovery_poc); + int total_lists = currSlice->mb_aff_frame_flag ? 6 : (currSlice->slice_type == B_SLICE ? 2 : 1); + // for (j = 0; j < 6; j++) { //for (j = 0; j < (currSlice->slice_type==B_SLICE?2:1); j++) { + for( j = 0; j < total_lists; j++ ) + { + // note that if we always set this to MAX_LIST_SIZE, we avoid crashes with invalid ref_idx being set + // since currently this is done at the slice level, it seems safe to do so. + // Note for some reason I get now a mismatch between version 12 and this one in cabac. I wonder why. + //for (i = 0; i < currSlice->listXsize[j]; i++) + for( i = 0; i < MAX_LIST_SIZE; i++ ) + { + StorablePicture *curr_ref = currSlice->listX[j][i]; + if( curr_ref ) + { + curr_ref->no_ref = noref && (curr_ref == vidref); + curr_ref->cur_imgY = curr_ref->imgY; + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * decodes one slice + ************************************************************************ + */ +void decode_one_slice( Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + Boolean end_of_slice = FALSE; + Macroblock *currMB = NULL; + + currSlice->cod_counter = -1; + + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + change_plane_JV( p_Vid, currSlice->colour_plane_id, currSlice); + } + else + { + currSlice->mb_data = p_Vid->mb_data; + currSlice->dec_picture = p_Vid->dec_picture; + currSlice->siblock = p_Vid->siblock; + currSlice->ipredmode = p_Vid->ipredmode; + currSlice->intra_block = p_Vid->intra_block; + } + + if( currSlice->slice_type == B_SLICE ) + { + compute_colocated( currSlice, currSlice->listX); + } + + if( currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE ) + init_cur_imgy( currSlice, p_Vid); + + /* Edited by Joao Carreira */ + if( p_Vid->p_Inp->error_prop && currSlice->slice_type != I_SLICE ) + ProjectMotionToCurrSlice( p_Vid, currSlice->dec_picture, currSlice); + + //reset_ec_flags(p_Vid); + + //#ifdef DISABLE_MB_DECODING + // currSlice->num_dec_mb = p_Vid->PicSizeInMbs; + // return; + //#endif + currSlice->p_Vid->n_SKIP = 0; + + while( end_of_slice == FALSE ) // loop over macroblocks + { + +#if TRACE + fprintf(p_Dec->p_trace,"\n*********** POC: %i (I/P) MB: %i Slice: %i Type %d **********\n", currSlice->ThisPOC, currSlice->current_mb_nr, currSlice->current_slice_nr, currSlice->slice_type); +#endif + + // Initializes the current macroblock + start_macroblock( currSlice, &currMB); + // Get the syntax elements from the NAL + currSlice->read_one_macroblock( currMB); + + //if( MBCounter++ == 1536 ) + // continue; + + decode_one_macroblock( currMB, currSlice->dec_picture); + + if( currSlice->mb_aff_frame_flag && currMB->mb_field ) + { + currSlice->num_ref_idx_active[LIST_0] >>= 1; + currSlice->num_ref_idx_active[LIST_1] >>= 1; + } + +#if (DISABLE_ERC == 0) + ercWriteMBMODEandMV(currMB); +#endif + + end_of_slice = exit_macroblock( currSlice, (!currSlice->mb_aff_frame_flag || currSlice->current_mb_nr % 2)); + + currMB->is_decoded = 1; + } + //reset_ec_flags(p_Vid); + + /* Edited by Jo���o Carreira */ + if( currSlice->dec_picture->disparity ) + free_storable_picture( currSlice->dec_picture->disparity); + if( p_Vid->p_Inp->error_prop ) + fercFreeMotionPropInfo( currSlice->dec_picture); + + //! Edited by Joao Carreira -> simple prediction parser +// if( p_Vid->p_Inp->PredictionParser ) +// { +// //parse_prediction( p_Vid, currSlice, p_Vid->dec_picture); +// //parse_mv_prediction( p_Vid, currSlice, p_Vid->dec_picture); +// if( p_Vid->dec_picture->frame_no == 4 && p_Vid->dec_picture->view_id == 1 ) +// parse_mv_values( p_Vid, currSlice, p_Vid->dec_picture, 1); +// +// if( p_Vid->dec_picture->frame_no == 4 && p_Vid->dec_picture->view_id == 0 ) +// parse_mv_values( p_Vid, currSlice, p_Vid->dec_picture, 1); +// } +} + +#if (MVC_EXTENSION_ENABLE) +int GetVOIdx( VideoParameters *p_Vid, int iViewId) +{ + int iVOIdx = -1; + int *piViewIdMap; + if( p_Vid->active_subset_sps ) + { + piViewIdMap = p_Vid->active_subset_sps->view_id; + for( iVOIdx = p_Vid->active_subset_sps->num_views_minus1; iVOIdx >= 0; iVOIdx-- ) + if( piViewIdMap[iVOIdx] == iViewId ) + break; + } + else + { + subset_seq_parameter_set_rbsp_t *curr_subset_sps; + int i; + + curr_subset_sps = p_Vid->SubsetSeqParSet; + for( i = 0; i < MAXSPS; i++ ) + { + if( curr_subset_sps->num_views_minus1 >= 0 && curr_subset_sps->sps.Valid ) + { + break; + } + curr_subset_sps++; + } + + if( i < MAXSPS ) + { + p_Vid->active_subset_sps = curr_subset_sps; + + piViewIdMap = p_Vid->active_subset_sps->view_id; + for( iVOIdx = p_Vid->active_subset_sps->num_views_minus1; iVOIdx >= 0; iVOIdx-- ) + if( piViewIdMap[iVOIdx] == iViewId ) + break; + + return iVOIdx; + } + else + { + iVOIdx = 0; + } + } + + return iVOIdx; +} + +int GetViewIdx( VideoParameters *p_Vid, int iVOIdx) +{ + int iViewIdx = iVOIdx; + int *piViewIdMap; + + if( p_Vid->active_subset_sps ) + { + assert( p_Vid->active_subset_sps->num_views_minus1 >= iVOIdx && iVOIdx >= 0); + piViewIdMap = p_Vid->active_subset_sps->view_id; + iViewIdx = piViewIdMap[iVOIdx]; + } + + return iViewIdx; +} +int get_maxViewIdx( VideoParameters *p_Vid, int view_id, int anchor_pic_flag, int listidx) +{ + int VOIdx; + int maxViewIdx = 0; + + VOIdx = view_id; + if( VOIdx >= 0 ) + { + if( anchor_pic_flag ) + maxViewIdx = listidx ? p_Vid->active_subset_sps->num_anchor_refs_l1[VOIdx] : p_Vid->active_subset_sps->num_anchor_refs_l0[VOIdx]; + else + maxViewIdx = listidx ? p_Vid->active_subset_sps->num_non_anchor_refs_l1[VOIdx] : p_Vid->active_subset_sps->num_non_anchor_refs_l0[VOIdx]; + } + + return maxViewIdx; +} +#endif diff --git a/ldecod/src/intra16x16_pred.c b/ldecod/src/intra16x16_pred.c new file mode 100644 index 0000000..ec7e665 --- /dev/null +++ b/ldecod/src/intra16x16_pred.c @@ -0,0 +1,348 @@ +/*! + ************************************************************************************* + * \file intra16x16_pred.c + * + * \brief + * Functions for intra 16x16 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra16x16_pred.h" +#include "mb_access.h" +#include "image.h" + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 DC prediction mode + * + * \return + * DECODING_OK decoding of intra_prediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_dc_pred(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int s0 = 0, s1 = 0, s2 = 0; + + int i,j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + + PixelPos a, b; + + int up_avail, left_avail; + + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &a); + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + left_avail = a.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + left_avail = a.available ? currSlice->intra_block[a.mb_addr]: 0; + } + + // Sum top predictors + if (up_avail) + { + imgpel *pel = &imgY[b.pos_y][b.pos_x]; + for (i = 0; i < MB_BLOCK_SIZE; ++i) + { + s1 += *pel++; + } + } + + // Sum left predictors + if (left_avail) + { + int pos_y = a.pos_y; + int pos_x = a.pos_x; + for (i = 0; i < MB_BLOCK_SIZE; ++i) + { + s2 += imgY[pos_y++][pos_x]; + } + } + + if (up_avail && left_avail) + s0 = (s1 + s2 + 16)>>5; // no edge + else if (!up_avail && left_avail) + s0 = (s2 + 8)>>4; // upper edge + else if (up_avail && !left_avail) + s0 = (s1 + 8)>>4; // left edge + else + s0 = p_Vid->dc_pred_value_comp[pl]; // top left corner, nothing to predict from + + for(j = 0; j < MB_BLOCK_SIZE; ++j) + { +#if (IMGTYPE == 0) + memset(mb_pred[j], s0, MB_BLOCK_SIZE * sizeof(imgpel)); +#else + for(i = 0; i < MB_BLOCK_SIZE; i += 4) + { + mb_pred[j][i ]=(imgpel) s0; + mb_pred[j][i + 1]=(imgpel) s0; + mb_pred[j][i + 2]=(imgpel) s0; + mb_pred[j][i + 3]=(imgpel) s0; + } +#endif + } + + return DECODING_OK; + +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 vertical prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_vert_pred(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos b; //!< pixel position p(0,-1) + + int up_avail; + + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + } + + if (!up_avail) + error ("invalid 16x16 intra pred Mode VERT_PRED_16",500); + { + imgpel **prd = &currSlice->mb_pred[pl][0]; + imgpel *src = &(imgY[b.pos_y][b.pos_x]); + + for(j=0;jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + imgpel prediction; + int pos_y, pos_x; + + PixelPos a; + + int left_avail; + + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &a); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + left_avail = a.available; + } + else + { + left_avail = a.available ? currSlice->intra_block[a.mb_addr]: 0; + } + + if (!left_avail) + error ("invalid 16x16 intra pred Mode HOR_PRED_16",500); + + pos_y = a.pos_y; + pos_x = a.pos_x; + + for(j = 0; j < MB_BLOCK_SIZE; ++j) + { +#if (IMGTYPE == 0) + imgpel *prd = mb_pred[j]; + prediction = imgY[pos_y++][pos_x]; + + memset(prd, prediction, MB_BLOCK_SIZE * sizeof(imgpel)); +#else + int i; + imgpel *prd = mb_pred[j]; + prediction = imgY[pos_y++][pos_x]; + + for(i = 0; i < MB_BLOCK_SIZE; i += 4) + { + *prd++= prediction; // store predicted 16x16 block + *prd++= prediction; // store predicted 16x16 block + *prd++= prediction; // store predicted 16x16 block + *prd++= prediction; // store predicted 16x16 block + } +#endif + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 horizontal prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_plane_pred(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j; + + int ih = 0, iv = 0; + int ib,ic,iaa; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + imgpel *mpr_line; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + int pos_y, pos_x; + + PixelPos a, b, d; + + int up_avail, left_avail, left_up_avail; + + getNonAffNeighbour(currMB, -1, -1, p_Vid->mb_size[IS_LUMA], &d); + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &a); + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + left_avail = a.available; + left_up_avail = d.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + left_avail = a.available ? currSlice->intra_block[a.mb_addr] : 0; + left_up_avail = d.available ? currSlice->intra_block[d.mb_addr] : 0; + } + + if (!up_avail || !left_up_avail || !left_avail) + error ("invalid 16x16 intra pred Mode PLANE_16",500); + + mpr_line = &imgY[b.pos_y][b.pos_x+7]; + pos_y = a.pos_y + 7; + pos_x = a.pos_x; + for (i = 1; i < 8; ++i) + { + ih += i*(mpr_line[i] - mpr_line[-i]); + iv += i*(imgY[pos_y + i][pos_x] - imgY[pos_y - i][pos_x]); + } + + ih += 8*(mpr_line[8] - imgY[d.pos_y][d.pos_x]); + iv += 8*(imgY[pos_y + 8][pos_x] - imgY[d.pos_y][d.pos_x]); + + ib=(5 * ih + 32)>>6; + ic=(5 * iv + 32)>>6; + + iaa=16 * (mpr_line[8] + imgY[pos_y + 8][pos_x]); + for (j = 0;j < MB_BLOCK_SIZE; ++j) + { + int ibb = iaa + (j - 7) * ic + 16; + imgpel *prd = mb_pred[j]; + for (i = 0;i < MB_BLOCK_SIZE; i += 4) + { + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 7) * ib) >> 5)); + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 6) * ib) >> 5)); + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 5) * ib) >> 5)); + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 4) * ib) >> 5)); + } + }// store plane prediction + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 intra prediction blocks + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * SEARCH_SYNC search next sync element as errors while decoding occured + *********************************************************************** + */ +int intra_pred_16x16_normal(Macroblock *currMB, //!< Current Macroblock + ColorPlane pl, //!< Current colorplane (for 4:4:4) + int predmode) //!< prediction mode +{ + switch (predmode) + { + case VERT_PRED_16: // vertical prediction from block above + return (intra16x16_vert_pred(currMB, pl)); + break; + case HOR_PRED_16: // horizontal prediction from left block + return (intra16x16_hor_pred(currMB, pl)); + break; + case DC_PRED_16: // DC prediction + return (intra16x16_dc_pred(currMB, pl)); + break; + case PLANE_16:// 16 bit integer plan pred + return (intra16x16_plane_pred(currMB, pl)); + break; + default: + { // indication of fault in bitstream,exit + printf("illegal 16x16 intra prediction mode input: %d\n",predmode); + return SEARCH_SYNC; + } + } +} + diff --git a/ldecod/src/intra16x16_pred_mbaff.c b/ldecod/src/intra16x16_pred_mbaff.c new file mode 100644 index 0000000..741e86b --- /dev/null +++ b/ldecod/src/intra16x16_pred_mbaff.c @@ -0,0 +1,320 @@ +/*! + ************************************************************************************* + * \file intra16x16_pred_mbaff.c + * + * \brief + * Functions for intra 16x16 prediction (MBAFF) + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra16x16_pred.h" +#include "mb_access.h" +#include "image.h" + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 DC prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_dc_pred_mbaff(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int s0 = 0, s1 = 0, s2 = 0; + + int i,j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + + PixelPos b; //!< pixel position p(0,-1) + PixelPos left[17]; //!< pixel positions p(-1, -1..15) + + int up_avail, left_avail; + + s1=s2=0; + + for (i=0;i<17;++i) + { + getAffNeighbour(currMB, -1, i-1, p_Vid->mb_size[IS_LUMA], &left[i]); + } + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + left_avail = left[1].available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + for (i = 1, left_avail = 1; i < 17; ++i) + left_avail &= left[i].available ? currSlice->intra_block[left[i].mb_addr]: 0; + } + + for (i = 0; i < MB_BLOCK_SIZE; ++i) + { + if (up_avail) + s1 += imgY[b.pos_y][b.pos_x+i]; // sum hor pix + if (left_avail) + s2 += imgY[left[i + 1].pos_y][left[i + 1].pos_x]; // sum vert pix + } + if (up_avail && left_avail) + s0 = (s1 + s2 + 16)>>5; // no edge + else if (!up_avail && left_avail) + s0 = (s2 + 8)>>4; // upper edge + else if (up_avail && !left_avail) + s0 = (s1 + 8)>>4; // left edge + else + s0 = p_Vid->dc_pred_value_comp[pl]; // top left corner, nothing to predict from + + for(j = 0; j < MB_BLOCK_SIZE; ++j) + { +#if (IMGTYPE == 0) + memset(mb_pred[j], s0, MB_BLOCK_SIZE * sizeof(imgpel)); +#else + for(i = 0; i < MB_BLOCK_SIZE; ++i) + { + mb_pred[j][i]=(imgpel) s0; + } +#endif + } + + return DECODING_OK; +} + + + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 vertical prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_vert_pred_mbaff(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos b; //!< pixel position p(0,-1) + + int up_avail; + + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + } + + if (!up_avail) + error ("invalid 16x16 intra pred Mode VERT_PRED_16",500); + { + imgpel **prd = &currSlice->mb_pred[pl][0]; + imgpel *src = &(imgY[b.pos_y][b.pos_x]); + + for(j=0;jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int i,j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + imgpel prediction; + + PixelPos left[17]; //!< pixel positions p(-1, -1..15) + + int left_avail; + + for (i=0;i<17;++i) + { + getAffNeighbour(currMB, -1, i-1, p_Vid->mb_size[IS_LUMA], &left[i]); + } + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + left_avail = left[1].available; + } + else + { + for (i = 1, left_avail = 1; i < 17; ++i) + left_avail &= left[i].available ? currSlice->intra_block[left[i].mb_addr]: 0; + } + + if (!left_avail) + error ("invalid 16x16 intra pred Mode HOR_PRED_16",500); + + for(j = 0; j < MB_BLOCK_SIZE; ++j) + { + prediction = imgY[left[j+1].pos_y][left[j+1].pos_x]; + for(i = 0; i < MB_BLOCK_SIZE; ++i) + mb_pred[j][i]= prediction; // store predicted 16x16 block + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 horizontal prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_plane_pred_mbaff(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j; + + int ih = 0, iv = 0; + int ib,ic,iaa; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + imgpel *mpr_line; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + PixelPos b; //!< pixel position p(0,-1) + PixelPos left[17]; //!< pixel positions p(-1, -1..15) + + int up_avail, left_avail, left_up_avail; + + for (i=0;i<17; ++i) + { + getAffNeighbour(currMB, -1, i-1, p_Vid->mb_size[IS_LUMA], &left[i]); + } + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + left_avail = left[1].available; + left_up_avail = left[0].available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + for (i = 1, left_avail = 1; i < 17; ++i) + left_avail &= left[i].available ? currSlice->intra_block[left[i].mb_addr]: 0; + left_up_avail = left[0].available ? currSlice->intra_block[left[0].mb_addr]: 0; + } + + if (!up_avail || !left_up_avail || !left_avail) + error ("invalid 16x16 intra pred Mode PLANE_16",500); + + mpr_line = &imgY[b.pos_y][b.pos_x+7]; + for (i = 1; i < 8; ++i) + { + ih += i*(mpr_line[i] - mpr_line[-i]); + iv += i*(imgY[left[8+i].pos_y][left[8+i].pos_x] - imgY[left[8-i].pos_y][left[8-i].pos_x]); + } + + ih += 8*(mpr_line[8] - imgY[left[0].pos_y][left[0].pos_x]); + iv += 8*(imgY[left[16].pos_y][left[16].pos_x] - imgY[left[0].pos_y][left[0].pos_x]); + + ib=(5 * ih + 32)>>6; + ic=(5 * iv + 32)>>6; + + iaa=16 * (mpr_line[8] + imgY[left[16].pos_y][left[16].pos_x]); + for (j = 0;j < MB_BLOCK_SIZE; ++j) + { + for (i = 0;i < MB_BLOCK_SIZE; ++i) + { + mb_pred[j][i] = (imgpel) iClip1(max_imgpel_value, ((iaa + (i - 7) * ib + (j - 7) * ic + 16) >> 5)); + } + }// store plane prediction + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 intra prediction blocks + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * SEARCH_SYNC search next sync element as errors while decoding occured + *********************************************************************** + */ +int intra_pred_16x16_mbaff(Macroblock *currMB, //!< Current Macroblock + ColorPlane pl, //!< Current colorplane (for 4:4:4) + int predmode) //!< prediction mode +{ + switch (predmode) + { + case VERT_PRED_16: // vertical prediction from block above + return (intra16x16_vert_pred_mbaff(currMB, pl)); + break; + case HOR_PRED_16: // horizontal prediction from left block + return (intra16x16_hor_pred_mbaff(currMB, pl)); + break; + case DC_PRED_16: // DC prediction + return (intra16x16_dc_pred_mbaff(currMB, pl)); + break; + case PLANE_16:// 16 bit integer plan pred + return (intra16x16_plane_pred_mbaff(currMB, pl)); + break; + default: + { // indication of fault in bitstream,exit + printf("illegal 16x16 intra prediction mode input: %d\n",predmode); + return SEARCH_SYNC; + } + } +} + diff --git a/ldecod/src/intra16x16_pred_normal.c b/ldecod/src/intra16x16_pred_normal.c new file mode 100644 index 0000000..1854b33 --- /dev/null +++ b/ldecod/src/intra16x16_pred_normal.c @@ -0,0 +1,350 @@ +/*! + ************************************************************************************* + * \file intra16x16_pred.c + * + * \brief + * Functions for intra 16x16 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra16x16_pred.h" +#include "mb_access.h" +#include "image.h" + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 DC prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_dc_pred(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int s0 = 0, s1 = 0, s2 = 0; + + int i,j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + + PixelPos a, b; + + int up_avail, left_avail; + + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &a); + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + left_avail = a.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + left_avail = a.available ? currSlice->intra_block[a.mb_addr]: 0; + } + + // Sum top predictors + if (up_avail) + { + imgpel *pel = &imgY[b.pos_y][b.pos_x]; + for (i = 0; i < MB_BLOCK_SIZE; ++i) + { + s1 += *pel++; + } + } + + // Sum left predictors + if (left_avail) + { + int pos_y = a.pos_y; + int pos_x = a.pos_x; + for (i = 0; i < MB_BLOCK_SIZE; ++i) + { + s2 += imgY[pos_y++][pos_x]; + } + } + + if (up_avail && left_avail) + s0 = (s1 + s2 + 16)>>5; // no edge + else if (!up_avail && left_avail) + s0 = (s2 + 8)>>4; // upper edge + else if (up_avail && !left_avail) + s0 = (s1 + 8)>>4; // left edge + else + s0 = p_Vid->dc_pred_value_comp[pl]; // top left corner, nothing to predict from + + for(j = 0; j < MB_BLOCK_SIZE; ++j) + { +#if (IMGTYPE == 0) + memset(mb_pred[j], s0, MB_BLOCK_SIZE * sizeof(imgpel)); +#else + for(i = 0; i < MB_BLOCK_SIZE; i += 4) + { + mb_pred[j][i ]=(imgpel) s0; + mb_pred[j][i + 1]=(imgpel) s0; + mb_pred[j][i + 2]=(imgpel) s0; + mb_pred[j][i + 3]=(imgpel) s0; + } +#endif + } + + return DECODING_OK; + +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 vertical prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_vert_pred(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int j; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos b; //!< pixel position p(0,-1) + + int up_avail; + + //getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + p_Vid->getNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + } + + if (!up_avail) + error ("invalid 16x16 intra pred Mode VERT_PRED_16",500); + { + imgpel **prd = &currSlice->mb_pred[pl][0]; + imgpel *src = &(imgY[b.pos_y][b.pos_x]); + + for(j=0;jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; +#if (IMGTYPE == 0) + int j; +#else + int i, j; +#endif + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + imgpel prediction; + int pos_y, pos_x; + + PixelPos a; + + int left_avail; + + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &a); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + left_avail = a.available; + } + else + { + left_avail = a.available ? currSlice->intra_block[a.mb_addr]: 0; + } + + if (!left_avail) + error ("invalid 16x16 intra pred Mode HOR_PRED_16",500); + + pos_y = a.pos_y; + pos_x = a.pos_x; + + for(j = 0; j < MB_BLOCK_SIZE; ++j) + { + imgpel *prd = mb_pred[j]; + prediction = imgY[pos_y++][pos_x]; +#if (IMGTYPE == 0) + memset(prd, prediction, MB_BLOCK_SIZE * sizeof(imgpel)); +#else + for(i = 0; i < MB_BLOCK_SIZE; i += 4) + { + *prd++= prediction; // store predicted 16x16 block + *prd++= prediction; // store predicted 16x16 block + *prd++= prediction; // store predicted 16x16 block + *prd++= prediction; // store predicted 16x16 block + } +#endif + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 horizontal prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra16x16_plane_pred(Macroblock *currMB, ColorPlane pl) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j; + + int ih = 0, iv = 0; + int ib,ic,iaa; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &(currSlice->mb_pred[pl][0]); + imgpel *mpr_line; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + int pos_y, pos_x; + + PixelPos a, b, d; + + int up_avail, left_avail, left_up_avail; + + getNonAffNeighbour(currMB, -1, -1, p_Vid->mb_size[IS_LUMA], &d); + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &a); + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &b); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = b.available; + left_avail = a.available; + left_up_avail = d.available; + } + else + { + up_avail = b.available ? currSlice->intra_block[b.mb_addr] : 0; + left_avail = a.available ? currSlice->intra_block[a.mb_addr] : 0; + left_up_avail = d.available ? currSlice->intra_block[d.mb_addr] : 0; + } + + if (!up_avail || !left_up_avail || !left_avail) + error ("invalid 16x16 intra pred Mode PLANE_16",500); + + mpr_line = &imgY[b.pos_y][b.pos_x+7]; + pos_y = a.pos_y + 7; + pos_x = a.pos_x; + for (i = 1; i < 8; ++i) + { + ih += i*(mpr_line[i] - mpr_line[-i]); + iv += i*(imgY[pos_y + i][pos_x] - imgY[pos_y - i][pos_x]); + } + + ih += 8*(mpr_line[8] - imgY[d.pos_y][d.pos_x]); + iv += 8*(imgY[pos_y + 8][pos_x] - imgY[d.pos_y][d.pos_x]); + + ib=(5 * ih + 32)>>6; + ic=(5 * iv + 32)>>6; + + iaa=16 * (mpr_line[8] + imgY[pos_y + 8][pos_x]); + for (j = 0;j < MB_BLOCK_SIZE; ++j) + { + int ibb = iaa + (j - 7) * ic + 16; + imgpel *prd = mb_pred[j]; + for (i = 0;i < MB_BLOCK_SIZE; i += 4) + { + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 7) * ib) >> 5)); + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 6) * ib) >> 5)); + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 5) * ib) >> 5)); + *prd++ = (imgpel) iClip1(max_imgpel_value, ((ibb + (i - 4) * ib) >> 5)); + } + }// store plane prediction + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 16x16 intra prediction blocks + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * SEARCH_SYNC search next sync element as errors while decoding occured + *********************************************************************** + */ +int intrapred_16x16_normal(Macroblock *currMB, //!< Current Macroblock + ColorPlane pl, //!< Current colorplane (for 4:4:4) + int predmode) //!< prediction mode +{ + switch (predmode) + { + case VERT_PRED_16: // vertical prediction from block above + return (intra16x16_vert_pred(currMB, pl)); + break; + case HOR_PRED_16: // horizontal prediction from left block + return (intra16x16_hor_pred(currMB, pl)); + break; + case DC_PRED_16: // DC prediction + return (intra16x16_dc_pred(currMB, pl)); + break; + case PLANE_16:// 16 bit integer plan pred + return (intra16x16_plane_pred(currMB, pl)); + break; + default: + { // indication of fault in bitstream,exit + printf("illegal 16x16 intra prediction mode input: %d\n",predmode); + return SEARCH_SYNC; + } + } +} + diff --git a/ldecod/src/intra4x4_pred.c b/ldecod/src/intra4x4_pred.c new file mode 100644 index 0000000..fa93b5a --- /dev/null +++ b/ldecod/src/intra4x4_pred.c @@ -0,0 +1,833 @@ +/*! + ************************************************************************************* + * \file intra4x4_pred.c + * + * \brief + * Functions for intra 4x4 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra4x4_pred.h" +#include "mb_access.h" +#include "image.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 4x4 block are labelled a..p. The predictor pels above +// are labelled A..H, from the left I..L, and from above left X, as follows: +// +// X A B C D E F G H +// I a b c d +// J e f g h +// K i j k l +// L m n o p +// + +// Predictor array index definitions +#define P_X (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 DC prediction mode + * + * \param currMB + * current MB structure + * \param pl + * color plane + * \param ioff + * pixel offset X within MB + * \param joff + * pixel offset Y within MB + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_dc_pred(Macroblock *currMB, + ColorPlane pl, + int ioff, + int joff) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int j; + int s0 = 0; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel *curpel = NULL; + + PixelPos pix_a, pix_b; + + int block_available_up; + int block_available_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + getNonAffNeighbour(currMB, ioff - 1, joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1, p_Vid->mb_size[IS_LUMA], &pix_b); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + } + + // form predictor pels + if (block_available_up) + { + curpel = &imgY[pix_b.pos_y][pix_b.pos_x]; + s0 += *curpel++; + s0 += *curpel++; + s0 += *curpel++; + s0 += *curpel; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + s0 += *(*(img_pred ++) + pos_x); + s0 += *(*(img_pred ++) + pos_x); + s0 += *(*(img_pred ++) + pos_x); + s0 += *(*(img_pred ) + pos_x); + } + + if (block_available_up && block_available_left) + { + // no edge + s0 = (s0 + 4)>>3; + } + else if (!block_available_up && block_available_left) + { + // upper edge + s0 = (s0 + 2)>>2; + } + else if (block_available_up && !block_available_left) + { + // left edge + s0 = (s0 + 2)>>2; + } + else //if (!block_available_up && !block_available_left) + { + // top left corner, nothing to predict from + s0 = p_Vid->dc_pred_value_comp[pl]; + } + + for (j=joff; j < joff + BLOCK_SIZE; ++j) + { + // store DC prediction + mb_pred[j][ioff ] = (imgpel) s0; + mb_pred[j][ioff + 1] = (imgpel) s0; + mb_pred[j][ioff + 2] = (imgpel) s0; + mb_pred[j][ioff + 3] = (imgpel) s0; + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int block_available_up; + PixelPos pix_b; + + getNonAffNeighbour(currMB, ioff, joff - 1 , p_Vid->mb_size[IS_LUMA], &pix_b); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + } + + if (!block_available_up) + { + printf ("warning: Intra_4x4_Vertical prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + } + else + { + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel *imgY = (pl) ? &currSlice->dec_picture->imgUV[pl - 1][pix_b.pos_y][pix_b.pos_x] : &currSlice->dec_picture->imgY[pix_b.pos_y][pix_b.pos_x]; + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff ][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal prediction mode + * + * \param currMB + * current MB structure + * \param pl + * color plane + * \param ioff + * pixel offset X within MB + * \param joff + * pixel offset Y within MB + * + * \return + * DECODING_OK decoding of intra prediction mode was successful + * + *********************************************************************** + */ +static int intra4x4_hor_pred(Macroblock *currMB, + ColorPlane pl, + int ioff, + int joff) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + PixelPos pix_a; + + int block_available_left; + + getNonAffNeighbour(currMB, ioff - 1 , joff, p_Vid->mb_size[IS_LUMA], &pix_a); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block[pix_a.mb_addr]: 0; + } + else + { + block_available_left = pix_a.available; + } + + if (!block_available_left) + printf ("warning: Intra_4x4_Horizontal prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else +#if (IMGTYPE == 0) + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + + memset((*(mb_pred++) + ioff), *(*(img_pred++) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + memset((*(mb_pred++) + ioff), *(*(img_pred++) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + memset((*(mb_pred++) + ioff), *(*(img_pred++) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + memset((*(mb_pred ) + ioff), *(*(img_pred ) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + } +#else + { + int j; + int pos_y = pix_a.pos_y; + int pos_x = pix_a.pos_x; + imgpel *predrow, prediction; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + for(j=0;jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + getNonAffNeighbour(currMB, ioff -1 , joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Diagonal_Down_Right prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[7]; + imgpel PredPel[13]; + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + P_I = *(*(img_pred++) + pix_x); + P_J = *(*(img_pred++) + pix_x); + P_K = *(*(img_pred++) + pix_x); + P_L = *(*(img_pred ) + pix_x); + + P_X = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((P_L + (P_K << 1) + P_J + 2) >> 2); + PredPixel[1] = (imgpel) ((P_K + (P_J << 1) + P_I + 2) >> 2); + PredPixel[2] = (imgpel) ((P_J + (P_I << 1) + P_X + 2) >> 2); + PredPixel[3] = (imgpel) ((P_I + (P_X << 1) + P_A + 2) >> 2); + PredPixel[4] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + PredPixel[5] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + PredPixel[6] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[3], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 diagonal down left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_diag_down_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_b, pix_c; + + int block_available_up; + int block_available_up_right; + + getNonAffNeighbour(currMB, ioff , joff - 1, p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff + 4, joff - 1, p_Vid->mb_size[IS_LUMA], &pix_c); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + } + + if (!block_available_up) + printf ("warning: Intra_4x4_Diagonal_Down_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + else + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel PredPixel[8]; + imgpel PredPel[25]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + + // P_E through P_H + if (block_available_up_right) + { + memcpy(&PredPel[5], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[5], PredPel[4], BLOCK_SIZE * sizeof(imgpel)); +#else + P_E = P_F = P_G = P_H = P_D; +#endif + } + + PredPixel[0] = (imgpel) ((P_A + P_C + 2*(P_B) + 2) >> 2); + PredPixel[1] = (imgpel) ((P_B + P_D + 2*(P_C) + 2) >> 2); + PredPixel[2] = (imgpel) ((P_C + P_E + 2*(P_D) + 2) >> 2); + PredPixel[3] = (imgpel) ((P_D + P_F + 2*(P_E) + 2) >> 2); + PredPixel[4] = (imgpel) ((P_E + P_G + 2*(P_F) + 2) >> 2); + PredPixel[5] = (imgpel) ((P_F + P_H + 2*(P_G) + 2) >> 2); + PredPixel[6] = (imgpel) ((P_G + 3*(P_H) + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[3], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical right prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_right_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_a, pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + getNonAffNeighbour(currMB, ioff -1 , joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block[pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Vertical_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel PredPixel[10]; + imgpel PredPel[13]; + + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + + P_I = *(*(img_pred++) + pix_x); + P_J = *(*(img_pred++) + pix_x); + P_K = *(*(img_pred++) + pix_x); + + P_X = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((P_X + (P_I << 1) + P_J + 2) >> 2); + PredPixel[1] = (imgpel) ((P_X + P_A + 1) >> 1); + PredPixel[2] = (imgpel) ((P_A + P_B + 1) >> 1); + PredPixel[3] = (imgpel) ((P_B + P_C + 1) >> 1); + PredPixel[4] = (imgpel) ((P_C + P_D + 1) >> 1); + PredPixel[5] = (imgpel) ((P_I + (P_J << 1) + P_K + 2) >> 2); + PredPixel[6] = (imgpel) ((P_I + (P_X << 1) + P_A + 2) >> 2); + PredPixel[7] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + PredPixel[8] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + PredPixel[9] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[5], 4 * sizeof(imgpel)); + + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_b, pix_c; + + int block_available_up; + int block_available_up_right; + + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff +4 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_c); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + } + + + if (!block_available_up) + printf ("warning: Intra_4x4_Vertical_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + + // P_E through P_H + if (block_available_up_right) + { + memcpy(&PredPel[5], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[5], PredPel[4], BLOCK_SIZE * sizeof(imgpel)); +#else + P_E = P_F = P_G = P_H = P_D; +#endif + } + + PredPixel[0] = (imgpel) ((P_A + P_B + 1) >> 1); + PredPixel[1] = (imgpel) ((P_B + P_C + 1) >> 1); + PredPixel[2] = (imgpel) ((P_C + P_D + 1) >> 1); + PredPixel[3] = (imgpel) ((P_D + P_E + 1) >> 1); + PredPixel[4] = (imgpel) ((P_E + P_F + 1) >> 1); + PredPixel[5] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + PredPixel[6] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + PredPixel[7] = (imgpel) ((P_C + 2*P_D + P_E + 2) >> 2); + PredPixel[8] = (imgpel) ((P_D + 2*P_E + P_F + 2) >> 2); + PredPixel[9] = (imgpel) ((P_E + 2*P_F + P_G + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[5], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal up prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_hor_up_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_a; + + int block_available_left; + + getNonAffNeighbour(currMB, ioff -1 , joff, p_Vid->mb_size[IS_LUMA], &pix_a); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block[pix_a.mb_addr]: 0; + } + else + { + block_available_left = pix_a.available; + } + + if (!block_available_left) + printf ("warning: Intra_4x4_Horizontal_Up prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + + // form predictor pels + P_I = *(*(img_pred++) + pix_x); + P_J = *(*(img_pred++) + pix_x); + P_K = *(*(img_pred++) + pix_x); + P_L = *(*(img_pred ) + pix_x); + + PredPixel[0] = (imgpel) ((P_I + P_J + 1) >> 1); + PredPixel[1] = (imgpel) ((P_I + (P_J << 1) + P_K + 2) >> 2); + PredPixel[2] = (imgpel) ((P_J + P_K + 1) >> 1); + PredPixel[3] = (imgpel) ((P_J + (P_K << 1) + P_L + 2) >> 2); + PredPixel[4] = (imgpel) ((P_K + P_L + 1) >> 1); + PredPixel[5] = (imgpel) ((P_K + (P_L << 1) + P_L + 2) >> 2); + PredPixel[6] = (imgpel) P_L; + PredPixel[7] = (imgpel) P_L; + PredPixel[8] = (imgpel) P_L; + PredPixel[9] = (imgpel) P_L; + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[4], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal down prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_hor_down_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_a, pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + getNonAffNeighbour(currMB, ioff -1 , joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Horizontal_Down prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + + P_I = *(*(img_pred++) + pix_x); + P_J = *(*(img_pred++) + pix_x); + P_K = *(*(img_pred++) + pix_x); + P_L = *(*(img_pred ) + pix_x); + + P_X = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((P_K + P_L + 1) >> 1); + PredPixel[1] = (imgpel) ((P_J + (P_K << 1) + P_L + 2) >> 2); + PredPixel[2] = (imgpel) ((P_J + P_K + 1) >> 1); + PredPixel[3] = (imgpel) ((P_I + (P_J << 1) + P_K + 2) >> 2); + PredPixel[4] = (imgpel) ((P_I + P_J + 1) >> 1); + PredPixel[5] = (imgpel) ((P_X + (P_I << 1) + P_J + 2) >> 2); + PredPixel[6] = (imgpel) ((P_X + P_I + 1) >> 1); + PredPixel[7] = (imgpel) ((P_I + (P_X << 1) + P_A + 2) >> 2); + PredPixel[8] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + PredPixel[9] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[4], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 intra prediction blocks + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * SEARCH_SYNC search next sync element as errors while decoding occured + *********************************************************************** + */ +int intra_pred_4x4_normal(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff, //!< pixel offset Y within MB + int img_block_x, //!< location of block X, multiples of 4 + int img_block_y) //!< location of block Y, multiples of 4 +{ + VideoParameters *p_Vid = currMB->p_Vid; + byte predmode = p_Vid->ipredmode[img_block_y][img_block_x]; + currMB->ipmode_DPCM = predmode; //For residual DPCM + + switch (predmode) + { + case DC_PRED: + return (intra4x4_dc_pred(currMB, pl, ioff, joff)); + break; + case VERT_PRED: + return (intra4x4_vert_pred(currMB, pl, ioff, joff)); + break; + case HOR_PRED: + return (intra4x4_hor_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_RIGHT_PRED: + return (intra4x4_diag_down_right_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_LEFT_PRED: + return (intra4x4_diag_down_left_pred(currMB, pl, ioff, joff)); + break; + case VERT_RIGHT_PRED: + return (intra4x4_vert_right_pred(currMB, pl, ioff, joff)); + break; + case VERT_LEFT_PRED: + return (intra4x4_vert_left_pred(currMB, pl, ioff, joff)); + break; + case HOR_UP_PRED: + return (intra4x4_hor_up_pred(currMB, pl, ioff, joff)); + break; + case HOR_DOWN_PRED: + return (intra4x4_hor_down_pred(currMB, pl, ioff, joff)); + default: + printf("Error: illegal intra_4x4 prediction mode: %d\n", (int) predmode); + return SEARCH_SYNC; + break; + } +} diff --git a/ldecod/src/intra4x4_pred_mbaff.c b/ldecod/src/intra4x4_pred_mbaff.c new file mode 100644 index 0000000..a4cc79b --- /dev/null +++ b/ldecod/src/intra4x4_pred_mbaff.c @@ -0,0 +1,826 @@ +/*! + ************************************************************************************* + * \file intra4x4_pred.c + * + * \brief + * Functions for intra 4x4 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra4x4_pred.h" +#include "mb_access.h" +#include "image.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 4x4 block are labelled a..p. The predictor pels above +// are labelled A..H, from the left I..L, and from above left X, as follows: +// +// X A B C D E F G H +// I a b c d +// J e f g h +// K i j k l +// L m n o p +// + +// Predictor array index definitions +#define P_X (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 DC prediction mode + * + * \param currMB + * current MB structure + * \param pl + * color plane + * \param ioff + * pixel offset X within MB + * \param joff + * pixel offset Y within MB + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_dc_pred_mbaff(Macroblock *currMB, + ColorPlane pl, + int ioff, + int joff) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j; + int s0 = 0; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a[4], pix_b; + + int block_available_up; + int block_available_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + for (i=0;i<4;++i) + { + getAffNeighbour(currMB, ioff - 1, joff + i, p_Vid->mb_size[IS_LUMA], &pix_a[i]); + } + getAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<4;++i) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + } + + // form predictor pels + if (block_available_up) + { + s0 += imgY[pix_b.pos_y][pix_b.pos_x + 0]; + s0 += imgY[pix_b.pos_y][pix_b.pos_x + 1]; + s0 += imgY[pix_b.pos_y][pix_b.pos_x + 2]; + s0 += imgY[pix_b.pos_y][pix_b.pos_x + 3]; + } + + if (block_available_left) + { + s0 += imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + s0 += imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + s0 += imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + s0 += imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + } + + if (block_available_up && block_available_left) + { + // no edge + s0 = (s0 + 4)>>3; + } + else if (!block_available_up && block_available_left) + { + // upper edge + s0 = (s0 + 2)>>2; + } + else if (block_available_up && !block_available_left) + { + // left edge + s0 = (s0 + 2)>>2; + } + else //if (!block_available_up && !block_available_left) + { + // top left corner, nothing to predict from + s0 = p_Vid->dc_pred_value_comp[pl]; + } + + for (j=joff; j < joff + BLOCK_SIZE; ++j) + { + // store DC prediction + mb_pred[j][ioff ] = (imgpel) s0; + mb_pred[j][ioff + 1] = (imgpel) s0; + mb_pred[j][ioff + 2] = (imgpel) s0; + mb_pred[j][ioff + 3] = (imgpel) s0; + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int block_available_up; + PixelPos pix_b; + + getAffNeighbour(currMB, ioff, joff - 1 , p_Vid->mb_size[IS_LUMA], &pix_b); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + } + + if (!block_available_up) + { + printf ("warning: Intra_4x4_Vertical prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + } + else + { + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel *imgY = (pl) ? &currSlice->dec_picture->imgUV[pl - 1][pix_b.pos_y][pix_b.pos_x] : &currSlice->dec_picture->imgY[pix_b.pos_y][pix_b.pos_x]; + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff ][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal prediction mode + * + * \param currMB + * current MB structure + * \param pl + * color plane + * \param ioff + * pixel offset X within MB + * \param joff + * pixel offset Y within MB + * + * \return + * DECODING_OK decoding of intra prediction mode was successful + * + *********************************************************************** + */ +static int intra4x4_hor_pred_mbaff(Macroblock *currMB, + ColorPlane pl, + int ioff, + int joff) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + int i,j; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a[4]; + + int block_available_left; + + imgpel *predrow, prediction, **mb_pred = currSlice->mb_pred[pl]; + + for (i=0;i<4;++i) + { + getAffNeighbour(currMB, ioff -1 , joff +i , p_Vid->mb_size[IS_LUMA], &pix_a[i]); + } + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<4;++i) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + } + else + { + block_available_left = pix_a[0].available; + } + + if (!block_available_left) + printf ("warning: Intra_4x4_Horizontal prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + + for(j=0;jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a[4]; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + for (i=0;i<4;++i) + { + getAffNeighbour(currMB, ioff -1 , joff +i , p_Vid->mb_size[IS_LUMA], &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<4;++i) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Diagonal_Down_Right prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[7]; + imgpel PredPel[13]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + + P_I = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_J = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_K = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_L = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + + P_X = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((P_L + (P_K << 1) + P_J + 2) >> 2); + PredPixel[1] = (imgpel) ((P_K + (P_J << 1) + P_I + 2) >> 2); + PredPixel[2] = (imgpel) ((P_J + (P_I << 1) + P_X + 2) >> 2); + PredPixel[3] = (imgpel) ((P_I + (P_X << 1) + P_A + 2) >> 2); + PredPixel[4] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + PredPixel[5] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + PredPixel[6] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[3], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 diagonal down left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_diag_down_left_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_b, pix_c; + + int block_available_up; + int block_available_up_right; + + getAffNeighbour(currMB, ioff , joff - 1, p_Vid->mb_size[IS_LUMA], &pix_b); + getAffNeighbour(currMB, ioff + 4, joff - 1, p_Vid->mb_size[IS_LUMA], &pix_c); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + } + + if (!block_available_up) + printf ("warning: Intra_4x4_Diagonal_Down_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + else + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel PredPixel[8]; + imgpel PredPel[25]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + // P_E through P_H + if (block_available_up_right) + { + memcpy(&PredPel[5], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { + P_E = P_F = P_G = P_H = P_D; + } + + PredPixel[0] = (imgpel) ((P_A + P_C + 2*(P_B) + 2) >> 2); + PredPixel[1] = (imgpel) ((P_B + P_D + 2*(P_C) + 2) >> 2); + PredPixel[2] = (imgpel) ((P_C + P_E + 2*(P_D) + 2) >> 2); + PredPixel[3] = (imgpel) ((P_D + P_F + 2*(P_E) + 2) >> 2); + PredPixel[4] = (imgpel) ((P_E + P_G + 2*(P_F) + 2) >> 2); + PredPixel[5] = (imgpel) ((P_F + P_H + 2*(P_G) + 2) >> 2); + PredPixel[6] = (imgpel) ((P_G + 3*(P_H) + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[3], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical right prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_right_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a[4]; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + for (i=0;i<4;++i) + { + getAffNeighbour(currMB, ioff -1 , joff +i , p_Vid->mb_size[IS_LUMA], &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<4;++i) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Vertical_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + + P_I = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_J = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_K = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + + P_X = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((P_X + (P_I << 1) + P_J + 2) >> 2); + PredPixel[1] = (imgpel) ((P_X + P_A + 1) >> 1); + PredPixel[2] = (imgpel) ((P_A + P_B + 1) >> 1); + PredPixel[3] = (imgpel) ((P_B + P_C + 1) >> 1); + PredPixel[4] = (imgpel) ((P_C + P_D + 1) >> 1); + PredPixel[5] = (imgpel) ((P_I + (P_J << 1) + P_K + 2) >> 2); + PredPixel[6] = (imgpel) ((P_I + (P_X << 1) + P_A + 2) >> 2); + PredPixel[7] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + PredPixel[8] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + PredPixel[9] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[5], 4 * sizeof(imgpel)); + + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_left_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_b, pix_c; + + int block_available_up; + int block_available_up_right; + + getAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getAffNeighbour(currMB, ioff +4 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_c); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + } + + + if (!block_available_up) + printf ("warning: Intra_4x4_Vertical_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + // P_E through P_H + if (block_available_up_right) + { + memcpy(&PredPel[5], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { + P_E = P_F = P_G = P_H = P_D; + } + + PredPixel[0] = (imgpel) ((P_A + P_B + 1) >> 1); + PredPixel[1] = (imgpel) ((P_B + P_C + 1) >> 1); + PredPixel[2] = (imgpel) ((P_C + P_D + 1) >> 1); + PredPixel[3] = (imgpel) ((P_D + P_E + 1) >> 1); + PredPixel[4] = (imgpel) ((P_E + P_F + 1) >> 1); + PredPixel[5] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + PredPixel[6] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + PredPixel[7] = (imgpel) ((P_C + 2*P_D + P_E + 2) >> 2); + PredPixel[8] = (imgpel) ((P_D + 2*P_E + P_F + 2) >> 2); + PredPixel[9] = (imgpel) ((P_E + 2*P_F + P_G + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[5], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal up prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_hor_up_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a[4]; + + int block_available_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + for (i=0;i<4;++i) + { + getAffNeighbour(currMB, ioff -1 , joff +i , p_Vid->mb_size[IS_LUMA], &pix_a[i]); + } + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<4;++i) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + } + else + { + block_available_left = pix_a[0].available; + } + + if (!block_available_left) + printf ("warning: Intra_4x4_Horizontal_Up prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + + // form predictor pels + P_I = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_J = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_K = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_L = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + + PredPixel[0] = (imgpel) ((P_I + P_J + 1) >> 1); + PredPixel[1] = (imgpel) ((P_I + (P_J << 1) + P_K + 2) >> 2); + PredPixel[2] = (imgpel) ((P_J + P_K + 1) >> 1); + PredPixel[3] = (imgpel) ((P_J + (P_K << 1) + P_L + 2) >> 2); + PredPixel[4] = (imgpel) ((P_K + P_L + 1) >> 1); + PredPixel[5] = (imgpel) ((P_K + (P_L << 1) + P_L + 2) >> 2); + PredPixel[6] = (imgpel) P_L; + PredPixel[7] = (imgpel) P_L; + PredPixel[8] = (imgpel) P_L; + PredPixel[9] = (imgpel) P_L; + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[4], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal down prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_hor_down_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a[4]; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + for (i=0;i<4;++i) + { + getAffNeighbour(currMB, ioff -1 , joff +i , p_Vid->mb_size[IS_LUMA], &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<4;++i) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Horizontal_Down prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[10]; + imgpel PredPel[13]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + // P_A through P_D + memcpy(&PredPel[1], pred_pel, BLOCK_SIZE * sizeof(imgpel)); + + P_I = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_J = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_K = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_L = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + + P_X = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((P_K + P_L + 1) >> 1); + PredPixel[1] = (imgpel) ((P_J + (P_K << 1) + P_L + 2) >> 2); + PredPixel[2] = (imgpel) ((P_J + P_K + 1) >> 1); + PredPixel[3] = (imgpel) ((P_I + (P_J << 1) + P_K + 2) >> 2); + PredPixel[4] = (imgpel) ((P_I + P_J + 1) >> 1); + PredPixel[5] = (imgpel) ((P_X + (P_I << 1) + P_J + 2) >> 2); + PredPixel[6] = (imgpel) ((P_X + P_I + 1) >> 1); + PredPixel[7] = (imgpel) ((P_I + (P_X << 1) + P_A + 2) >> 2); + PredPixel[8] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + PredPixel[9] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[4], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 intra prediction blocks + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * SEARCH_SYNC search next sync element as errors while decoding occured + *********************************************************************** + */ +int intra_pred_4x4_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff, //!< pixel offset Y within MB + int img_block_x, //!< location of block X, multiples of 4 + int img_block_y) //!< location of block Y, multiples of 4 +{ + VideoParameters *p_Vid = currMB->p_Vid; + byte predmode = p_Vid->ipredmode[img_block_y][img_block_x]; + currMB->ipmode_DPCM = predmode; //For residual DPCM + + switch (predmode) + { + case DC_PRED: + return (intra4x4_dc_pred_mbaff(currMB, pl, ioff, joff)); + break; + case VERT_PRED: + return (intra4x4_vert_pred_mbaff(currMB, pl, ioff, joff)); + break; + case HOR_PRED: + return (intra4x4_hor_pred_mbaff(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_RIGHT_PRED: + return (intra4x4_diag_down_right_pred_mbaff(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_LEFT_PRED: + return (intra4x4_diag_down_left_pred_mbaff(currMB, pl, ioff, joff)); + break; + case VERT_RIGHT_PRED: + return (intra4x4_vert_right_pred_mbaff(currMB, pl, ioff, joff)); + break; + case VERT_LEFT_PRED: + return (intra4x4_vert_left_pred_mbaff(currMB, pl, ioff, joff)); + break; + case HOR_UP_PRED: + return (intra4x4_hor_up_pred_mbaff(currMB, pl, ioff, joff)); + break; + case HOR_DOWN_PRED: + return (intra4x4_hor_down_pred_mbaff(currMB, pl, ioff, joff)); + default: + printf("Error: illegal intra_4x4 prediction mode: %d\n", (int) predmode); + return SEARCH_SYNC; + break; + } +} diff --git a/ldecod/src/intra4x4_pred_normal.c b/ldecod/src/intra4x4_pred_normal.c new file mode 100644 index 0000000..0c37933 --- /dev/null +++ b/ldecod/src/intra4x4_pred_normal.c @@ -0,0 +1,816 @@ +/*! + ************************************************************************************* + * \file intra4x4_pred.c + * + * \brief + * Functions for intra 4x4 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra4x4_pred.h" +#include "mb_access.h" +#include "image.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 4x4 block are labelled a..p. The predictor pels above +// are labelled A..H, from the left I..L, and from above left X, as follows: +// +// X A B C D E F G H +// I a b c d +// J e f g h +// K i j k l +// L m n o p +// + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 DC prediction mode + * + * \param currMB + * current MB structure + * \param pl + * color plane + * \param ioff + * pixel offset X within MB + * \param joff + * pixel offset Y within MB + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_dc_pred(Macroblock *currMB, + ColorPlane pl, + int ioff, + int joff) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int j; + int s0 = 0; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel *curpel = NULL; + + PixelPos pix_a, pix_b; + + int block_available_up; + int block_available_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + getNonAffNeighbour(currMB, ioff - 1, joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1, p_Vid->mb_size[IS_LUMA], &pix_b); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + } + + // form predictor pels + if (block_available_up) + { + curpel = &imgY[pix_b.pos_y][pix_b.pos_x]; + s0 += *curpel++; + s0 += *curpel++; + s0 += *curpel++; + s0 += *curpel; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + s0 += *(*(img_pred ++) + pos_x); + s0 += *(*(img_pred ++) + pos_x); + s0 += *(*(img_pred ++) + pos_x); + s0 += *(*(img_pred ) + pos_x); + } + + if (block_available_up && block_available_left) + { + // no edge + s0 = (s0 + 4)>>3; + } + else if (!block_available_up && block_available_left) + { + // upper edge + s0 = (s0 + 2)>>2; + } + else if (block_available_up && !block_available_left) + { + // left edge + s0 = (s0 + 2)>>2; + } + else //if (!block_available_up && !block_available_left) + { + // top left corner, nothing to predict from + s0 = p_Vid->dc_pred_value_comp[pl]; + } + + for (j=joff; j < joff + BLOCK_SIZE; ++j) + { + // store DC prediction + mb_pred[j][ioff ] = (imgpel) s0; + mb_pred[j][ioff + 1] = (imgpel) s0; + mb_pred[j][ioff + 2] = (imgpel) s0; + mb_pred[j][ioff + 3] = (imgpel) s0; + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int block_available_up; + PixelPos pix_b; + + getNonAffNeighbour(currMB, ioff, joff - 1 , p_Vid->mb_size[IS_LUMA], &pix_b); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + } + + if (!block_available_up) + { + printf ("warning: Intra_4x4_Vertical prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + } + else + { + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel *imgY = (pl) ? &currSlice->dec_picture->imgUV[pl - 1][pix_b.pos_y][pix_b.pos_x] : &currSlice->dec_picture->imgY[pix_b.pos_y][pix_b.pos_x]; + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff++][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + memcpy(&(mb_pred[joff ][ioff]), imgY, BLOCK_SIZE * sizeof(imgpel)); + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal prediction mode + * + * \param currMB + * current MB structure + * \param pl + * color plane + * \param ioff + * pixel offset X within MB + * \param joff + * pixel offset Y within MB + * + * \return + * DECODING_OK decoding of intra prediction mode was successful + * + *********************************************************************** + */ +static int intra4x4_hor_pred(Macroblock *currMB, + ColorPlane pl, + int ioff, + int joff) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + PixelPos pix_a; + + int block_available_left; + + getNonAffNeighbour(currMB, ioff - 1 , joff, p_Vid->mb_size[IS_LUMA], &pix_a); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block[pix_a.mb_addr]: 0; + } + else + { + block_available_left = pix_a.available; + } + + if (!block_available_left) + printf ("warning: Intra_4x4_Horizontal prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else +#if (IMGTYPE == 0) + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + + memset((*(mb_pred++) + ioff), *(*(img_pred++) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + memset((*(mb_pred++) + ioff), *(*(img_pred++) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + memset((*(mb_pred++) + ioff), *(*(img_pred++) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + memset((*(mb_pred ) + ioff), *(*(img_pred ) + pos_x), BLOCK_SIZE * sizeof (imgpel)); + } +#else + { + int j; + int pos_y = pix_a.pos_y; + int pos_x = pix_a.pos_x; + imgpel *predrow, prediction; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + for(j=0;jp_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + + PixelPos pix_a; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + + getNonAffNeighbour(currMB, ioff -1 , joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Diagonal_Down_Right prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[7]; + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + // form predictor pels + imgpel p_a = *pred_pel++; + imgpel p_b = *pred_pel++; + imgpel p_c = *pred_pel++; + imgpel p_d = *pred_pel ; + + imgpel p_i = *(*(img_pred++) + pix_x); + imgpel p_j = *(*(img_pred++) + pix_x); + imgpel p_k = *(*(img_pred++) + pix_x); + imgpel p_l = *(*(img_pred ) + pix_x); + + imgpel p_x = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((p_l + 2*p_k + p_j + 2) >> 2); + PredPixel[1] = (imgpel) ((p_k + 2*p_j + p_i + 2) >> 2); + PredPixel[2] = (imgpel) ((p_j + 2*p_i + p_x + 2) >> 2); + PredPixel[3] = (imgpel) ((p_i + 2*p_x + p_a + 2) >> 2); + PredPixel[4] = (imgpel) ((p_x + 2*p_a + p_b + 2) >> 2); + PredPixel[5] = (imgpel) ((p_a + 2*p_b + p_c + 2) >> 2); + PredPixel[6] = (imgpel) ((p_b + 2*p_c + p_d + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[3], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 diagonal down left prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_diag_down_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_b, pix_c; + + int block_available_up; + int block_available_up_right; + + p_Vid->getNeighbour(currMB, ioff , joff - 1, p_Vid->mb_size[IS_LUMA], &pix_b); + p_Vid->getNeighbour(currMB, ioff + 4, joff - 1, p_Vid->mb_size[IS_LUMA], &pix_c); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + } + + if (!block_available_up) + printf ("warning: Intra_4x4_Diagonal_Down_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + else + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel p_e, p_f, p_g, p_h; + imgpel PredPixel[8]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + imgpel p_a = *pred_pel++; + imgpel p_b = *pred_pel++; + imgpel p_c = *pred_pel++; + imgpel p_d = *pred_pel ; + + if (block_available_up_right) + { + pred_pel = &imgY[pix_c.pos_y][pix_c.pos_x]; + p_e = *pred_pel++; + p_f = *pred_pel++; + p_g = *pred_pel++; + p_h = *pred_pel ; + } + else + { + p_e = p_f = p_g = p_h = p_d; + } + + PredPixel[0] = (imgpel) ((p_a + p_c + 2*(p_b) + 2) >> 2); + PredPixel[1] = (imgpel) ((p_b + p_d + 2*(p_c) + 2) >> 2); + PredPixel[2] = (imgpel) ((p_c + p_e + 2*(p_d) + 2) >> 2); + PredPixel[3] = (imgpel) ((p_d + p_f + 2*(p_e) + 2) >> 2); + PredPixel[4] = (imgpel) ((p_e + p_g + 2*(p_f) + 2) >> 2); + PredPixel[5] = (imgpel) ((p_f + p_h + 2*(p_g) + 2) >> 2); + PredPixel[6] = (imgpel) ((p_g + 3*(p_h) + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[3], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical right prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_right_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_a, pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + getNonAffNeighbour(currMB, ioff -1 , joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block[pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Vertical_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + { + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel PredPixel[10]; + + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + // form predictor pels + imgpel p_a = *pred_pel++; + imgpel p_b = *pred_pel++; + imgpel p_c = *pred_pel++; + imgpel p_d = *pred_pel ; + + imgpel p_i = *(*(img_pred++) + pix_x); + imgpel p_j = *(*(img_pred++) + pix_x); + imgpel p_k = *(*(img_pred++) + pix_x); + + imgpel p_x = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((p_x + 2*p_i + p_j + 2) >> 2); + PredPixel[1] = (imgpel) ((p_x + p_a + 1) >> 1); + PredPixel[2] = (imgpel) ((p_a + p_b + 1) >> 1); + PredPixel[3] = (imgpel) ((p_b + p_c + 1) >> 1); + PredPixel[4] = (imgpel) ((p_c + p_d + 1) >> 1); + PredPixel[5] = (imgpel) ((p_i + 2*p_j + p_k + 2) >> 2); + PredPixel[6] = (imgpel) ((p_i + 2*p_x + p_a + 2) >> 2); + PredPixel[7] = (imgpel) ((p_x + 2*p_a + p_b + 2) >> 2); + PredPixel[8] = (imgpel) ((p_a + 2*p_b + p_c + 2) >> 2); + PredPixel[9] = (imgpel) ((p_b + 2*p_c + p_d + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[5], 4 * sizeof(imgpel)); + + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 vertical left prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_vert_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_b, pix_c; + + int block_available_up; + int block_available_up_right; + + p_Vid->getNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + p_Vid->getNeighbour(currMB, ioff +4 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_c); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + } + else + { + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + } + + + if (!block_available_up) + printf ("warning: Intra_4x4_Vertical_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + { + imgpel PredPixel[10]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + imgpel p_a = *pred_pel++; + imgpel p_b = *pred_pel++; + imgpel p_c = *pred_pel++; + imgpel p_d = *pred_pel ; + imgpel p_e, p_f, p_g; + + if (block_available_up_right) + { + imgpel *pred_pel = &imgY[pix_c.pos_y][pix_c.pos_x]; + p_e = *pred_pel++; + p_f = *pred_pel++; + p_g = *pred_pel++; + } + else + { + p_e = p_f = p_g = p_d; + } + + PredPixel[0] = (imgpel) ((p_a + p_b + 1) >> 1); + PredPixel[1] = (imgpel) ((p_b + p_c + 1) >> 1); + PredPixel[2] = (imgpel) ((p_c + p_d + 1) >> 1); + PredPixel[3] = (imgpel) ((p_d + p_e + 1) >> 1); + PredPixel[4] = (imgpel) ((p_e + p_f + 1) >> 1); + PredPixel[5] = (imgpel) ((p_a + 2*p_b + p_c + 2) >> 2); + PredPixel[6] = (imgpel) ((p_b + 2*p_c + p_d + 2) >> 2); + PredPixel[7] = (imgpel) ((p_c + 2*p_d + p_e + 2) >> 2); + PredPixel[8] = (imgpel) ((p_d + 2*p_e + p_f + 2) >> 2); + PredPixel[9] = (imgpel) ((p_e + 2*p_f + p_g + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[5], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[1], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + } + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal up prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_hor_up_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_a; + + int block_available_left; + + getNonAffNeighbour(currMB, ioff -1 , joff, p_Vid->mb_size[IS_LUMA], &pix_a); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block[pix_a.mb_addr]: 0; + } + else + { + block_available_left = pix_a.available; + } + + if (!block_available_left) + printf ("warning: Intra_4x4_Horizontal_Up prediction mode not allowed at mb %d\n",(int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[10]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + + // form predictor pels + imgpel p_i = *(*(img_pred++) + pix_x); + imgpel p_j = *(*(img_pred++) + pix_x); + imgpel p_k = *(*(img_pred++) + pix_x); + imgpel p_l = *(*(img_pred ) + pix_x); + + PredPixel[0] = (imgpel) ((p_i + p_j + 1) >> 1); + PredPixel[1] = (imgpel) ((p_i + 2*p_j + p_k + 2) >> 2); + PredPixel[2] = (imgpel) ((p_j + p_k + 1) >> 1); + PredPixel[3] = (imgpel) ((p_j + 2*p_k + p_l + 2) >> 2); + PredPixel[4] = (imgpel) ((p_k + p_l + 1) >> 1); + PredPixel[5] = (imgpel) ((p_k + 2*p_l + p_l + 2) >> 2); + PredPixel[6] = (imgpel) p_l; + PredPixel[7] = (imgpel) p_l; + PredPixel[8] = (imgpel) p_l; + PredPixel[9] = (imgpel) p_l; + + memcpy(&mb_pred[joff++][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[4], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 horizontal down prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static int intra4x4_hor_down_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos pix_a, pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + + getNonAffNeighbour(currMB, ioff -1 , joff , p_Vid->mb_size[IS_LUMA], &pix_a); + getNonAffNeighbour(currMB, ioff , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_b); + getNonAffNeighbour(currMB, ioff -1 , joff -1 , p_Vid->mb_size[IS_LUMA], &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_4x4_Horizontal_Down prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + else + { + imgpel PredPixel[10]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; + imgpel **mb_pred = currSlice->mb_pred[pl]; + + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pix_x = pix_a.pos_x; + imgpel *pred_pel = &imgY[pix_b.pos_y][pix_b.pos_x]; + + // form predictor pels + imgpel p_a = *pred_pel++; + imgpel p_b = *pred_pel++; + imgpel p_c = *pred_pel++; + + imgpel p_i = *(*(img_pred++) + pix_x); + imgpel p_j = *(*(img_pred++) + pix_x); + imgpel p_k = *(*(img_pred++) + pix_x); + imgpel p_l = *(*(img_pred ) + pix_x); + + imgpel p_x = imgY[pix_d.pos_y][pix_d.pos_x]; + + PredPixel[0] = (imgpel) ((p_k + p_l + 1) >> 1); + PredPixel[1] = (imgpel) ((p_j + 2*p_k + p_l + 2) >> 2); + PredPixel[2] = (imgpel) ((p_j + p_k + 1) >> 1); + PredPixel[3] = (imgpel) ((p_i + 2*p_j + p_k + 2) >> 2); + PredPixel[4] = (imgpel) ((p_i + p_j + 1) >> 1); + PredPixel[5] = (imgpel) ((p_x + 2*p_i + p_j + 2) >> 2); + PredPixel[6] = (imgpel) ((p_x + p_i + 1) >> 1); + PredPixel[7] = (imgpel) ((p_i + 2*p_x + p_a + 2) >> 2); + PredPixel[8] = (imgpel) ((p_x + 2*p_a + p_b + 2) >> 2); + PredPixel[9] = (imgpel) ((p_a + 2*p_b + p_c + 2) >> 2); + + memcpy(&mb_pred[joff++][ioff], &PredPixel[6], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[4], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff++][ioff], &PredPixel[2], 4 * sizeof(imgpel)); + memcpy(&mb_pred[joff ][ioff], &PredPixel[0], 4 * sizeof(imgpel)); + } + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 4x4 intra prediction blocks + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * SEARCH_SYNC search next sync element as errors while decoding occured + *********************************************************************** + */ +int intra4x4_pred_normal(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff, //!< pixel offset Y within MB + int img_block_x, //!< location of block X, multiples of 4 + int img_block_y) //!< location of block Y, multiples of 4 +{ + VideoParameters *p_Vid = currMB->p_Vid; + byte predmode = p_Vid->ipredmode[img_block_y][img_block_x]; + currMB->ipmode_DPCM = predmode; //For residual DPCM + + switch (predmode) + { + case DC_PRED: + return (intra4x4_dc_pred(currMB, pl, ioff, joff)); + break; + case VERT_PRED: + return (intra4x4_vert_pred(currMB, pl, ioff, joff)); + break; + case HOR_PRED: + return (intra4x4_hor_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_RIGHT_PRED: + return (intra4x4_diag_down_right_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_LEFT_PRED: + return (intra4x4_diag_down_left_pred(currMB, pl, ioff, joff)); + break; + case VERT_RIGHT_PRED: + return (intra4x4_vert_right_pred(currMB, pl, ioff, joff)); + break; + case VERT_LEFT_PRED: + return (intra4x4_vert_left_pred(currMB, pl, ioff, joff)); + break; + case HOR_UP_PRED: + return (intra4x4_hor_up_pred(currMB, pl, ioff, joff)); + break; + case HOR_DOWN_PRED: + return (intra4x4_hor_down_pred(currMB, pl, ioff, joff)); + default: + printf("Error: illegal intra_4x4 prediction mode: %d\n", (int) predmode); + return SEARCH_SYNC; + break; + } +} diff --git a/ldecod/src/intra8x8_pred.c b/ldecod/src/intra8x8_pred.c new file mode 100644 index 0000000..5e276d2 --- /dev/null +++ b/ldecod/src/intra8x8_pred.c @@ -0,0 +1,1546 @@ +/*! + ************************************************************************************* + * \file intra8x8_pred.c + * + * \brief + * Functions for intra 8x8 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra8x8_pred.h" +#include "mb_access.h" +#include "image.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 8x8 block are labeled a..p. The predictor pels above +// are labeled A..H, from the left I..P, and from above left X, as follows: +// +// Z A B C D E F G H I J K L M N O P +// Q a1 b1 c1 d1 e1 f1 g1 h1 +// R a2 b2 c2 d2 e2 f2 g2 h2 +// S a3 b3 c3 d3 e3 f3 g3 h3 +// T a4 b4 c4 d4 e4 f4 g4 h4 +// U a5 b5 c5 d5 e5 f5 g5 h5 +// V a6 b6 c6 d6 e6 f6 g6 h6 +// W a7 b7 c7 d7 e7 f7 g7 h7 +// X a8 b8 c8 d8 e8 f8 g8 h8 + + +// Predictor array index definitions +#define P_Z (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) +#define P_M (PredPel[13]) +#define P_N (PredPel[14]) +#define P_O (PredPel[15]) +#define P_P (PredPel[16]) +#define P_Q (PredPel[17]) +#define P_R (PredPel[18]) +#define P_S (PredPel[19]) +#define P_T (PredPel[20]) +#define P_U (PredPel[21]) +#define P_V (PredPel[22]) +#define P_W (PredPel[23]) +#define P_X (PredPel[24]) + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction + ************************************************************************************* + */ +static inline void LowPassForIntra8x8Pred(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[16] = (imgpel) ((P_P + (P_P<<1) + P_O + 2)>>2); + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((P_Z + (P_Q<<1) + P_R + 2)>>2); + else + LoopArray[17] = (imgpel) ((P_Q + (P_Q<<1) + P_R + 2)>>2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[24] = (imgpel) ((P_W + (P_X<<1) + P_X + 2) >> 2); + } + + memcpy(&PredPel[0], &LoopArray[0], 25 * sizeof(imgpel)); +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction (Horizontal) + ************************************************************************************* + */ +static inline void LowPassForIntra8x8PredHor(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[16] = (imgpel) ((P_P + (P_P<<1) + P_O + 2)>>2); + } + + + memcpy(&PredPel[0], &LoopArray[0], 17 * sizeof(imgpel)); +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction (Vertical) + ************************************************************************************* + */ +static inline void LowPassForIntra8x8PredVer(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + // These functions need some cleanup and can be further optimized. + // For convenience, let us copy all data for now. It is obvious that the filtering makes things a bit more "complex" + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((P_Z + (P_Q<<1) + P_R + 2)>>2); + else + LoopArray[17] = (imgpel) ((P_Q + (P_Q<<1) + P_R + 2)>>2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[24] = (imgpel) ((P_W + (P_X<<1) + P_X + 2) >> 2); + } + + memcpy(&PredPel[0], &LoopArray[0], 25 * sizeof(imgpel)); +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 DC prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_dc_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + int i,j; + int s0 = 0; + imgpel PredPel[25]; // array of predictor pels + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + StorablePicture *dec_picture = currSlice->dec_picture; + imgpel **imgY = (pl) ? dec_picture->imgUV[pl - 1] : dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff, mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + if (block_available_up && block_available_left) + { + // no edge + s0 = (P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X + 8) >> 4; + } + else if (!block_available_up && block_available_left) + { + // upper edge + s0 = (P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X + 4) >> 3; + } + else if (block_available_up && !block_available_left) + { + // left edge + s0 = (P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + 4) >> 3; + } + else //if (!block_available_up && !block_available_left) + { + // top left corner, nothing to predict from + s0 = p_Vid->dc_pred_value_comp[pl]; + } + + for(i = ioff; i < ioff + BLOCK_SIZE_8x8; i++) + mpr[joff][i] = (imgpel) s0; + + for(j = joff + 1; j < joff + BLOCK_SIZE_8x8; j++) + memcpy(&mpr[j][ioff], &mpr[j - 1][ioff], BLOCK_SIZE_8x8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_8x8_Vertical prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8PredHor(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + for (i=joff; i < joff + BLOCK_SIZE_8x8; i++) + { + memcpy(&mpr[i][ioff], &PredPel[1], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + + int j; + imgpel PredPel[25]; // array of predictor pels + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + +#if (IMGTYPE != 0) + int ipos0 = ioff , ipos1 = ioff + 1, ipos2 = ioff + 2, ipos3 = ioff + 3; + int ipos4 = ioff + 4, ipos5 = ioff + 5, ipos6 = ioff + 6, ipos7 = ioff + 7; +#endif + int jpos; + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_left) + printf ("warning: Intra_8x8_Horizontal prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8PredVer(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + for (j=0; j < BLOCK_SIZE_8x8; j++) + { + jpos = j + joff; +#if (IMGTYPE == 0) + memset(&mpr[jpos][ioff], (imgpel) (&P_Q)[j], 8 * sizeof(imgpel)); +#else + mpr[jpos][ipos0] = + mpr[jpos][ipos1] = + mpr[jpos][ipos2] = + mpr[jpos][ipos3] = + mpr[jpos][ipos4] = + mpr[jpos][ipos5] = + mpr[jpos][ipos6] = + mpr[jpos][ipos7] = (imgpel) (&P_Q)[j]; +#endif + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 diagonal down right prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_diag_down_right_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Diagonal_Down_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + // Mode DIAG_DOWN_RIGHT_PRED + PredArray[ 0] = (imgpel) ((P_X + P_V + ((P_W) << 1) + 2) >> 2); + PredArray[ 1] = (imgpel) ((P_W + P_U + ((P_V) << 1) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_V + P_T + ((P_U) << 1) + 2) >> 2); + PredArray[ 3] = (imgpel) ((P_U + P_S + ((P_T) << 1) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_T + P_R + ((P_S) << 1) + 2) >> 2); + PredArray[ 5] = (imgpel) ((P_S + P_Q + ((P_R) << 1) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_R + P_Z + ((P_Q) << 1) + 2) >> 2); + PredArray[ 7] = (imgpel) ((P_Q + P_A + ((P_Z) << 1) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_Z + P_B + ((P_A) << 1) + 2) >> 2); + PredArray[ 9] = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + PredArray[10] = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + PredArray[11] = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + PredArray[12] = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + PredArray[13] = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + PredArray[14] = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + + pred_pels = &PredArray[7]; + + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, pred_pels--, 8 * sizeof(imgpel)); + memcpy((*mb_pred ) + ioff, pred_pels , 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 diagonal down left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_diag_down_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_8x8_Diagonal_Down_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + // Mode DIAG_DOWN_LEFT_PRED + *Pred++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_G + P_I + ((P_H) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_H + P_J + ((P_I) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_I + P_K + ((P_J) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_J + P_L + ((P_K) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_K + P_M + ((P_L) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_L + P_N + ((P_M) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_M + P_O + ((P_N) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_N + P_P + ((P_O) << 1) + 2) >> 2); + *Pred = (imgpel) ((P_O + P_P + ((P_P) << 1) + 2) >> 2); + + Pred = &PredArray[ 0]; + + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, Pred++, 8 * sizeof(imgpel)); + memcpy((*mb_pred ) + ioff, Pred , 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical right prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_right_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Vertical_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + pred_pels = PredArray; + *pred_pels++ = (imgpel) ((P_V + P_T + ((P_U) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_T + P_R + ((P_S) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_R + P_Z + ((P_Q) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_Z + P_A + 1) >> 1); + *pred_pels++ = (imgpel) ((P_A + P_B + 1) >> 1); + *pred_pels++ = (imgpel) ((P_B + P_C + 1) >> 1); + *pred_pels++ = (imgpel) ((P_C + P_D + 1) >> 1); + *pred_pels++ = (imgpel) ((P_D + P_E + 1) >> 1); + *pred_pels++ = (imgpel) ((P_E + P_F + 1) >> 1); + *pred_pels++ = (imgpel) ((P_F + P_G + 1) >> 1); + *pred_pels++ = (imgpel) ((P_G + P_H + 1) >> 1); + + *pred_pels++ = (imgpel) ((P_W + P_U + ((P_V) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_U + P_S + ((P_T) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_S + P_Q + ((P_R) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_Q + P_A + ((P_Z) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_Z + P_B + ((P_A) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *pred_pels = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + + memcpy((*mb_pred++) + ioff, &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[14], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[13], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[12], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy((*mb_pred ) + ioff, &PredArray[11], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel *pred_pel = &PredArray[0]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_4x4_Vertical_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + *pred_pel++ = (imgpel) ((P_A + P_B + 1) >> 1); + *pred_pel++ = (imgpel) ((P_B + P_C + 1) >> 1); + *pred_pel++ = (imgpel) ((P_C + P_D + 1) >> 1); + *pred_pel++ = (imgpel) ((P_D + P_E + 1) >> 1); + *pred_pel++ = (imgpel) ((P_E + P_F + 1) >> 1); + *pred_pel++ = (imgpel) ((P_F + P_G + 1) >> 1); + *pred_pel++ = (imgpel) ((P_G + P_H + 1) >> 1); + *pred_pel++ = (imgpel) ((P_H + P_I + 1) >> 1); + *pred_pel++ = (imgpel) ((P_I + P_J + 1) >> 1); + *pred_pel++ = (imgpel) ((P_J + P_K + 1) >> 1); + *pred_pel++ = (imgpel) ((P_K + P_L + 1) >> 1); + *pred_pel++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_G + P_I + ((P_H) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_H + P_J + ((P_I) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_I + P_K + ((P_J) << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_J + P_L + ((P_K) << 1) + 2) >> 2); + *pred_pel = (imgpel) ((P_K + P_M + ((P_L) << 1) + 2) >> 2); + + memcpy((*mb_pred++) + ioff, &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[11], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[12], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[13], 8 * sizeof(imgpel)); + memcpy((*mb_pred++) + ioff, &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy((*mb_pred ) + ioff, &PredArray[14], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal up prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_up_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int jpos0 = joff , jpos1 = joff + 1, jpos2 = joff + 2, jpos3 = joff + 3; + int jpos4 = joff + 4, jpos5 = joff + 5, jpos6 = joff + 6, jpos7 = joff + 7; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_left) + printf ("warning: Intra_8x8_Horizontal_Up prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_Q + P_R + 1) >> 1); + PredArray[ 1] = (imgpel) ((P_S + P_Q + ((P_R) << 1) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_R + P_S + 1) >> 1); + PredArray[ 3] = (imgpel) ((P_T + P_R + ((P_S) << 1) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_S + P_T + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_U + P_S + ((P_T) << 1) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_T + P_U + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_V + P_T + ((P_U) << 1) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_U + P_V + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_W + P_U + ((P_V) << 1) + 2) >> 2); + PredArray[10] = (imgpel) ((P_V + P_W + 1) >> 1); + PredArray[11] = (imgpel) ((P_X + P_V + ((P_W) << 1) + 2) >> 2); + PredArray[12] = (imgpel) ((P_W + P_X + 1) >> 1); + PredArray[13] = (imgpel) ((P_W + P_X + ((P_X) << 1) + 2) >> 2); + PredArray[14] = (imgpel) P_X; + PredArray[15] = (imgpel) P_X; + PredArray[16] = (imgpel) P_X; + PredArray[17] = (imgpel) P_X; + PredArray[18] = (imgpel) P_X; + PredArray[19] = (imgpel) P_X; + PredArray[20] = (imgpel) P_X; + PredArray[21] = (imgpel) P_X; + + memcpy(&mpr[jpos0][ioff], &PredArray[0], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos1][ioff], &PredArray[2], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos2][ioff], &PredArray[4], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos3][ioff], &PredArray[6], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos4][ioff], &PredArray[8], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos5][ioff], &PredArray[10], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos6][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos7][ioff], &PredArray[14], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal down prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_down_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels; + imgpel **mb_pred = &currSlice->mb_pred[pl][joff]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Horizontal_Down prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + pred_pels = PredArray; + + *pred_pels++ = (imgpel) ((P_X + P_W + 1) >> 1); + *pred_pels++ = (imgpel) ((P_V + P_X + (P_W << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_W + P_V + 1) >> 1); + *pred_pels++ = (imgpel) ((P_U + P_W + ((P_V) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_V + P_U + 1) >> 1); + *pred_pels++ = (imgpel) ((P_T + P_V + ((P_U) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_U + P_T + 1) >> 1); + *pred_pels++ = (imgpel) ((P_S + P_U + ((P_T) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_T + P_S + 1) >> 1); + *pred_pels++ = (imgpel) ((P_R + P_T + ((P_S) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_S + P_R + 1) >> 1); + *pred_pels++ = (imgpel) ((P_Q + P_S + ((P_R) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_R + P_Q + 1) >> 1); + *pred_pels++ = (imgpel) ((P_Z + P_R + ((P_Q) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_Q + P_Z + 1) >> 1); + *pred_pels++ = (imgpel) ((P_Q + P_A + ((P_Z) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_Z + P_B + ((P_A) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *pred_pels++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *pred_pels = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + + pred_pels = &PredArray[14]; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred++) + ioff, pred_pels, 8 * sizeof(imgpel)); + pred_pels -= 2; + memcpy((*mb_pred ) + ioff, pred_pels, 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + ************************************************************************ + * \brief + * Make intra 8x8 prediction according to all 9 prediction modes. + * The routine uses left and upper neighbouring points from + * previous coded blocks to do this (if available). Notice that + * inaccessible neighbouring points are signalled with a negative + * value in the predmode array . + * + * \par Input: + * Starting point of current 8x8 block image position + * + ************************************************************************ + */ +int intra_pred_8x8_normal(Macroblock *currMB, //!< Current Macroblock + ColorPlane pl, //!< Current color plane + int ioff, //!< ioff + int joff) //!< joff + +{ + int block_x = (currMB->block_x) + (ioff >> 2); + int block_y = (currMB->block_y) + (joff >> 2); + byte predmode = currMB->p_Slice->ipredmode[block_y][block_x]; + + currMB->ipmode_DPCM = predmode; //For residual DPCM + + switch (predmode) + { + case DC_PRED: + return (intra8x8_dc_pred(currMB, pl, ioff, joff)); + break; + case VERT_PRED: + return (intra8x8_vert_pred(currMB, pl, ioff, joff)); + break; + case HOR_PRED: + return (intra8x8_hor_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_RIGHT_PRED: + return (intra8x8_diag_down_right_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_LEFT_PRED: + return (intra8x8_diag_down_left_pred(currMB, pl, ioff, joff)); + break; + case VERT_RIGHT_PRED: + return (intra8x8_vert_right_pred(currMB, pl, ioff, joff)); + break; + case VERT_LEFT_PRED: + return (intra8x8_vert_left_pred(currMB, pl, ioff, joff)); + break; + case HOR_UP_PRED: + return (intra8x8_hor_up_pred(currMB, pl, ioff, joff)); + break; + case HOR_DOWN_PRED: + return (intra8x8_hor_down_pred(currMB, pl, ioff, joff)); + default: + printf("Error: illegal intra_8x8 prediction mode: %d\n", (int) predmode); + return SEARCH_SYNC; + break; + } +} + + diff --git a/ldecod/src/intra8x8_pred_mbaff.c b/ldecod/src/intra8x8_pred_mbaff.c new file mode 100644 index 0000000..f599415 --- /dev/null +++ b/ldecod/src/intra8x8_pred_mbaff.c @@ -0,0 +1,1571 @@ +/*! + ************************************************************************************* + * \file intra8x8_pred.c + * + * \brief + * Functions for intra 8x8 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra8x8_pred.h" +#include "mb_access.h" +#include "image.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 8x8 block are labeled a..p. The predictor pels above +// are labeled A..H, from the left I..P, and from above left X, as follows: +// +// Z A B C D E F G H I J K L M N O P +// Q a1 b1 c1 d1 e1 f1 g1 h1 +// R a2 b2 c2 d2 e2 f2 g2 h2 +// S a3 b3 c3 d3 e3 f3 g3 h3 +// T a4 b4 c4 d4 e4 f4 g4 h4 +// U a5 b5 c5 d5 e5 f5 g5 h5 +// V a6 b6 c6 d6 e6 f6 g6 h6 +// W a7 b7 c7 d7 e7 f7 g7 h7 +// X a8 b8 c8 d8 e8 f8 g8 h8 + + +// Predictor array index definitions +#define P_Z (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) +#define P_M (PredPel[13]) +#define P_N (PredPel[14]) +#define P_O (PredPel[15]) +#define P_P (PredPel[16]) +#define P_Q (PredPel[17]) +#define P_R (PredPel[18]) +#define P_S (PredPel[19]) +#define P_T (PredPel[20]) +#define P_U (PredPel[21]) +#define P_V (PredPel[22]) +#define P_W (PredPel[23]) +#define P_X (PredPel[24]) + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction + ************************************************************************************* + */ +static inline void LowPassForIntra8x8Pred(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[16] = (imgpel) ((P_P + (P_P<<1) + P_O + 2)>>2); + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((P_Z + (P_Q<<1) + P_R + 2)>>2); + else + LoopArray[17] = (imgpel) ((P_Q + (P_Q<<1) + P_R + 2)>>2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[24] = (imgpel) ((P_W + (P_X<<1) + P_X + 2) >> 2); + } + + memcpy(&PredPel[0], &LoopArray[0], 25 * sizeof(imgpel)); +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction (Horizontal) + ************************************************************************************* + */ +static inline void LowPassForIntra8x8PredHor(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[16] = (imgpel) ((P_P + (P_P<<1) + P_O + 2)>>2); + } + + + memcpy(&PredPel[0], &LoopArray[0], 17 * sizeof(imgpel)); +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction (Vertical) + ************************************************************************************* + */ +static inline void LowPassForIntra8x8PredVer(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + // These functions need some cleanup and can be further optimized. + // For convenience, let us copy all data for now. It is obvious that the filtering makes things a bit more "complex" + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((P_Z + (P_Q<<1) + P_R + 2)>>2); + else + LoopArray[17] = (imgpel) ((P_Q + (P_Q<<1) + P_R + 2)>>2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[24] = (imgpel) ((P_W + (P_X<<1) + P_X + 2) >> 2); + } + + memcpy(&PredPel[0], &LoopArray[0], 25 * sizeof(imgpel)); +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 DC prediction mode + * + * \return + * DECODING_OK decoding of intra_prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_dc_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + int i,j; + int s0 = 0; + imgpel PredPel[25]; // array of predictor pels + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + StorablePicture *dec_picture = currSlice->dec_picture; + imgpel **imgY = (pl) ? dec_picture->imgUV[pl - 1] : dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + if (block_available_up && block_available_left) + { + // no edge + s0 = (P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X + 8) >> 4; + } + else if (!block_available_up && block_available_left) + { + // upper edge + s0 = (P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X + 4) >> 3; + } + else if (block_available_up && !block_available_left) + { + // left edge + s0 = (P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + 4) >> 3; + } + else //if (!block_available_up && !block_available_left) + { + // top left corner, nothing to predict from + s0 = p_Vid->dc_pred_value_comp[pl]; + } + + for(j = joff; j < joff + BLOCK_SIZE_8x8; j++) + for(i = ioff; i < ioff + BLOCK_SIZE_8x8; i++) + mpr[j][i] = (imgpel) s0; + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical prediction mode + * + * \return + * DECODING_OK decoding of intra_prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_8x8_Vertical prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8PredHor(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + for (i=joff; i < joff + BLOCK_SIZE_8x8; i++) + { + memcpy(&mpr[i][ioff], &PredPel[1], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal prediction mode + * + * \return + * DECODING_OK decoding of intra_prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + + int i,j; + imgpel PredPel[25]; // array of predictor pels + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + +#if (IMGTYPE != 0) + int ipos0 = ioff , ipos1 = ioff + 1, ipos2 = ioff + 2, ipos3 = ioff + 3; + int ipos4 = ioff + 4, ipos5 = ioff + 5, ipos6 = ioff + 6, ipos7 = ioff + 7; +#endif + int jpos; + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_left) + printf ("warning: Intra_8x8_Horizontal prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8PredVer(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + for (j=0; j < BLOCK_SIZE_8x8; j++) + { + jpos = j + joff; +#if (IMGTYPE == 0) + memset(&mpr[jpos][ioff], (imgpel) (&P_Q)[j], 8 * sizeof(imgpel)); +#else + mpr[jpos][ipos0] = + mpr[jpos][ipos1] = + mpr[jpos][ipos2] = + mpr[jpos][ipos3] = + mpr[jpos][ipos4] = + mpr[jpos][ipos5] = + mpr[jpos][ipos6] = + mpr[jpos][ipos7] = (imgpel) (&P_Q)[j]; +#endif + } + + return DECODING_OK; +} + + /*! + *********************************************************************** + * \brief + * makes and returns 8x8 diagonal down right prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_diag_down_right_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Diagonal_Down_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + // Mode DIAG_DOWN_RIGHT_PRED + PredArray[ 0] = (imgpel) ((P_X + P_V + 2*(P_W) + 2) >> 2); + PredArray[ 1] = (imgpel) ((P_W + P_U + 2*(P_V) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_V + P_T + 2*(P_U) + 2) >> 2); + PredArray[ 3] = (imgpel) ((P_U + P_S + 2*(P_T) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_T + P_R + 2*(P_S) + 2) >> 2); + PredArray[ 5] = (imgpel) ((P_S + P_Q + 2*(P_R) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_R + P_Z + 2*(P_Q) + 2) >> 2); + PredArray[ 7] = (imgpel) ((P_Q + P_A + 2*(P_Z) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_Z + P_B + 2*(P_A) + 2) >> 2); + PredArray[ 9] = (imgpel) ((P_A + P_C + 2*(P_B) + 2) >> 2); + PredArray[10] = (imgpel) ((P_B + P_D + 2*(P_C) + 2) >> 2); + PredArray[11] = (imgpel) ((P_C + P_E + 2*(P_D) + 2) >> 2); + PredArray[12] = (imgpel) ((P_D + P_F + 2*(P_E) + 2) >> 2); + PredArray[13] = (imgpel) ((P_E + P_G + 2*(P_F) + 2) >> 2); + PredArray[14] = (imgpel) ((P_F + P_H + 2*(P_G) + 2) >> 2); + + memcpy(&mpr[joff++][ioff], &PredArray[7], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[6], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[5], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[4], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[3], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[2], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[1], 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], &PredArray[0], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 diagonal down left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_diag_down_left_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_8x8_Diagonal_Down_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + // Mode DIAG_DOWN_LEFT_PRED + *Pred++ = (imgpel) ((P_A + P_C + 2*(P_B) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + 2*(P_C) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + 2*(P_D) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + 2*(P_E) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + 2*(P_F) + 2) >> 2); + *Pred++ = (imgpel) ((P_F + P_H + 2*(P_G) + 2) >> 2); + *Pred++ = (imgpel) ((P_G + P_I + 2*(P_H) + 2) >> 2); + *Pred++ = (imgpel) ((P_H + P_J + 2*(P_I) + 2) >> 2); + *Pred++ = (imgpel) ((P_I + P_K + 2*(P_J) + 2) >> 2); + *Pred++ = (imgpel) ((P_J + P_L + 2*(P_K) + 2) >> 2); + *Pred++ = (imgpel) ((P_K + P_M + 2*(P_L) + 2) >> 2); + *Pred++ = (imgpel) ((P_L + P_N + 2*(P_M) + 2) >> 2); + *Pred++ = (imgpel) ((P_M + P_O + 2*(P_N) + 2) >> 2); + *Pred++ = (imgpel) ((P_N + P_P + 2*(P_O) + 2) >> 2); + *Pred = (imgpel) ((P_O + 3*(P_P) + 2) >> 2); + + Pred = &PredArray[ 0]; + + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], Pred , 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical right prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_right_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Vertical_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_V + P_T + (P_U << 1) + 2) >> 2); + PredArray[ 1] = (imgpel) ((P_T + P_R + (P_S << 1) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_R + P_Z + (P_Q << 1) + 2) >> 2); + PredArray[ 3] = (imgpel) ((P_Z + P_A + 1) >> 1); + PredArray[ 4] = (imgpel) ((P_A + P_B + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_B + P_C + 1) >> 1); + PredArray[ 6] = (imgpel) ((P_C + P_D + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_D + P_E + 1) >> 1); + PredArray[ 8] = (imgpel) ((P_E + P_F + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_F + P_G + 1) >> 1); + PredArray[10] = (imgpel) ((P_G + P_H + 1) >> 1); + + PredArray[11] = (imgpel) ((P_W + P_U + (P_V << 1) + 2) >> 2); + PredArray[12] = (imgpel) ((P_U + P_S + (P_T << 1) + 2) >> 2); + PredArray[13] = (imgpel) ((P_S + P_Q + (P_R << 1) + 2) >> 2); + PredArray[14] = (imgpel) ((P_Q + P_A + 2*P_Z + 2) >> 2); + PredArray[15] = (imgpel) ((P_Z + P_B + 2*P_A + 2) >> 2); + PredArray[16] = (imgpel) ((P_A + P_C + 2*P_B + 2) >> 2); + PredArray[17] = (imgpel) ((P_B + P_D + 2*P_C + 2) >> 2); + PredArray[18] = (imgpel) ((P_C + P_E + 2*P_D + 2) >> 2); + PredArray[19] = (imgpel) ((P_D + P_F + 2*P_E + 2) >> 2); + PredArray[20] = (imgpel) ((P_E + P_G + 2*P_F + 2) >> 2); + PredArray[21] = (imgpel) ((P_F + P_H + 2*P_G + 2) >> 2); + + memcpy(&mpr[joff++][ioff], &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[14], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[13], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], &PredArray[11], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical left prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_left_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel *pred_pel = &PredArray[0]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_4x4_Vertical_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + *pred_pel++ = (imgpel) ((P_A + P_B + 1) >> 1); + *pred_pel++ = (imgpel) ((P_B + P_C + 1) >> 1); + *pred_pel++ = (imgpel) ((P_C + P_D + 1) >> 1); + *pred_pel++ = (imgpel) ((P_D + P_E + 1) >> 1); + *pred_pel++ = (imgpel) ((P_E + P_F + 1) >> 1); + *pred_pel++ = (imgpel) ((P_F + P_G + 1) >> 1); + *pred_pel++ = (imgpel) ((P_G + P_H + 1) >> 1); + *pred_pel++ = (imgpel) ((P_H + P_I + 1) >> 1); + *pred_pel++ = (imgpel) ((P_I + P_J + 1) >> 1); + *pred_pel++ = (imgpel) ((P_J + P_K + 1) >> 1); + *pred_pel++ = (imgpel) ((P_K + P_L + 1) >> 1); + *pred_pel++ = (imgpel) ((P_A + P_C + 2*P_B + 2) >> 2); + *pred_pel++ = (imgpel) ((P_B + P_D + 2*P_C + 2) >> 2); + *pred_pel++ = (imgpel) ((P_C + P_E + 2*P_D + 2) >> 2); + *pred_pel++ = (imgpel) ((P_D + P_F + 2*P_E + 2) >> 2); + *pred_pel++ = (imgpel) ((P_E + P_G + 2*P_F + 2) >> 2); + *pred_pel++ = (imgpel) ((P_F + P_H + 2*P_G + 2) >> 2); + *pred_pel++ = (imgpel) ((P_G + P_I + 2*P_H + 2) >> 2); + *pred_pel++ = (imgpel) ((P_H + P_J + (P_I << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_I + P_K + (P_J << 1) + 2) >> 2); + *pred_pel++ = (imgpel) ((P_J + P_L + (P_K << 1) + 2) >> 2); + *pred_pel = (imgpel) ((P_K + P_M + (P_L << 1) + 2) >> 2); + + memcpy(&mpr[joff++][ioff], &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[11], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[13], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], &PredArray[14], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal up prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_up_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int jpos0 = joff , jpos1 = joff + 1, jpos2 = joff + 2, jpos3 = joff + 3; + int jpos4 = joff + 4, jpos5 = joff + 5, jpos6 = joff + 6, jpos7 = joff + 7; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_left) + printf ("warning: Intra_8x8_Horizontal_Up prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_Q + P_R + 1) >> 1); + PredArray[ 1] = (imgpel) ((P_S + P_Q + (P_R << 1) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_R + P_S + 1) >> 1); + PredArray[ 3] = (imgpel) ((P_T + P_R + (P_S << 1) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_S + P_T + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_U + P_S + (P_T << 1) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_T + P_U + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_V + P_T + (P_U << 1) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_U + P_V + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_W + P_U + (P_V << 1) + 2) >> 2); + PredArray[10] = (imgpel) ((P_V + P_W + 1) >> 1); + PredArray[11] = (imgpel) ((P_X + P_V + (P_W << 1) + 2) >> 2); + PredArray[12] = (imgpel) ((P_W + P_X + 1) >> 1); + PredArray[13] = (imgpel) ((P_W + P_X + (P_X << 1) + 2) >> 2); + PredArray[14] = (imgpel) P_X; + PredArray[15] = (imgpel) P_X; + PredArray[16] = (imgpel) P_X; + PredArray[17] = (imgpel) P_X; + PredArray[18] = (imgpel) P_X; + PredArray[19] = (imgpel) P_X; + PredArray[20] = (imgpel) P_X; + PredArray[21] = (imgpel) P_X; + + memcpy(&mpr[jpos0][ioff], &PredArray[0], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos1][ioff], &PredArray[2], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos2][ioff], &PredArray[4], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos3][ioff], &PredArray[6], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos4][ioff], &PredArray[8], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos5][ioff], &PredArray[10], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos6][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos7][ioff], &PredArray[14], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal down prediction mode + * + * \return + * DECODING_OK decoding of intra prediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_down_pred_mbaff(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int jpos0 = joff , jpos1 = joff + 1, jpos2 = joff + 2, jpos3 = joff + 3; + int jpos4 = joff + 4, jpos5 = joff + 5, jpos6 = joff + 6, jpos7 = joff + 7; + + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i=0;i<8;i++) + { + getAffNeighbour(currMB, ioff - 1, joff + i, mb_size, &pix_a[i]); + } + + getAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? currSlice->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Horizontal_Down prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &imgY[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[1], p_Vid->dc_pred_value_comp[pl], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; +#endif + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &imgY[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + else + { +#if (IMGTYPE == 0) + memset(&PredPel[9], PredPel[8], BLOCK_SIZE_8x8 * sizeof(imgpel)); +#else + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; +#endif + } + + if (block_available_left) + { + P_Q = imgY[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = imgY[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = imgY[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = imgY[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = imgY[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = imgY[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = imgY[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = imgY[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_X + P_W + 1) >> 1); + PredArray[ 1] = (imgpel) ((P_V + P_X + (P_W << 1) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_W + P_V + 1) >> 1); + PredArray[ 3] = (imgpel) ((P_U + P_W + (P_V << 1) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_V + P_U + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_T + P_V + (P_U << 1) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_U + P_T + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_S + P_U + (P_T << 1) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_T + P_S + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_R + P_T + (P_S << 1) + 2) >> 2); + PredArray[10] = (imgpel) ((P_S + P_R + 1) >> 1); + PredArray[11] = (imgpel) ((P_Q + P_S + (P_R << 1) + 2) >> 2); + PredArray[12] = (imgpel) ((P_R + P_Q + 1) >> 1); + PredArray[13] = (imgpel) ((P_Z + P_R + (P_Q << 1) + 2) >> 2); + PredArray[14] = (imgpel) ((P_Q + P_Z + 1) >> 1); + PredArray[15] = (imgpel) ((P_Q + P_A + 2*P_Z + 2) >> 2); + PredArray[16] = (imgpel) ((P_Z + P_B + 2*P_A + 2) >> 2); + PredArray[17] = (imgpel) ((P_A + P_C + 2*P_B + 2) >> 2); + PredArray[18] = (imgpel) ((P_B + P_D + 2*P_C + 2) >> 2); + PredArray[19] = (imgpel) ((P_C + P_E + 2*P_D + 2) >> 2); + PredArray[20] = (imgpel) ((P_D + P_F + 2*P_E + 2) >> 2); + PredArray[21] = (imgpel) ((P_E + P_G + 2*P_F + 2) >> 2); + + memcpy(&mpr[jpos0][ioff], &PredArray[14], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos1][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos2][ioff], &PredArray[10], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos3][ioff], &PredArray[ 8], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos4][ioff], &PredArray[ 6], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos5][ioff], &PredArray[ 4], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos6][ioff], &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos7][ioff], &PredArray[ 0], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + ************************************************************************ + * \brief + * Make intra 8x8 prediction according to all 9 prediction modes. + * The routine uses left and upper neighbouring points from + * previous coded blocks to do this (if available). Notice that + * inaccessible neighbouring points are signalled with a negative + * value in the predmode array . + * + * \par Input: + * Starting point of current 8x8 block image position + * + ************************************************************************ + */ +int intra_pred_8x8_mbaff(Macroblock *currMB, //!< Current Macroblock + ColorPlane pl, //!< Current color plane + int ioff, //!< ioff + int joff) //!< joff + +{ + int block_x = (currMB->block_x) + (ioff >> 2); + int block_y = (currMB->block_y) + (joff >> 2); + byte predmode = currMB->p_Slice->ipredmode[block_y][block_x]; + + currMB->ipmode_DPCM = predmode; //For residual DPCM + + switch (predmode) + { + case DC_PRED: + return (intra8x8_dc_pred_mbaff(currMB, pl, ioff, joff)); + break; + case VERT_PRED: + return (intra8x8_vert_pred_mbaff(currMB, pl, ioff, joff)); + break; + case HOR_PRED: + return (intra8x8_hor_pred_mbaff(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_RIGHT_PRED: + return (intra8x8_diag_down_right_pred_mbaff(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_LEFT_PRED: + return (intra8x8_diag_down_left_pred_mbaff(currMB, pl, ioff, joff)); + break; + case VERT_RIGHT_PRED: + return (intra8x8_vert_right_pred_mbaff(currMB, pl, ioff, joff)); + break; + case VERT_LEFT_PRED: + return (intra8x8_vert_left_pred_mbaff(currMB, pl, ioff, joff)); + break; + case HOR_UP_PRED: + return (intra8x8_hor_up_pred_mbaff(currMB, pl, ioff, joff)); + break; + case HOR_DOWN_PRED: + return (intra8x8_hor_down_pred_mbaff(currMB, pl, ioff, joff)); + default: + printf("Error: illegal intra_8x8 prediction mode: %d\n", (int) predmode); + return SEARCH_SYNC; + break; + } +} + + + diff --git a/ldecod/src/intra8x8_pred_normal.c b/ldecod/src/intra8x8_pred_normal.c new file mode 100644 index 0000000..1122f6f --- /dev/null +++ b/ldecod/src/intra8x8_pred_normal.c @@ -0,0 +1,1612 @@ +/*! + ************************************************************************************* + * \file intra8x8_pred.c + * + * \brief + * Functions for intra 8x8 prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra8x8_pred.h" +#include "mb_access.h" +#include "image.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 8x8 block are labeled a..p. The predictor pels above +// are labeled A..H, from the left I..P, and from above left X, as follows: +// +// Z A B C D E F G H I J K L M N O P +// Q a1 b1 c1 d1 e1 f1 g1 h1 +// R a2 b2 c2 d2 e2 f2 g2 h2 +// S a3 b3 c3 d3 e3 f3 g3 h3 +// T a4 b4 c4 d4 e4 f4 g4 h4 +// U a5 b5 c5 d5 e5 f5 g5 h5 +// V a6 b6 c6 d6 e6 f6 g6 h6 +// W a7 b7 c7 d7 e7 f7 g7 h7 +// X a8 b8 c8 d8 e8 f8 g8 h8 + + +// Predictor array index definitions +#define P_Z (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) +#define P_M (PredPel[13]) +#define P_N (PredPel[14]) +#define P_O (PredPel[15]) +#define P_P (PredPel[16]) +#define P_Q (PredPel[17]) +#define P_R (PredPel[18]) +#define P_S (PredPel[19]) +#define P_T (PredPel[20]) +#define P_U (PredPel[21]) +#define P_V (PredPel[22]) +#define P_W (PredPel[23]) +#define P_X (PredPel[24]) + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction + ************************************************************************************* + */ +static inline void LowPassForIntra8x8Pred(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[16] = (imgpel) ((P_P + (P_P<<1) + P_O + 2)>>2); + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((P_Z + (P_Q<<1) + P_R + 2)>>2); + else + LoopArray[17] = (imgpel) ((P_Q + (P_Q<<1) + P_R + 2)>>2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[24] = (imgpel) ((P_W + (P_X<<1) + P_X + 2) >> 2); + } + + memcpy(&PredPel[0], &LoopArray[0], 25 * sizeof(imgpel)); +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction (Horizontal) + ************************************************************************************* + */ +static inline void LowPassForIntra8x8PredHor(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2)>>2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[16] = (imgpel) ((P_P + (P_P<<1) + P_O + 2)>>2); + } + + + memcpy(&PredPel[0], &LoopArray[0], 17 * sizeof(imgpel)); +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction (Vertical) + ************************************************************************************* + */ +static inline void LowPassForIntra8x8PredVer(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + // These functions need some cleanup and can be further optimized. + // For convenience, let us copy all data for now. It is obvious that the filtering makes things a bit more "complex" + int i; + imgpel LoopArray[25]; + + memcpy(&LoopArray[0], &PredPel[0], 25 * sizeof(imgpel)); + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) ((P_Q + (P_Z<<1) + P_A + 2)>>2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_A + 2)>>2); + else if (block_left) + LoopArray[0] = (imgpel) ((P_Z + (P_Z<<1) + P_Q + 2)>>2); + } + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((P_Z + (P_Q<<1) + P_R + 2)>>2); + else + LoopArray[17] = (imgpel) ((P_Q + (P_Q<<1) + P_R + 2)>>2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2)>>2); + } + LoopArray[24] = (imgpel) ((P_W + (P_X<<1) + P_X + 2) >> 2); + } + + memcpy(&PredPel[0], &LoopArray[0], 25 * sizeof(imgpel)); +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 DC prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_dc_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + int i,j; + int s0 = 0; + imgpel PredPel[25]; // array of predictor pels + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + StorablePicture *dec_picture = currSlice->dec_picture; + imgpel **imgY = (pl) ? dec_picture->imgUV[pl - 1] : dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff, mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + if (block_available_up && block_available_left) + { + // no edge + s0 = (P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X + 8) >> 4; + } + else if (!block_available_up && block_available_left) + { + // upper edge + s0 = (P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X + 4) >> 3; + } + else if (block_available_up && !block_available_left) + { + // left edge + s0 = (P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + 4) >> 3; + } + else //if (!block_available_up && !block_available_left) + { + // top left corner, nothing to predict from + s0 = p_Vid->dc_pred_value_comp[pl]; + } + + for(j = joff; j < joff + BLOCK_SIZE_8x8; j++) + for(i = ioff; i < ioff + BLOCK_SIZE_8x8; i++) + mpr[j][i] = (imgpel) s0; + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i; + imgpel PredPel[25]; // array of predictor pels + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_8x8_Vertical prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = *(pred_pels ++); + P_B = *(pred_pels ++); + P_C = *(pred_pels ++); + P_D = *(pred_pels ++); + P_E = *(pred_pels ++); + P_F = *(pred_pels ++); + P_G = *(pred_pels ++); + P_H = *pred_pels; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = *(pred_pels ++); + P_J = *(pred_pels ++); + P_K = *(pred_pels ++); + P_L = *(pred_pels ++); + P_M = *(pred_pels ++); + P_N = *(pred_pels ++); + P_O = *(pred_pels ++); + P_P = *pred_pels; + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8PredHor(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + for (i=joff; i < joff + BLOCK_SIZE_8x8; i++) + { + memcpy(&mpr[i][ioff], (&P_A), BLOCK_SIZE_8x8 * sizeof(imgpel)); + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + + int j; + imgpel PredPel[25]; // array of predictor pels + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + +#if (IMGTYPE != 0) + int ipos0 = ioff , ipos1 = ioff + 1, ipos2 = ioff + 2, ipos3 = ioff + 3; + int ipos4 = ioff + 4, ipos5 = ioff + 5, ipos6 = ioff + 6, ipos7 = ioff + 7; +#endif + int jpos; + imgpel **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_left) + printf ("warning: Intra_8x8_Horizontal prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8PredVer(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + for (j=0; j < BLOCK_SIZE_8x8; j++) + { + jpos = j + joff; +#if (IMGTYPE == 0) + memset(&mpr[jpos][ioff], (imgpel) (&P_Q)[j], 8 * sizeof(imgpel)); +#else + mpr[jpos][ipos0] = + mpr[jpos][ipos1] = + mpr[jpos][ipos2] = + mpr[jpos][ipos3] = + mpr[jpos][ipos4] = + mpr[jpos][ipos5] = + mpr[jpos][ipos6] = + mpr[jpos][ipos7] = (imgpel) (&P_Q)[j]; +#endif + } + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 diagonal down right prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_diag_down_right_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Diagonal_Down_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + // Mode DIAG_DOWN_RIGHT_PRED + PredArray[ 0] = (imgpel) ((P_X + P_V + 2*(P_W) + 2) >> 2); + PredArray[ 1] = (imgpel) ((P_W + P_U + 2*(P_V) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_V + P_T + 2*(P_U) + 2) >> 2); + PredArray[ 3] = (imgpel) ((P_U + P_S + 2*(P_T) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_T + P_R + 2*(P_S) + 2) >> 2); + PredArray[ 5] = (imgpel) ((P_S + P_Q + 2*(P_R) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_R + P_Z + 2*(P_Q) + 2) >> 2); + PredArray[ 7] = (imgpel) ((P_Q + P_A + 2*(P_Z) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_Z + P_B + 2*(P_A) + 2) >> 2); + PredArray[ 9] = (imgpel) ((P_A + P_C + 2*(P_B) + 2) >> 2); + PredArray[10] = (imgpel) ((P_B + P_D + 2*(P_C) + 2) >> 2); + PredArray[11] = (imgpel) ((P_C + P_E + 2*(P_D) + 2) >> 2); + PredArray[12] = (imgpel) ((P_D + P_F + 2*(P_E) + 2) >> 2); + PredArray[13] = (imgpel) ((P_E + P_G + 2*(P_F) + 2) >> 2); + PredArray[14] = (imgpel) ((P_F + P_H + 2*(P_G) + 2) >> 2); + + memcpy(&mpr[joff++][ioff], &PredArray[7], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[6], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[5], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[4], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[3], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[2], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[1], 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], &PredArray[0], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 diagonal down left prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_diag_down_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_8x8_Diagonal_Down_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + // Mode DIAG_DOWN_LEFT_PRED + *Pred++ = (imgpel) ((P_A + P_C + 2*(P_B) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + 2*(P_C) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + 2*(P_D) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + 2*(P_E) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + 2*(P_F) + 2) >> 2); + *Pred++ = (imgpel) ((P_F + P_H + 2*(P_G) + 2) >> 2); + *Pred++ = (imgpel) ((P_G + P_I + 2*(P_H) + 2) >> 2); + *Pred++ = (imgpel) ((P_H + P_J + 2*(P_I) + 2) >> 2); + *Pred++ = (imgpel) ((P_I + P_K + 2*(P_J) + 2) >> 2); + *Pred++ = (imgpel) ((P_J + P_L + 2*(P_K) + 2) >> 2); + *Pred++ = (imgpel) ((P_K + P_M + 2*(P_L) + 2) >> 2); + *Pred++ = (imgpel) ((P_L + P_N + 2*(P_M) + 2) >> 2); + *Pred++ = (imgpel) ((P_M + P_O + 2*(P_N) + 2) >> 2); + *Pred++ = (imgpel) ((P_N + P_P + 2*(P_O) + 2) >> 2); + *Pred = (imgpel) ((P_O + 3*(P_P) + 2) >> 2); + + Pred = &PredArray[ 0]; + + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], Pred++, 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], Pred , 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical right prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_right_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Vertical_Right prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_V + P_T + 2*P_U + 2) >> 2); + PredArray[ 1] = (imgpel) ((P_T + P_R + 2*P_S + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_R + P_Z + 2*P_Q + 2) >> 2); + PredArray[ 3] = (imgpel) ((P_Z + P_A + 1) >> 1); + PredArray[ 4] = (imgpel) ((P_A + P_B + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_B + P_C + 1) >> 1); + PredArray[ 6] = (imgpel) ((P_C + P_D + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_D + P_E + 1) >> 1); + PredArray[ 8] = (imgpel) ((P_E + P_F + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_F + P_G + 1) >> 1); + PredArray[10] = (imgpel) ((P_G + P_H + 1) >> 1); + + PredArray[11] = (imgpel) ((P_W + P_U + 2*P_V + 2) >> 2); + PredArray[12] = (imgpel) ((P_U + P_S + 2*P_T + 2) >> 2); + PredArray[13] = (imgpel) ((P_S + P_Q + 2*P_R + 2) >> 2); + PredArray[14] = (imgpel) ((P_Q + P_A + 2*P_Z + 2) >> 2); + PredArray[15] = (imgpel) ((P_Z + P_B + 2*P_A + 2) >> 2); + PredArray[16] = (imgpel) ((P_A + P_C + 2*P_B + 2) >> 2); + PredArray[17] = (imgpel) ((P_B + P_D + 2*P_C + 2) >> 2); + PredArray[18] = (imgpel) ((P_C + P_E + 2*P_D + 2) >> 2); + PredArray[19] = (imgpel) ((P_D + P_F + 2*P_E + 2) >> 2); + PredArray[20] = (imgpel) ((P_E + P_G + 2*P_F + 2) >> 2); + PredArray[21] = (imgpel) ((P_F + P_H + 2*P_G + 2) >> 2); + + memcpy(&mpr[joff++][ioff], &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[14], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[13], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], &PredArray[11], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 vertical left prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_vert_left_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel *pred_pel = &PredArray[0]; + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_up) + printf ("warning: Intra_4x4_Vertical_Left prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + *pred_pel++ = (imgpel) ((P_A + P_B + 1) >> 1); + *pred_pel++ = (imgpel) ((P_B + P_C + 1) >> 1); + *pred_pel++ = (imgpel) ((P_C + P_D + 1) >> 1); + *pred_pel++ = (imgpel) ((P_D + P_E + 1) >> 1); + *pred_pel++ = (imgpel) ((P_E + P_F + 1) >> 1); + *pred_pel++ = (imgpel) ((P_F + P_G + 1) >> 1); + *pred_pel++ = (imgpel) ((P_G + P_H + 1) >> 1); + *pred_pel++ = (imgpel) ((P_H + P_I + 1) >> 1); + *pred_pel++ = (imgpel) ((P_I + P_J + 1) >> 1); + *pred_pel++ = (imgpel) ((P_J + P_K + 1) >> 1); + *pred_pel++ = (imgpel) ((P_K + P_L + 1) >> 1); + *pred_pel++ = (imgpel) ((P_A + P_C + 2*P_B + 2) >> 2); + *pred_pel++ = (imgpel) ((P_B + P_D + 2*P_C + 2) >> 2); + *pred_pel++ = (imgpel) ((P_C + P_E + 2*P_D + 2) >> 2); + *pred_pel++ = (imgpel) ((P_D + P_F + 2*P_E + 2) >> 2); + *pred_pel++ = (imgpel) ((P_E + P_G + 2*P_F + 2) >> 2); + *pred_pel++ = (imgpel) ((P_F + P_H + 2*P_G + 2) >> 2); + *pred_pel++ = (imgpel) ((P_G + P_I + 2*P_H + 2) >> 2); + *pred_pel++ = (imgpel) ((P_H + P_J + 2*P_I + 2) >> 2); + *pred_pel++ = (imgpel) ((P_I + P_K + 2*P_J + 2) >> 2); + *pred_pel++ = (imgpel) ((P_J + P_L + 2*P_K + 2) >> 2); + *pred_pel = (imgpel) ((P_K + P_M + 2*P_L + 2) >> 2); + + memcpy(&mpr[joff++][ioff], &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[11], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[13], 8 * sizeof(imgpel)); + memcpy(&mpr[joff++][ioff], &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy(&mpr[joff ][ioff], &PredArray[14], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal up prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_up_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[16]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int jpos0 = joff , jpos1 = joff + 1, jpos2 = joff + 2, jpos3 = joff + 3; + int jpos4 = joff + 4, jpos5 = joff + 5, jpos6 = joff + 6, jpos7 = joff + 7; + +#if (IMGTYPE == 0) + int ipos3 = ioff + 3, ipos5 = ioff + 5, ipos7 = ioff + 7; +#else + int ipos0 = ioff , ipos1 = ioff + 1, ipos2 = ioff + 2, ipos3 = ioff + 3; + int ipos4 = ioff + 4, ipos5 = ioff + 5, ipos6 = ioff + 6, ipos7 = ioff + 7; +#endif + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if (!block_available_left) + printf ("warning: Intra_8x8_Horizontal_Up prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_Q + P_R + 1) >> 1); + PredArray[ 1] = (imgpel) ((P_S + P_Q + 2*P_R + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_R + P_S + 1) >> 1); + PredArray[ 3] = (imgpel) ((P_T + P_R + 2*P_S + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_S + P_T + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_U + P_S + 2*P_T + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_T + P_U + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_V + P_T + 2*P_U + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_U + P_V + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_W + P_U + 2*P_V + 2) >> 2); + PredArray[10] = (imgpel) ((P_V + P_W + 1) >> 1); + PredArray[11] = (imgpel) ((P_X + P_V + 2*P_W + 2) >> 2); + PredArray[12] = (imgpel) ((P_W + P_X + 1) >> 1); + PredArray[13] = (imgpel) ((P_W + 3*P_X + 2) >> 2); + PredArray[14] = (imgpel) P_X; + + memcpy(&mpr[jpos0][ioff], &PredArray[0], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos1][ioff], &PredArray[2], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos2][ioff], &PredArray[4], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos3][ioff], &PredArray[6], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos4][ioff], &PredArray[8], 7 * sizeof(imgpel)); + memcpy(&mpr[jpos5][ioff], &PredArray[10], 5 * sizeof(imgpel)); + memcpy(&mpr[jpos6][ioff], &PredArray[12], 3 * sizeof(imgpel)); + +#if (IMGTYPE == 0) + mpr[jpos4][ipos7] = PredArray[14]; + memset(&mpr[jpos5][ipos5], PredArray[14], 3 * sizeof(imgpel)); + memset(&mpr[jpos6][ipos3], PredArray[14], 5 * sizeof(imgpel)); + memset(&mpr[jpos7][ioff ], PredArray[14], 8 * sizeof(imgpel)); +#else + mpr[jpos4][ipos7] = PredArray[14]; + mpr[jpos5][ipos5] = mpr[jpos5][ipos6] = mpr[jpos5][ipos7] = PredArray[14]; + mpr[jpos6][ipos3] = mpr[jpos6][ipos4] = mpr[jpos6][ipos5] = mpr[jpos6][ipos6] = mpr[jpos6][ipos7] = PredArray[14]; + mpr[jpos7][ipos0] = mpr[jpos7][ipos1] = mpr[jpos7][ipos2] = mpr[jpos7][ipos3] = + mpr[jpos7][ipos4] = mpr[jpos7][ipos5] = mpr[jpos7][ipos6] = mpr[jpos7][ipos7] = PredArray[14]; +#endif + return DECODING_OK; +} + +/*! + *********************************************************************** + * \brief + * makes and returns 8x8 horizontal down prediction mode + * + * \return + * DECODING_OK decoding of intraprediction mode was successful \n + * + *********************************************************************** + */ +static inline int intra8x8_hor_down_pred(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< current image plane + int ioff, //!< pixel offset X within MB + int joff) //!< pixel offset Y within MB +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + imgpel PredPel[25]; // array of predictor pels + imgpel PredArray[22]; // array of final prediction values + imgpel **imgY = (pl) ? currSlice->dec_picture->imgUV[pl - 1] : currSlice->dec_picture->imgY; // For MB level frame/field coding tools -- set default to imgY + + PixelPos pix_a; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int jpos0 = joff , jpos1 = joff + 1, jpos2 = joff + 2, jpos3 = joff + 3; + int jpos4 = joff + 4, jpos5 = joff + 5, jpos6 = joff + 6, jpos7 = joff + 7; + + imgpel *pred_pels, **mpr = currSlice->mb_pred[pl]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + getNonAffNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + getNonAffNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + getNonAffNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + getNonAffNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + block_available_left = pix_a.available ? currSlice->intra_block [pix_a.mb_addr] : 0; + block_available_up = pix_b.available ? currSlice->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? currSlice->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? currSlice->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + if ((!block_available_up)||(!block_available_left)||(!block_available_up_left)) + printf ("warning: Intra_8x8_Horizontal_Down prediction mode not allowed at mb %d\n", (int) currSlice->current_mb_nr); + + // form predictor pels + if (block_available_up) + { + pred_pels = &imgY[pix_b.pos_y][pix_b.pos_x]; + P_A = pred_pels[0]; + P_B = pred_pels[1]; + P_C = pred_pels[2]; + P_D = pred_pels[3]; + P_E = pred_pels[4]; + P_F = pred_pels[5]; + P_G = pred_pels[6]; + P_H = pred_pels[7]; + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_right) + { + pred_pels = &imgY[pix_c.pos_y][pix_c.pos_x]; + P_I = pred_pels[0]; + P_J = pred_pels[1]; + P_K = pred_pels[2]; + P_L = pred_pels[3]; + P_M = pred_pels[4]; + P_N = pred_pels[5]; + P_O = pred_pels[6]; + P_P = pred_pels[7]; + + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + imgpel **img_pred = &imgY[pix_a.pos_y]; + int pos_x = pix_a.pos_x; + P_Q = *(*(img_pred ++) + pos_x); + P_R = *(*(img_pred ++) + pos_x); + P_S = *(*(img_pred ++) + pos_x); + P_T = *(*(img_pred ++) + pos_x); + P_U = *(*(img_pred ++) + pos_x); + P_V = *(*(img_pred ++) + pos_x); + P_W = *(*(img_pred ++) + pos_x); + P_X = *(*(img_pred ) + pos_x); + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + if (block_available_up_left) + { + P_Z = imgY[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = (imgpel) p_Vid->dc_pred_value_comp[pl]; + } + + LowPassForIntra8x8Pred(&(P_Z), block_available_up_left, block_available_up, block_available_left); + + PredArray[ 0] = (imgpel) ((P_X + P_W + 1) >> 1); + PredArray[ 1] = (imgpel) ((P_V + P_X + 2*P_W + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_W + P_V + 1) >> 1); + PredArray[ 3] = (imgpel) ((P_U + P_W + 2*P_V + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_V + P_U + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_T + P_V + 2*P_U + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_U + P_T + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_S + P_U + 2*P_T + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_T + P_S + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_R + P_T + 2*P_S + 2) >> 2); + PredArray[10] = (imgpel) ((P_S + P_R + 1) >> 1); + PredArray[11] = (imgpel) ((P_Q + P_S + 2*P_R + 2) >> 2); + PredArray[12] = (imgpel) ((P_R + P_Q + 1) >> 1); + PredArray[13] = (imgpel) ((P_Z + P_R + 2*P_Q + 2) >> 2); + PredArray[14] = (imgpel) ((P_Q + P_Z + 1) >> 1); + PredArray[15] = (imgpel) ((P_Q + P_A + 2*P_Z + 2) >> 2); + PredArray[16] = (imgpel) ((P_Z + P_B + 2*P_A + 2) >> 2); + PredArray[17] = (imgpel) ((P_A + P_C + 2*P_B + 2) >> 2); + PredArray[18] = (imgpel) ((P_B + P_D + 2*P_C + 2) >> 2); + PredArray[19] = (imgpel) ((P_C + P_E + 2*P_D + 2) >> 2); + PredArray[20] = (imgpel) ((P_D + P_F + 2*P_E + 2) >> 2); + PredArray[21] = (imgpel) ((P_E + P_G + 2*P_F + 2) >> 2); + + memcpy(&mpr[jpos0][ioff], &PredArray[14], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos1][ioff], &PredArray[12], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos2][ioff], &PredArray[10], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos3][ioff], &PredArray[ 8], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos4][ioff], &PredArray[ 6], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos5][ioff], &PredArray[ 4], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos6][ioff], &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(&mpr[jpos7][ioff], &PredArray[ 0], 8 * sizeof(imgpel)); + + return DECODING_OK; +} + +/*! + ************************************************************************ + * \brief + * Make intra 8x8 prediction according to all 9 prediction modes. + * The routine uses left and upper neighbouring points from + * previous coded blocks to do this (if available). Notice that + * inaccessible neighbouring points are signalled with a negative + * value in the predmode array . + * + * \par Input: + * Starting point of current 8x8 block image position + * + ************************************************************************ + */ +int intrapred8x8_normal(Macroblock *currMB, //!< Current Macroblock + ColorPlane pl, //!< Current color plane + int ioff, //!< ioff + int joff) //!< joff + +{ + int block_x = (currMB->block_x) + (ioff >> 2); + int block_y = (currMB->block_y) + (joff >> 2); + byte predmode = currMB->p_Slice->ipredmode[block_y][block_x]; + + currMB->ipmode_DPCM = predmode; //For residual DPCM + + switch (predmode) + { + case DC_PRED: + return (intra8x8_dc_pred(currMB, pl, ioff, joff)); + break; + case VERT_PRED: + return (intra8x8_vert_pred(currMB, pl, ioff, joff)); + break; + case HOR_PRED: + return (intra8x8_hor_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_RIGHT_PRED: + return (intra8x8_diag_down_right_pred(currMB, pl, ioff, joff)); + break; + case DIAG_DOWN_LEFT_PRED: + return (intra8x8_diag_down_left_pred(currMB, pl, ioff, joff)); + break; + case VERT_RIGHT_PRED: + return (intra8x8_vert_right_pred(currMB, pl, ioff, joff)); + break; + case VERT_LEFT_PRED: + return (intra8x8_vert_left_pred(currMB, pl, ioff, joff)); + break; + case HOR_UP_PRED: + return (intra8x8_hor_up_pred(currMB, pl, ioff, joff)); + break; + case HOR_DOWN_PRED: + return (intra8x8_hor_down_pred(currMB, pl, ioff, joff)); + default: + printf("Error: illegal intra_8x8 prediction mode: %d\n", (int) predmode); + return SEARCH_SYNC; + break; + } +} + + diff --git a/ldecod/src/intra_chroma_pred.c b/ldecod/src/intra_chroma_pred.c new file mode 100644 index 0000000..be81ade --- /dev/null +++ b/ldecod/src/intra_chroma_pred.c @@ -0,0 +1,363 @@ +/*! + ************************************************************************************* + * \file intra_chroma_pred.c + * + * \brief + * Functions for intra chroma prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "block.h" +#include "mb_access.h" +#include "image.h" + + +static void intra_chroma_DC_single(imgpel **curr_img, int up_avail, int left_avail, PixelPos up, PixelPos left, int blk_x, int blk_y, int *pred, int direction ) +{ + int i; + int s0 = 0; + + if ((direction && up_avail) || (!left_avail && up_avail)) + { + imgpel *cur_pel = &curr_img[up.pos_y][up.pos_x + blk_x]; + for (i = 0; i < 4;++i) + s0 += *(cur_pel++); + *pred = (s0 + 2) >> 2; + } + else if (left_avail) + { + imgpel **cur_pel = &(curr_img[left.pos_y + blk_y - 1]); + int pos_x = left.pos_x; + for (i = 0; i < 4;++i) + s0 += *((*cur_pel++) + pos_x); + *pred = (s0 + 2) >> 2; + } +} + + +static void intra_chroma_DC_all(imgpel **curr_img, int up_avail, int left_avail, PixelPos up, PixelPos left, int blk_x, int blk_y, int *pred ) +{ + int i; + int s0 = 0, s1 = 0; + + if (up_avail) + { + imgpel *cur_pel = &curr_img[up.pos_y][up.pos_x + blk_x]; + for (i = 0; i < 4;++i) + s0 += *(cur_pel++); + } + + if (left_avail) + { + imgpel **cur_pel = &(curr_img[left.pos_y + blk_y - 1]); + int pos_x = left.pos_x; + for (i = 0; i < 4;++i) + s1 += *((*cur_pel++) + pos_x); + } + + if (up_avail && left_avail) + *pred = (s0 + s1 + 4) >> 3; + else if (up_avail) + *pred = (s0 + 2) >> 2; + else if (left_avail) + *pred = (s1 + 2) >> 2; +} + +static void intrapred_chroma_dc(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + int b8, b4; + int yuv = dec_picture->chroma_format_idc - 1; + int blk_x, blk_y; + int pred, pred1; + static const int block_pos[3][4][4]= //[yuv][b8][b4] + { + { {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}} + }; + + PixelPos up; //!< pixel position p(0,-1) + PixelPos left; //!< pixel positions p(-1, -1..16) + int up_avail, left_avail; + imgpel **imgUV0 = dec_picture->imgUV[0]; + imgpel **imgUV1 = dec_picture->imgUV[1]; + imgpel **mb_pred0 = currSlice->mb_pred[0 + 1]; + imgpel **mb_pred1 = currSlice->mb_pred[1 + 1]; + + + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_CHROMA], &left); + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = up.available; + left_avail = left.available; + } + else + { + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + left_avail = left.available ? currSlice->intra_block[left.mb_addr]: 0; + } + + // DC prediction + // Note that unlike what is stated in many presentations and papers, this mode does not operate + // the same way as I_16x16 DC prediction. + for(b8 = 0; b8 < (p_Vid->num_uv_blocks) ;++b8) + { + for (b4 = 0; b4 < 4; ++b4) + { + blk_y = subblk_offset_y[yuv][b8][b4]; + blk_x = subblk_offset_x[yuv][b8][b4]; + pred = p_Vid->dc_pred_value_comp[1]; + pred1 = p_Vid->dc_pred_value_comp[2]; + //===== get prediction value ===== + switch (block_pos[yuv][b8][b4]) + { + case 0: //===== TOP LEFT ===== + intra_chroma_DC_all (imgUV0, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred); + intra_chroma_DC_all (imgUV1, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred1); + break; + case 1: //===== TOP RIGHT ===== + intra_chroma_DC_single(imgUV0, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred, 1); + intra_chroma_DC_single(imgUV1, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred1, 1); + break; + case 2: //===== BOTTOM LEFT ===== + intra_chroma_DC_single(imgUV0, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred, 0); + intra_chroma_DC_single(imgUV1, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred1, 0); + break; + case 3: //===== BOTTOM RIGHT ===== + intra_chroma_DC_all (imgUV0, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred); + intra_chroma_DC_all (imgUV1, up_avail, left_avail, up, left, blk_x, blk_y + 1, &pred1); + break; + } + +#if (IMGTYPE == 0) + { + int jj; + for (jj = blk_y; jj < blk_y + BLOCK_SIZE; ++jj) + { + memset(&mb_pred0[jj][blk_x], pred, BLOCK_SIZE * sizeof(imgpel)); + memset(&mb_pred1[jj][blk_x], pred1, BLOCK_SIZE * sizeof(imgpel)); + } + } +#else + { + int jj, ii; + for (jj = blk_y; jj < blk_y + BLOCK_SIZE; ++jj) + { + for (ii = blk_x; ii < blk_x + BLOCK_SIZE; ++ii) + { + mb_pred0[jj][ii]=(imgpel) pred; + mb_pred1[jj][ii]=(imgpel) pred1; + } + } + } +#endif + } + } +} + +static void intrapred_chroma_hor(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos a; //!< pixel positions p(-1, -1..16) + int left_avail; + + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_CHROMA], &a); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + left_avail = a.available; + else + left_avail = a.available ? currMB->p_Slice->intra_block[a.mb_addr]: 0; + // Horizontal Prediction + if (!left_avail ) + error("unexpected HOR_PRED_8 chroma intra prediction mode",-1); + else + { + Slice *currSlice = currMB->p_Slice; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + + int j; + StorablePicture *dec_picture = currSlice->dec_picture; +#if (IMGTYPE != 0) + int i, pred, pred1; +#endif + int pos_y = a.pos_y; + int pos_x = a.pos_x; + imgpel **mb_pred0 = currSlice->mb_pred[0 + 1]; + imgpel **mb_pred1 = currSlice->mb_pred[1 + 1]; + imgpel **i0 = &dec_picture->imgUV[0][pos_y]; + imgpel **i1 = &dec_picture->imgUV[1][pos_y]; + + for (j = 0; j < cr_MB_y; ++j) + { +#if (IMGTYPE == 0) + memset(mb_pred0[j], (*i0++)[pos_x], cr_MB_x * sizeof(imgpel)); + memset(mb_pred1[j], (*i1++)[pos_x], cr_MB_x * sizeof(imgpel)); +#else + pred = (*i0++)[pos_x]; + pred1 = (*i1++)[pos_x]; + for (i = 0; i < cr_MB_x; ++i) + { + mb_pred0[j][i]=(imgpel) pred; + mb_pred1[j][i]=(imgpel) pred1; + } +#endif + + } + } +} + +static void intrapred_chroma_ver(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int j; + StorablePicture *dec_picture = currSlice->dec_picture; + + PixelPos up; //!< pixel position p(0,-1) + int up_avail; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + up_avail = up.available; + else + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + // Vertical Prediction + if (!up_avail) + error("unexpected VERT_PRED_8 chroma intra prediction mode",-1); + else + { + imgpel **mb_pred0 = currSlice->mb_pred[1]; + imgpel **mb_pred1 = currSlice->mb_pred[2]; + imgpel *i0 = &(dec_picture->imgUV[0][up.pos_y][up.pos_x]); + imgpel *i1 = &(dec_picture->imgUV[1][up.pos_y][up.pos_x]); + + for (j = 0; j < cr_MB_y; ++j) + { + memcpy(mb_pred0[j], i0, cr_MB_x * sizeof(imgpel)); + memcpy(mb_pred1[j], i1, cr_MB_x * sizeof(imgpel)); + } + } +} + +static void intrapred_chroma_plane(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + + PixelPos up; //!< pixel position p(0,-1) + PixelPos up_left; + PixelPos left; //!< pixel positions p(-1, -1..16) + int up_avail, left_avail, left_up_avail; + + getNonAffNeighbour(currMB, -1, -1, p_Vid->mb_size[IS_CHROMA], &up_left); + getNonAffNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_CHROMA], &left); + getNonAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = up.available; + left_avail = left.available; + left_up_avail = up_left.available; + } + else + { + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + left_avail = left.available ? currSlice->intra_block[left.mb_addr]: 0; + left_up_avail = up_left.available ? currSlice->intra_block[up_left.mb_addr]: 0; + } + // plane prediction + if (!left_up_avail || !left_avail || !up_avail) + error("unexpected PLANE_8 chroma intra prediction mode",-1); + else + { + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + int cr_MB_y2 = (cr_MB_y >> 1); + int cr_MB_x2 = (cr_MB_x >> 1); + + int i,j; + int ih, iv, ib, ic, iaa; + int uv; + for (uv = 0; uv < 2; uv++) + { + imgpel **imgUV = dec_picture->imgUV[uv]; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + imgpel *upPred = &imgUV[up.pos_y][up.pos_x]; + int pos_x = up_left.pos_x; + int pos_y1 = left.pos_y + cr_MB_y2; + int pos_y2 = pos_y1 - 2; + //imgpel **predU1 = &imgUV[pos_y1]; + imgpel **predU2 = &imgUV[pos_y2]; + ih = cr_MB_x2 * (upPred[cr_MB_x - 1] - imgUV[up_left.pos_y][pos_x]); + + for (i = 0; i < cr_MB_x2 - 1; ++i) + ih += (i + 1) * (upPred[cr_MB_x2 + i] - upPred[cr_MB_x2 - 2 - i]); + + iv = cr_MB_y2 * (imgUV[left.pos_y + cr_MB_y - 1][pos_x] - imgUV[up_left.pos_y][pos_x]); + + for (i = 0; i < cr_MB_y2 - 1; ++i) + { + iv += (i + 1)*(*(imgUV[pos_y1++] + pos_x) - *((*predU2--) + pos_x)); + } + + ib= ((cr_MB_x == 8 ? 17 : 5) * ih + 2 * cr_MB_x)>>(cr_MB_x == 8 ? 5 : 6); + ic= ((cr_MB_y == 8 ? 17 : 5) * iv + 2 * cr_MB_y)>>(cr_MB_y == 8 ? 5 : 6); + + iaa = ((imgUV[pos_y1][pos_x] + upPred[cr_MB_x-1]) << 4); + + for (j = 0; j < cr_MB_y; ++j) + { + int plane = iaa + (j - cr_MB_y2 + 1) * ic + 16 - (cr_MB_x2 - 1) * ib; + + for (i = 0; i < cr_MB_x; ++i) + mb_pred[j][i]=(imgpel) iClip1(max_imgpel_value, ((i * ib + plane) >> 5)); + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Chroma Intra prediction. Note that many operations can be moved + * outside since they are repeated for both components for no reason. + ************************************************************************ + */ +void intra_pred_chroma(Macroblock *currMB) +{ + switch (currMB->c_ipred_mode) + { + case DC_PRED_8: + intrapred_chroma_dc(currMB); + break; + case HOR_PRED_8: + intrapred_chroma_hor(currMB); + break; + case VERT_PRED_8: + intrapred_chroma_ver(currMB); + break; + case PLANE_8: + intrapred_chroma_plane(currMB); + break; + default: + error("illegal chroma intra prediction mode", 600); + break; + } +} + diff --git a/ldecod/src/intra_chroma_pred_mbaff.c b/ldecod/src/intra_chroma_pred_mbaff.c new file mode 100644 index 0000000..cbd0ae8 --- /dev/null +++ b/ldecod/src/intra_chroma_pred_mbaff.c @@ -0,0 +1,359 @@ +/*! + ************************************************************************************* + * \file intra_chroma_pred.c + * + * \brief + * Functions for intra chroma prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "block.h" +#include "mb_access.h" +#include "image.h" + +static void intra_chroma_DC_single_mbaff(imgpel **curr_img, int up_avail, int left_avail, PixelPos up, PixelPos left[17], int blk_x, int blk_y, int *pred, int direction ) +{ + int i; + int s0 = 0; + + if ((direction && up_avail) || (!left_avail && up_avail)) + { + for (i = blk_x; i < (blk_x + 4);++i) + s0 += curr_img[up.pos_y][up.pos_x + i]; + *pred = (s0 + 2) >> 2; + } + else if (left_avail) + { + for (i = blk_y; i < (blk_y + 4);++i) + s0 += curr_img[left[i].pos_y][left[i].pos_x]; + *pred = (s0 + 2) >> 2; + } +} + +void intrapred_chroma_ver_mbaff(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int j; + StorablePicture *dec_picture = currSlice->dec_picture; + + PixelPos up; //!< pixel position p(0,-1) + int up_avail; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + up_avail = up.available; + else + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + // Vertical Prediction + if (!up_avail) + error("unexpected VERT_PRED_8 chroma intra prediction mode",-1); + else + { + imgpel **mb_pred0 = currSlice->mb_pred[1]; + imgpel **mb_pred1 = currSlice->mb_pred[2]; + imgpel *i0 = &(dec_picture->imgUV[0][up.pos_y][up.pos_x]); + imgpel *i1 = &(dec_picture->imgUV[1][up.pos_y][up.pos_x]); + + for (j = 0; j < cr_MB_y; ++j) + { + memcpy(&(mb_pred0[j][0]),i0, cr_MB_x * sizeof(imgpel)); + memcpy(&(mb_pred1[j][0]),i1, cr_MB_x * sizeof(imgpel)); + } + } +} + + +static void intra_chroma_DC_all_mbaff(imgpel **curr_img, int up_avail, int left_avail, PixelPos up, PixelPos left[17], int blk_x, int blk_y, int *pred ) +{ + int i; + int s0 = 0, s1 = 0; + + if (up_avail) + for (i = blk_x; i < (blk_x + 4);++i) + s0 += curr_img[up.pos_y][up.pos_x + i]; + + if (left_avail) + for (i = blk_y; i < (blk_y + 4);++i) + s1 += curr_img[left[i].pos_y][left[i].pos_x]; + + if (up_avail && left_avail) + *pred = (s0 + s1 + 4) >> 3; + else if (up_avail) + *pred = (s0 + 2) >> 2; + else if (left_avail) + *pred = (s1 + 2) >> 2; +} + + +/*! + ************************************************************************ + * \brief + * Chroma Intra prediction. Note that many operations can be moved + * outside since they are repeated for both components for no reason. + ************************************************************************ + */ +void intra_pred_chroma_mbaff(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int i,j, ii, jj; + StorablePicture *dec_picture = currSlice->dec_picture; + + int ih, iv, ib, ic, iaa; + + int b8, b4; + int yuv = dec_picture->chroma_format_idc - 1; + int blk_x, blk_y; + int pred; + static const int block_pos[3][4][4]= //[yuv][b8][b4] + { + { {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}} + }; + + switch (currMB->c_ipred_mode) + { + case DC_PRED_8: + { + PixelPos up; //!< pixel position p(0,-1) + PixelPos left[17]; //!< pixel positions p(-1, -1..16) + + int up_avail, left_avail[2]; + + int cr_MB_y = p_Vid->mb_cr_size_y; + int cr_MB_y2 = (cr_MB_y >> 1); + + for (i=0; i < cr_MB_y + 1 ; ++i) + getAffNeighbour(currMB, -1, i-1, p_Vid->mb_size[IS_CHROMA], &left[i]); + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = up.available; + left_avail[0] = left_avail[1] = left[1].available; + } + else + { + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + for (i=0, left_avail[0] = 1; i < cr_MB_y2;++i) + left_avail[0] &= left[i + 1].available ? currSlice->intra_block[left[i + 1].mb_addr]: 0; + + for (i = cr_MB_y2, left_avail[1] = 1; iintra_block[left[i + 1].mb_addr]: 0; + + } + // DC prediction + // Note that unlike what is stated in many presentations and papers, this mode does not operate + // the same way as I_16x16 DC prediction. + { + int pred1; + imgpel **imgUV0 = dec_picture->imgUV[0]; + imgpel **imgUV1 = dec_picture->imgUV[1]; + imgpel **mb_pred0 = currSlice->mb_pred[0 + 1]; + imgpel **mb_pred1 = currSlice->mb_pred[1 + 1]; + for(b8 = 0; b8 < (p_Vid->num_uv_blocks) ;++b8) + { + for (b4 = 0; b4 < 4; ++b4) + { + blk_y = subblk_offset_y[yuv][b8][b4]; + blk_x = subblk_offset_x[yuv][b8][b4]; + + pred = p_Vid->dc_pred_value_comp[1]; + pred1 = p_Vid->dc_pred_value_comp[2]; + //===== get prediction value ===== + switch (block_pos[yuv][b8][b4]) + { + case 0: //===== TOP LEFT ===== + intra_chroma_DC_all_mbaff (imgUV0, up_avail, left_avail[0], up, left, blk_x, blk_y + 1, &pred); + intra_chroma_DC_all_mbaff (imgUV1, up_avail, left_avail[0], up, left, blk_x, blk_y + 1, &pred1); + break; + case 1: //===== TOP RIGHT ===== + intra_chroma_DC_single_mbaff (imgUV0, up_avail, left_avail[0], up, left, blk_x, blk_y + 1, &pred, 1); + intra_chroma_DC_single_mbaff (imgUV1, up_avail, left_avail[0], up, left, blk_x, blk_y + 1, &pred1, 1); + break; + case 2: //===== BOTTOM LEFT ===== + intra_chroma_DC_single_mbaff (imgUV0, up_avail, left_avail[1], up, left, blk_x, blk_y + 1, &pred, 0); + intra_chroma_DC_single_mbaff (imgUV1, up_avail, left_avail[1], up, left, blk_x, blk_y + 1, &pred1, 0); + break; + case 3: //===== BOTTOM RIGHT ===== + intra_chroma_DC_all_mbaff (imgUV0, up_avail, left_avail[1], up, left, blk_x, blk_y + 1, &pred); + intra_chroma_DC_all_mbaff (imgUV1, up_avail, left_avail[1], up, left, blk_x, blk_y + 1, &pred1); + break; + } + + for (jj = blk_y; jj < blk_y + BLOCK_SIZE; ++jj) + { + for (ii = blk_x; ii < blk_x + BLOCK_SIZE; ++ii) + { + mb_pred0[jj][ii]=(imgpel) pred; + mb_pred1[jj][ii]=(imgpel) pred1; + } + } + } + } + } + } + break; + case HOR_PRED_8: + { + PixelPos left[17]; //!< pixel positions p(-1, -1..16) + + int left_avail[2]; + + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + int cr_MB_y2 = (cr_MB_y >> 1); + + for (i=0; i < cr_MB_y + 1 ; ++i) + getAffNeighbour(currMB, -1, i-1, p_Vid->mb_size[IS_CHROMA], &left[i]); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + left_avail[0] = left_avail[1] = left[1].available; + } + else + { + for (i=0, left_avail[0] = 1; i < cr_MB_y2;++i) + left_avail[0] &= left[i + 1].available ? currSlice->intra_block[left[i + 1].mb_addr]: 0; + + for (i = cr_MB_y2, left_avail[1] = 1; iintra_block[left[i + 1].mb_addr]: 0; + } + // Horizontal Prediction + if (!left_avail[0] || !left_avail[1]) + error("unexpected HOR_PRED_8 chroma intra prediction mode",-1); + else + { + int pred1; + imgpel **mb_pred0 = currSlice->mb_pred[0 + 1]; + imgpel **mb_pred1 = currSlice->mb_pred[1 + 1]; + imgpel **i0 = dec_picture->imgUV[0]; + imgpel **i1 = dec_picture->imgUV[1]; + for (j = 0; j < cr_MB_y; ++j) + { + pred = i0[left[1 + j].pos_y][left[1 + j].pos_x]; + pred1 = i1[left[1 + j].pos_y][left[1 + j].pos_x]; + for (i = 0; i < cr_MB_x; ++i) + { + mb_pred0[j][i]=(imgpel) pred; + mb_pred1[j][i]=(imgpel) pred1; + } + } + } + } + break; + case VERT_PRED_8: + { + PixelPos up; //!< pixel position p(0,-1) + + int up_avail; + + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + up_avail = up.available; + else + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + // Vertical Prediction + if (!up_avail) + error("unexpected VERT_PRED_8 chroma intra prediction mode",-1); + else + { + imgpel **mb_pred0 = currSlice->mb_pred[0 + 1]; + imgpel **mb_pred1 = currSlice->mb_pred[1 + 1]; + imgpel *i0 = &(dec_picture->imgUV[0][up.pos_y][up.pos_x]); + imgpel *i1 = &(dec_picture->imgUV[1][up.pos_y][up.pos_x]); + for (j = 0; j < cr_MB_y; ++j) + { + memcpy(&(mb_pred0[j][0]),i0, cr_MB_x * sizeof(imgpel)); + memcpy(&(mb_pred1[j][0]),i1, cr_MB_x * sizeof(imgpel)); + } + } + } + break; + case PLANE_8: + { + PixelPos up; //!< pixel position p(0,-1) + PixelPos left[17]; //!< pixel positions p(-1, -1..16) + + int up_avail, left_avail[2], left_up_avail; + + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + int cr_MB_y2 = (cr_MB_y >> 1); + int cr_MB_x2 = (cr_MB_x >> 1); + + for (i=0; i < cr_MB_y + 1 ; ++i) + getAffNeighbour(currMB, -1, i-1, p_Vid->mb_size[IS_CHROMA], &left[i]); + getAffNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &up); + + if (!p_Vid->active_pps->constrained_intra_pred_flag) + { + up_avail = up.available; + left_avail[0] = left_avail[1] = left[1].available; + left_up_avail = left[0].available; + } + else + { + up_avail = up.available ? currSlice->intra_block[up.mb_addr] : 0; + for (i=0, left_avail[0] = 1; i < cr_MB_y2;++i) + left_avail[0] &= left[i + 1].available ? currSlice->intra_block[left[i + 1].mb_addr]: 0; + + for (i = cr_MB_y2, left_avail[1] = 1; iintra_block[left[i + 1].mb_addr]: 0; + + left_up_avail = left[0].available ? currSlice->intra_block[left[0].mb_addr]: 0; + } + // plane prediction + if (!left_up_avail || !left_avail[0] || !left_avail[1] || !up_avail) + error("unexpected PLANE_8 chroma intra prediction mode",-1); + else + { + int uv; + for (uv = 0; uv < 2; uv++) + { + imgpel **imgUV = dec_picture->imgUV[uv]; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + imgpel *upPred = &imgUV[up.pos_y][up.pos_x]; + + ih = cr_MB_x2 * (upPred[cr_MB_x - 1] - imgUV[left[0].pos_y][left[0].pos_x]); + for (i = 0; i < cr_MB_x2 - 1; ++i) + ih += (i + 1) * (upPred[cr_MB_x2 + i] - upPred[cr_MB_x2 - 2 - i]); + + iv = cr_MB_y2 * (imgUV[left[cr_MB_y].pos_y][left[cr_MB_y].pos_x] - imgUV[left[0].pos_y][left[0].pos_x]); + for (i = 0; i < cr_MB_y2 - 1; ++i) + iv += (i + 1)*(imgUV[left[cr_MB_y2 + 1 + i].pos_y][left[cr_MB_y2 + 1 + i].pos_x] - + imgUV[left[cr_MB_y2 - 1 - i].pos_y][left[cr_MB_y2 - 1 - i].pos_x]); + + ib= ((cr_MB_x == 8 ? 17 : 5) * ih + 2 * cr_MB_x)>>(cr_MB_x == 8 ? 5 : 6); + ic= ((cr_MB_y == 8 ? 17 : 5) * iv + 2 * cr_MB_y)>>(cr_MB_y == 8 ? 5 : 6); + + iaa=16*(imgUV[left[cr_MB_y].pos_y][left[cr_MB_y].pos_x] + upPred[cr_MB_x-1]); + + for (j = 0; j < cr_MB_y; ++j) + for (i = 0; i < cr_MB_x; ++i) + mb_pred[j][i]=(imgpel) iClip1(max_imgpel_value, ((iaa + (i - cr_MB_x2 + 1) * ib + (j - cr_MB_y2 + 1) * ic + 16) >> 5)); + } + } + } + break; + default: + error("illegal chroma intra prediction mode", 600); + break; + } +} diff --git a/ldecod/src/intra_pred_common.c b/ldecod/src/intra_pred_common.c new file mode 100644 index 0000000..d82e421 --- /dev/null +++ b/ldecod/src/intra_pred_common.c @@ -0,0 +1,43 @@ +/*! + ************************************************************************************* + * \file intra_pred_common.c + * + * \brief + * functions for setting up intra prediction modes + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ +#include "global.h" +#include "intra4x4_pred.h" +#include "intra8x8_pred.h" +#include "intra16x16_pred.h" +#include "mb_access.h" +#include "image.h" + + +extern void intra_pred_chroma (Macroblock *currMB); +extern void intra_pred_chroma_mbaff(Macroblock *currMB); + + +void set_intra_prediction_modes(Slice *currSlice) +{ + if (currSlice->mb_aff_frame_flag) + { + currSlice->intra_pred_4x4 = intra_pred_4x4_mbaff; + currSlice->intra_pred_8x8 = intra_pred_8x8_mbaff; + currSlice->intra_pred_16x16 = intra_pred_16x16_mbaff; + currSlice->intra_pred_chroma = intra_pred_chroma_mbaff; + } + else + { + currSlice->intra_pred_4x4 = intra_pred_4x4_normal; + currSlice->intra_pred_8x8 = intra_pred_8x8_normal; + currSlice->intra_pred_16x16 = intra_pred_16x16_normal; + currSlice->intra_pred_chroma = intra_pred_chroma; + } +} diff --git a/ldecod/src/ldecod.c b/ldecod/src/ldecod.c new file mode 100644 index 0000000..be81418 --- /dev/null +++ b/ldecod/src/ldecod.c @@ -0,0 +1,1693 @@ + +/*! +*********************************************************************** +* \mainpage +* This is the H.264/AVC decoder reference software. For detailed documentation +* see the comments in each file. +* +* The JM software web site is located at: +* http://iphome.hhi.de/suehring/tml +* +* For bug reporting and known issues see: +* https://ipbt.hhi.fraunhofer.de +* +* \author +* The main contributors are listed in contributors.h +* +* \version +* JM 18.1 (FRExt) +* +* \note +* tags are used for document system "doxygen" +* available at http://www.doxygen.org +*/ +/*! +* \file +* ldecod.c +* \brief +* H.264/AVC reference decoder project main() +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Inge Lille-Langoy +* - Rickard Sjoberg +* - Stephan Wenger +* - Jani Lainema +* - Sebastian Purreiter +* - Byeong-Moon Jeon +* - Gabi Blaettermann +* - Ye-Kui Wang +* - Valeri George +* - Karsten Suehring +* +*********************************************************************** +*/ + +#include "contributors.h" + +//#include + +#include "global.h" +#include "annexb.h" +#include "image.h" +#include "memalloc.h" +#include "mc_prediction.h" +#include "mbuffer.h" +#include "leaky_bucket.h" +#include "fmo.h" +#include "output.h" +#include "cabac.h" +#include "parset.h" +#include "sei.h" +#include "erc_api.h" +#include "quant.h" +#include "block.h" +#include "nalu.h" +#include "img_io.h" +#include "loopfilter.h" +#include "rtp.h" +#include "input.h" +#include "output.h" +#include "h264decoder.h" +#include "dec_statistics.h" +#include "typedefs.h" + +#include "report.h" +#include "report_dec.h" + +/* Edited by Joao Carreira */ +#include "transcode_dec.h" +#include "stream_parser.h" +#include "ferc_api.h" + +#define LOGFILE "log.dec" +#define DATADECFILE "dataDec.txt" +#define TRACEFILE "trace_dec.txt" + +// Decoder definition. This should be the only global variable in the entire +// software. Global variables should be avoided. +DecoderParams *p_Dec; +char errortext[ET_SIZE]; + +// Prototypes of static functions +static void Report (VideoParameters *p_Vid); +static void init (VideoParameters *p_Vid); + +void init_frext(VideoParameters *p_Vid); + + + + +/*! +************************************************************************ +* \brief +* Error handling procedure. Print error message to stdout and exit +* with supplied code. +* \param text +* Error message +* \param code +* Exit code +************************************************************************ +*/ +void error(char *text, int code) +{ + printf( "%s\n", text); + if (p_Dec) + { +#if (MVC_EXTENSION_ENABLE) + flush_dpb(p_Dec->p_Vid->p_Dpb_layer[1]); +#endif + flush_dpb(p_Dec->p_Vid->p_Dpb_layer[0]); + + } +#if(_DEBUG) +#if( WIN32 ) + system("pause"); +#endif +#endif + exit(code); +} + +static void reset_dpb( VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb ) +{ + p_Dpb->p_Vid = p_Vid; + p_Dpb->init_done = 0; +} +/*! +*********************************************************************** +* \brief +* Allocate the Video Parameters structure +* \par Output: +* Video Parameters VideoParameters *p_Vid +*********************************************************************** +*/ +static void alloc_video_params( VideoParameters **p_Vid) +{ + int i; + if ((*p_Vid = (VideoParameters *) calloc(1, sizeof(VideoParameters)))==NULL) + no_mem_exit("alloc_video_params: p_Vid"); + + if (((*p_Vid)->old_slice = (OldSliceParams *) calloc(1, sizeof(OldSliceParams)))==NULL) + no_mem_exit("alloc_video_params: p_Vid->old_slice"); +#if(MVC_EXTENSION_ENABLE) + for( i=0;isnr[i] = (SNRParameters *)calloc(1, sizeof(SNRParameters)))==NULL) + no_mem_exit("alloc_video_params: p_Vid->snr"); + } +#else + if (((*p_Vid)->snr = (SNRParameters *)calloc(1, sizeof(SNRParameters)))==NULL) + no_mem_exit("alloc_video_params: p_Vid->snr"); +#endif + + // Allocate new dpb buffer + for (i = 0; i < MAX_NUM_DPB_LAYERS; i++) + { + if (((*p_Vid)->p_Dpb_layer[i] = (DecodedPictureBuffer*)calloc(1, sizeof(DecodedPictureBuffer)))==NULL) + no_mem_exit("alloc_video_params: p_Vid->p_Dpb_layer[i]"); + (*p_Vid)->p_Dpb_layer[i]->layer_id = i; + reset_dpb(*p_Vid, (*p_Vid)->p_Dpb_layer[i]); + if(((*p_Vid)->p_EncodePar[i] = (CodingParameters *)calloc(1, sizeof(CodingParameters))) == NULL) + no_mem_exit("alloc_video_params:p_Vid->p_EncodePar[i]"); + ((*p_Vid)->p_EncodePar[i])->layer_id = i; + if(((*p_Vid)->p_LayerPar[i] = (LayerParameters *)calloc(1, sizeof(LayerParameters))) == NULL) + no_mem_exit("alloc_video_params:p_Vid->p_LayerPar[i]"); + ((*p_Vid)->p_LayerPar[i])->layer_id = i; + } + (*p_Vid)->global_init_done[0] = (*p_Vid)->global_init_done[1] = 0; + +#if (ENABLE_OUTPUT_TONEMAPPING) + if (((*p_Vid)->seiToneMapping = (ToneMappingSEI*)calloc(1, sizeof(ToneMappingSEI)))==NULL) + no_mem_exit("alloc_video_params: (*p_Vid)->seiToneMapping"); +#endif + + if(((*p_Vid)->ppSliceList = (Slice **) calloc(MAX_NUM_DECSLICES, sizeof(Slice *))) == NULL) + { + no_mem_exit("alloc_video_params: p_Vid->ppSliceList"); + } + (*p_Vid)->iNumOfSlicesAllocated = MAX_NUM_DECSLICES; + //(*p_Vid)->currentSlice = NULL; + (*p_Vid)->pNextSlice = NULL; + (*p_Vid)->nalu = AllocNALU(MAX_CODED_FRAME_SIZE); + (*p_Vid)->pDecOuputPic = (DecodedPicList *)calloc(1, sizeof(DecodedPicList)); + (*p_Vid)->pNextPPS = AllocPPS(); + (*p_Vid)->first_sps = TRUE; + + + for (i=0;inFramesConceal[i] = (*p_Vid)->nFramesDecoded[i] = (*p_Vid)->nFramesOut[i] = 0; + // Alloc frame pattern + if( !(*p_Vid)->p_PFrames[i]) + { + (*p_Vid)->p_PFrames[i] = (int *)calloc(INITAL_PFRAMES_LENGTH, sizeof(int)); + (*p_Vid)->n_PFrames[i] = INITAL_PFRAMES_LENGTH; + } + } + +} + + +/*! +*********************************************************************** +* \brief +* Allocate the Input structure +* \par Output: +* Input Parameters InputParameters *p_Vid +*********************************************************************** +*/ +static void alloc_params( InputParameters **p_Inp ) +{ + if ((*p_Inp = (InputParameters *) calloc(1, sizeof(InputParameters)))==NULL) + no_mem_exit("alloc_params: p_Inp"); +} + +/*! +*********************************************************************** +* \brief +* Allocate the Decoder Structure +* \par Output: +* Decoder Parameters +*********************************************************************** +*/ +static int alloc_decoder( DecoderParams **p_Dec) +{ + if ((*p_Dec = (DecoderParams *) calloc(1, sizeof(DecoderParams)))==NULL) + { + printf( "alloc_decoder: p_Dec\n"); + return -1; + } + + alloc_video_params(&((*p_Dec)->p_Vid)); + alloc_params(&((*p_Dec)->p_Inp)); + (*p_Dec)->p_Vid->p_Inp = (*p_Dec)->p_Inp; + (*p_Dec)->p_trace = NULL; + (*p_Dec)->bufferSize = 0; + (*p_Dec)->bitcounter = 0; + return 0; +} + +/*! +*********************************************************************** +* \brief +* Free the Image structure +* \par Input: +* Image Parameters VideoParameters *p_Vid +*********************************************************************** +*/ +static void free_img( VideoParameters *p_Vid) +{ + int i; + if (p_Vid != NULL) + { + if ( p_Vid->p_Inp->FileFormat == PAR_OF_ANNEXB ) + { + free_annex_b (&p_Vid->annex_b); + } +#if (ENABLE_OUTPUT_TONEMAPPING) + if (p_Vid->seiToneMapping != NULL) + { + free (p_Vid->seiToneMapping); + p_Vid->seiToneMapping = NULL; + } +#endif + + // Free new dpb layers + for (i = 0; i < MAX_NUM_DPB_LAYERS; i++) + { + if (p_Vid->p_Dpb_layer[i] != NULL) + { + free (p_Vid->p_Dpb_layer[i]); + p_Vid->p_Dpb_layer[i] = NULL; + } + if(p_Vid->p_EncodePar[i]) + { + free(p_Vid->p_EncodePar[i]); + p_Vid->p_EncodePar[i] = NULL; + } + if(p_Vid->p_LayerPar[i]) + { + free(p_Vid->p_LayerPar[i]); + p_Vid->p_LayerPar[i] = NULL; + } + } +#if( MVC_EXTENSION_ENABLE ) + for(i=0;isnr[i] != NULL) + { + free (p_Vid->snr[i]); + p_Vid->snr[i] = NULL; + } + } +#else + if (p_Vid->snr != NULL) + { + free (p_Vid->snr); + p_Vid->snr = NULL; + } +#endif + if (p_Vid->old_slice != NULL) + { + free (p_Vid->old_slice); + p_Vid->old_slice = NULL; + } + + if(p_Vid->pNextSlice) + { + free_slice(p_Vid->pNextSlice); + p_Vid->pNextSlice=NULL; + } + if(p_Vid->ppSliceList) + { + int i; + for(i=0; iiNumOfSlicesAllocated; i++) + if(p_Vid->ppSliceList[i]) + free_slice(p_Vid->ppSliceList[i]); + free(p_Vid->ppSliceList); + } + if(p_Vid->nalu) + { + FreeNALU(p_Vid->nalu); + p_Vid->nalu=NULL; + } + //free memory; + FreeDecPicList(p_Vid->pDecOuputPic); + if(p_Vid->pNextPPS) + { + FreePPS(p_Vid->pNextPPS); + p_Vid->pNextPPS = NULL; + } + + // clear decoder statistics +#if ENABLE_DEC_STATS + delete_dec_stats(p_Vid->dec_stats); + free (p_Vid->dec_stats); +#endif + + /* Edited by Joao Carreira */ + closeTranscodeModule(p_Vid); + free_parse_nalu(p_Vid); + free_prediction_parser( p_Vid ); + fercCloseFrameConcealment( p_Vid ); + for (i=0;ip_PFrames[i]) + { + free(p_Vid->p_PFrames[i]); + p_Vid->n_PFrames[i] = 0; + } + } + + + free (p_Vid); + p_Vid = NULL; + } +} + +void FreeDecPicList(DecodedPicList *pDecPicList) +{ + while(pDecPicList) + { + DecodedPicList *pPicNext = pDecPicList->pNext; + if(pDecPicList->pY) + { + free(pDecPicList->pY); + pDecPicList->pY = NULL; + pDecPicList->pU = NULL; + pDecPicList->pV = NULL; + } + free(pDecPicList); + pDecPicList = pPicNext; + } +} + +/*! +*********************************************************************** +* \brief +* Initilize some arrays +*********************************************************************** +*/ +static void init(VideoParameters *p_Vid) //!< video parameters +{ + int i; + InputParameters *p_Inp = p_Vid->p_Inp; + p_Vid->oldFrameSizeInMbs = (unsigned int) -1; + + p_Vid->imgY_ref = NULL; + p_Vid->imgUV_ref = NULL; + + p_Vid->recovery_point = 0; + p_Vid->recovery_point_found = 0; + p_Vid->recovery_poc = 0x7fffffff; /* set to a max value */ + + p_Vid->idr_psnr_number = p_Inp->ref_offset; + p_Vid->psnr_number=0; + + p_Vid->number = 0; + p_Vid->type = I_SLICE; + + //p_Vid->dec_ref_pic_marking_buffer = NULL; + + p_Vid->g_nFrame = 0; + // B pictures + p_Vid->Bframe_ctr = 0; + + for(i=0;isnr[i]->frame_ctr = 0; + } + + // time for total decoding session + p_Vid->tot_time = 0; + + p_Vid->dec_picture = NULL; + /*// reference flag initialization + for(i=0;i<17;++i) + { + p_Vid->ref_flag[i] = 1; + }*/ + + p_Vid->MbToSliceGroupMap = NULL; + p_Vid->MapUnitToSliceGroupMap = NULL; + + p_Vid->LastAccessUnitExists = 0; + p_Vid->NALUCount = 0; + + + p_Vid->out_buffer = NULL; + p_Vid->pending_output = NULL; + p_Vid->pending_output_state = FRAME; + p_Vid->recovery_flag = 0; + + +#if (ENABLE_OUTPUT_TONEMAPPING) + init_tone_mapping_sei(p_Vid->seiToneMapping); +#endif + +#if (MVC_EXTENSION_ENABLE) + p_Vid->last_pic_width_in_mbs_minus1 = 0; + p_Vid->last_pic_height_in_map_units_minus1 = 0; + p_Vid->last_max_dec_frame_buffering = 0; +#endif + + p_Vid->newframe = 0; + p_Vid->previous_frame_num = 0; + + p_Vid->iLumaPadX = MCBUF_LUMA_PAD_X; + p_Vid->iLumaPadY = MCBUF_LUMA_PAD_Y; + p_Vid->iChromaPadX = MCBUF_CHROMA_PAD_X; + p_Vid->iChromaPadY = MCBUF_CHROMA_PAD_Y; + + p_Vid->iPostProcess = 0; + p_Vid->bDeblockEnable = 0x3; + p_Vid->last_dec_view_id = -1; + p_Vid->last_dec_layer_id = -1; + +#if ENABLE_DEC_STATS + if ((p_Vid->dec_stats = (DecStatParameters *) malloc (sizeof (DecStatParameters)))== NULL) + no_mem_exit ("init: p_Vid->dec_stats"); + init_dec_stats(p_Vid->dec_stats); +#endif +} + +/*! +*********************************************************************** +* \brief +* Initialize FREXT variables +*********************************************************************** +*/ +void init_frext(VideoParameters *p_Vid) //!< video parameters +{ + //pel bitdepth init + p_Vid->bitdepth_luma_qp_scale = 6 * (p_Vid->bitdepth_luma - 8); + + if(p_Vid->bitdepth_luma > p_Vid->bitdepth_chroma || p_Vid->active_sps->chroma_format_idc == YUV400) + p_Vid->pic_unit_bitsize_on_disk = (p_Vid->bitdepth_luma > 8)? 16:8; + else + p_Vid->pic_unit_bitsize_on_disk = (p_Vid->bitdepth_chroma > 8)? 16:8; + p_Vid->dc_pred_value_comp[0] = 1<<(p_Vid->bitdepth_luma - 1); + p_Vid->max_pel_value_comp[0] = (1<bitdepth_luma) - 1; + p_Vid->mb_size[0][0] = p_Vid->mb_size[0][1] = MB_BLOCK_SIZE; + + if (p_Vid->active_sps->chroma_format_idc != YUV400) + { + //for chrominance part + p_Vid->bitdepth_chroma_qp_scale = 6 * (p_Vid->bitdepth_chroma - 8); + p_Vid->dc_pred_value_comp[1] = (1 << (p_Vid->bitdepth_chroma - 1)); + p_Vid->dc_pred_value_comp[2] = p_Vid->dc_pred_value_comp[1]; + p_Vid->max_pel_value_comp[1] = (1 << p_Vid->bitdepth_chroma) - 1; + p_Vid->max_pel_value_comp[2] = (1 << p_Vid->bitdepth_chroma) - 1; + p_Vid->num_blk8x8_uv = (1 << p_Vid->active_sps->chroma_format_idc) & (~(0x1)); + p_Vid->num_uv_blocks = (p_Vid->num_blk8x8_uv >> 1); + p_Vid->num_cdc_coeff = (p_Vid->num_blk8x8_uv << 1); + p_Vid->mb_size[1][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = (p_Vid->active_sps->chroma_format_idc==YUV420 || p_Vid->active_sps->chroma_format_idc==YUV422)? 8 : 16; + p_Vid->mb_size[1][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = (p_Vid->active_sps->chroma_format_idc==YUV444 || p_Vid->active_sps->chroma_format_idc==YUV422)? 16 : 8; + + p_Vid->subpel_x = p_Vid->mb_cr_size_x == 8 ? 7 : 3; + p_Vid->subpel_y = p_Vid->mb_cr_size_y == 8 ? 7 : 3; + p_Vid->shiftpel_x = p_Vid->mb_cr_size_x == 8 ? 3 : 2; + p_Vid->shiftpel_y = p_Vid->mb_cr_size_y == 8 ? 3 : 2; + p_Vid->total_scale = p_Vid->shiftpel_x + p_Vid->shiftpel_y; + } + else + { + p_Vid->bitdepth_chroma_qp_scale = 0; + p_Vid->max_pel_value_comp[1] = 0; + p_Vid->max_pel_value_comp[2] = 0; + p_Vid->num_blk8x8_uv = 0; + p_Vid->num_uv_blocks = 0; + p_Vid->num_cdc_coeff = 0; + p_Vid->mb_size[1][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = 0; + p_Vid->mb_size[1][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = 0; + p_Vid->subpel_x = 0; + p_Vid->subpel_y = 0; + p_Vid->shiftpel_x = 0; + p_Vid->shiftpel_y = 0; + p_Vid->total_scale = 0; + } + + p_Vid->mb_cr_size = p_Vid->mb_cr_size_x * p_Vid->mb_cr_size_y; + p_Vid->mb_size_blk[0][0] = p_Vid->mb_size_blk[0][1] = p_Vid->mb_size[0][0] >> 2; + p_Vid->mb_size_blk[1][0] = p_Vid->mb_size_blk[2][0] = p_Vid->mb_size[1][0] >> 2; + p_Vid->mb_size_blk[1][1] = p_Vid->mb_size_blk[2][1] = p_Vid->mb_size[1][1] >> 2; + + p_Vid->mb_size_shift[0][0] = p_Vid->mb_size_shift[0][1] = CeilLog2_sf (p_Vid->mb_size[0][0]); + p_Vid->mb_size_shift[1][0] = p_Vid->mb_size_shift[2][0] = CeilLog2_sf (p_Vid->mb_size[1][0]); + p_Vid->mb_size_shift[1][1] = p_Vid->mb_size_shift[2][1] = CeilLog2_sf (p_Vid->mb_size[1][1]); +} + +/*! +************************************************************************ +* \brief +* Reports the gathered information to appropriate outputs +* +* \par Input: +* InputParameters *p_Inp, +* VideoParameters *p_Vid, +* struct snr_par *stat +* +* \par Output: +* None +************************************************************************ +*/ +void Report(VideoParameters *p_Vid) +{ + static const char yuv_formats[4][4]= { {"400"}, {"420"}, {"422"}, {"444"} }; + pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps; + InputParameters *p_Inp = p_Vid->p_Inp; + SNRParameters *snr = p_Vid->snr[0]; +#define OUTSTRING_SIZE 255 + char string[OUTSTRING_SIZE]; + FILE *p_log; + +#ifndef WIN32 + time_t now; + struct tm *l_time; +#else + char timebuf[128]; +#endif + + // normalize time + p_Vid->tot_time = timenorm(p_Vid->tot_time); + + if (p_Inp->silent == FALSE) + { + printf("-------------------- Average SNR all frames ------------------------------\n"); + printf(" SNR Y(dB) : %5.2f\n",snr->snra[0]); + printf(" SNR U(dB) : %5.2f\n",snr->snra[1]); + printf(" SNR V(dB) : %5.2f\n",snr->snra[2]); + + printf(" Total decoding time : %.3f sec (%.3f fps)[%d frm/%" FORMAT_OFF_T " ms]\n",p_Vid->tot_time*0.001,(snr->frame_ctr ) * 1000.0 / p_Vid->tot_time, snr->frame_ctr, p_Vid->tot_time); + printf("--------------------------------------------------------------------------\n"); + printf(" Exit JM %s decoder, ver %s ",JM, VERSION); + printf("\n"); + } + else + { + printf("\n----------------------- Decoding Completed -------------------------------\n"); + printf(" Total decoding time : %.3f sec (%.3f fps)[%d frm/%" FORMAT_OFF_T " ms]\n",p_Vid->tot_time*0.001, (snr->frame_ctr) * 1000.0 / p_Vid->tot_time, snr->frame_ctr, p_Vid->tot_time); + printf("--------------------------------------------------------------------------\n"); + printf(" Exit JM %s decoder, ver %s ",JM, VERSION); + printf("\n"); + } + + // write to log file + printf(" Output status file : %s \n",LOGFILE); + snprintf(string, OUTSTRING_SIZE, "%s", LOGFILE); + + if ((p_log=fopen(string,"r"))==0) // check if file exist + { + if ((p_log=fopen(string,"a"))==0) + { + snprintf(errortext, ET_SIZE, "Error open file %s for appending",string); + error(errortext, 500); + } + else // Create header to new file + { + fprintf(p_log," -------------------------------------------------------------------------------------------------------------------\n"); + fprintf(p_log,"| Decoder statistics. This file is made first time, later runs are appended |\n"); + fprintf(p_log," ------------------------------------------------------------------------------------------------------------------- \n"); + fprintf(p_log,"| ver | Date | Time | Sequence |#Img| Format | YUV |Coding|SNRY 1|SNRU 1|SNRV 1|SNRY N|SNRU N|SNRV N|\n"); + fprintf(p_log," -------------------------------------------------------------------------------------------------------------------\n"); + } + } + else + { + fclose(p_log); + p_log=fopen(string,"a"); // File exist,just open for appending + } + + fprintf(p_log,"|%s/%-4s", VERSION, EXT_VERSION); + +#ifdef WIN32 + _strdate( timebuf ); + fprintf(p_log,"| %1.5s |",timebuf ); + + _strtime( timebuf); + fprintf(p_log," % 1.5s |",timebuf); +#else + now = time ((time_t *) NULL); // Get the system time and put it into 'now' as 'calender time' + time (&now); + l_time = localtime (&now); + strftime (string, sizeof string, "%d-%b-%Y", l_time); + fprintf(p_log,"| %1.5s |",string ); + + strftime (string, sizeof string, "%H:%M:%S", l_time); + fprintf(p_log,"| %1.5s |",string ); +#endif + + fprintf(p_log,"%20.20s|",p_Inp->infile); + + fprintf(p_log,"%3d |",p_Vid->number); + fprintf(p_log,"%4dx%-4d|", p_Vid->width, p_Vid->height); + fprintf(p_log," %s |", &(yuv_formats[p_Vid->yuv_format][0])); + + if (active_pps) + { + if (active_pps->entropy_coding_mode_flag == (Boolean) CAVLC) + fprintf(p_log," CAVLC|"); + else + fprintf(p_log," CABAC|"); + } + + fprintf(p_log,"%6.3f|",snr->snr1[0]); + fprintf(p_log,"%6.3f|",snr->snr1[1]); + fprintf(p_log,"%6.3f|",snr->snr1[2]); + fprintf(p_log,"%6.3f|",snr->snra[0]); + fprintf(p_log,"%6.3f|",snr->snra[1]); + fprintf(p_log,"%6.3f|",snr->snra[2]); + fprintf(p_log,"\n"); + fclose(p_log); + + snprintf(string, OUTSTRING_SIZE,"%s", DATADECFILE); + p_log=fopen(string,"a"); + + if(p_Vid->Bframe_ctr != 0) // B picture used + { + fprintf(p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5d " + "%2.2f %2.2f %2.2f %5d " + "%2.2f %2.2f %2.2f %5d %.3f\n", + p_Vid->number, 0, p_Vid->ppSliceList[0]->qp, + snr->snr1[0], + snr->snr1[1], + snr->snr1[2], + 0, + 0.0, + 0.0, + 0.0, + 0, + snr->snra[0], + snr->snra[1], + snr->snra[2], + 0, + (double)0.001*p_Vid->tot_time/(p_Vid->number + p_Vid->Bframe_ctr - 1)); + } + else + { + fprintf(p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5d " + "%2.2f %2.2f %2.2f %5d " + "%2.2f %2.2f %2.2f %5d %.3f\n", + p_Vid->number, 0, p_Vid->ppSliceList[0]? p_Vid->ppSliceList[0]->qp: 0, + snr->snr1[0], + snr->snr1[1], + snr->snr1[2], + 0, + 0.0, + 0.0, + 0.0, + 0, + snr->snra[0], + snr->snra[1], + snr->snra[2], + 0, + p_Vid->number ? ((double)0.001*p_Vid->tot_time/p_Vid->number) : 0.0); + } + fclose(p_log); +} + +/*! +************************************************************************ +* \brief +* Allocates a stand-alone partition structure. Structure should +* be freed by FreePartition(); +* data structures +* +* \par Input: +* n: number of partitions in the array +* \par return +* pointer to DataPartition Structure, zero-initialized +************************************************************************ +*/ + +DataPartition *AllocPartition(int n) +{ + DataPartition *partArr, *dataPart; + int i; + + partArr = (DataPartition *) calloc(n, sizeof(DataPartition)); + if (partArr == NULL) + { + snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for Data Partition failed"); + error(errortext, 100); + } + + for (i = 0; i < n; ++i) // loop over all data partitions + { + dataPart = &(partArr[i]); + dataPart->bitstream = (Bitstream *) calloc(1, sizeof(Bitstream)); + if (dataPart->bitstream == NULL) + { + snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for Bitstream failed"); + error(errortext, 100); + } + dataPart->bitstream->streamBuffer = (byte *) calloc(MAX_CODED_FRAME_SIZE, sizeof(byte)); + if (dataPart->bitstream->streamBuffer == NULL) + { + snprintf(errortext, ET_SIZE, "AllocPartition: Memory allocation for streamBuffer failed"); + error(errortext, 100); + } + } + return partArr; +} + + + + +/*! +************************************************************************ +* \brief +* Frees a partition structure (array). +* +* \par Input: +* Partition to be freed, size of partition Array (Number of Partitions) +* +* \par return +* None +* +* \note +* n must be the same as for the corresponding call of AllocPartition +************************************************************************ +*/ +void FreePartition (DataPartition *dp, int n) +{ + int i; + + assert (dp != NULL); + assert (dp->bitstream != NULL); + assert (dp->bitstream->streamBuffer != NULL); + for (i=0; istreamBuffer); + free (dp[i].bitstream); + } + free (dp); +} + + +/*! +************************************************************************ +* \brief +* Allocates the slice structure along with its dependent +* data structures +* +* \par Input: +* Input Parameters InputParameters *p_Inp, VideoParameters *p_Vid +************************************************************************ +*/ +Slice *malloc_slice(InputParameters *p_Inp, VideoParameters *p_Vid) +{ + int i, j, memory_size = 0; + Slice *currSlice; + + currSlice = (Slice *) calloc(1, sizeof(Slice)); + if ( currSlice == NULL) + { + snprintf(errortext, ET_SIZE, "Memory allocation for Slice datastruct in NAL-mode %d failed", p_Inp->FileFormat); + error(errortext,100); + } + + // create all context models + currSlice->mot_ctx = create_contexts_MotionInfo(); + currSlice->tex_ctx = create_contexts_TextureInfo(); + + currSlice->max_part_nr = 3; //! assume data partitioning (worst case) for the following mallocs() + currSlice->partArr = AllocPartition(currSlice->max_part_nr); + + memory_size += get_mem2Dwp (&(currSlice->wp_params), 2, MAX_REFERENCE_PICTURES); + + memory_size += get_mem3Dint(&(currSlice->wp_weight), 2, MAX_REFERENCE_PICTURES, 3); + memory_size += get_mem3Dint(&(currSlice->wp_offset), 6, MAX_REFERENCE_PICTURES, 3); + memory_size += get_mem4Dint(&(currSlice->wbp_weight), 6, MAX_REFERENCE_PICTURES, MAX_REFERENCE_PICTURES, 3); + + memory_size += get_mem3Dpel(&(currSlice->mb_pred), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem3Dpel(&(currSlice->mb_rec ), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem3Dint(&(currSlice->mb_rres), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem3Dint(&(currSlice->cof ), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + // memory_size += get_mem3Dint(&(currSlice->fcf ), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + allocate_pred_mem(currSlice); +#if (MVC_EXTENSION_ENABLE) + currSlice->view_id = MVC_INIT_VIEW_ID; + currSlice->inter_view_flag = 0; + currSlice->anchor_pic_flag = 0; +#endif + // reference flag initialization + for(i=0;i<17;++i) + { + currSlice->ref_flag[i] = 1; + } + for (i = 0; i < 6; i++) + { + currSlice->listX[i] = calloc(MAX_LIST_SIZE, sizeof (StorablePicture*)); // +1 for reordering + if (NULL==currSlice->listX[i]) + no_mem_exit("malloc_slice: currSlice->listX[i]"); + } + for (j = 0; j < 6; j++) + { + for (i = 0; i < MAX_LIST_SIZE; i++) + { + currSlice->listX[j][i] = NULL; + } + currSlice->listXsize[j]=0; + } + + return currSlice; +} + + +/*! +************************************************************************ +* \brief +* Memory frees of the Slice structure and of its dependent +* data structures +* +* \par Input: +* Input Parameters Slice *currSlice +************************************************************************ +*/ +void free_slice(Slice *currSlice) +{ + int i; + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + free_ref_pic_list_reordering_buffer(currSlice); + free_pred_mem(currSlice); + free_mem3Dint(currSlice->cof ); + free_mem3Dint(currSlice->mb_rres); + free_mem3Dpel(currSlice->mb_rec ); + free_mem3Dpel(currSlice->mb_pred); + + free_mem2Dwp (currSlice->wp_params ); + free_mem3Dint(currSlice->wp_weight ); + free_mem3Dint(currSlice->wp_offset ); + free_mem4Dint(currSlice->wbp_weight); + + FreePartition (currSlice->partArr, 3); + + //if (1) + { + // delete all context models + delete_contexts_MotionInfo (currSlice->mot_ctx); + delete_contexts_TextureInfo(currSlice->tex_ctx); + } + + for (i=0; i<6; i++) + { + if (currSlice->listX[i]) + { + free (currSlice->listX[i]); + currSlice->listX[i] = NULL; + } + } + while (currSlice->dec_ref_pic_marking_buffer) + { + DecRefPicMarking_t *tmp_drpm=currSlice->dec_ref_pic_marking_buffer; + currSlice->dec_ref_pic_marking_buffer=tmp_drpm->Next; + free (tmp_drpm); + } + + free(currSlice); + currSlice = NULL; +} + +/*! +************************************************************************ +* \brief +* Dynamic memory allocation of frame size related global buffers +* buffers are defined in global.h, allocated memory must be freed in +* void free_global_buffers() +* +* \par Input: +* Input Parameters VideoParameters *p_Vid +* +* \par Output: +* Number of allocated bytes +*********************************************************************** +*/ +int init_global_buffers(VideoParameters *p_Vid, int layer_id) +{ + int memory_size=0; + int i; + CodingParameters *cps = p_Vid->p_EncodePar[layer_id]; + BlockPos* PicPos; + + if (p_Vid->global_init_done[layer_id]) + { + free_layer_buffers(p_Vid, layer_id); + } + + // allocate memory for reference frame in find_snr + memory_size += get_mem2Dpel(&cps->imgY_ref, cps->height, cps->width); + if (cps->yuv_format != YUV400) + { + memory_size += get_mem3Dpel(&cps->imgUV_ref, 2, cps->height_cr, cps->width_cr); + } + else + cps->imgUV_ref = NULL; + + // allocate memory in structure p_Vid + if( (cps->separate_colour_plane_flag != 0) ) + { + for( i=0; imb_data_JV[i]) = (Macroblock *) calloc(cps->FrameSizeInMbs, sizeof(Macroblock))) == NULL) + no_mem_exit("init_global_buffers: cps->mb_data_JV"); + } + cps->mb_data = NULL; + } + else + { + if(((cps->mb_data) = (Macroblock *) calloc(cps->FrameSizeInMbs, sizeof(Macroblock))) == NULL) + no_mem_exit("init_global_buffers: cps->mb_data"); + } + if( (cps->separate_colour_plane_flag != 0) ) + { + for( i=0; iintra_block_JV[i]) = (char*) calloc(cps->FrameSizeInMbs, sizeof(char))) == NULL) + no_mem_exit("init_global_buffers: cps->intra_block_JV"); + } + cps->intra_block = NULL; + } + else + { + if(((cps->intra_block) = (char*) calloc(cps->FrameSizeInMbs, sizeof(char))) == NULL) + no_mem_exit("init_global_buffers: cps->intra_block"); + } + + + //memory_size += get_mem2Dint(&PicPos,p_Vid->FrameSizeInMbs + 1,2); //! Helper array to access macroblock positions. We add 1 to also consider last MB. + if(((cps->PicPos) = (BlockPos*) calloc(cps->FrameSizeInMbs + 1, sizeof(BlockPos))) == NULL) + no_mem_exit("init_global_buffers: PicPos"); + + PicPos = cps->PicPos; + for (i = 0; i < (int) cps->FrameSizeInMbs + 1;++i) + { + PicPos[i].x = (short) (i % cps->PicWidthInMbs); + PicPos[i].y = (short) (i / cps->PicWidthInMbs); + } + + if( (cps->separate_colour_plane_flag != 0) ) + { + for( i=0; iipredmode_JV[i]), 4*cps->FrameHeightInMbs, 4*cps->PicWidthInMbs); + } + cps->ipredmode = NULL; + } + else + memory_size += get_mem2D(&(cps->ipredmode), 4*cps->FrameHeightInMbs, 4*cps->PicWidthInMbs); + + // CAVLC mem + memory_size += get_mem4D(&(cps->nz_coeff), cps->FrameSizeInMbs, 3, BLOCK_SIZE, BLOCK_SIZE); + if( (cps->separate_colour_plane_flag != 0) ) + { + for( i=0; isiblock_JV[i]), cps->FrameHeightInMbs, cps->PicWidthInMbs); + if(cps->siblock_JV[i]== NULL) + no_mem_exit("init_global_buffers: p_Vid->siblock_JV"); + } + cps->siblock = NULL; + } + else + { + memory_size += get_mem2Dint(&(cps->siblock), cps->FrameHeightInMbs, cps->PicWidthInMbs); + } + init_qp_process(cps); + cps->oldFrameSizeInMbs = cps->FrameSizeInMbs; + + if(layer_id == 0 ) + init_output(cps, ((cps->pic_unit_bitsize_on_disk+7) >> 3)); + else + cps->img2buf = p_Vid->p_EncodePar[0]->img2buf; + p_Vid->global_init_done[layer_id] = 1; + + return (memory_size); +} + +/*! +************************************************************************ +* \brief +* Free allocated memory of frame size related global buffers +* buffers are defined in global.h, allocated memory is allocated in +* int init_global_buffers() +* +* \par Input: +* Input Parameters VideoParameters *p_Vid +* +* \par Output: +* none +* +************************************************************************ +*/ +void free_layer_buffers(VideoParameters *p_Vid, int layer_id) +{ + CodingParameters *cps = p_Vid->p_EncodePar[layer_id]; + + if(!p_Vid->global_init_done[layer_id]) + return; + + if (cps->imgY_ref) + { + free_mem2Dpel (cps->imgY_ref); + cps->imgY_ref = NULL; + } + if (cps->imgUV_ref) + { + free_mem3Dpel (cps->imgUV_ref); + cps->imgUV_ref = NULL; + } + // CAVLC free mem + if (cps->nz_coeff) + { + free_mem4D(cps->nz_coeff); + cps->nz_coeff = NULL; + } + + // free mem, allocated for structure p_Vid + if( (cps->separate_colour_plane_flag != 0) ) + { + int i; + for(i=0; imb_data_JV[i]); + cps->mb_data_JV[i] = NULL; + free_mem2Dint(cps->siblock_JV[i]); + cps->siblock_JV[i] = NULL; + free_mem2D(cps->ipredmode_JV[i]); + cps->ipredmode_JV[i] = NULL; + free (cps->intra_block_JV[i]); + cps->intra_block_JV[i] = NULL; + } + } + else + { + if (cps->mb_data != NULL) + { + free(cps->mb_data); + cps->mb_data = NULL; + } + if(cps->siblock) + { + free_mem2Dint(cps->siblock); + cps->siblock = NULL; + } + if(cps->ipredmode) + { + free_mem2D(cps->ipredmode); + cps->ipredmode = NULL; + } + if(cps->intra_block) + { + free (cps->intra_block); + cps->intra_block = NULL; + } + } + if(cps->PicPos) + { + free(cps->PicPos); + cps->PicPos = NULL; + } + + free_qp_matrices(cps); + + + p_Vid->global_init_done[layer_id] = 0; +} + +void free_global_buffers(VideoParameters *p_Vid) +{ + if(p_Vid->dec_picture) + { + free_storable_picture(p_Vid->dec_picture); + p_Vid->dec_picture = NULL; + } +#if MVC_EXTENSION_ENABLE + if(p_Vid->active_subset_sps && p_Vid->active_subset_sps->sps.Valid && (p_Vid->active_subset_sps->sps.profile_idc==MVC_HIGH||p_Vid->active_subset_sps->sps.profile_idc == STEREO_HIGH)) + free_img_data( p_Vid, &(p_Vid->tempData3) ); +#endif +} + +void report_stats_on_error(void) +{ + //free_encoder_memory(p_Vid); + exit (-1); +} + +void ClearDecPicList(VideoParameters *p_Vid) +{ + DecodedPicList *pPic = p_Vid->pDecOuputPic, *pPrior = NULL; + //find the head first; + while(pPic && !pPic->bValid) + { + pPrior = pPic; + pPic = pPic->pNext; + } + + if(pPic && (pPic != p_Vid->pDecOuputPic)) + { + //move all nodes before pPic to the end; + DecodedPicList *pPicTail = pPic; + while(pPicTail->pNext) + pPicTail = pPicTail->pNext; + + pPicTail->pNext = p_Vid->pDecOuputPic; + p_Vid->pDecOuputPic = pPic; + pPrior->pNext = NULL; + } +} + +DecodedPicList *get_one_avail_dec_pic_from_list(DecodedPicList *pDecPicList, int b3D, int view_id) +{ + DecodedPicList *pPic = pDecPicList, *pPrior = NULL; + if(b3D) + { + while(pPic && (pPic->bValid &(1<pNext; + } + } + else + { + while(pPic && (pPic->bValid)) + { + pPrior = pPic; + pPic = pPic->pNext; + } + } + + if(!pPic) + { + pPic = (DecodedPicList *)calloc(1, sizeof(*pPic)); + pPrior->pNext = pPic; + } + + return pPic; +} +/************************************ +Interface: OpenDecoder +Return: +0: NOERROR; +<0: ERROR; +************************************/ +int OpenDecoder(InputParameters *p_Inp) +{ + int iRet; + DecoderParams *pDecoder; + + iRet = alloc_decoder(&p_Dec); + if(iRet) + { + return (iRet|DEC_ERRMASK); + } + init_time(); + + pDecoder = p_Dec; + //Configure (pDecoder->p_Vid, pDecoder->p_Inp, argc, argv); + memcpy(pDecoder->p_Inp, p_Inp, sizeof(InputParameters)); + pDecoder->p_Vid->conceal_mode = p_Inp->conceal_mode; + pDecoder->p_Vid->ref_poc_gap = p_Inp->ref_poc_gap; + pDecoder->p_Vid->poc_gap = p_Inp->poc_gap; +#if TRACE + if ((pDecoder->p_trace = fopen(TRACEFILE,"w"))==0) // append new statistic at the end + { + snprintf(errortext, ET_SIZE, "Error open file %s!",TRACEFILE); + //error(errortext,500); + return -1; + } +#endif + +#if (!MVC_EXTENSION_ENABLE) + if((strcasecmp(p_Inp->outfile, "\"\"")!=0) && (strlen(p_Inp->outfile)>0)) + { + if ((pDecoder->p_Vid->p_out = open(p_Inp->outfile, OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ",p_Inp->outfile); + error(errortext,500); + } + } + else + pDecoder->p_Vid->p_out = -1; +#else + { + int i; + VideoParameters *p_Vid = pDecoder->p_Vid; + // Set defaults + p_Vid->p_out = -1; + for(i = 0; i < MAX_VIEW_NUM; i++) + { + p_Vid->p_out_mvc[i] = -1; + } + + //! Edited by Joao Carreira + if (p_Inp->DecodeAllLayers == 1) + { + //int view; + //for(view=0; viewoutfile, "\"\"")!=0) && (strlen(p_Inp->outfile)>0)) + { + if( (strcasecmp(p_Inp->outfile, "\"\"")!=0) && ((p_Vid->p_out_mvc[0]=open(p_Inp->outfile, OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) ) + { + snprintf(errortext, ET_SIZE, "Error open file %s ",p_Inp->outfile); + error(errortext,500); + } + } + p_Vid->p_out = p_Vid->p_out_mvc[0]; + } + } +#endif + +#if (!MVC_EXTENSION_ENABLE) + if(strlen(pDecoder->p_Inp->reffile)>0 && strcmp(pDecoder->p_Inp->reffile, "\"\"")) + { + if ((pDecoder->p_Vid->p_ref = open(pDecoder->p_Inp->reffile, OPENFLAGS_READ))==-1) + { + printf(" Input reference file : %s does not exist \n",pDecoder->p_Inp->reffile); + printf(" SNR values are not available\n"); + } + } + else + pDecoder->p_Vid->p_ref = -1; +#else + { + int i; + VideoParameters *p_Vid = pDecoder->p_Vid; + // Set defaults + p_Vid->p_out = -1; + for(i = 0; i < MAX_VIEW_NUM; i++) + { + p_Vid->p_ref_mvc[i] = -1; + } + + if (p_Inp->DecodeAllLayers == 1) + { + //OpenRefFiles(p_Vid, 0, 1); + OpenRefFiles_per_layer(p_Vid, 0); + } + else + { //Normal AVC + if((strcasecmp(p_Inp->outfile, "\"\"")!=0) && (strlen(p_Inp->outfile)>0)) + { + if( (strcasecmp(p_Inp->outfile, "\"\"")!=0) && ((p_Vid->p_out_mvc[0]=open(p_Inp->outfile, OPENFLAGS_READ))==-1) ) + { + snprintf(errortext, ET_SIZE, "Error open file %s ",p_Inp->outfile); + error(errortext,500); + } + } + p_Vid->p_out = p_Vid->p_out_mvc[0]; + } + } +#endif + + switch( pDecoder->p_Inp->FileFormat ) + { + default: + case PAR_OF_ANNEXB: + malloc_annex_b(pDecoder->p_Vid, &pDecoder->p_Vid->annex_b); + open_annex_b(pDecoder->p_Inp->infile, pDecoder->p_Vid->annex_b); + break; + case PAR_OF_RTP: + OpenRTPFile(pDecoder->p_Inp->infile, &pDecoder->p_Vid->BitStreamFile); + break; + } + + // Allocate Slice data struct + //pDecoder->p_Vid->currentSlice = NULL; //malloc_slice(pDecoder->p_Inp, pDecoder->p_Vid); + + init_old_slice(pDecoder->p_Vid->old_slice); + + init(pDecoder->p_Vid); + + init_out_buffer(pDecoder->p_Vid); + + init_parse_nalu(pDecoder->p_Vid); + init_prediction_parser(pDecoder->p_Vid); + + pDecoder->p_Vid->p_Transcode = NULL; + + //! Error Concealment + fercOpenFrameConcealment( pDecoder->p_Vid ); + +#if (MVC_EXTENSION_ENABLE) + pDecoder->p_Vid->active_sps = NULL; + pDecoder->p_Vid->active_subset_sps = NULL; + init_subset_sps_list(pDecoder->p_Vid->SubsetSeqParSet, MAXSPS); +#endif + + +#if _FLTDBG_ + pDecoder->p_Vid->fpDbg = fopen("c:/fltdbg.txt", "a"); + fprintf(pDecoder->p_Vid->fpDbg, "\ndecoder is opened.\n"); +#endif + + initInput( pDecoder->p_Vid , &(pDecoder->p_Inp->source) , &(pDecoder->p_Inp->output) ); + + return DEC_OPEN_NOERR; +} + +/************************************ +Interface: DecodeOneFrame +Return: +0: NOERROR; +1: Finished decoding; +others: Error Code; +************************************/ +int DecodeOneFrame(DecodedPicList **ppDecPicList) +{ + int iRet; + DecoderParams *pDecoder = p_Dec; + ClearDecPicList(pDecoder->p_Vid); + iRet = decode_one_frame(pDecoder); + if(iRet == SOP) + { + iRet = DEC_SUCCEED; + } + else if(iRet == EOS) + { + iRet = DEC_EOS; + } + else + { + iRet |= DEC_ERRMASK; + } + + *ppDecPicList = pDecoder->p_Vid->pDecOuputPic; + return iRet; +} + +int FinitDecoder(DecodedPicList **ppDecPicList) +{ + int i; + DecoderParams *pDecoder = p_Dec; + if(!pDecoder) + return DEC_GEN_NOERR; + ClearDecPicList(pDecoder->p_Vid); +#if (MVC_EXTENSION_ENABLE) + for(i=MAX_NUM_DPB_LAYERS-1; i>=0;i--) + { + flush_dpb(pDecoder->p_Vid->p_Dpb_layer[i]); + } + //flush_dpb(pDecoder->p_Vid->p_Dpb_layer[1]); + //flush_dpb(pDecoder->p_Vid->p_Dpb_layer[0]); +#else + flush_dpb(pDecoder->p_Vid->p_Dpb_layer[0]); +#endif +#if (PAIR_FIELDS_IN_OUTPUT) + flush_pending_output(pDecoder->p_Vid, pDecoder->p_Vid->p_out); +#endif + if (pDecoder->p_Inp->FileFormat == PAR_OF_ANNEXB) + { + reset_annex_b(pDecoder->p_Vid->annex_b); + } + pDecoder->p_Vid->newframe = 0; + pDecoder->p_Vid->previous_frame_num = 0; + *ppDecPicList = pDecoder->p_Vid->pDecOuputPic; + return DEC_GEN_NOERR; +} + +int CloseDecoder() +{ + int i; + + DecoderParams *pDecoder = p_Dec; + if(!pDecoder) + return DEC_CLOSE_NOERR; + + + //Report (pDecoder->p_Vid); + FinalReport (pDecoder->p_Vid); + + + FmoFinit(pDecoder->p_Vid); + for(i=0;ip_Vid, i); + } + //free_layer_buffers(pDecoder->p_Vid, i); + //free_layer_buffers(pDecoder->p_Vid, 1); + free_global_buffers(pDecoder->p_Vid); + switch( pDecoder->p_Inp->FileFormat ) + { + default: + case PAR_OF_ANNEXB: + close_annex_b(pDecoder->p_Vid->annex_b); + break; + case PAR_OF_RTP: + CloseRTPFile(&pDecoder->p_Vid->BitStreamFile); + break; + } + +#if (MVC_EXTENSION_ENABLE) + for(i=0;ip_Vid->p_out_mvc[i] != -1) + { + close(pDecoder->p_Vid->p_out_mvc[i]); + } + if (pDecoder->p_Vid->p_ref_mvc[i] != -1) + { + close(pDecoder->p_Vid->p_ref_mvc[i]); + } + } +#else + if(pDecoder->p_Vid->p_out >=0) + close(pDecoder->p_Vid->p_out); + + if (pDecoder->p_Vid->p_ref != -1) + close(pDecoder->p_Vid->p_ref); +#endif + + +#if TRACE + fclose(pDecoder->p_trace); +#endif + + ercClose(pDecoder->p_Vid, pDecoder->p_Vid->erc_errorVar); + + CleanUpPPS(pDecoder->p_Vid); +#if (MVC_EXTENSION_ENABLE) + for(i=0; ip_Vid->SubsetSeqParSet+i); + } +#endif + + for(i=0; ip_Vid->p_Dpb_layer[i]); + + + uninit_out_buffer(pDecoder->p_Vid); +#if _FLTDBG_ + if(pDecoder->p_Vid->fpDbg) + { + fprintf(pDecoder->p_Vid->fpDbg, "decoder is closed.\n"); + fclose(pDecoder->p_Vid->fpDbg); + pDecoder->p_Vid->fpDbg = NULL; + } +#endif + + free_img (pDecoder->p_Vid); + free (pDecoder->p_Inp); + + free(pDecoder); + + p_Dec = NULL; + return DEC_CLOSE_NOERR; +} + +#if (MVC_EXTENSION_ENABLE) +void OpenOutputFiles(VideoParameters *p_Vid, int view0_id, int view1_id) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + char out_ViewFileName[2][FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + if ((strcasecmp(p_Inp->outfile, "\"\"")!=0) && (strlen(p_Inp->outfile)>0)) + { + strcpy(chBuf, p_Inp->outfile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + if (strcmp("nul", chBuf)) + { + sprintf(out_ViewFileName[0], "%s_ViewId%02d.yuv", chBuf, view0_id); + sprintf(out_ViewFileName[1], "%s_ViewId%02d.yuv", chBuf, view1_id); + if(p_Vid->p_out_mvc[0] >= 0) + { + close(p_Vid->p_out_mvc[0]); + p_Vid->p_out_mvc[0] = -1; + } + if ((p_Vid->p_out_mvc[0]=open(out_ViewFileName[0], OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName[0]); + error(errortext,500); + } + + if(p_Vid->p_out_mvc[1] >= 0) + { + close(p_Vid->p_out_mvc[1]); + p_Vid->p_out_mvc[1] = -1; + } + if ((p_Vid->p_out_mvc[1]=open(out_ViewFileName[1], OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName[1]); + error(errortext,500); + } + } + } +} + +void OpenOutputFiles_per_layer(VideoParameters *p_Vid, int view_id) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + char out_ViewFileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + if ((strcasecmp(p_Inp->outfile, "\"\"")!=0) && (strlen(p_Inp->outfile)>0)) + { + strcpy(chBuf, p_Inp->outfile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + if (strcmp("nul", chBuf)) + { + sprintf(out_ViewFileName, "%s_ViewId%02d.yuv", chBuf, view_id); + + if(p_Vid->p_out_mvc[view_id] >= 0) + { + return; + } + if ((p_Vid->p_out_mvc[view_id]=open(out_ViewFileName, OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName); + error(errortext,500); + } + } + } +} + +void OpenRefFiles(VideoParameters *p_Vid, int view0_id, int view1_id) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + char out_ViewFileName[2][FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + if ((strcasecmp(p_Inp->outfile, "\"\"")!=0) && (strlen(p_Inp->reffile)>0)) + { + strcpy(chBuf, p_Inp->reffile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + if (strcmp("nul", chBuf)) + { + sprintf(out_ViewFileName[0], "%s_ViewId%02d.yuv", chBuf, view0_id); + sprintf(out_ViewFileName[1], "%s_ViewId%02d.yuv", chBuf, view1_id); + if(p_Vid->p_ref_mvc[0] >= 0) + { + close(p_Vid->p_ref_mvc[0]); + p_Vid->p_ref_mvc[0] = -1; + } + if ((p_Vid->p_ref_mvc[0]=open(out_ViewFileName[0], OPENFLAGS_READ))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName[0]); + p_Vid->p_ref_mvc[0] = -1; + } + + if(p_Vid->p_ref_mvc[1] >= 0) + { + close(p_Vid->p_ref_mvc[1]); + p_Vid->p_ref_mvc[1] = -1; + } + if ((p_Vid->p_ref_mvc[1]=open(out_ViewFileName[1], OPENFLAGS_READ))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName[1]); + p_Vid->p_ref_mvc[1] = -1; + } + } + } +} + +void OpenRefFiles_per_layer(VideoParameters *p_Vid, int view_id) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + char out_ViewFileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + if ((strcasecmp(p_Inp->outfile, "\"\"")!=0) && (strlen(p_Inp->reffile)>0)) + { + strcpy(chBuf, p_Inp->reffile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + if (strcmp("nul", chBuf)) + { + sprintf(out_ViewFileName, "%s_ViewId%02d.yuv", chBuf, view_id); + if(p_Vid->p_ref_mvc[view_id] >= 0) + { + return; + } + if ((p_Vid->p_ref_mvc[view_id]=open(out_ViewFileName, OPENFLAGS_READ))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName); + p_Vid->p_ref_mvc[view_id] = -1; + } + } + } +} + +#endif + +void set_global_coding_par(VideoParameters *p_Vid, CodingParameters *cps) +{ + p_Vid->bitdepth_chroma = 0; + p_Vid->width_cr = 0; + p_Vid->height_cr = 0; + p_Vid->lossless_qpprime_flag = cps->lossless_qpprime_flag; + p_Vid->max_vmv_r = cps->max_vmv_r; + + // Fidelity Range Extensions stuff (part 1) + p_Vid->bitdepth_luma = cps->bitdepth_luma; + p_Vid->bitdepth_scale[0] = cps->bitdepth_scale[0]; + p_Vid->bitdepth_chroma = cps->bitdepth_chroma; + p_Vid->bitdepth_scale[1] = cps->bitdepth_scale[1]; + + p_Vid->max_frame_num = cps->max_frame_num; + p_Vid->PicWidthInMbs = cps->PicWidthInMbs; + p_Vid->PicHeightInMapUnits = cps->PicHeightInMapUnits; + p_Vid->FrameHeightInMbs = cps->FrameHeightInMbs; + p_Vid->FrameSizeInMbs = cps->FrameSizeInMbs; + + p_Vid->yuv_format = cps->yuv_format; + p_Vid->separate_colour_plane_flag = cps->separate_colour_plane_flag; + p_Vid->ChromaArrayType = cps->ChromaArrayType; + + p_Vid->width = cps->width; + p_Vid->height = cps->height; + p_Vid->iLumaPadX = MCBUF_LUMA_PAD_X; + p_Vid->iLumaPadY = MCBUF_LUMA_PAD_Y; + p_Vid->iChromaPadX = MCBUF_CHROMA_PAD_X; + p_Vid->iChromaPadY = MCBUF_CHROMA_PAD_Y; + if (p_Vid->yuv_format == YUV420) + { + p_Vid->width_cr = (p_Vid->width >> 1); + p_Vid->height_cr = (p_Vid->height >> 1); + } + else if (p_Vid->yuv_format == YUV422) + { + p_Vid->width_cr = (p_Vid->width >> 1); + p_Vid->height_cr = p_Vid->height; + p_Vid->iChromaPadY = MCBUF_CHROMA_PAD_Y*2; + } + else if (p_Vid->yuv_format == YUV444) + { + //YUV444 + p_Vid->width_cr = p_Vid->width; + p_Vid->height_cr = p_Vid->height; + p_Vid->iChromaPadX = p_Vid->iLumaPadX; + p_Vid->iChromaPadY = p_Vid->iLumaPadY; + } + + init_frext(p_Vid); +} diff --git a/ldecod/src/leaky_bucket.c b/ldecod/src/leaky_bucket.c new file mode 100644 index 0000000..46b2ef6 --- /dev/null +++ b/ldecod/src/leaky_bucket.c @@ -0,0 +1,139 @@ + +/*! + ************************************************************************ + * \file leaky_bucket.c + * + * \brief + * Calculate if decoder leaky bucket parameters meets HRD constraints specified by encoder. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Shankar Regunathan + ************************************************************************ + */ + +#include "contributors.h" +#include "global.h" + +#ifdef _LEAKYBUCKET_ +/*! + *********************************************************************** + * \brief + * Function to get unsigned long word from a file. + * \param fp + * Filepointer + * \return + * unsigned long double word + * \par SideEffects + * None. + * \par Notes + * File should be opened to read in binary format. + * \author + * Shankar Regunathan shanre@microsoft.com + * \date + * December 06, 2001. + *********************************************************************** + */ +/* gets unsigned double stored in Big Endian Order */ +unsigned long GetBigDoubleWord(FILE *fp) +{ + unsigned long dw; + dw = (unsigned long) (fgetc(fp) & 0xFF); + dw = ((unsigned long) (fgetc(fp) & 0xFF)) | (dw << 0x08); + dw = ((unsigned long) (fgetc(fp) & 0xFF)) | (dw << 0x08); + dw = ((unsigned long) (fgetc(fp) & 0xFF)) | (dw << 0x08); + return(dw); +} + +/*! + *********************************************************************** + * \brief + * Calculates if decoder leaky bucket parameters meets HRD constraints specified by encoder. + * \param p_Inp + * Structure which contains decoder leaky bucket parameters. + * \return + * None + * \par SideEffects + * None. + * \par Notes + * Failure if LeakyBucketParam file is missing or if it does not have + * the correct number of entries. + * \author + * Shankar Regunathan shanre@microsoft.com + * \date + * December 06, 2001. + *********************************************************************** + */ + +/* Main Routine to verify HRD compliance */ +void calc_buffer(InputParameters *p_Inp) +{ + unsigned long NumberLeakyBuckets, *Rmin, *Bmin, *Fmin; + float B_interp, F_interp; + unsigned long iBucket; + float dnr, frac1, frac2; + unsigned long R_decoder, B_decoder, F_decoder; + FILE *outf; + + if ((outf=fopen(p_Inp->LeakyBucketParamFile,"rb"))==NULL) + { + snprintf(errortext, ET_SIZE, "Error open file %s \n",p_Inp->LeakyBucketParamFile); + error(errortext,1); + } + + NumberLeakyBuckets = GetBigDoubleWord(outf); + printf(" Number Leaky Buckets: %8ld \n\n", NumberLeakyBuckets); + Rmin = calloc(NumberLeakyBuckets, sizeof(unsigned long)); + Bmin = calloc(NumberLeakyBuckets, sizeof(unsigned long)); + Fmin = calloc(NumberLeakyBuckets, sizeof(unsigned long)); + + for(iBucket =0; iBucket < NumberLeakyBuckets; iBucket++) + { + Rmin[iBucket] = GetBigDoubleWord(outf); + Bmin[iBucket] = GetBigDoubleWord(outf); + Fmin[iBucket] = GetBigDoubleWord(outf); + printf(" %8ld %8ld %8ld \n", Rmin[iBucket], Bmin[iBucket], Fmin[iBucket]); + } + fclose(outf); + + R_decoder = p_Inp->R_decoder; + F_decoder = p_Inp->F_decoder; + B_decoder = p_Inp->B_decoder; + + for( iBucket =0; iBucket < NumberLeakyBuckets; iBucket++) + { + if(R_decoder < Rmin[iBucket]) + break; + } + + printf("\n"); + if(iBucket > 0 ) + { + if(iBucket < NumberLeakyBuckets) + { + dnr = (float) (Rmin[iBucket] - Rmin[iBucket-1]); + frac1 = (float) (R_decoder - Rmin[iBucket-1]); + frac2 = (float) (Rmin[iBucket] - R_decoder); + B_interp = (float) (Bmin[iBucket] * frac1 + Bmin[iBucket-1] * frac2) /dnr; + F_interp = (float) (Fmin[iBucket] * frac1 + Fmin[iBucket-1] * frac2) /dnr; + } + else { + B_interp = (float) Bmin[iBucket-1]; + F_interp = (float) Fmin[iBucket-1]; + } + printf(" Min.buffer %8.2f Decoder buffer size %ld \n Minimum Delay %8.2f DecoderDelay %ld \n", B_interp, B_decoder, F_interp, F_decoder); + if(B_decoder > B_interp && F_decoder > F_interp) + printf(" HRD Compliant \n"); + else + printf(" HRD Non Compliant \n"); + } + else { // (iBucket = 0) + printf(" Decoder Rate is too small; HRD cannot be verified \n"); + } + + free(Rmin); + free(Bmin); + free(Fmin); + return; +} +#endif diff --git a/ldecod/src/loopFilter.c b/ldecod/src/loopFilter.c new file mode 100644 index 0000000..79dfe32 --- /dev/null +++ b/ldecod/src/loopFilter.c @@ -0,0 +1,664 @@ + +/*! + ************************************************************************************* + * \file loopFilter.c + * + * \brief + * Filter to reduce blocking artifacts on a macroblock level. + * The filter strength is QP dependent. + * + * \author + * Contributors: + * - Peter List Peter.List@t-systems.de: Original code (13-Aug-2001) + * - Jani Lainema Jani.Lainema@nokia.com: Some bug fixing, removal of recursiveness (16-Aug-2001) + * - Peter List Peter.List@t-systems.de: inplace filtering and various simplifications (10-Jan-2002) + * - Anthony Joch anthony@ubvideo.com: Simplified switching between filters and + * non-recursive default filter. (08-Jul-2002) + * - Cristina Gomila cristina.gomila@thomson.net: Simplification of the chroma deblocking + * from JVT-E089 (21-Nov-2002) + * - Alexis Michael Tourapis atour@dolby.com: Speed/Architecture improvements (08-Feb-2007) + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "loopfilter.h" +#include "loop_filter.h" + +static void DeblockMb (VideoParameters *p_Vid, StorablePicture *p, int MbQAddr); +static void perform_db (VideoParameters *p_Vid, StorablePicture *p, int MbQAddr); +static void get_db_strength(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr); + +extern void set_loop_filter_functions_mbaff(VideoParameters *p_Vid); +extern void set_loop_filter_functions_normal(VideoParameters *p_Vid); +extern void deblock_normal(VideoParameters *p_Vid, StorablePicture *p); +extern void get_strength_ver_MBAff (byte *Strength, Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p); +extern void get_strength_hor_MBAff (byte *Strength, Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p); + +#if (JM_PARALLEL_DEBLOCK == 0) +/*! + ***************************************************************************************** + * \brief + * Filter all macroblocks in order of increasing macroblock address. + ***************************************************************************************** + */ +void DeblockPicture(VideoParameters *p_Vid, StorablePicture *p) +{ + unsigned i; + if (p->mb_aff_frame_flag) + { + for (i = 0; i < p->PicSizeInMbs; ++i) + { + if( p_Vid->mb_data[i].is_decoded ) + DeblockMb( p_Vid, p, i ) ; + } + } + else + { + // deblock_normal( p_Vid, p); + + for (i = 0; i < p->PicSizeInMbs; ++i) + { + //if( p_Vid->mb_data[i].is_decoded ) + get_db_strength( p_Vid, p, i ) ; + } + for (i = 0; i < p->PicSizeInMbs; ++i) + { + //if( p_Vid->mb_data[i].is_decoded ) + perform_db( p_Vid, p, i ) ; + } + + } +} +#else +static void DeblockParallel(VideoParameters *p_Vid, StorablePicture *p, unsigned int column, int block, int n_last) +{ + int i, j; + + for (j = 0; j < GROUP_SIZE; j++) + { + i = block++ * (p_Vid->PicWidthInMbs - 2) + column; + + perform_db( p_Vid, p, i ) ; + if (block == n_last) break; + } +} + +/*! + ***************************************************************************************** + * \brief + * Filter all macroblocks in a diagonal manner to enable parallelization. + ***************************************************************************************** + */ +void DeblockPicture(VideoParameters *p_Vid, StorablePicture *p) +{ + int iheightMBs =(p_Vid->PicSizeInMbs/p_Vid->PicWidthInMbs); + unsigned int i, k = p->PicWidthInMbs + 2 * (iheightMBs - 1); + +#if defined(OPENMP) + int j; + #pragma omp parallel for +#endif + for (j = 0; j < p->PicSizeInMbs; ++j) + { + get_db_strength( p_Vid, p, j ) ; + } + + for (i = 0; i < k; i++) + { + int nn; + int n_last = imin(iheightMBs, (i >> 1) + 1); + int n_start = (i < p->PicWidthInMbs) ? 0 : ((i - p->PicWidthInMbs) >> 1) + 1; + +#if defined(OPENMP) + #pragma omp parallel for +#endif + for (nn = n_start; nn < n_last; nn += GROUP_SIZE) + DeblockParallel(p_Vid, p, i, nn, n_last); + } +} +#endif + +// likely already set - see testing via asserts +static void init_neighbors(VideoParameters *p_Vid) +{ + int i, j; + int width = p_Vid->PicWidthInMbs; + int height = p_Vid->PicHeightInMbs; + int size = p_Vid->PicSizeInMbs; + Macroblock *currMB = &p_Vid->mb_data[0]; + // do the top left corner + currMB->mbup = NULL; + currMB->mbleft = NULL; + currMB++; + // do top row + for (i = 1; i < width; i++) + { + currMB->mbup = NULL; + currMB->mbleft = currMB - 1; + currMB++; + } + + // do left edge + for (i = width; i < size; i += width) + { + currMB->mbup = currMB - width; + currMB->mbleft = NULL; + currMB += width; + } + // do all others + for (j = width + 1; j < width * height + 1; j += width) + { + currMB = &p_Vid->mb_data[j]; + for (i = 1; i < width; i++) + { + currMB->mbup = currMB - width; + currMB->mbleft = currMB - 1; + currMB++; + } + } +} + + +void init_Deblock(VideoParameters *p_Vid, int mb_aff_frame_flag) +{ + if(p_Vid->yuv_format == YUV444 && p_Vid->separate_colour_plane_flag) + { + change_plane_JV(p_Vid, PLANE_Y, NULL); + init_neighbors(p_Dec->p_Vid); + change_plane_JV(p_Vid, PLANE_U, NULL); + init_neighbors(p_Dec->p_Vid); + change_plane_JV(p_Vid, PLANE_V, NULL); + init_neighbors(p_Dec->p_Vid); + change_plane_JV(p_Vid, PLANE_Y, NULL); + } + else + init_neighbors(p_Dec->p_Vid); + if (mb_aff_frame_flag == 1) + { + set_loop_filter_functions_mbaff(p_Vid); + } + else + { + set_loop_filter_functions_normal(p_Vid); + } +} + +/*! + ***************************************************************************************** + * \brief + * Deblocking filter for one macroblock. + ***************************************************************************************** + */ + +static void DeblockMb(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + int edge; + + byte Strength[16]; + int64 *p_Strength64 = (int64 *) Strength; + short mb_x, mb_y; + + int filterNon8x8LumaEdgesFlag[4] = {1,1,1,1}; + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + int edge_cr; + + imgpel **imgY = p->imgY; + imgpel ***imgUV = p->imgUV; + Slice *currSlice = MbQ->p_Slice; + int mvlimit = ((p->structure!=FRAME) || (p->mb_aff_frame_flag && MbQ->mb_field)) ? 2 : 4; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->mb_type == I8MB) + assert(MbQ->luma_transform_size_8x8_flag); + + filterNon8x8LumaEdgesFlag[1] = + filterNon8x8LumaEdgesFlag[3] = !(MbQ->luma_transform_size_8x8_flag); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (p->mb_aff_frame_flag && mb_y == MB_BLOCK_SIZE && MbQ->mb_field) + filterTopMbEdgeFlag = 0; + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = (p->mb_aff_frame_flag && !MbQ->mb_field && (MbQAddr & 0x01)) ? 1 : MbQ->mbAvailB; + } + + if (p->mb_aff_frame_flag == 1) + CheckAvailabilityOfNeighborsMBAFF(MbQ); + + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc != YUV444) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P8x16) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + // Strength for 4 blks in 1 stripe + get_strength_ver_MBAff(Strength, MbQ, edge << 2, mvlimit, p); + + if ((p_Strength64[0]) || (p_Strength64[1])) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaVer( PLANE_Y, imgY, Strength, MbQ, edge << 2); + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaVer(PLANE_U, imgUV[0], Strength, MbQ, edge << 2); + p_Vid->EdgeLoopLumaVer(PLANE_V, imgUV[1], Strength, MbQ, edge << 2); + } + } + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaVer( imgUV[0], Strength, MbQ, edge_cr, 0, p); + p_Vid->EdgeLoopChromaVer( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc==YUV420) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + // Strength for 4 blks in 1 stripe + get_strength_hor_MBAff(Strength, MbQ, edge << 2, mvlimit, p); + + if ((p_Strength64[0]) || (p_Strength64[1])) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaHor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, edge << 2, p); + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, edge << 2, p); + } + } + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + + if (!edge && !MbQ->mb_field && MbQ->mixedModeEdgeFlag) //currSlice->mixedModeEdgeFlag) + { + // this is the extra horizontal edge between a frame macroblock pair and a field above it + MbQ->DeblockCall = 2; + get_strength_hor_MBAff(Strength, MbQ, MB_BLOCK_SIZE, mvlimit, p); // Strength for 4 blks in 1 stripe + + //if( *((int*)Strength) ) // only if one of the 4 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + + p_Vid->EdgeLoopLumaHor(PLANE_Y, imgY, Strength, MbQ, MB_BLOCK_SIZE, p) ; + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, p) ; + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, p) ; + } + } + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, 0, p) ; + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, 1, p) ; + } + } + } + MbQ->DeblockCall = 1; + } + } + }//end edge + + MbQ->DeblockCall = 0; + } +} + +/*! + ***************************************************************************************** + * \brief + * Deblocking filter for one macroblock. + ***************************************************************************************** + */ +static void get_db_strength(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + int edge; + + short mb_x, mb_y; + + int filterNon8x8LumaEdgesFlag[4] = {1,1,1,1}; + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + + Slice *currSlice = MbQ->p_Slice; + int mvlimit = ((p->structure!=FRAME) || (p->mb_aff_frame_flag && MbQ->mb_field)) ? 2 : 4; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->mb_type == I8MB) + assert(MbQ->luma_transform_size_8x8_flag); + + filterNon8x8LumaEdgesFlag[1] = + filterNon8x8LumaEdgesFlag[3] = !(MbQ->luma_transform_size_8x8_flag); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (p->mb_aff_frame_flag && mb_y == MB_BLOCK_SIZE && MbQ->mb_field) + filterTopMbEdgeFlag = 0; + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = (p->mb_aff_frame_flag && !MbQ->mb_field && (MbQAddr & 0x01)) ? 1 : MbQ->mbAvailB; + } + + if (p->mb_aff_frame_flag == 1) + CheckAvailabilityOfNeighborsMBAFF(MbQ); + + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc != YUV444) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P8x16) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + // Strength for 4 blks in 1 stripe + p_Vid->GetStrengthVer(MbQ, edge, mvlimit, p); + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc==YUV420) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + p_Vid->GetStrengthHor(MbQ, edge, mvlimit, p); + } + }//end edge + + MbQ->DeblockCall = 0; + } +} + + +static void perform_db(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + int edge; + + short mb_x, mb_y; + + int filterNon8x8LumaEdgesFlag[4] = {1,1,1,1}; + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + int edge_cr; + + imgpel **imgY = p->imgY; + imgpel ***imgUV = p->imgUV; + Slice *currSlice = MbQ->p_Slice; + int mvlimit = ((p->structure!=FRAME) || (p->mb_aff_frame_flag && MbQ->mb_field)) ? 2 : 4; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->mb_type == I8MB) + assert(MbQ->luma_transform_size_8x8_flag); + + filterNon8x8LumaEdgesFlag[1] = + filterNon8x8LumaEdgesFlag[3] = !(MbQ->luma_transform_size_8x8_flag); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (p->mb_aff_frame_flag && mb_y == MB_BLOCK_SIZE && MbQ->mb_field) + filterTopMbEdgeFlag = 0; + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = (p->mb_aff_frame_flag && !MbQ->mb_field && (MbQAddr & 0x01)) ? 1 : MbQ->mbAvailB; + } + + if (p->mb_aff_frame_flag == 1) + CheckAvailabilityOfNeighborsMBAFF(MbQ); + + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc != YUV444) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P8x16) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaVer( PLANE_Y, imgY, Strength, MbQ, edge << 2); + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaVer(PLANE_U, imgUV[0], Strength, MbQ, edge << 2); + p_Vid->EdgeLoopLumaVer(PLANE_V, imgUV[1], Strength, MbQ, edge << 2); + } + } + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaVer( imgUV[0], Strength, MbQ, edge_cr, 0, p); + p_Vid->EdgeLoopChromaVer( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc==YUV420) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int64 *) Strength)) || ((*(((int64 *) Strength) + 1)))) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaHor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, edge << 2, p); + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, edge << 2, p); + } + } + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + + if (!edge && !MbQ->mb_field && MbQ->mixedModeEdgeFlag) //currSlice->mixedModeEdgeFlag) + { + // this is the extra horizontal edge between a frame macroblock pair and a field above it + MbQ->DeblockCall = 2; + p_Vid->GetStrengthHor(MbQ, 4, mvlimit, p); // Strength for 4 blks in 1 stripe + + //if( *((int*)Strength) ) // only if one of the 4 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + + p_Vid->EdgeLoopLumaHor(PLANE_Y, imgY, Strength, MbQ, MB_BLOCK_SIZE, p) ; + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, p) ; + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, p) ; + } + } + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, 0, p) ; + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, 1, p) ; + } + } + } + MbQ->DeblockCall = 1; + } + } + }//end edge + + MbQ->DeblockCall = 0; + } +} + diff --git a/ldecod/src/loop_filter_mbaff.c b/ldecod/src/loop_filter_mbaff.c new file mode 100644 index 0000000..87cbc41 --- /dev/null +++ b/ldecod/src/loop_filter_mbaff.c @@ -0,0 +1,1147 @@ + +/*! + ************************************************************************************* + * \file loop_filter_mbaff.c + * + * \brief + * Filter to reduce blocking artifacts on a macroblock level. + * The filter strength is QP dependent. + * + * \author + * Contributors: + * - Peter List Peter.List@t-systems.de: Original code (13-Aug-2001) + * - Jani Lainema Jani.Lainema@nokia.com: Some bug fixing, removal of recursiveness (16-Aug-2001) + * - Peter List Peter.List@t-systems.de: inplace filtering and various simplifications (10-Jan-2002) + * - Anthony Joch anthony@ubvideo.com: Simplified switching between filters and + * non-recursive default filter. (08-Jul-2002) + * - Cristina Gomila cristina.gomila@thomson.net: Simplification of the chroma deblocking + * from JVT-E089 (21-Nov-2002) + * - Alexis Michael Tourapis atour@dolby.com: Speed/Architecture improvements (08-Feb-2007) + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "loopfilter.h" +#include "loop_filter.h" + +//static void get_strength_ver_MBAff (Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p); +//static void get_strength_hor_MBAff (Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p); +static void edge_loop_luma_ver_MBAff (ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge); +static void edge_loop_luma_hor_MBAff (ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, StorablePicture *p); +static void edge_loop_chroma_ver_MBAff (imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p); +static void edge_loop_chroma_hor_MBAff (imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p); + +void set_loop_filter_functions_mbaff(VideoParameters *p_Vid) +{ + //p_Vid->GetStrengthVer = get_strength_ver_MBAff; + //p_Vid->GetStrengthHor = get_strength_hor_MBAff; + p_Vid->EdgeLoopLumaVer = edge_loop_luma_ver_MBAff; + p_Vid->EdgeLoopLumaHor = edge_loop_luma_hor_MBAff; + p_Vid->EdgeLoopChromaVer = edge_loop_chroma_ver_MBAff; + p_Vid->EdgeLoopChromaHor = edge_loop_chroma_hor_MBAff; +} + + +Macroblock* get_non_aff_neighbor_luma(Macroblock *mb, int xN, int yN) +{ + if (xN < 0) + return(mb->mbleft); + else if (yN < 0) + return(mb->mbup); + else + return(mb); +} + +Macroblock* get_non_aff_neighbor_chroma(Macroblock *mb, int xN, int yN, int block_width,int block_height) +{ + if (xN < 0) + { + if (yN < block_height) + return(mb->mbleft); + else + return(NULL); + } + else if (xN < block_width) + { + if (yN < 0) + return(mb->mbup); + else if (yN < block_height) + return(mb); + else + return(NULL); + } + else + return(NULL); +} + + +/*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for MBAFF) + ********************************************************************************************* + */ +void get_strength_ver_MBAff(byte *Strength, Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p) +{ + //byte *Strength = MbQ->strength_ver[edge]; + short blkP, blkQ, idx; + //short blk_x, blk_x2, blk_y, blk_y2 ; + + int StrValue; + short mb_x, mb_y; + + Macroblock *MbP; + + PixelPos pixP; + VideoParameters *p_Vid = MbQ->p_Vid; + BlockPos *PicPos = p_Vid->PicPos; + + if ((p->slice_type==SP_SLICE)||(p->slice_type==SI_SLICE) ) + { + for( idx = 0; idx < MB_BLOCK_SIZE; ++idx ) + { + getAffNeighbour(MbQ, edge - 1, idx, p_Vid->mb_size[IS_LUMA], &pixP); + blkQ = (short) ((idx & 0xFFFC) + (edge >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + MbQ->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); //currSlice->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + + Strength[idx] = (edge == 0) ? 4 : 3; + } + } + else + { + getAffNeighbour(MbQ, edge - 1, 0, p_Vid->mb_size[IS_LUMA], &pixP); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + // Neighboring Frame MBs + if ((MbQ->mb_field == FALSE && MbP->mb_field == FALSE)) + { + MbQ->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + if (MbQ->is_intra_block == TRUE || MbP->is_intra_block == TRUE) + { + //printf("idx %d %d %d %d %d\n", idx, pixP.x, pixP.y, pixP.pos_x, pixP.pos_y); + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + else + { + get_mb_block_pos_mbaff (PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + for( idx = 0; idx < MB_BLOCK_SIZE; idx += BLOCK_SIZE) + { + blkQ = (short) ((idx & 0xFFFC) + (edge >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + if (((MbQ->s_cbp[0].blk & i64_power2(blkQ)) != 0) || ((MbP->s_cbp[0].blk & i64_power2(blkP)) != 0)) + StrValue = 2; + else if (edge && ((MbQ->mb_type == 1) || (MbQ->mb_type == 2))) + StrValue = 0; // if internal edge of certain types, we already know StrValue should be 0 + else // for everything else, if no coefs, but vector difference >= 1 set Strength=1 + { + int blk_y = ((mb_y<<2) + (blkQ >> 2)); + int blk_x = ((mb_x<<2) + (blkQ & 3)); + int blk_y2 = (pixP.pos_y >> 2); + int blk_x2 = (pixP.pos_x >> 2); + + PicMotionParams *mv_info_p = &p->mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &p->mv_info[blk_y2][blk_x2]; + StorablePicturePtr ref_p0 = mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1))||((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0==ref_q0) + { + StrValue = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)); + } + else + { + StrValue = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit)); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + + StrValue = (byte) (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + &&( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit))); + } + } + else + { + StrValue = 1; + } + } + *(int*)(Strength+idx) = StrValue * 0x01010101; + pixP.y += 4; + pixP.pos_y += 4; + } + } + } + else + { + for( idx = 0; idx < MB_BLOCK_SIZE; ++idx ) + { + getAffNeighbour(MbQ, edge - 1, idx, p_Vid->mb_size[IS_LUMA], &pixP); + blkQ = (short) ((idx & 0xFFFC) + (edge >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + MbQ->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + + // Start with Strength=3. or Strength=4 for Mb-edge + Strength[idx] = (edge == 0 && (((!p->mb_aff_frame_flag && (p->structure==FRAME)) || + (p->mb_aff_frame_flag && !MbP->mb_field && !MbQ->mb_field)) || + ((p->mb_aff_frame_flag || (p->structure!=FRAME))))) ? 4 : 3; + + if (MbQ->is_intra_block == FALSE && MbP->is_intra_block == FALSE) + { + if (((MbQ->s_cbp[0].blk & i64_power2(blkQ)) != 0) || ((MbP->s_cbp[0].blk & i64_power2(blkP)) != 0)) + Strength[idx] = 2 ; + else + { + // if no coefs, but vector difference >= 1 set Strength=1 + // if this is a mixed mode edge then one set of reference pictures will be frame and the + // other will be field + if(MbQ->mixedModeEdgeFlag) //if (currSlice->mixedModeEdgeFlag) + { + Strength[idx] = 1; + } + else + { + get_mb_block_pos_mbaff (PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + { + int blk_y = ((mb_y<<2) + (blkQ >> 2)); + int blk_x = ((mb_x<<2) + (blkQ & 3)); + int blk_y2 = (pixP.pos_y >> 2); + int blk_x2 = (pixP.pos_x >> 2); + + PicMotionParams *mv_info_p = &p->mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &p->mv_info[blk_y2][blk_x2]; + StorablePicturePtr ref_p0 = mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1))||((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + Strength[idx]=0; + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0==ref_q0) + { + Strength[idx] = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)); + } + else + { + Strength[idx] = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit)); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + + Strength[idx] = (byte) (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + &&( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit))); + } + } + else + { + Strength[idx] = 1; + } + } + } + } + } + } + } + } +} + +/*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for MBAFF) + ********************************************************************************************* + */ +void get_strength_hor_MBAff(byte *Strength, Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p) +{ + short blkP, blkQ, idx; + short blk_x, blk_x2, blk_y, blk_y2 ; + + int StrValue; + int xQ, yQ = (edge < MB_BLOCK_SIZE ? edge : 1); + short mb_x, mb_y; + + Macroblock *MbP; + + PixelPos pixP; + VideoParameters *p_Vid = MbQ->p_Vid; + BlockPos *PicPos = p_Vid->PicPos; + + if ((p->slice_type==SP_SLICE)||(p->slice_type==SI_SLICE) ) + { + for( idx = 0; idx < MB_BLOCK_SIZE; idx += BLOCK_SIZE) + { + xQ = idx; + getAffNeighbour(MbQ, xQ, yQ - 1, p_Vid->mb_size[IS_LUMA], &pixP); + + blkQ = (short) ((yQ & 0xFFFC) + (xQ >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + MbQ->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + + StrValue = (edge == 0 && (!MbP->mb_field && !MbQ->mb_field)) ? 4 : 3; + + *(int*)(Strength+idx) = StrValue * 0x01010101; + } + } + else + { + getAffNeighbour(MbQ, 0, yQ - 1, p_Vid->mb_size[IS_LUMA], &pixP); + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + MbQ->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + + // Set intra mode deblocking + if (MbQ->is_intra_block == TRUE || MbP->is_intra_block == TRUE) + { + StrValue = (edge == 0 && (!MbP->mb_field && !MbQ->mb_field)) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + else + { + for( idx = 0; idx < MB_BLOCK_SIZE; idx += BLOCK_SIZE ) + { + xQ = idx; + getAffNeighbour(MbQ, xQ, yQ - 1, p_Vid->mb_size[IS_LUMA], &pixP); + + blkQ = (short) ((yQ & 0xFFFC) + (xQ >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + if (((MbQ->s_cbp[0].blk & i64_power2(blkQ)) != 0) || ((MbP->s_cbp[0].blk & i64_power2(blkP)) != 0)) + { + StrValue = 2; + } + else + { + // if no coefs, but vector difference >= 1 set Strength=1 + // if this is a mixed mode edge then one set of reference pictures will be frame and the + // other will be field + if(MbQ->mixedModeEdgeFlag) //if (currSlice->mixedModeEdgeFlag) + { + StrValue = 1; + } + else + { + get_mb_block_pos_mbaff (PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + blk_y = (short) ((mb_y<<2) + (blkQ >> 2)); + blk_x = (short) ((mb_x<<2) + (blkQ & 3)); + blk_y2 = (short) (pixP.pos_y >> 2); + blk_x2 = (short) (pixP.pos_x >> 2); + + { + PicMotionParams *mv_info_p = &p->mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &p->mv_info[blk_y2][blk_x2]; + StorablePicturePtr ref_p0 = mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || + ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + StrValue = 0; + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0==ref_q0) + { + StrValue = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)); + } + else + { + StrValue = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit)); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + StrValue = (byte) (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + &&( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit))); + } + } + else + { + StrValue = 1; + } + } + } + } + *(int*)(Strength+idx) = StrValue * 0x01010101; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Super MB Frame coded MBs + ***************************************************************************************** + */ +static void edge_loop_luma_ver_MBAff(ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge) +{ + int pel, Strng ; + imgpel L2 = 0, L1, L0, R0, R1, R2 = 0; + int Alpha = 0, Beta = 0 ; + const byte* ClipTab = NULL; + int indexA, indexB; + + int QP; + + PixelPos pixP, pixQ; + + VideoParameters *p_Vid = MbQ->p_Vid; + int bitdepth_scale = pl? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + + Macroblock *MbP; + imgpel *SrcPtrP, *SrcPtrQ; + + if (MbQ->DFDisableIdc == 0) + { + for( pel = 0 ; pel < MB_BLOCK_SIZE ; ++pel ) + { + getAffNeighbour(MbQ, edge - 1, pel, p_Vid->mb_size[IS_LUMA], &pixP); + + if (pixP.available) + { + if( (Strng = Strength[pel]) != 0) + { + getAffNeighbour(MbQ, edge, pel, p_Vid->mb_size[IS_LUMA], &pixQ); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + + SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + // Average QP of the two blocks + QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + Beta = BETA_TABLE [indexB] * bitdepth_scale; + ClipTab = CLIP_TAB[indexA]; + + L0 = SrcPtrP[ 0] ; + R0 = SrcPtrQ[ 0] ; + + if( iabs( R0 - L0 ) < Alpha ) + { + L1 = SrcPtrP[-1]; + R1 = SrcPtrQ[ 1]; + + if ((iabs( R0 - R1) < Beta ) && (iabs(L0 - L1) < Beta )) + { + L2 = SrcPtrP[-2]; + R2 = SrcPtrQ[ 2]; + if(Strng == 4 ) // INTRA strong filtering + { + int RL0 = L0 + R0; + int small_gap = (iabs( R0 - L0 ) < ((Alpha >> 2) + 2)); + int aq = ( iabs( R0 - R2) < Beta ) & small_gap; + int ap = ( iabs( L0 - L2) < Beta ) & small_gap; + + if (ap) + { + int L3 = SrcPtrP[-3]; + SrcPtrP[-2 ] = (imgpel) ((((L3 + L2) << 1) + L2 + L1 + RL0 + 4) >> 3); + SrcPtrP[-1 ] = (imgpel) (( L2 + L1 + L0 + R0 + 2) >> 2); + SrcPtrP[ 0 ] = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + } + else + { + SrcPtrP[ 0 ] = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2) ; + } + + if (aq) + { + imgpel R3 = SrcPtrQ[ 3]; + SrcPtrQ[ 0 ] = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + SrcPtrQ[ 1 ] = (imgpel) (( R2 + R0 + R1 + L0 + 2) >> 2); + SrcPtrQ[ 2 ] = (imgpel) ((((R3 + R2) << 1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + SrcPtrQ[ 0 ] = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + else // normal filtering + { + int RL0 = (L0 + R0 + 1) >> 1; + int aq = (iabs( R0 - R2) < Beta); + int ap = (iabs( L0 - L2) < Beta); + + int C0 = ClipTab[ Strng ] * bitdepth_scale; + int tc0 = (C0 + ap + aq) ; + int dif = iClip3( -tc0, tc0, (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3) ; + + if( ap && (C0 != 0)) + *(SrcPtrP - 1) += iClip3( -C0, C0, ( L2 + RL0 - (L1 << 1)) >> 1 ) ; + + if (dif) + { + *SrcPtrP = (imgpel) iClip1 (max_imgpel_value, L0 + dif) ; + *SrcPtrQ = (imgpel) iClip1 (max_imgpel_value, R0 - dif) ; + } + + if( aq && (C0 != 0)) + *(SrcPtrQ + 1) += iClip3( -C0, C0, ( R2 + RL0 - (R1 << 1)) >> 1 ) ; + } + } + } + } + } + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Super MB Frame coded MBs + ***************************************************************************************** + */ +static void edge_loop_luma_hor_MBAff(ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, + int edge, StorablePicture *p) +{ + int width = p->iLumaStride; //p->size_x; + int pel, Strng ; + int PelNum = pl? pelnum_cr[1][p->chroma_format_idc] : MB_BLOCK_SIZE; + + int yQ = (edge < MB_BLOCK_SIZE ? edge : 1); + + PixelPos pixP, pixQ; + + VideoParameters *p_Vid = MbQ->p_Vid; + int bitdepth_scale = pl? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + getAffNeighbour(MbQ, 0, yQ - 1, p_Vid->mb_size[IS_LUMA], &pixP); + + if (pixP.available || (MbQ->DFDisableIdc == 0)) + { + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + + Macroblock *MbP = &(p_Vid->mb_data[pixP.mb_addr]); + + int incQ = ((MbP->mb_field && !MbQ->mb_field) ? 2 * width : width); + int incP = ((MbQ->mb_field && !MbP->mb_field) ? 2 * width : width); + + // Average QP of the two blocks + int QP = pl? ((MbP->qpc[pl - 1] + MbQ->qpc[pl - 1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta )!= 0) + { + const byte* ClipTab = CLIP_TAB[indexA]; + getAffNeighbour(MbQ, 0, yQ, p_Vid->mb_size[IS_LUMA], &pixQ); + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + if( (Strng = Strength[pel]) != 0) + { + imgpel *SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + imgpel *SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + imgpel L0 = *SrcPtrP; + imgpel R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + imgpel L1 = SrcPtrP[-incP]; + imgpel R1 = SrcPtrQ[ incQ]; + + if ((iabs( R0 - R1) < Beta ) && (iabs(L0 - L1) < Beta )) + { + imgpel L2 = SrcPtrP[-incP*2]; + imgpel R2 = SrcPtrQ[ incQ*2]; + if(Strng == 4 ) // INTRA strong filtering + { + int RL0 = L0 + R0; + int small_gap = (iabs( R0 - L0 ) < ((Alpha >> 2) + 2)); + int aq = ( iabs( R0 - R2) < Beta ) & small_gap; + int ap = ( iabs( L0 - L2) < Beta ) & small_gap; + + if (ap) + { + imgpel L3 = SrcPtrP[-incP*3]; + SrcPtrP[-incP * 2] = (imgpel) ((((L3 + L2) << 1) + L2 + L1 + RL0 + 4) >> 3); + SrcPtrP[-incP ] = (imgpel) (( L2 + L1 + L0 + R0 + 2) >> 2); + SrcPtrP[ 0 ] = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + } + else + { + SrcPtrP[ 0 ] = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2) ; + } + + if (aq) + { + imgpel R3 = SrcPtrQ[ incQ*3]; + SrcPtrQ[ 0 ] = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + SrcPtrQ[ incQ ] = (imgpel) (( R2 + R0 + R1 + L0 + 2) >> 2); + SrcPtrQ[ incQ * 2 ] = (imgpel) ((((R3 + R2) << 1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + SrcPtrQ[ 0 ] = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + else // normal filtering + { + int RL0 = (L0 + R0 + 1) >> 1; + int aq = (iabs( R0 - R2) < Beta); + int ap = (iabs( L0 - L2) < Beta); + + int C0 = ClipTab[ Strng ] * bitdepth_scale; + int tc0 = (C0 + ap + aq) ; + int dif = iClip3( -tc0, tc0, (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3) ; + + if( ap && (C0 != 0)) + *(SrcPtrP - incP) += iClip3( -C0, C0, ( L2 + RL0 - (L1 << 1)) >> 1 ) ; + + if (dif) + { + *SrcPtrP = (imgpel) iClip1 (max_imgpel_value, L0 + dif) ; + *SrcPtrQ = (imgpel) iClip1 (max_imgpel_value, R0 - dif) ; + } + + if( aq && (C0 != 0)) + *(SrcPtrQ + incQ) += iClip3( -C0, C0, ( R2 + RL0 - (R1 << 1)) >> 1 ) ; + } + } + } + } + pixP.pos_x++; + pixQ.pos_x++; + } + } + } +} + + + +/*! +***************************************************************************************** +* \brief +* Filters chroma block edge for MBAFF types +***************************************************************************************** + */ +static void edge_loop_chroma_ver_MBAff(imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p) +{ + int pel, Strng ; + + imgpel L1, L0, R0, R1; + int Alpha = 0, Beta = 0; + const byte* ClipTab = NULL; + int indexA, indexB; + VideoParameters *p_Vid = MbQ->p_Vid; + int PelNum = pelnum_cr[0][p->chroma_format_idc]; + int StrengthIdx; + int QP; + int xQ = edge, yQ; + PixelPos pixP, pixQ; + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + Macroblock *MbP; + imgpel *SrcPtrP, *SrcPtrQ; + + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + yQ = pel; + getAffNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_CHROMA], &pixQ); + getAffNeighbour(MbQ, xQ - 1, yQ, p_Vid->mb_size[IS_CHROMA], &pixP); + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + StrengthIdx = (PelNum == 8) ? ((MbQ->mb_field && !MbP->mb_field) ? pel << 1 :((pel >> 1) << 2) + (pel & 0x01)) : pel; + + if (pixP.available || (MbQ->DFDisableIdc == 0)) + { + if( (Strng = Strength[StrengthIdx]) != 0) + { + SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + // Average QP of the two blocks + QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + Beta = BETA_TABLE [indexB] * bitdepth_scale; + ClipTab = CLIP_TAB[indexA]; + + L0 = *SrcPtrP; + R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + L1 = SrcPtrP[-1]; + R1 = SrcPtrQ[ 1]; + if( ((iabs( R0 - R1) - Beta < 0) && (iabs(L0 - L1) - Beta < 0 )) ) + { + if( Strng == 4 ) // INTRA strong filtering + { + SrcPtrQ[0] = (imgpel) ( ((R1 << 1) + R0 + L1 + 2) >> 2 ); + SrcPtrP[0] = (imgpel) ( ((L1 << 1) + L0 + R1 + 2) >> 2 ); + } + else + { + int C0 = ClipTab[ Strng ] * bitdepth_scale; + int tc0 = (C0 + 1); + int dif = iClip3( -tc0, tc0, ( ((R0 - L0) << 2) + (L1 - R1) + 4) >> 3 ); + + if (dif) + { + *SrcPtrP = (imgpel) iClip1 ( max_imgpel_value, L0 + dif ); + *SrcPtrQ = (imgpel) iClip1 ( max_imgpel_value, R0 - dif ); + } + } + } + } + } + } + } +} + +/*! +***************************************************************************************** +* \brief +* Filters chroma block edge for MBAFF types +***************************************************************************************** + */ +static void edge_loop_chroma_hor_MBAff(imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + int PelNum = pelnum_cr[1][p->chroma_format_idc]; + int yQ = (edge < MB_BLOCK_SIZE? edge : 1); + PixelPos pixP, pixQ; + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + int width = p->iChromaStride; //p->size_x_cr; + + getAffNeighbour(MbQ, 0, yQ - 1, p_Vid->mb_size[IS_CHROMA], &pixP); + getAffNeighbour(MbQ, 0, yQ, p_Vid->mb_size[IS_CHROMA], &pixQ); + + if (pixP.available || (MbQ->DFDisableIdc == 0)) + { + Macroblock *MbP = &(p_Vid->mb_data[pixP.mb_addr]); + + int incQ = ((MbP->mb_field && !MbQ->mb_field) ? 2 * width : width); + int incP = ((MbQ->mb_field && !MbP->mb_field) ? 2 * width : width); + + // Average QP of the two blocks + int QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta )!= 0) + { + const byte* ClipTab = CLIP_TAB[indexA]; + int pel, Strng ; + int StrengthIdx; + for( pel = 0 ; pel < PelNum ; ++pel ) + { + StrengthIdx = (PelNum == 8) ? ((MbQ->mb_field && !MbP->mb_field) ? pel << 1 :((pel >> 1) << 2) + (pel & 0x01)) : pel; + + if( (Strng = Strength[StrengthIdx]) != 0) + { + imgpel *SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + imgpel *SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + imgpel L0 = *SrcPtrP; + imgpel R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + imgpel L1 = SrcPtrP[-incP]; + imgpel R1 = SrcPtrQ[ incQ]; + if( ((iabs( R0 - R1) - Beta < 0) && (iabs(L0 - L1) - Beta < 0 )) ) + { + if( Strng == 4 ) // INTRA strong filtering + { + SrcPtrQ[0] = (imgpel) ( ((R1 << 1) + R0 + L1 + 2) >> 2 ); + SrcPtrP[0] = (imgpel) ( ((L1 << 1) + L0 + R1 + 2) >> 2 ); + } + else + { + int C0 = ClipTab[ Strng ] * bitdepth_scale; + int tc0 = (C0 + 1); + int dif = iClip3( -tc0, tc0, ( ((R0 - L0) << 2) + (L1 - R1) + 4) >> 3 ); + + if (dif) + { + *SrcPtrP = (imgpel) iClip1 ( max_imgpel_value, L0 + dif ); + *SrcPtrQ = (imgpel) iClip1 ( max_imgpel_value, R0 - dif ); + } + } + } + } + } + pixP.pos_x++; + pixQ.pos_x++; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Get Deblocking filter strength for one macroblock. + ***************************************************************************************** + */ +void get_db_strength_mbaff(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + int edge; + + short mb_x, mb_y; + + int filterNon8x8LumaEdgesFlag[4] = {1,1,1,1}; + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + + Slice *currSlice = MbQ->p_Slice; + int mvlimit = ((p->structure!=FRAME) || (p->mb_aff_frame_flag && MbQ->mb_field)) ? 2 : 4; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->mb_type == I8MB) + assert(MbQ->luma_transform_size_8x8_flag); + + filterNon8x8LumaEdgesFlag[1] = + filterNon8x8LumaEdgesFlag[3] = !(MbQ->luma_transform_size_8x8_flag); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (p->mb_aff_frame_flag && mb_y == MB_BLOCK_SIZE && MbQ->mb_field) + filterTopMbEdgeFlag = 0; + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = (p->mb_aff_frame_flag && !MbQ->mb_field && (MbQAddr & 0x01)) ? 1 : MbQ->mbAvailB; + } + + CheckAvailabilityOfNeighborsMBAFF(MbQ); + + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc != YUV444) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P8x16) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + // Strength for 4 blks in 1 stripe + p_Vid->GetStrengthVer(MbQ, edge, mvlimit, p); + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc==YUV420) + continue; + else if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + p_Vid->GetStrengthHor(MbQ, edge, mvlimit, p); + } + }//end edge + + MbQ->DeblockCall = 0; + } +} + + +/*! + ***************************************************************************************** + * \brief + * Performing Deblocking for one macroblock. + ***************************************************************************************** + */ +void perform_db_mbaff(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + int edge; + + short mb_x, mb_y; + + int filterNon8x8LumaEdgesFlag[4] = {1,1,1,1}; + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + int edge_cr; + + imgpel **imgY = p->imgY; + imgpel ***imgUV = p->imgUV; + Slice *currSlice = MbQ->p_Slice; + int mvlimit = ((p->structure!=FRAME) || (p->mb_aff_frame_flag && MbQ->mb_field)) ? 2 : 4; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->mb_type == I8MB) + assert(MbQ->luma_transform_size_8x8_flag); + + filterNon8x8LumaEdgesFlag[1] = + filterNon8x8LumaEdgesFlag[3] = !(MbQ->luma_transform_size_8x8_flag); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (p->mb_aff_frame_flag && mb_y == MB_BLOCK_SIZE && MbQ->mb_field) + filterTopMbEdgeFlag = 0; + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = (p->mb_aff_frame_flag && !MbQ->mb_field && (MbQAddr & 0x01)) ? 1 : MbQ->mbAvailB; + } + + CheckAvailabilityOfNeighborsMBAFF(MbQ); + + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc != YUV444) + continue; + else if (edge > 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P8x16) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int64 *) Strength)) || ((*(((int64 *) Strength) + 1)))) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaVer( PLANE_Y, imgY, Strength, MbQ, edge << 2); + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaVer(PLANE_U, imgUV[0], Strength, MbQ, edge << 2); + p_Vid->EdgeLoopLumaVer(PLANE_V, imgUV[1], Strength, MbQ, edge << 2); + } + } + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaVer( imgUV[0], Strength, MbQ, edge_cr, 0, p); + p_Vid->EdgeLoopChromaVer( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc==YUV420) + continue; + else if (edge > 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int64 *) Strength)) || ((*(((int64 *) Strength) + 1)))) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaHor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, edge << 2, p); + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, edge << 2, p); + } + } + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + + if (!edge && !MbQ->mb_field && MbQ->mixedModeEdgeFlag) //currSlice->mixedModeEdgeFlag) + { + // this is the extra horizontal edge between a frame macroblock pair and a field above it + MbQ->DeblockCall = 2; + p_Vid->GetStrengthHor(MbQ, 4, mvlimit, p); // Strength for 4 blks in 1 stripe + + //if( *((int*)Strength) ) // only if one of the 4 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + + p_Vid->EdgeLoopLumaHor(PLANE_Y, imgY, Strength, MbQ, MB_BLOCK_SIZE, p) ; + if(currSlice->chroma444_not_separate) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, p) ; + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, p) ; + } + } + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, 0, p) ; + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, 1, p) ; + } + } + } + MbQ->DeblockCall = 1; + } + } + }//end edge + + MbQ->DeblockCall = 0; + } +} + diff --git a/ldecod/src/loop_filter_normal.c b/ldecod/src/loop_filter_normal.c new file mode 100644 index 0000000..7fc353b --- /dev/null +++ b/ldecod/src/loop_filter_normal.c @@ -0,0 +1,1576 @@ + +/*! + ************************************************************************************* + * \file loop_filter_normal.c + * + * \brief + * Loop filter to reduce blocking artifacts on a macroblock level (normal). + * The filter strength is QP dependent. + * + * \author + * Contributors: + * - Peter List Peter.List@t-systems.de: Original code (13-Aug-2001) + * - Jani Lainema Jani.Lainema@nokia.com: Some bug fixing, removal of recursiveness (16-Aug-2001) + * - Peter List Peter.List@t-systems.de: inplace filtering and various simplifications (10-Jan-2002) + * - Anthony Joch anthony@ubvideo.com: Simplified switching between filters and + * non-recursive default filter. (08-Jul-2002) + * - Cristina Gomila cristina.gomila@thomson.net: Simplification of the chroma deblocking + * from JVT-E089 (21-Nov-2002) + * - Alexis Michael Tourapis atour@dolby.com: Speed/Architecture improvements (08-Feb-2007) + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "loopfilter.h" +#include "loop_filter.h" + +static void get_strength_ver (Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p); +static void get_strength_hor (Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p); +static void edge_loop_luma_ver (ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge); +static void edge_loop_luma_hor (ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, StorablePicture *p); +static void edge_loop_chroma_ver (imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p); +static void edge_loop_chroma_hor (imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p); + + +void set_loop_filter_functions_normal(VideoParameters *p_Vid) +{ + p_Vid->GetStrengthVer = get_strength_ver; + p_Vid->GetStrengthHor = get_strength_hor; + p_Vid->EdgeLoopLumaVer = edge_loop_luma_ver; + p_Vid->EdgeLoopLumaHor = edge_loop_luma_hor; + p_Vid->EdgeLoopChromaVer = edge_loop_chroma_ver; + p_Vid->EdgeLoopChromaHor = edge_loop_chroma_hor; +} + + +static Macroblock* get_non_aff_neighbor_luma(Macroblock *mb, int xN, int yN) +{ + if (xN < 0) + return(mb->mbleft); + else if (yN < 0) + return(mb->mbup); + else + return(mb); +} + +static Macroblock* get_non_aff_neighbor_chroma(Macroblock *mb, int xN, int yN, int block_width,int block_height) +{ + if (xN < 0) + { + if (yN < block_height) + return(mb->mbleft); + else + return(NULL); + } + else if (xN < block_width) + { + if (yN < 0) + return(mb->mbup); + else if (yN < block_height) + return(mb); + else + return(NULL); + } + else + return(NULL); +} + +#define get_x_luma(x) (x & 15) +#define get_y_luma(y) (y & 15) +#define get_pos_x_luma(mb,x) (mb->pix_x + (x & 15)) +#define get_pos_y_luma(mb,y) (mb->pix_y + (y & 15)) +#define get_pos_x_chroma(mb,x,max) (mb->pix_c_x + (x & max)) +#define get_pos_y_chroma(mb,y,max) (mb->pix_c_y + (y & max)) + + /*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for different Frame or Field types) + ********************************************************************************************* + */ +static void get_strength_ver(Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p) +{ + byte *Strength = MbQ->strength_ver[edge]; + Slice *currSlice = MbQ->p_Slice; + int StrValue; + BlockPos *PicPos = MbQ->p_Vid->PicPos; + + if ((currSlice->slice_type==SP_SLICE)||(currSlice->slice_type==SI_SLICE) ) + { + // Set strength to either 3 or 4 regardless of pixel position + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, BLOCK_SIZE * sizeof(byte)); + } + else + { + if (MbQ->is_intra_block == FALSE) + { + Macroblock *MbP; + int xQ = (edge << 2) - 1; + Macroblock *neighbor = get_non_aff_neighbor_luma(MbQ, xQ, 0); + MbP = (edge) ? MbQ : neighbor; + + if (edge || MbP->is_intra_block == FALSE) + { + if (edge && (currSlice->slice_type == P_SLICE && MbQ->mb_type == PSKIP)) + { + memset(Strength, 0, BLOCK_SIZE * sizeof(byte)); + } + else if (edge && ((MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + { + int blkP, blkQ, idx; + + for( idx = 0 ; idx < MB_BLOCK_SIZE ; idx += BLOCK_SIZE ) + { + blkQ = idx + (edge); + blkP = idx + (get_x_luma(xQ) >> 2); + if ((MbQ->s_cbp[0].blk & (i64_power2(blkQ) | i64_power2(blkP))) != 0) + StrValue = 2; + else + StrValue = 0; // if internal edge of certain types, then we already know StrValue should be 0 + + Strength[idx >> 2] = StrValue; + } + } + else + { + int blkP, blkQ, idx; + BlockPos mb = PicPos[ MbQ->mbAddrX ]; + mb.x <<= BLOCK_SHIFT; + mb.y <<= BLOCK_SHIFT; + + for( idx = 0 ; idx < MB_BLOCK_SIZE ; idx += BLOCK_SIZE ) + { + blkQ = idx + (edge); + blkP = idx + (get_x_luma(xQ) >> 2); + if (((MbQ->s_cbp[0].blk & i64_power2(blkQ)) != 0) || ((MbP->s_cbp[0].blk & i64_power2(blkP)) != 0)) + StrValue = 2; + else // for everything else, if no coefs, but vector difference >= 1 set Strength=1 + { + int blk_y = mb.y + (blkQ >> 2); + int blk_x = mb.x + (blkQ & 3); + int blk_y2 = (short)(get_pos_y_luma(neighbor, 0) + idx) >> 2; + int blk_x2 = (short)(get_pos_x_luma(neighbor, xQ) ) >> 2; + PicMotionParams *mv_info_p = &p->mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &p->mv_info[blk_y2][blk_x2]; + StorablePicturePtr ref_p0 = mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0 == ref_q0) + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit); + } + else + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + StrValue = (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + && ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit) + )); + } + } + else + StrValue = 1; + } + //*(int*)(Strength+(idx >> 2)) = StrValue; // * 0x01010101; + Strength[idx >> 2] = StrValue; + } + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, BLOCK_SIZE * sizeof(byte)); + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, BLOCK_SIZE * sizeof(byte)); + } + } +} + + /*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for different Frame or Field types) + ********************************************************************************************* + */ +static void get_strength_hor(Macroblock *MbQ, int edge, int mvlimit, StorablePicture *p) +{ + byte *Strength = MbQ->strength_hor[edge]; + int StrValue; + Slice *currSlice = MbQ->p_Slice; + BlockPos *PicPos = MbQ->p_Vid->PicPos; + + if ((currSlice->slice_type==SP_SLICE)||(currSlice->slice_type==SI_SLICE) ) + { + // Set strength to either 3 or 4 regardless of pixel position + StrValue = (edge == 0 && (((p->structure==FRAME)))) ? 4 : 3; + memset(Strength, (byte) StrValue, BLOCK_SIZE * sizeof(byte)); + } + else + { + if (MbQ->is_intra_block == FALSE) + { + Macroblock *MbP; + int yQ = (edge < BLOCK_SIZE ? (edge << 2) - 1: 0); + + Macroblock *neighbor = get_non_aff_neighbor_luma(MbQ, 0, yQ); + + MbP = (edge) ? MbQ : neighbor; + + if (edge || MbP->is_intra_block == FALSE) + { + if (edge && (currSlice->slice_type == P_SLICE && MbQ->mb_type == PSKIP)) + { + memset(Strength, 0, BLOCK_SIZE * sizeof(byte)); + } + else if (edge && ((MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + { + int blkP, blkQ, idx; + + for( idx = 0 ; idx < BLOCK_SIZE ; idx ++ ) + { + blkQ = (yQ + 1) + idx; + blkP = (get_y_luma(yQ) & 0xFFFC) + idx; + + if ((MbQ->s_cbp[0].blk & (i64_power2(blkQ) | i64_power2(blkP))) != 0) + StrValue = 2; + else + StrValue = 0; // if internal edge of certain types, we already know StrValue should be 0 + + *(int*)(Strength + idx) = StrValue; + } + } + else + { + int blkP, blkQ, idx; + BlockPos mb = PicPos[ MbQ->mbAddrX ]; + mb.x <<= 2; + mb.y <<= 2; + + for( idx = 0 ; idx < BLOCK_SIZE ; idx ++) + { + blkQ = (yQ + 1) + idx; + blkP = (get_y_luma(yQ) & 0xFFFC) + idx; + + if (((MbQ->s_cbp[0].blk & i64_power2(blkQ)) != 0) || ((MbP->s_cbp[0].blk & i64_power2(blkP)) != 0)) + StrValue = 2; + else // for everything else, if no coefs, but vector difference >= 1 set Strength=1 + { + int blk_y = mb.y + (blkQ >> 2); + int blk_x = mb.x + (blkQ & 3); + int blk_y2 = get_pos_y_luma(neighbor,yQ) >> 2; + int blk_x2 = ((short)(get_pos_x_luma(neighbor,0)) >> 2) + idx; + + PicMotionParams *mv_info_p = &p->mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &p->mv_info[blk_y2][blk_x2]; + + StorablePicturePtr ref_p0 = mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0 == ref_q0) + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit); + } + else + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + StrValue = (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + && ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit) + )); + } + } + else + StrValue = 1; + } + *(int*)(Strength + idx) = StrValue; + } + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0 && (p->structure == FRAME)) ? 4 : 3; + memset(Strength, (byte) StrValue, BLOCK_SIZE * sizeof(byte)); + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0 && (p->structure == FRAME)) ? 4 : 3; + memset(Strength, (byte) StrValue, BLOCK_SIZE * sizeof(byte)); + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Vertical Deblocking with Strength = 4 + ***************************************************************************************** + */ +static void luma_ver_deblock_strong(imgpel **cur_img, int pos_x1, int Alpha, int Beta) +{ + int i; + for( i = 0 ; i < BLOCK_SIZE ; ++i ) + { + imgpel *SrcPtrP = *(cur_img++) + pos_x1; + imgpel *SrcPtrQ = SrcPtrP + 1; + imgpel L0 = *SrcPtrP; + imgpel R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + imgpel R1 = *(SrcPtrQ + 1); + imgpel L1 = *(SrcPtrP - 1); + if ((iabs( R0 - R1) < Beta) && (iabs(L0 - L1) < Beta)) + { + if ((iabs( R0 - L0 ) < ((Alpha >> 2) + 2))) + { + imgpel R2 = *(SrcPtrQ + 2); + imgpel L2 = *(SrcPtrP - 2); + int RL0 = L0 + R0; + + if (( iabs( L0 - L2) < Beta )) + { + imgpel L3 = *(SrcPtrP - 3); + *(SrcPtrP--) = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + *(SrcPtrP--) = (imgpel) (( L2 + L1 + RL0 + 2) >> 2); + *(SrcPtrP ) = (imgpel) ((((L3 + L2) <<1) + L2 + L1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrP = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2); + } + + if (( iabs( R0 - R2) < Beta )) + { + imgpel R3 = *(SrcPtrQ + 3); + *(SrcPtrQ++) = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + *(SrcPtrQ++) = (imgpel) (( R2 + R0 + L0 + R1 + 2) >> 2); + *(SrcPtrQ ) = (imgpel) ((((R3 + R2) <<1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrQ = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + else + { + *SrcPtrP = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2); + *SrcPtrQ = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Vertical Deblocking with Normal Strength + ***************************************************************************************** + */ +static void luma_ver_deblock_normal(imgpel **cur_img, int pos_x1, int Alpha, int Beta, int C0, int max_imgpel_value) +{ + int i; + imgpel *SrcPtrP, *SrcPtrQ; + int edge_diff; + + if (C0 == 0) + { + for( i= 0 ; i < BLOCK_SIZE ; ++i ) + { + SrcPtrP = *(cur_img++) + pos_x1; + SrcPtrQ = SrcPtrP + 1; + edge_diff = *SrcPtrQ - *SrcPtrP; + + if( iabs( edge_diff ) < Alpha ) + { + imgpel *SrcPtrQ1 = SrcPtrQ + 1; + imgpel *SrcPtrP1 = SrcPtrP - 1; + + if ((iabs( *SrcPtrQ - *SrcPtrQ1) < Beta) && (iabs(*SrcPtrP - *SrcPtrP1) < Beta)) + { + imgpel R2 = *(SrcPtrQ1 + 1); + imgpel L2 = *(SrcPtrP1 - 1); + + int aq = (iabs(*SrcPtrQ - R2) < Beta); + int ap = (iabs(*SrcPtrP - L2) < Beta); + + int tc0 = (ap + aq) ; + int dif = iClip3( -tc0, tc0, (((edge_diff) << 2) + (*SrcPtrP1 - *SrcPtrQ1) + 4) >> 3 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1(max_imgpel_value, *SrcPtrP + dif); + *SrcPtrQ = (imgpel) iClip1(max_imgpel_value, *SrcPtrQ - dif); + } + } + } + } + } + else + { + for( i= 0 ; i < BLOCK_SIZE ; ++i ) + { + SrcPtrP = *(cur_img++) + pos_x1; + SrcPtrQ = SrcPtrP + 1; + edge_diff = *SrcPtrQ - *SrcPtrP; + + if( iabs( edge_diff ) < Alpha ) + { + imgpel *SrcPtrQ1 = SrcPtrQ + 1; + imgpel *SrcPtrP1 = SrcPtrP - 1; + + if ((iabs( *SrcPtrQ - *SrcPtrQ1) < Beta) && (iabs(*SrcPtrP - *SrcPtrP1) < Beta)) + { + int RL0 = (*SrcPtrP + *SrcPtrQ + 1) >> 1; + imgpel R2 = *(SrcPtrQ1 + 1); + imgpel L2 = *(SrcPtrP1 - 1); + + int aq = (iabs(*SrcPtrQ - R2) < Beta); + int ap = (iabs(*SrcPtrP - L2) < Beta); + + int tc0 = (C0 + ap + aq) ; + int dif = iClip3( -tc0, tc0, (((edge_diff) << 2) + (*SrcPtrP1 - *SrcPtrQ1) + 4) >> 3 ); + + if( ap ) + *SrcPtrP1 = (imgpel) (*SrcPtrP1 + iClip3( -C0, C0, (L2 + RL0 - (*SrcPtrP1<<1)) >> 1 )); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1(max_imgpel_value, *SrcPtrP + dif); + *SrcPtrQ = (imgpel) iClip1(max_imgpel_value, *SrcPtrQ - dif); + } + + if( aq ) + *SrcPtrQ1 = (imgpel) (*SrcPtrQ1 + iClip3( -C0, C0, (R2 + RL0 - (*SrcPtrQ1<<1)) >> 1 )); + } + } + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Frame or Field coded MBs + ***************************************************************************************** + */ +static void edge_loop_luma_ver(ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + Macroblock *MbP = get_non_aff_neighbor_luma(MbQ, edge - 1, 0); + + if (MbP || (MbQ->DFDisableIdc== 0)) + { + int bitdepth_scale = pl ? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + + // Average QP of the two blocks + int QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + MbQ->DFAlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + MbQ->DFBetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta )!= 0) + { + const byte *ClipTab = CLIP_TAB[indexA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + int pos_x1 = get_pos_x_luma(MbP, (edge - 1)); + imgpel **cur_img = &Img[get_pos_y_luma(MbP, 0)]; + int pel; + + for( pel = 0 ; pel < MB_BLOCK_SIZE ; pel += 4 ) + { + if(*Strength == 4 ) // INTRA strong filtering + { + luma_ver_deblock_strong(cur_img, pos_x1, Alpha, Beta); + } + else if( *Strength != 0) // normal filtering + { + luma_ver_deblock_normal(cur_img, pos_x1, Alpha, Beta, ClipTab[ *Strength ] * bitdepth_scale, max_imgpel_value); + } + cur_img += 4; + Strength ++; + } + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Horizontal Deblocking with Strength = 4 + ***************************************************************************************** + */ +static void luma_hor_deblock_strong(imgpel *imgP, imgpel *imgQ, int width, int Alpha, int Beta) +{ + int pixel; + int inc_dim2 = width * 2; + int inc_dim3 = width * 3; + for( pixel = 0 ; pixel < BLOCK_SIZE ; ++pixel ) + { + imgpel *SrcPtrP = imgP++; + imgpel *SrcPtrQ = imgQ++; + imgpel L0 = *SrcPtrP; + imgpel R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + imgpel L1 = *(SrcPtrP - width); + imgpel R1 = *(SrcPtrQ + width); + + if ((iabs( R0 - R1) < Beta) && (iabs(L0 - L1) < Beta)) + { + if ((iabs( R0 - L0 ) < ((Alpha >> 2) + 2))) + { + imgpel L2 = *(SrcPtrP - inc_dim2); + imgpel R2 = *(SrcPtrQ + inc_dim2); + int RL0 = L0 + R0; + + if (( iabs( L0 - L2) < Beta )) + { + imgpel L3 = *(SrcPtrP - inc_dim3); + *(SrcPtrP ) = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + *(SrcPtrP -= width) = (imgpel) (( L2 + L1 + RL0 + 2) >> 2); + *(SrcPtrP - width) = (imgpel) ((((L3 + L2) <<1) + L2 + L1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrP = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2); + } + + if (( iabs( R0 - R2) < Beta )) + { + imgpel R3 = *(SrcPtrQ + inc_dim3); + *(SrcPtrQ ) = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + *(SrcPtrQ += width ) = (imgpel) (( R2 + R0 + L0 + R1 + 2) >> 2); + *(SrcPtrQ + width ) = (imgpel) ((((R3 + R2) <<1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrQ = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + else + { + *SrcPtrP = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2); + *SrcPtrQ = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Horizontal Deblocking with Strength = 4 + ***************************************************************************************** + */ +static void luma_hor_deblock_normal(imgpel *imgP, imgpel *imgQ, int width, int Alpha, int Beta, int C0, int max_imgpel_value) +{ + int i; + int edge_diff; + int tc0, dif, aq, ap; + + if (C0 == 0) + { + for( i= 0 ; i < BLOCK_SIZE ; ++i ) + { + edge_diff = *imgQ - *imgP; + + if( iabs( edge_diff ) < Alpha ) + { + imgpel *SrcPtrQ1 = imgQ + width; + imgpel *SrcPtrP1 = imgP - width; + + if ((iabs( *imgQ - *SrcPtrQ1) < Beta) && (iabs(*imgP - *SrcPtrP1) < Beta)) + { + imgpel R2 = *(SrcPtrQ1 + width); + imgpel L2 = *(SrcPtrP1 - width); + + aq = (iabs(*imgQ - R2) < Beta); + ap = (iabs(*imgP - L2) < Beta); + + tc0 = (ap + aq) ; + dif = iClip3( -tc0, tc0, (((edge_diff) << 2) + (*SrcPtrP1 - *SrcPtrQ1) + 4) >> 3 ); + + if (dif != 0) + { + *imgP = (imgpel) iClip1(max_imgpel_value, *imgP + dif); + *imgQ = (imgpel) iClip1(max_imgpel_value, *imgQ - dif); + } + } + } + imgP++; + imgQ++; + } + } + else + { + for( i= 0 ; i < BLOCK_SIZE ; ++i ) + { + edge_diff = *imgQ - *imgP; + + if( iabs( edge_diff ) < Alpha ) + { + imgpel *SrcPtrQ1 = imgQ + width; + imgpel *SrcPtrP1 = imgP - width; + + if ((iabs( *imgQ - *SrcPtrQ1) < Beta) && (iabs(*imgP - *SrcPtrP1) < Beta)) + { + int RL0 = (*imgP + *imgQ + 1) >> 1; + imgpel R2 = *(SrcPtrQ1 + width); + imgpel L2 = *(SrcPtrP1 - width); + + aq = (iabs(*imgQ - R2) < Beta); + ap = (iabs(*imgP - L2) < Beta); + + tc0 = (C0 + ap + aq) ; + dif = iClip3( -tc0, tc0, (((edge_diff) << 2) + (*SrcPtrP1 - *SrcPtrQ1) + 4) >> 3 ); + + if( ap ) + *SrcPtrP1 = (imgpel) (*SrcPtrP1 + iClip3( -C0, C0, (L2 + RL0 - (*SrcPtrP1<<1)) >> 1 )); + + if (dif != 0) + { + *imgP = (imgpel) iClip1(max_imgpel_value, *imgP + dif); + *imgQ = (imgpel) iClip1(max_imgpel_value, *imgQ - dif); + } + + if( aq ) + *SrcPtrQ1 = (imgpel) (*SrcPtrQ1 + iClip3( -C0, C0, (R2 + RL0 - (*SrcPtrQ1<<1)) >> 1 )); + } + } + imgP++; + imgQ++; + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Frame or Field coded MBs + ***************************************************************************************** + */ +static void edge_loop_luma_hor(ColorPlane pl, imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, StorablePicture *p) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + int ypos = (edge < MB_BLOCK_SIZE ? edge - 1: 0); + Macroblock *MbP = get_non_aff_neighbor_luma(MbQ, 0, ypos); + + if (MbP || (MbQ->DFDisableIdc== 0)) + { + int bitdepth_scale = pl ? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + + // Average QP of the two blocks + int QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + MbQ->DFAlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + MbQ->DFBetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta )!= 0) + { + const byte *ClipTab = CLIP_TAB[indexA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + int width = p->iLumaStride; //p->size_x; + + imgpel *imgP = &Img[get_pos_y_luma(MbP, ypos)][get_pos_x_luma(MbP, 0)]; + imgpel *imgQ = imgP + width; + int pel; + + for( pel = 0 ; pel < BLOCK_SIZE ; pel++ ) + { + if(*Strength == 4 ) // INTRA strong filtering + { + luma_hor_deblock_strong(imgP, imgQ, width, Alpha, Beta); + } + else if( *Strength != 0) // normal filtering + { + luma_hor_deblock_normal(imgP, imgQ, width, Alpha, Beta, ClipTab[ *Strength ] * bitdepth_scale, max_imgpel_value); + } + imgP += 4; + imgQ += 4; + Strength ++; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters chroma block edge for Frame or Field coded pictures + ***************************************************************************************** + */ +static void edge_loop_chroma_ver(imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + int block_width = p_Vid->mb_cr_size_x; + int block_height = p_Vid->mb_cr_size_y; + int xQ = edge - 1; + int yQ = 0; + + Macroblock *MbP = get_non_aff_neighbor_chroma(MbQ,xQ,yQ,block_width,block_height); + + if (MbP || (MbQ->DFDisableIdc == 0)) + { + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + + // Average QP of the two blocks + int QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta) != 0) + { + const int PelNum = pelnum_cr[0][p->chroma_format_idc]; + const byte *ClipTab = CLIP_TAB[indexA]; + + int pel; + int pos_x1 = get_pos_x_chroma(MbP, xQ, (block_width - 1)); + imgpel **cur_img = &Img[get_pos_y_chroma(MbP,yQ, (block_height - 1))]; + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + int Strng = Strength[(PelNum == 8) ? (pel >> 1) : (pel >> 2)]; + + if( Strng != 0) + { + imgpel *SrcPtrP = *cur_img + pos_x1; + imgpel *SrcPtrQ = SrcPtrP + 1; + int edge_diff = *SrcPtrQ - *SrcPtrP; + + if ( iabs( edge_diff ) < Alpha ) + { + imgpel R1 = *(SrcPtrQ + 1); + if ( iabs(*SrcPtrQ - R1) < Beta ) + { + imgpel L1 = *(SrcPtrP - 1); + if ( iabs(*SrcPtrP - L1) < Beta ) + { + if( Strng == 4 ) // INTRA strong filtering + { + *SrcPtrP = (imgpel) ( ((L1 << 1) + *SrcPtrP + R1 + 2) >> 2 ); + *SrcPtrQ = (imgpel) ( ((R1 << 1) + *SrcPtrQ + L1 + 2) >> 2 ); + } + else + { + int tc0 = ClipTab[ Strng ] * bitdepth_scale + 1; + int dif = iClip3( -tc0, tc0, ( ((edge_diff) << 2) + (L1 - R1) + 4) >> 3 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrP + dif ); + *SrcPtrQ = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrQ - dif ); + } + } + } + } + } + } + cur_img++; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters chroma block edge for Frame or Field coded pictures + ***************************************************************************************** + */ +static void edge_loop_chroma_hor(imgpel** Img, byte *Strength, Macroblock *MbQ, int edge, int uv, StorablePicture *p) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + int block_width = p_Vid->mb_cr_size_x; + int block_height = p_Vid->mb_cr_size_y; + int xQ = 0; + int yQ = (edge < 16 ? edge - 1: 0); + + Macroblock *MbP = get_non_aff_neighbor_chroma(MbQ,xQ,yQ,block_width,block_height); + + if (MbP || (MbQ->DFDisableIdc == 0)) + { + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + int width = p->iChromaStride; //p->size_x_cr; + + // Average QP of the two blocks + int QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta) != 0) + { + const int PelNum = pelnum_cr[1][p->chroma_format_idc]; + const byte *ClipTab = CLIP_TAB[indexA]; + + int pel; + + imgpel *imgP = &Img[get_pos_y_chroma(MbP,yQ, (block_height-1))][get_pos_x_chroma(MbP,xQ, (block_width - 1))]; + imgpel *imgQ = imgP + width ; + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + int Strng = Strength[(PelNum == 8) ? (pel >> 1) : (pel >> 2)]; + + if( Strng != 0) + { + imgpel *SrcPtrP = imgP; + imgpel *SrcPtrQ = imgQ; + int edge_diff = *imgQ - *imgP; + + if ( iabs( edge_diff ) < Alpha ) + { + imgpel R1 = *(SrcPtrQ + width); + if ( iabs(*SrcPtrQ - R1) < Beta ) + { + imgpel L1 = *(SrcPtrP - width); + if ( iabs(*SrcPtrP - L1) < Beta ) + { + if( Strng == 4 ) // INTRA strong filtering + { + *SrcPtrP = (imgpel) ( ((L1 << 1) + *SrcPtrP + R1 + 2) >> 2 ); + *SrcPtrQ = (imgpel) ( ((R1 << 1) + *SrcPtrQ + L1 + 2) >> 2 ); + } + else + { + int tc0 = ClipTab[ Strng ] * bitdepth_scale + 1; + int dif = iClip3( -tc0, tc0, ( ((edge_diff) << 2) + (L1 - R1) + 4) >> 3 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrP + dif ); + *SrcPtrQ = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrQ - dif ); + } + } + } + } + } + } + imgP++; + imgQ++; + } + } + } +} + +static void perform_db_dep_normal(Macroblock *MbQ, StorablePicture *p) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + Slice *currSlice = MbQ->p_Slice; + int edge; + + short mb_x, mb_y; + + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + + imgpel **imgY = p->imgY; + imgpel ***imgUV = p->imgUV; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQ->mbAddrX, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (MbQ->DFDisableIdc == 2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = MbQ->mbAvailB; + } + + if (MbQ->luma_transform_size_8x8_flag) + { + // Vertical deblocking + for (edge = 0; edge < 4 ; edge += 2) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + //if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc != YUV444) + if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, edge << 2); + edge_loop_luma_ver(PLANE_U, imgUV[0], Strength, MbQ, edge << 2); + edge_loop_luma_ver(PLANE_V, imgUV[1], Strength, MbQ, edge << 2); + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; edge += 2 ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + edge_loop_luma_hor(PLANE_U, imgUV[0], Strength, MbQ, edge << 2, p); + edge_loop_luma_hor(PLANE_V, imgUV[1], Strength, MbQ, edge << 2, p); + } + } + }//end edge + } + else + { + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P16x8))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P8x16) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, edge << 2); + edge_loop_luma_ver(PLANE_U, imgUV[0], Strength, MbQ, edge << 2); + edge_loop_luma_ver(PLANE_V, imgUV[1], Strength, MbQ, edge << 2); + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (edge > 0) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + edge_loop_luma_hor(PLANE_U, imgUV[0], Strength, MbQ, edge << 2, p); + edge_loop_luma_hor(PLANE_V, imgUV[1], Strength, MbQ, edge << 2, p); + } + } + }//end edge + } +} + +static void perform_db_ind_normal(Macroblock *MbQ, StorablePicture *p) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + Slice *currSlice = MbQ->p_Slice; + //short mb_x, mb_y; + + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + + imgpel **imgY = p->imgY; + imgpel ***imgUV = p->imgUV; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + MbQ->DeblockCall = 1; + //get_mb_pos (p_Vid, MbQ->mbAddrX, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + filterLeftMbEdgeFlag = (MbQ->pix_x != 0); + filterTopMbEdgeFlag = (MbQ->pix_y != 0); + + if (MbQ->DFDisableIdc == 2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = MbQ->mbAvailB; + } + + if (MbQ->luma_transform_size_8x8_flag) + { + int edge, edge_cr; + + // Vertical deblocking + for (edge = 0; edge < 4 ; edge += 2) + { + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, edge << 2); + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_ver( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_ver( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; edge += 2 ) + { + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_hor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_hor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + } + else + { + if (((MbQ->mb_type == PSKIP) && (currSlice->slice_type == P_SLICE)) || ((MbQ->mb_type == P16x16) && (MbQ->cbp == 0))) + { + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[0]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, 0); + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + if( (imgUV != NULL)) + { + edge_loop_chroma_ver( imgUV[0], Strength, MbQ, 0, 0, p); + edge_loop_chroma_ver( imgUV[1], Strength, MbQ, 0, 1, p); + } + } + } + } + + // horizontal deblocking + + if( filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[0]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, 0, p) ; + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + if( (imgUV != NULL)) + { + edge_loop_chroma_hor( imgUV[0], Strength, MbQ, 0, 0, p); + edge_loop_chroma_hor( imgUV[1], Strength, MbQ, 0, 1, p); + } + } + } + } + } + else if ((MbQ->mb_type == P16x8) && (MbQ->cbp == 0)) + { + int edge, edge_cr; + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[0]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, 0); + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + if (imgUV != NULL) + { + edge_loop_chroma_ver( imgUV[0], Strength, MbQ, 0, 0, p); + edge_loop_chroma_ver( imgUV[1], Strength, MbQ, 0, 1, p); + } + } + } + } + + // horizontal deblocking + for( edge = 0; edge < 4 ; edge += 2) + { + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_hor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_hor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + } + else if ((MbQ->mb_type == P8x16) && (MbQ->cbp == 0)) + { + int edge, edge_cr; + // Vertical deblocking + for (edge = 0; edge < 4 ; edge += 2) + { + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, edge << 2); + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_ver( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_ver( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + if( filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[0]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, 0, p) ; + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + if (imgUV != NULL) + { + edge_loop_chroma_hor( imgUV[0], Strength, MbQ, 0, 0, p); + edge_loop_chroma_hor( imgUV[1], Strength, MbQ, 0, 1, p); + } + } + } + } + } + else if ((currSlice->slice_type == B_SLICE) && (MbQ->mb_type == BSKIP_DIRECT) && (active_sps->direct_8x8_inference_flag) && (MbQ->cbp == 0)) + { + int edge, edge_cr; + // Vertical deblocking + for (edge = 0; edge < 4 ; edge += 2) + { + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, edge << 2); + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_ver( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_ver( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; edge += 2) + { + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_hor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_hor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + } + else + { + int edge, edge_cr; + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + if( edge || filterLeftMbEdgeFlag ) + { + byte *Strength = MbQ->strength_ver[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_ver( PLANE_Y, imgY, Strength, MbQ, edge << 2); + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[0][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_ver( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_ver( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + if( edge || filterTopMbEdgeFlag ) + { + byte *Strength = MbQ->strength_hor[edge]; + + if ((*((int *) Strength))) // only if one of the 16 Strength bytes is != 0 + { + edge_loop_luma_hor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p) ; + + if (active_sps->chroma_format_idc==YUV420 || active_sps->chroma_format_idc==YUV422) + { + edge_cr = chroma_edge[1][edge][p->chroma_format_idc]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + edge_loop_chroma_hor( imgUV[0], Strength, MbQ, edge_cr, 0, p); + edge_loop_chroma_hor( imgUV[1], Strength, MbQ, edge_cr, 1, p); + } + } + } + } + }//end edge + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Deblocking filter for one macroblock. + ***************************************************************************************** + */ +static void perform_db_normal(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + if(MbQ->p_Slice->chroma444_not_separate) + perform_db_dep_normal(MbQ, p); + else + perform_db_ind_normal(MbQ, p); + MbQ->DeblockCall = 0; + } +} + +/*! + ***************************************************************************************** + * \brief + * Get deblocking filter strength parameters. + ***************************************************************************************** + */ +static void get_db_strength_normal(VideoParameters *p_Vid, StorablePicture *p, int MbQAddr, int *piCnt) +{ + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + } + else + { + *piCnt = (*piCnt < 0)? MbQAddr: (*piCnt); + if(MbQ->luma_transform_size_8x8_flag) + { + int filterLeftMbEdgeFlag = (MbQ->pix_x != 0); + int filterTopMbEdgeFlag = (MbQ->pix_y != 0); + + int mvlimit = (p->structure!=FRAME) ? 2 : 4; + + MbQ->DeblockCall = 1; + //get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = MbQ->mbAvailB; + } + + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + get_strength_ver(MbQ, 0, mvlimit, p); + get_strength_ver(MbQ, 2, mvlimit, p); + + // horizontal deblocking + if( filterTopMbEdgeFlag ) + get_strength_hor(MbQ, 0, mvlimit, p); + get_strength_hor(MbQ, 2, mvlimit, p); + } + else + { + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + + Slice *currSlice = MbQ->p_Slice; + int mvlimit = (p->structure!=FRAME) ? 2 : 4; + + MbQ->DeblockCall = 1; + //get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + filterLeftMbEdgeFlag = (MbQ->pix_x != 0); + filterTopMbEdgeFlag = (MbQ->pix_y != 0); + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = MbQ->mbAvailB; + } + + if ((currSlice->slice_type == P_SLICE && MbQ->mb_type == PSKIP) || ((MbQ->mb_type == P16x16) && (MbQ->cbp == 0))) + { + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + get_strength_ver(MbQ, 0, mvlimit, p); + + // horizontal deblocking + if( filterTopMbEdgeFlag ) + get_strength_hor(MbQ, 0, mvlimit, p); + } + else if ((MbQ->mb_type == P16x8) && (MbQ->cbp == 0)) + { + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + get_strength_ver(MbQ, 0, mvlimit, p); + + // horizontal deblocking + if( filterTopMbEdgeFlag ) + get_strength_hor(MbQ, 0, mvlimit, p); + get_strength_hor(MbQ, 2, mvlimit, p); + } + else if ((MbQ->mb_type == P8x16) && (MbQ->cbp == 0)) + { + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + get_strength_ver(MbQ, 0, mvlimit, p); + get_strength_ver(MbQ, 2, mvlimit, p); + + // horizontal deblocking + if( filterTopMbEdgeFlag ) + get_strength_hor(MbQ, 0, mvlimit, p); + } + else if ((currSlice->slice_type == B_SLICE) && (MbQ->mb_type == BSKIP_DIRECT) && (p_Vid->active_sps->direct_8x8_inference_flag) && (MbQ->cbp == 0)) + { + // Vertical + if( filterLeftMbEdgeFlag ) + get_strength_ver(MbQ, 0, mvlimit, p); + get_strength_ver(MbQ, 2, mvlimit, p); + + // Horizontal + if( filterTopMbEdgeFlag ) + get_strength_hor(MbQ, 0, mvlimit, p); + get_strength_hor(MbQ, 2, mvlimit, p); + } + else + { + // Vertical deblocking + if( filterLeftMbEdgeFlag ) + get_strength_ver(MbQ, 0, mvlimit, p); + get_strength_ver(MbQ, 1, mvlimit, p); + get_strength_ver(MbQ, 2, mvlimit, p); + get_strength_ver(MbQ, 3, mvlimit, p); + + // Horizontal deblocking + if( filterTopMbEdgeFlag ) + get_strength_hor(MbQ, 0, mvlimit, p); + get_strength_hor(MbQ, 1, mvlimit, p); + get_strength_hor(MbQ, 2, mvlimit, p); + get_strength_hor(MbQ, 3, mvlimit, p); + } + } + MbQ->DeblockCall = 0; + } +} + + +void deblock_normal(VideoParameters *p_Vid, StorablePicture *p) +{ + unsigned int i; + int j=-1; + for (i = 0; i < p->PicSizeInMbs; ++i) + { + get_db_strength_normal( p_Vid, p, i, &j) ; + } + for (i = 0; i < p->PicSizeInMbs; ++i) + { + perform_db_normal( p_Vid, p, i ) ; + } +} diff --git a/ldecod/src/macroblock.c b/ldecod/src/macroblock.c new file mode 100644 index 0000000..026466e --- /dev/null +++ b/ldecod/src/macroblock.c @@ -0,0 +1,1494 @@ +/*! + *********************************************************************** + * \file macroblock.c + * + * \brief + * Decode a Macroblock + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langøy + * - Rickard Sjoberg + * - Jani Lainema + * - Sebastian Purreiter + * - Thomas Wedi + * - Detlev Marpe + * - Gabi Blaettermann + * - Ye-Kui Wang + * - Lowell Winger + * - Alexis Michael Tourapis + *********************************************************************** +*/ + +#include "contributors.h" + +#include + +#include "block.h" +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_mvc.h" +#include "elements.h" +//#include "errorconcealment.h" +#include "macroblock.h" +#include "fmo.h" +#include "cabac.h" +#include "vlc.h" +#include "image.h" +#include "mb_access.h" +#include "biaridecod.h" +#include "transform.h" +#include "mc_prediction.h" +#include "quant.h" +#include "mv_prediction.h" +#include "mb_prediction.h" +#include "fast_memory.h" +#include "filehandle.h" + + +#if TRACE +#define TRACE_STRING(s) strncpy(currSE.tracestring, s, TRACESTRING_SIZE) +#define TRACE_DECBITS(i) dectracebitcnt(1) +#define TRACE_printf(s) sprintf(type, "%s", s); +#define TRACE_STRING_P(s) strncpy(currSE->tracestring, s, TRACESTRING_SIZE) +#else +#define TRACE_STRING(s) +#define TRACE_DECBITS(i) +#define TRACE_printf(s) +#define TRACE_STRING_P(s) +#endif + +//! look up tables for FRExt_chroma support +void dectracebitcnt(int count); + + +extern void setup_read_macroblock (Slice *currSlice); +extern void set_read_CBP_and_coeffs_cabac (Slice *currSlice); +extern void set_read_CBP_and_coeffs_cavlc (Slice *currSlice); +extern void read_coeff_4x4_CAVLC (Macroblock *currMB, int block_type, int i, int j, int levarr[16], int runarr[16], int *number_coefficients); +extern void read_coeff_4x4_CAVLC_444 (Macroblock *currMB, int block_type, int i, int j, int levarr[16], int runarr[16], int *number_coefficients); + +static void read_motion_info_from_NAL_p_slice (Macroblock *currMB); +static void read_motion_info_from_NAL_b_slice (Macroblock *currMB); + +static int decode_one_component_i_slice (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +static int decode_one_component_p_slice (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +static int decode_one_component_b_slice (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +static int decode_one_component_sp_slice (Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture); +extern void update_direct_types (Slice *currSlice); +extern void set_intra_prediction_modes (Slice *currSlice); + +/*! + ************************************************************************ + * \brief + * Set context for reference frames + ************************************************************************ + */ +static inline int BType2CtxRef (int btype) +{ + return (btype >= 4); +} + +/*! + ************************************************************************ + * \brief + * Function for reading the reference picture indices using VLC + ************************************************************************ + */ +static char readRefPictureIdx_VLC(Macroblock *currMB, SyntaxElement *currSE, DataPartition *dP, char b8mode, int list) +{ +#if TRACE + trace_info(currSE, "ref_idx_l", list); +#endif + currSE->context = BType2CtxRef (b8mode); + currSE->value2 = list; + dP->readSyntaxElement (currMB, currSE, dP); + return (char) currSE->value1; +} + +/*! + ************************************************************************ + * \brief + * Function for reading the reference picture indices using FLC + ************************************************************************ + */ +static char readRefPictureIdx_FLC(Macroblock *currMB, SyntaxElement *currSE, DataPartition *dP, char b8mode, int list) +{ +#if TRACE + trace_info(currSE, "ref_idx_l", list); +#endif + + currSE->context = BType2CtxRef (b8mode); + currSE->len = 1; + readSyntaxElement_FLC(currSE, dP->bitstream); + currSE->value1 = 1 - currSE->value1; + + return (char) currSE->value1; +} + +/*! + ************************************************************************ + * \brief + * Dummy Function for reading the reference picture indices + ************************************************************************ + */ +static char readRefPictureIdx_Null(Macroblock *currMB, SyntaxElement *currSE, DataPartition *dP, char b8mode, int list) +{ + return 0; +} + +/*! + ************************************************************************ + * \brief + * Function to prepare reference picture indice function pointer + ************************************************************************ + */ +static void prepareListforRefIdx ( Macroblock *currMB, SyntaxElement *currSE, DataPartition *dP, int num_ref_idx_active, int refidx_present) +{ + if(num_ref_idx_active > 1) + { + if (currMB->p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + { + currSE->mapping = linfo_ue; + if (refidx_present) + currMB->readRefPictureIdx = (num_ref_idx_active == 2) ? readRefPictureIdx_FLC : readRefPictureIdx_VLC; + else + currMB->readRefPictureIdx = readRefPictureIdx_Null; + } + else + { + currSE->reading = readRefFrame_CABAC; + currMB->readRefPictureIdx = (refidx_present) ? readRefPictureIdx_VLC : readRefPictureIdx_Null; + } + } + else + currMB->readRefPictureIdx = readRefPictureIdx_Null; +} + +void set_chroma_qp(Macroblock* currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currMB->p_Slice->dec_picture; + int i; + + for (i=0; i<2; ++i) + { + currMB->qpc[i] = iClip3 ( -p_Vid->bitdepth_chroma_qp_scale, 51, currMB->qp + dec_picture->chroma_qp_offset[i] ); + currMB->qpc[i] = currMB->qpc[i] < 0 ? currMB->qpc[i] : QP_SCALE_CR[currMB->qpc[i]]; + currMB->qp_scaled[i + 1] = currMB->qpc[i] + p_Vid->bitdepth_chroma_qp_scale; + } +} + +/*! +************************************************************************ +* \brief +* updates chroma QP according to luma QP and bit depth +************************************************************************ +*/ +void update_qp(Macroblock *currMB, int qp) +{ + VideoParameters *p_Vid = currMB->p_Vid; + currMB->qp = qp; + currMB->qp_scaled[0] = qp + p_Vid->bitdepth_luma_qp_scale; + set_chroma_qp(currMB); + currMB->is_lossless = (Boolean) ((currMB->qp_scaled[0] == 0) && (p_Vid->lossless_qpprime_flag == 1)); +} + +void read_delta_quant(SyntaxElement *currSE, DataPartition *dP, Macroblock *currMB, const byte *partMap, int type) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + currSE->type = type; + + dP = &(currSlice->partArr[partMap[currSE->type]]); + + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + { + currSE->mapping = linfo_se; + } + else + currSE->reading= read_dQuant_CABAC; + + TRACE_STRING_P("mb_qp_delta"); + + dP->readSyntaxElement(currMB, currSE, dP); + currMB->delta_quant = (short) currSE->value1; + if ((currMB->delta_quant < -(26 + p_Vid->bitdepth_luma_qp_scale/2)) || (currMB->delta_quant > (25 + p_Vid->bitdepth_luma_qp_scale/2))) + { + printf("mb_qp_delta is out of range (%d)\n", currMB->delta_quant); + currMB->delta_quant = iClip3(-(26 + p_Vid->bitdepth_luma_qp_scale/2), (25 + p_Vid->bitdepth_luma_qp_scale/2), currMB->delta_quant); + + //error ("mb_qp_delta is out of range", 500); + } + + currSlice->qp = ((currSlice->qp + currMB->delta_quant + 52 + 2*p_Vid->bitdepth_luma_qp_scale)%(52+p_Vid->bitdepth_luma_qp_scale)) - p_Vid->bitdepth_luma_qp_scale; + update_qp(currMB, currSlice->qp); +} + +/*! + ************************************************************************ + * \brief + * Function to read reference picture indice values + ************************************************************************ + */ +static void readMBRefPictureIdx (SyntaxElement *currSE, DataPartition *dP, Macroblock *currMB, PicMotionParams **mv_info, int list, int step_v0, int step_h0) +{ + if (currMB->mb_type == 1) + { + if ((currMB->b8pdir[0] == list || currMB->b8pdir[0] == BI_PRED)) + { + int j, i; + char refframe; + + + currMB->subblock_x = 0; + currMB->subblock_y = 0; + refframe = currMB->readRefPictureIdx(currMB, currSE, dP, 1, list); + for (j = 0; j < step_v0; ++j) + { + char *ref_idx = &mv_info[j][currMB->block_x].ref_idx[list]; + // for (i = currMB->block_x; i < currMB->block_x + step_h0; ++i) + for (i = 0; i < step_h0; ++i) + { + //mv_info[j][i].ref_idx[list] = refframe; + *ref_idx = refframe; + ref_idx += sizeof(PicMotionParams); + } + } + } + } + else if (currMB->mb_type == 2) + { + int k, j, i, j0; + char refframe; + + for (j0 = 0; j0 < 4; j0 += step_v0) + { + k = j0; + + if ((currMB->b8pdir[k] == list || currMB->b8pdir[k] == BI_PRED)) + { + currMB->subblock_y = j0 << 2; + currMB->subblock_x = 0; + refframe = currMB->readRefPictureIdx(currMB, currSE, dP, currMB->b8mode[k], list); + for (j = j0; j < j0 + step_v0; ++j) + { + char *ref_idx = &mv_info[j][currMB->block_x].ref_idx[list]; + // for (i = currMB->block_x; i < currMB->block_x + step_h0; ++i) + for (i = 0; i < step_h0; ++i) + { + //mv_info[j][i].ref_idx[list] = refframe; + *ref_idx = refframe; + ref_idx += sizeof(PicMotionParams); + } + } + } + } + } + else if (currMB->mb_type == 3) + { + int k, j, i, i0; + char refframe; + + currMB->subblock_y = 0; + for (i0 = 0; i0 < 4; i0 += step_h0) + { + k = (i0 >> 1); + + if ((currMB->b8pdir[k] == list || currMB->b8pdir[k] == BI_PRED) && currMB->b8mode[k] != 0) + { + currMB->subblock_x = i0 << 2; + refframe = currMB->readRefPictureIdx(currMB, currSE, dP, currMB->b8mode[k], list); + for (j = 0; j < step_v0; ++j) + { + char *ref_idx = &mv_info[j][currMB->block_x + i0].ref_idx[list]; + // for (i = currMB->block_x; i < currMB->block_x + step_h0; ++i) + for (i = 0; i < step_h0; ++i) + { + //mv_info[j][i].ref_idx[list] = refframe; + *ref_idx = refframe; + ref_idx += sizeof(PicMotionParams); + } + } + } + } + } + else + { + int k, j, i, j0, i0; + char refframe; + + for (j0 = 0; j0 < 4; j0 += step_v0) + { + currMB->subblock_y = j0 << 2; + for (i0 = 0; i0 < 4; i0 += step_h0) + { + k = 2 * (j0 >> 1) + (i0 >> 1); + + if ((currMB->b8pdir[k] == list || currMB->b8pdir[k] == BI_PRED) && currMB->b8mode[k] != 0) + { + currMB->subblock_x = i0 << 2; + refframe = currMB->readRefPictureIdx(currMB, currSE, dP, currMB->b8mode[k], list); + for (j = j0; j < j0 + step_v0; ++j) + { + char *ref_idx = &mv_info[j][currMB->block_x + i0].ref_idx[list]; + //PicMotionParams *mvinfo = mv_info[j] + currMB->block_x + i0; + for (i = 0; i < step_h0; ++i) + { + //(mvinfo++)->ref_idx[list] = refframe; + *ref_idx = refframe; + ref_idx += sizeof(PicMotionParams); + } + } + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Function to read reference picture indice values + ************************************************************************ + */ +static void readMBMotionVectors (SyntaxElement *currSE, DataPartition *dP, Macroblock *currMB, int list, int step_h0, int step_v0) +{ + if (currMB->mb_type == 1) + { + if ((currMB->b8pdir[0] == list || currMB->b8pdir[0]== BI_PRED))//has forward vector + { + int i4, j4, ii, jj; + short curr_mvd[2]; + MotionVector pred_mv, curr_mv; + short (*mvd)[4][2]; + //VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **mv_info = currMB->p_Slice->dec_picture->mv_info; + PixelPos block[4]; // neighbor blocks + + currMB->subblock_x = 0; // position used for context determination + currMB->subblock_y = 0; // position used for context determination + i4 = currMB->block_x; + j4 = currMB->block_y; + mvd = &currMB->mvd [list][0]; + + get_neighbors(currMB, block, 0, 0, step_h0 << 2); + + // first get MV predictor + currMB->GetMVPredictor (currMB, block, &pred_mv, mv_info[j4][i4].ref_idx[list], mv_info, list, 0, 0, step_h0 << 2, step_v0 << 2); + + // X component +#if TRACE + trace_info(currSE, "mvd0_l", list); +#endif + currSE->value2 = list; // identifies the component; only used for context determination + dP->readSyntaxElement(currMB, currSE, dP); + curr_mvd[0] = (short) currSE->value1; + + // Y component +#if TRACE + trace_info(currSE, "mvd1_l", list); +#endif + currSE->value2 += 2; // identifies the component; only used for context determination + dP->readSyntaxElement(currMB, currSE, dP); + curr_mvd[1] = (short) currSE->value1; + + curr_mv.mv_x = (short)(curr_mvd[0] + pred_mv.mv_x); // compute motion vector x + curr_mv.mv_y = (short)(curr_mvd[1] + pred_mv.mv_y); // compute motion vector y + + for(jj = j4; jj < j4 + step_v0; ++jj) + { + PicMotionParams *mvinfo = mv_info[jj] + i4; + for(ii = i4; ii < i4 + step_h0; ++ii) + { + (mvinfo++)->mv[list] = curr_mv; + } + } + + // Init first line (mvd) + for(ii = 0; ii < step_h0; ++ii) + { + //*((int *) &mvd[0][ii][0]) = *((int *) curr_mvd); + mvd[0][ii][0] = curr_mvd[0]; + mvd[0][ii][1] = curr_mvd[1]; + } + + // now copy all other lines + for(jj = 1; jj < step_v0; ++jj) + { + memcpy(mvd[jj][0], mvd[0][0], 2 * step_h0 * sizeof(short)); + } + } + } + else + { + int i4, j4, ii, jj; + short curr_mvd[2]; + MotionVector pred_mv, curr_mv; + short (*mvd)[4][2]; + //VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **mv_info = currMB->p_Slice->dec_picture->mv_info; + PixelPos block[4]; // neighbor blocks + + int i, j, i0, j0, kk, k; + for (j0=0; j0<4; j0+=step_v0) + { + for (i0=0; i0<4; i0+=step_h0) + { + kk = 2 * (j0 >> 1) + (i0 >> 1); + + if ((currMB->b8pdir[kk] == list || currMB->b8pdir[kk]== BI_PRED) && (currMB->b8mode[kk] != 0))//has forward vector + { + char cur_ref_idx = mv_info[currMB->block_y+j0][currMB->block_x+i0].ref_idx[list]; + int mv_mode = currMB->b8mode[kk]; + int step_h = BLOCK_STEP [mv_mode][0]; + int step_v = BLOCK_STEP [mv_mode][1]; + int step_h4 = step_h << 2; + int step_v4 = step_v << 2; + + for (j = j0; j < j0 + step_v0; j += step_v) + { + currMB->subblock_y = j << 2; // position used for context determination + j4 = currMB->block_y + j; + mvd = &currMB->mvd [list][j]; + + for (i = i0; i < i0 + step_h0; i += step_h) + { + currMB->subblock_x = i << 2; // position used for context determination + i4 = currMB->block_x + i; + + get_neighbors(currMB, block, BLOCK_SIZE * i, BLOCK_SIZE * j, step_h4); + + // first get MV predictor + currMB->GetMVPredictor (currMB, block, &pred_mv, cur_ref_idx, mv_info, list, BLOCK_SIZE * i, BLOCK_SIZE * j, step_h4, step_v4); + + for (k=0; k < 2; ++k) + { +#if TRACE + trace_info(currSE, "mvd_l", list); +#endif + currSE->value2 = (k << 1) + list; // identifies the component; only used for context determination + dP->readSyntaxElement(currMB, currSE, dP); + curr_mvd[k] = (short) currSE->value1; + } + + curr_mv.mv_x = (short)(curr_mvd[0] + pred_mv.mv_x); // compute motion vector + curr_mv.mv_y = (short)(curr_mvd[1] + pred_mv.mv_y); // compute motion vector + + for(jj = j4; jj < j4 + step_v; ++jj) + { + PicMotionParams *mvinfo = mv_info[jj] + i4; + for(ii = i4; ii < i4 + step_h; ++ii) + { + (mvinfo++)->mv[list] = curr_mv; + } + } + + // Init first line (mvd) + for(ii = i; ii < i + step_h; ++ii) + { + //*((int *) &mvd[0][ii][0]) = *((int *) curr_mvd); + mvd[0][ii][0] = curr_mvd[0]; + mvd[0][ii][1] = curr_mvd[1]; + } + + // now copy all other lines + for(jj = 1; jj < step_v; ++jj) + { + memcpy(&mvd[jj][i][0], &mvd[0][i][0], 2 * step_h * sizeof(short)); + } + } + } + } + } + } + } +} + +void invScaleCoeff(Macroblock *currMB, int level, int run, int qp_per, int i, int j, int i0, int j0, int coef_ctr, const byte (*pos_scan4x4)[2], int (*InvLevelScale4x4)[4]) +{ + if (level != 0) /* leave if level == 0 */ + { + coef_ctr += run + 1; + + i0 = pos_scan4x4[coef_ctr][0]; + j0 = pos_scan4x4[coef_ctr][1]; + + currMB->s_cbp[0].blk |= i64_power2((j << 2) + i) ; + currMB->p_Slice->cof[0][(j<<2) + j0][(i<<2) + i0]= rshift_rnd_sf((level * InvLevelScale4x4[j0][i0]) << qp_per, 4); + } +} + +static inline void setup_mb_pos_info(Macroblock *currMB) +{ + int mb_x = currMB->mb.x; + int mb_y = currMB->mb.y; + currMB->block_x = mb_x << BLOCK_SHIFT; /* horizontal block position */ + currMB->block_y = mb_y << BLOCK_SHIFT; /* vertical block position */ + currMB->block_y_aff = currMB->block_y; /* interlace relative vertical position */ + currMB->pix_x = mb_x << MB_BLOCK_SHIFT; /* horizontal luma pixel position */ + currMB->pix_y = mb_y << MB_BLOCK_SHIFT; /* vertical luma pixel position */ + currMB->pix_c_x = mb_x * currMB->p_Vid->mb_cr_size_x; /* horizontal chroma pixel position */ + currMB->pix_c_y = mb_y * currMB->p_Vid->mb_cr_size_y; /* vertical chroma pixel position */ +} + +/*! + ************************************************************************ + * \brief + * initializes the current macroblock + ************************************************************************ + */ +void start_macroblock(Slice *currSlice, Macroblock **currMB) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + int mb_nr = currSlice->current_mb_nr; + + *currMB = &currSlice->mb_data[mb_nr]; + + (*currMB)->p_Slice = currSlice; + (*currMB)->p_Vid = p_Vid; + (*currMB)->mbAddrX = mb_nr; + + //assert (mb_nr < (int) p_Vid->PicSizeInMbs); + + /* Update coordinates of the current macroblock */ + if (currSlice->mb_aff_frame_flag) + { + (*currMB)->mb.x = (short) ( (mb_nr) % ((2*p_Vid->width) / MB_BLOCK_SIZE)); + (*currMB)->mb.y = (short) (2*((mb_nr) / ((2*p_Vid->width) / MB_BLOCK_SIZE))); + + (*currMB)->mb.y += ((*currMB)->mb.x & 0x01); + (*currMB)->mb.x >>= 1; + } + else + { + (*currMB)->mb = p_Vid->PicPos[mb_nr]; + } + + /* Define pixel/block positions */ + setup_mb_pos_info(*currMB); + + // reset intra mode + (*currMB)->is_intra_block = FALSE; + // reset mode info + (*currMB)->mb_type = 0; + (*currMB)->delta_quant = 0; + (*currMB)->cbp = 0; + (*currMB)->c_ipred_mode = DC_PRED_8; + + // Save the slice number of this macroblock. When the macroblock below + // is coded it will use this to decide if prediction for above is possible + (*currMB)->slice_nr = (short) currSlice->current_slice_nr; + + CheckAvailabilityOfNeighbors(*currMB); + + // Select appropriate MV predictor function + init_motion_vector_prediction(*currMB, currSlice->mb_aff_frame_flag); + + set_read_and_store_CBP(currMB, currSlice->active_sps->chroma_format_idc); + + // Reset syntax element entries in MB struct + + if (currSlice->slice_type != I_SLICE) + { + if (currSlice->slice_type != B_SLICE) + fast_memset((*currMB)->mvd[0][0][0], 0, MB_BLOCK_PARTITIONS * 2 * sizeof(short)); + else + fast_memset((*currMB)->mvd[0][0][0], 0, 2 * MB_BLOCK_PARTITIONS * 2 * sizeof(short)); + } + + fast_memset((*currMB)->s_cbp, 0, 3 * sizeof(CBPStructure)); + + // initialize currSlice->mb_rres + if (currSlice->is_reset_coeff == FALSE) + { + fast_memset_zero( currSlice->mb_rres[0][0], MB_PIXELS * sizeof(int)); + fast_memset_zero( currSlice->mb_rres[1][0], p_Vid->mb_cr_size * sizeof(int)); + fast_memset_zero( currSlice->mb_rres[2][0], p_Vid->mb_cr_size * sizeof(int)); + if (currSlice->is_reset_coeff_cr == FALSE) + { + fast_memset_zero( currSlice->cof[0][0], 3 * MB_PIXELS * sizeof(int)); + currSlice->is_reset_coeff_cr = TRUE; + } + else + { + fast_memset_zero( currSlice->cof[0][0], MB_PIXELS * sizeof(int)); + } + //fast_memset_zero( currSlice->cof[0][0], MB_PIXELS * sizeof(int)); + //fast_memset_zero( currSlice->cof[1][0], p_Vid->mb_cr_size * sizeof(int)); + //fast_memset_zero( currSlice->cof[2][0], p_Vid->mb_cr_size * sizeof(int)); + + //fast_memset(currSlice->fcf[0][0], 0, MB_PIXELS * sizeof(int)); // reset luma coeffs + //fast_memset(currSlice->fcf[1][0], 0, MB_PIXELS * sizeof(int)); + //fast_memset(currSlice->fcf[2][0], 0, MB_PIXELS * sizeof(int)); + + currSlice->is_reset_coeff = TRUE; + } + + // store filtering parameters for this MB + (*currMB)->DFDisableIdc = currSlice->DFDisableIdc; + (*currMB)->DFAlphaC0Offset = currSlice->DFAlphaC0Offset; + (*currMB)->DFBetaOffset = currSlice->DFBetaOffset; + (*currMB)->list_offset = 0; + (*currMB)->mixedModeEdgeFlag = 0; +} + +/*! + ************************************************************************ + * \brief + * set coordinates of the next macroblock + * check end_of_slice condition + ************************************************************************ + */ +Boolean exit_macroblock(Slice *currSlice, int eos_bit) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + + //! The if() statement below resembles the original code, which tested + //! p_Vid->current_mb_nr == p_Vid->PicSizeInMbs. Both is, of course, nonsense + //! In an error prone environment, one can only be sure to have a new + //! picture by checking the tr of the next slice header! + +// printf ("exit_macroblock: FmoGetLastMBOfPicture %d, p_Vid->current_mb_nr %d\n", FmoGetLastMBOfPicture(), p_Vid->current_mb_nr); + ++(currSlice->num_dec_mb); + + if(currSlice->current_mb_nr == p_Vid->PicSizeInMbs - 1) //if (p_Vid->num_dec_mb == p_Vid->PicSizeInMbs) + { + return TRUE; + } + // ask for last mb in the slice CAVLC + else + { + + currSlice->current_mb_nr = FmoGetNextMBNr (p_Vid, currSlice->current_mb_nr); + + if (currSlice->current_mb_nr == -1) // End of Slice group, MUST be end of slice + { + assert (currSlice->nal_startcode_follows (currSlice, eos_bit) == TRUE); + return TRUE; + } + + if(currSlice->nal_startcode_follows(currSlice, eos_bit) == FALSE) + return FALSE; + + if(currSlice->slice_type == I_SLICE || currSlice->slice_type == SI_SLICE || p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CABAC) + return TRUE; + if(currSlice->cod_counter <= 0) + return TRUE; + return FALSE; + } +} + +/*! + ************************************************************************ + * \brief + * Interpret the mb mode for P-Frames + ************************************************************************ + */ +static void interpret_mb_mode_P(Macroblock *currMB) +{ + static const short ICBPTAB[6] = {0,16,32,15,31,47}; + short mbmode = currMB->mb_type; + + if(mbmode < 4) + { + currMB->mb_type = mbmode; + memset(currMB->b8mode, mbmode, 4 * sizeof(char)); + memset(currMB->b8pdir, 0, 4 * sizeof(char)); + } + else if((mbmode == 4 || mbmode == 5)) + { + currMB->mb_type = P8x8; + currMB->p_Slice->allrefzero = (mbmode == 5); + } + else if(mbmode == 6) + { + currMB->is_intra_block = TRUE; + currMB->mb_type = I4MB; + memset(currMB->b8mode, IBLOCK, 4 * sizeof(char)); + memset(currMB->b8pdir, -1, 4 * sizeof(char)); + } + else if(mbmode == 31) + { + currMB->is_intra_block = TRUE; + currMB->mb_type = IPCM; + currMB->cbp = -1; + currMB->i16mode = 0; + + memset(currMB->b8mode, 0, 4 * sizeof(char)); + memset(currMB->b8pdir,-1, 4 * sizeof(char)); + } + else + { + currMB->is_intra_block = TRUE; + currMB->mb_type = I16MB; + currMB->cbp = ICBPTAB[((mbmode-7))>>2]; + currMB->i16mode = ((mbmode-7)) & 0x03; + memset(currMB->b8mode, 0, 4 * sizeof(char)); + memset(currMB->b8pdir,-1, 4 * sizeof(char)); + } +} + +/*! + ************************************************************************ + * \brief + * Interpret the mb mode for I-Frames + ************************************************************************ + */ +static void interpret_mb_mode_I(Macroblock *currMB) +{ + static const short ICBPTAB[6] = {0,16,32,15,31,47}; + short mbmode = currMB->mb_type; + + if (mbmode == 0) + { + currMB->is_intra_block = TRUE; + currMB->mb_type = I4MB; + memset(currMB->b8mode,IBLOCK,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + } + else if(mbmode == 25) + { + currMB->is_intra_block = TRUE; + currMB->mb_type=IPCM; + currMB->cbp= -1; + currMB->i16mode = 0; + + memset(currMB->b8mode, 0,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + } + else + { + currMB->is_intra_block = TRUE; + currMB->mb_type = I16MB; + currMB->cbp= ICBPTAB[(mbmode-1)>>2]; + currMB->i16mode = (mbmode-1) & 0x03; + memset(currMB->b8mode, 0, 4 * sizeof(char)); + memset(currMB->b8pdir,-1, 4 * sizeof(char)); + } +} + +/*! + ************************************************************************ + * \brief + * Interpret the mb mode for B-Frames + ************************************************************************ + */ +static void interpret_mb_mode_B(Macroblock *currMB) +{ + static const char offset2pdir16x16[12] = {0, 0, 1, 2, 0,0,0,0,0,0,0,0}; + static const char offset2pdir16x8[22][2] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,1},{0,0},{0,1},{0,0},{1,0}, + {0,0},{0,2},{0,0},{1,2},{0,0},{2,0},{0,0},{2,1},{0,0},{2,2},{0,0}}; + static const char offset2pdir8x16[22][2] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,1},{0,0},{0,1},{0,0}, + {1,0},{0,0},{0,2},{0,0},{1,2},{0,0},{2,0},{0,0},{2,1},{0,0},{2,2}}; + + static const char ICBPTAB[6] = {0,16,32,15,31,47}; + + short i, mbmode; + short mbtype = currMB->mb_type; + + //--- set mbtype, b8type, and b8pdir --- + if (mbtype == 0) // direct + { + mbmode=0; + memset(currMB->b8mode, 0, 4 * sizeof(char)); + memset(currMB->b8pdir, 2, 4 * sizeof(char)); + } + else if (mbtype == 23) // intra4x4 + { + currMB->is_intra_block = TRUE; + mbmode=I4MB; + memset(currMB->b8mode, IBLOCK,4 * sizeof(char)); + memset(currMB->b8pdir, -1,4 * sizeof(char)); + } + else if ((mbtype > 23) && (mbtype < 48) ) // intra16x16 + { + currMB->is_intra_block = TRUE; + mbmode=I16MB; + memset(currMB->b8mode, 0, 4 * sizeof(char)); + memset(currMB->b8pdir, -1, 4 * sizeof(char)); + + currMB->cbp = (int) ICBPTAB[(mbtype-24)>>2]; + currMB->i16mode = (mbtype-24) & 0x03; + } + else if (mbtype == 22) // 8x8(+split) + { + mbmode=P8x8; // b8mode and pdir is transmitted in additional codewords + } + else if (mbtype < 4) // 16x16 + { + mbmode = 1; + memset(currMB->b8mode, 1,4 * sizeof(char)); + memset(currMB->b8pdir, offset2pdir16x16[mbtype], 4 * sizeof(char)); + } + else if(mbtype == 48) + { + currMB->is_intra_block = TRUE; + mbmode=IPCM; + memset(currMB->b8mode, 0,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + + currMB->cbp= -1; + currMB->i16mode = 0; + } + else if ((mbtype & 0x01) == 0) // 16x8 + { + mbmode = 2; + memset(currMB->b8mode, 2,4 * sizeof(char)); + for(i=0;i<4;++i) + { + currMB->b8pdir[i] = offset2pdir16x8 [mbtype][i>>1]; + } + } + else + { + mbmode=3; + memset(currMB->b8mode, 3,4 * sizeof(char)); + for(i=0;i<4; ++i) + { + currMB->b8pdir[i] = offset2pdir8x16 [mbtype][i&0x01]; + } + } + currMB->mb_type = mbmode; +} + +/*! + ************************************************************************ + * \brief + * Interpret the mb mode for SI-Frames + ************************************************************************ + */ +static void interpret_mb_mode_SI(Macroblock *currMB) +{ + //VideoParameters *p_Vid = currMB->p_Vid; + const int ICBPTAB[6] = {0,16,32,15,31,47}; + short mbmode = currMB->mb_type; + + if (mbmode == 0) + { + currMB->is_intra_block = TRUE; + currMB->mb_type = SI4MB; + memset(currMB->b8mode,IBLOCK,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + currMB->p_Slice->siblock[currMB->mb.y][currMB->mb.x]=1; + } + else if (mbmode == 1) + { + currMB->is_intra_block = TRUE; + currMB->mb_type = I4MB; + memset(currMB->b8mode,IBLOCK,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + } + else if(mbmode == 26) + { + currMB->is_intra_block = TRUE; + currMB->mb_type=IPCM; + currMB->cbp= -1; + currMB->i16mode = 0; + memset(currMB->b8mode,0,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + } + + else + { + currMB->is_intra_block = TRUE; + currMB->mb_type = I16MB; + currMB->cbp= ICBPTAB[(mbmode-2)>>2]; + currMB->i16mode = (mbmode-2) & 0x03; + memset(currMB->b8mode,0,4 * sizeof(char)); + memset(currMB->b8pdir,-1,4 * sizeof(char)); + } +} + + +/*! + ************************************************************************ + * \brief + * Set mode interpretation based on slice type + ************************************************************************ + */ +void setup_slice_methods(Slice *currSlice) +{ + setup_read_macroblock (currSlice); + switch (currSlice->slice_type) + { + case P_SLICE: + currSlice->interpret_mb_mode = interpret_mb_mode_P; + currSlice->read_motion_info_from_NAL = read_motion_info_from_NAL_p_slice; + currSlice->decode_one_component = decode_one_component_p_slice; + currSlice->update_direct_mv_info = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->init_lists = currSlice->view_id ? init_lists_p_slice_mvc : init_lists_p_slice; +#else + currSlice->init_lists = init_lists_p_slice; +#endif + break; + case SP_SLICE: + currSlice->interpret_mb_mode = interpret_mb_mode_P; + currSlice->read_motion_info_from_NAL = read_motion_info_from_NAL_p_slice; + currSlice->decode_one_component = decode_one_component_sp_slice; + currSlice->update_direct_mv_info = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->init_lists = currSlice->view_id ? init_lists_p_slice_mvc : init_lists_p_slice; +#else + currSlice->init_lists = init_lists_p_slice; +#endif + break; + case B_SLICE: + currSlice->interpret_mb_mode = interpret_mb_mode_B; + currSlice->read_motion_info_from_NAL = read_motion_info_from_NAL_b_slice; + currSlice->decode_one_component = decode_one_component_b_slice; + update_direct_types(currSlice); +#if (MVC_EXTENSION_ENABLE) + currSlice->init_lists = currSlice->view_id ? init_lists_b_slice_mvc : init_lists_b_slice; +#else + currSlice->init_lists = init_lists_b_slice; +#endif + break; + case I_SLICE: + currSlice->interpret_mb_mode = interpret_mb_mode_I; + currSlice->read_motion_info_from_NAL = NULL; + currSlice->decode_one_component = decode_one_component_i_slice; + currSlice->update_direct_mv_info = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->init_lists = currSlice->view_id ? init_lists_i_slice_mvc : init_lists_i_slice; +#else + currSlice->init_lists = init_lists_i_slice; +#endif + break; + case SI_SLICE: + currSlice->interpret_mb_mode = interpret_mb_mode_SI; + currSlice->read_motion_info_from_NAL = NULL; + currSlice->decode_one_component = decode_one_component_i_slice; + currSlice->update_direct_mv_info = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->init_lists = currSlice->view_id ? init_lists_i_slice_mvc : init_lists_i_slice; +#else + currSlice->init_lists = init_lists_i_slice; +#endif + break; + default: + printf("Unsupported slice type\n"); + break; + } + + set_intra_prediction_modes(currSlice); + + if ( currSlice->p_Vid->active_sps->chroma_format_idc==YUV444 && (currSlice->p_Vid->separate_colour_plane_flag == 0) ) + currSlice->read_coeff_4x4_CAVLC = read_coeff_4x4_CAVLC_444; + else + currSlice->read_coeff_4x4_CAVLC = read_coeff_4x4_CAVLC; + + switch(currSlice->p_Vid->active_pps->entropy_coding_mode_flag) + { + case CABAC: + set_read_CBP_and_coeffs_cabac(currSlice); + break; + case CAVLC: + set_read_CBP_and_coeffs_cavlc(currSlice); + break; + default: + printf("Unsupported entropy coding mode\n"); + break; + } +} + + +/*! + ************************************************************************ + * \brief + * Get current block spatial neighbors + ************************************************************************ + */ +void get_neighbors(Macroblock *currMB, // <-- current Macroblock + PixelPos *block, // <--> neighbor blocks + int mb_x, // <-- block x position + int mb_y, // <-- block y position + int blockshape_x // <-- block width + ) +{ + int *mb_size = currMB->p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, mb_x - 1, mb_y , mb_size, block ); + get4x4Neighbour(currMB, mb_x, mb_y - 1, mb_size, block + 1); + get4x4Neighbour(currMB, mb_x + blockshape_x, mb_y - 1, mb_size, block + 2); + + if (mb_y > 0) + { + if (mb_x < 8) // first column of 8x8 blocks + { + if (mb_y == 8 ) + { + if (blockshape_x == MB_BLOCK_SIZE) + block[2].available = 0; + } + else if (mb_x + blockshape_x == 8) + { + block[2].available = 0; + } + } + else if (mb_x + blockshape_x == MB_BLOCK_SIZE) + { + block[2].available = 0; + } + } + + if (!block[2].available) + { + get4x4Neighbour(currMB, mb_x - 1, mb_y - 1, mb_size, block + 3); + block[2] = block[3]; + } +} + +/*! + ************************************************************************ + * \brief + * Read motion info + ************************************************************************ + */ +static void read_motion_info_from_NAL_p_slice (Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + SyntaxElement currSE; + DataPartition *dP = NULL; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + short partmode = ((currMB->mb_type == P8x8) ? 4 : currMB->mb_type); + int step_h0 = BLOCK_STEP [partmode][0]; + int step_v0 = BLOCK_STEP [partmode][1]; + + int j4; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParams *mv_info = NULL; + + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + PicMotionParams **p_mv_info = &dec_picture->mv_info[currMB->block_y]; + + //===== READ REFERENCE PICTURE INDICES ===== + currSE.type = SE_REFFRAME; + dP = &(currSlice->partArr[partMap[SE_REFFRAME]]); + + // For LIST_0, if multiple ref. pictures, read LIST_0 reference picture indices for the MB *********** + prepareListforRefIdx (currMB, &currSE, dP, currSlice->num_ref_idx_active[LIST_0], (currMB->mb_type != P8x8) || (!currSlice->allrefzero)); + readMBRefPictureIdx (&currSE, dP, currMB, p_mv_info, LIST_0, step_v0, step_h0); + + //===== READ MOTION VECTORS ===== + currSE.type = SE_MVD; + dP = &(currSlice->partArr[partMap[SE_MVD]]); + + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + currSE.mapping = linfo_se; + else + currSE.reading = currSlice->mb_aff_frame_flag ? read_mvd_CABAC_mbaff : read_MVD_CABAC; + + // LIST_0 Motion vectors + readMBMotionVectors (&currSE, dP, currMB, LIST_0, step_h0, step_v0); + + // record reference picture Ids for deblocking decisions + for(j4 = 0; j4 < 4;++j4) + { + mv_info = &p_mv_info[j4][currMB->block_x]; + mv_info->ref_pic[LIST_0] = list0[(short) mv_info->ref_idx[LIST_0]]; + mv_info++; + mv_info->ref_pic[LIST_0] = list0[(short) mv_info->ref_idx[LIST_0]]; + mv_info++; + mv_info->ref_pic[LIST_0] = list0[(short) mv_info->ref_idx[LIST_0]]; + mv_info++; + mv_info->ref_pic[LIST_0] = list0[(short) mv_info->ref_idx[LIST_0]]; + } +} + + +/*! +************************************************************************ +* \brief +* Read motion info +************************************************************************ +*/ +static void read_motion_info_from_NAL_b_slice (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + SyntaxElement currSE; + DataPartition *dP = NULL; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int partmode = ((currMB->mb_type == P8x8) ? 4 : currMB->mb_type); + int step_h0 = BLOCK_STEP [partmode][0]; + int step_v0 = BLOCK_STEP [partmode][1]; + + int j4, i4; + + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + PicMotionParams **p_mv_info = &dec_picture->mv_info[currMB->block_y]; + + if (currMB->mb_type == P8x8) + currSlice->update_direct_mv_info(currMB); + + //===== READ REFERENCE PICTURE INDICES ===== + currSE.type = SE_REFFRAME; + dP = &(currSlice->partArr[partMap[SE_REFFRAME]]); + + // For LIST_0, if multiple ref. pictures, read LIST_0 reference picture indices for the MB *********** + prepareListforRefIdx (currMB, &currSE, dP, currSlice->num_ref_idx_active[LIST_0], TRUE); + readMBRefPictureIdx (&currSE, dP, currMB, p_mv_info, LIST_0, step_v0, step_h0); + + // For LIST_1, if multiple ref. pictures, read LIST_1 reference picture indices for the MB *********** + prepareListforRefIdx (currMB, &currSE, dP, currSlice->num_ref_idx_active[LIST_1], TRUE); + readMBRefPictureIdx (&currSE, dP, currMB, p_mv_info, LIST_1, step_v0, step_h0); + + //===== READ MOTION VECTORS ===== + currSE.type = SE_MVD; + dP = &(currSlice->partArr[partMap[SE_MVD]]); + + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + currSE.mapping = linfo_se; + else + currSE.reading = currSlice->mb_aff_frame_flag ? read_mvd_CABAC_mbaff : read_MVD_CABAC; + + // LIST_0 Motion vectors + readMBMotionVectors (&currSE, dP, currMB, LIST_0, step_h0, step_v0); + // LIST_1 Motion vectors + readMBMotionVectors (&currSE, dP, currMB, LIST_1, step_h0, step_v0); + + // record reference picture Ids for deblocking decisions + + for(j4 = 0; j4 < 4; ++j4) + { + for(i4 = currMB->block_x; i4 < (currMB->block_x + 4); ++i4) + { + PicMotionParams *mv_info = &p_mv_info[j4][i4]; + short ref_idx = mv_info->ref_idx[LIST_0]; + + mv_info->ref_pic[LIST_0] = (ref_idx >= 0) ? list0[ref_idx] : NULL; + ref_idx = mv_info->ref_idx[LIST_1]; + mv_info->ref_pic[LIST_1] = (ref_idx >= 0) ? list1[ref_idx] : NULL; + } + } +} + + +/*! + ************************************************************************ + * \brief + * Data partitioning: Check if neighboring macroblock is needed for + * CAVLC context decoding, and disable current MB if data partition + * is missing. + ************************************************************************ + */ +void check_dp_neighbors (Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos up, left; + + p_Vid->getNeighbour(currMB, -1, 0, p_Vid->mb_size[1], &left); + p_Vid->getNeighbour(currMB, 0, -1, p_Vid->mb_size[1], &up); + + if ((currMB->is_intra_block == FALSE) || (!(p_Vid->active_pps->constrained_intra_pred_flag)) ) + { + if (left.available) + { + currMB->dpl_flag |= p_Vid->mb_data[left.mb_addr].dpl_flag; + } + if (up.available) + { + currMB->dpl_flag |= p_Vid->mb_data[up.mb_addr].dpl_flag; + } + } +} + + +/*! + ************************************************************************ + * \brief + * decode one color component in an I slice + ************************************************************************ + */ + +static int decode_one_component_i_slice(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + //For residual DPCM + currMB->ipmode_DPCM = NO_INTRA_PMODE; + if(currMB->mb_type == IPCM) + mb_pred_ipcm(currMB); + else if (currMB->mb_type==I16MB) + mb_pred_intra16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == I4MB) + mb_pred_intra4x4(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == I8MB) + mb_pred_intra8x8(currMB, curr_plane, currImg, dec_picture); + + return 1; +} + +/*! + ************************************************************************ + * \brief + * decode one color component for a p slice + ************************************************************************ + */ +static int decode_one_component_p_slice(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + //For residual DPCM + currMB->ipmode_DPCM = NO_INTRA_PMODE; + if(currMB->mb_type == IPCM) + mb_pred_ipcm(currMB); + else if (currMB->mb_type==I16MB) + mb_pred_intra16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == I4MB) + mb_pred_intra4x4(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == I8MB) + mb_pred_intra8x8(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == PSKIP) + mb_pred_skip(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == P16x16) + mb_pred_p_inter16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P16x8) + mb_pred_p_inter16x8(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P8x16) + mb_pred_p_inter8x16(currMB, curr_plane, dec_picture); + else + mb_pred_p_inter8x8(currMB, curr_plane, dec_picture); + + return 1; +} + + +/*! + ************************************************************************ + * \brief + * decode one color component for a sp slice + ************************************************************************ + */ +static int decode_one_component_sp_slice(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + //For residual DPCM + currMB->ipmode_DPCM = NO_INTRA_PMODE; + + if (currMB->mb_type == IPCM) + mb_pred_ipcm(currMB); + else if (currMB->mb_type==I16MB) + mb_pred_intra16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == I4MB) + mb_pred_intra4x4(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == I8MB) + mb_pred_intra8x8(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == PSKIP) + mb_pred_sp_skip(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P16x16) + mb_pred_p_inter16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P16x8) + mb_pred_p_inter16x8(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P8x16) + mb_pred_p_inter8x16(currMB, curr_plane, dec_picture); + else + mb_pred_p_inter8x8(currMB, curr_plane, dec_picture); + + return 1; +} + + + +/*! + ************************************************************************ + * \brief + * decode one color component for a b slice + ************************************************************************ + */ + +static int decode_one_component_b_slice(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + //For residual DPCM + currMB->ipmode_DPCM = NO_INTRA_PMODE; + + if(currMB->mb_type == IPCM) + mb_pred_ipcm(currMB); + else if (currMB->mb_type==I16MB) + mb_pred_intra16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == I4MB) + mb_pred_intra4x4(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == I8MB) + mb_pred_intra8x8(currMB, curr_plane, currImg, dec_picture); + else if (currMB->mb_type == P16x16) + mb_pred_p_inter16x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P16x8) + mb_pred_p_inter16x8(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == P8x16) + mb_pred_p_inter8x16(currMB, curr_plane, dec_picture); + else if (currMB->mb_type == BSKIP_DIRECT) + { + Slice *currSlice = currMB->p_Slice; + //! Edited by Joao Carreira + currMB->p_Vid->n_SKIP++; + if (currSlice->direct_spatial_mv_pred_flag == 0) + { + if (currSlice->active_sps->direct_8x8_inference_flag) + mb_pred_b_d8x8temporal (currMB, curr_plane, currImg, dec_picture); + else + mb_pred_b_d4x4temporal (currMB, curr_plane, currImg, dec_picture); + } + else + { + if (currSlice->active_sps->direct_8x8_inference_flag) + mb_pred_b_d8x8spatial (currMB, curr_plane, currImg, dec_picture); + else + mb_pred_b_d4x4spatial (currMB, curr_plane, currImg, dec_picture); + } + } + else + mb_pred_b_inter8x8 (currMB, curr_plane, dec_picture); + + return 1; +} + +// probably a better way (or place) to do this, but I'm not sure what (where) it is [CJV] +// this is intended to make get_block_luma faster, but I'm still performing +// this at the MB level, and it really should be done at the slice level +static void init_cur_imgy(VideoParameters *p_Vid,Slice *currSlice,int pl) +{ + int i,j; + if ((p_Vid->separate_colour_plane_flag == 0)) + { + StorablePicture *vidref = p_Vid->no_reference_picture; + int noref = (currSlice->framepoc < p_Vid->recovery_poc); + if (pl==PLANE_Y) + { + for (j = 0; j < 6; j++) // for (j = 0; j < (currSlice->slice_type==B_SLICE?2:1); j++) + { + for (i = 0; i < currSlice->listXsize[j] ; i++) + { + StorablePicture *curr_ref = currSlice->listX[j][i]; + if (curr_ref) + { + curr_ref->no_ref = noref && (curr_ref == vidref); + curr_ref->cur_imgY = curr_ref->imgY; + } + } + } + } + else + { + for (j = 0; j < 6; j++) //for (j = 0; j < (currSlice->slice_type==B_SLICE?2:1); j++) + { + for (i = 0; i < currSlice->listXsize[j]; i++) + { + StorablePicture *curr_ref = currSlice->listX[j][i]; + if (curr_ref) + { + curr_ref->no_ref = noref && (curr_ref == vidref); + curr_ref->cur_imgY = curr_ref->imgUV[pl-1]; + } + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * decode one macroblock + ************************************************************************ + */ + +int decode_one_macroblock(Macroblock *currMB, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + // macroblock decoding ************************************************** + if (currSlice->chroma444_not_separate) + { + if (!currMB->is_intra_block) + { + init_cur_imgy(p_Vid, currSlice, PLANE_Y); + currSlice->decode_one_component(currMB, PLANE_Y, dec_picture->imgY, dec_picture); + init_cur_imgy(p_Vid, currSlice, PLANE_U); + currSlice->decode_one_component(currMB, PLANE_U, dec_picture->imgUV[0], dec_picture); + init_cur_imgy(p_Vid, currSlice, PLANE_V); + currSlice->decode_one_component(currMB, PLANE_V, dec_picture->imgUV[1], dec_picture); + } + else + { + currSlice->decode_one_component(currMB, PLANE_Y, dec_picture->imgY, dec_picture); + currSlice->decode_one_component(currMB, PLANE_U, dec_picture->imgUV[0], dec_picture); + currSlice->decode_one_component(currMB, PLANE_V, dec_picture->imgUV[1], dec_picture); + } + currSlice->is_reset_coeff = FALSE; + currSlice->is_reset_coeff_cr = FALSE; + } + else + { + currSlice->decode_one_component(currMB, PLANE_Y, dec_picture->imgY, dec_picture); + } + + return 0; +} + + +/*! + ************************************************************************ + * \brief + * change target plane + * for 4:4:4 Independent mode + ************************************************************************ + */ +void change_plane_JV( VideoParameters *p_Vid, int nplane, Slice *pSlice) +{ + //Slice *currSlice = p_Vid->currentSlice; + //p_Vid->colour_plane_id = nplane; + p_Vid->mb_data = p_Vid->mb_data_JV[nplane]; + p_Vid->dec_picture = p_Vid->dec_picture_JV[nplane]; + p_Vid->siblock = p_Vid->siblock_JV[nplane]; + p_Vid->ipredmode = p_Vid->ipredmode_JV[nplane]; + p_Vid->intra_block = p_Vid->intra_block_JV[nplane]; + if(pSlice) + { + pSlice->mb_data = p_Vid->mb_data_JV[nplane]; + pSlice->dec_picture = p_Vid->dec_picture_JV[nplane]; + pSlice->siblock = p_Vid->siblock_JV[nplane]; + pSlice->ipredmode = p_Vid->ipredmode_JV[nplane]; + pSlice->intra_block = p_Vid->intra_block_JV[nplane]; + } +} + +/*! + ************************************************************************ + * \brief + * make frame picture from each plane data + * for 4:4:4 Independent mode + ************************************************************************ + */ +void make_frame_picture_JV(VideoParameters *p_Vid) +{ + int uv, line; + int nsize; + p_Vid->dec_picture = p_Vid->dec_picture_JV[0]; + //copy; + if(p_Vid->dec_picture->used_for_reference) + { + nsize = (p_Vid->dec_picture->size_y/BLOCK_SIZE)*(p_Vid->dec_picture->size_x/BLOCK_SIZE)*sizeof(PicMotionParams); + memcpy( &(p_Vid->dec_picture->JVmv_info[PLANE_Y][0][0]), &(p_Vid->dec_picture_JV[PLANE_Y]->mv_info[0][0]), nsize); + memcpy( &(p_Vid->dec_picture->JVmv_info[PLANE_U][0][0]), &(p_Vid->dec_picture_JV[PLANE_U]->mv_info[0][0]), nsize); + memcpy( &(p_Vid->dec_picture->JVmv_info[PLANE_V][0][0]), &(p_Vid->dec_picture_JV[PLANE_V]->mv_info[0][0]), nsize); + } + + // This could be done with pointers and seems not necessary + for( uv=0; uv<2; uv++ ) + { + for( line=0; lineheight; line++ ) + { + nsize = sizeof(imgpel) * p_Vid->width; + memcpy( p_Vid->dec_picture->imgUV[uv][line], p_Vid->dec_picture_JV[uv+1]->imgY[line], nsize ); + } + free_storable_picture(p_Vid->dec_picture_JV[uv+1]); + } +} + + diff --git a/ldecod/src/mb_access.c b/ldecod/src/mb_access.c new file mode 100644 index 0000000..1e51745 --- /dev/null +++ b/ldecod/src/mb_access.c @@ -0,0 +1,666 @@ + +/*! + ************************************************************************************* + * \file mb_access.c + * + * \brief + * Functions for macroblock neighborhoods + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + ************************************************************************************* + */ + +#include "global.h" +#include "mbuffer.h" +#include "mb_access.h" + +/*! + ************************************************************************ + * \brief + * returns 1 if the macroblock at the given address is available + ************************************************************************ + */ +Boolean mb_is_available(int mbAddr, Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + if ((mbAddr < 0) || (mbAddr > ((int)currSlice->dec_picture->PicSizeInMbs - 1))) + return FALSE; + + // the following line checks both: slice number and if the mb has been decoded + if (!currMB->DeblockCall) + { + if (currSlice->mb_data[mbAddr].slice_nr != currMB->slice_nr) + return FALSE; + } + + return TRUE; +} + + +/*! + ************************************************************************ + * \brief + * Checks the availability of neighboring macroblocks of + * the current macroblock for prediction and context determination; + ************************************************************************ + */ +void CheckAvailabilityOfNeighbors(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + StorablePicture *dec_picture = currSlice->dec_picture; //p_Vid->dec_picture; + const int mb_nr = currMB->mbAddrX; + BlockPos *PicPos = currMB->p_Vid->PicPos; + + if (dec_picture->mb_aff_frame_flag) + { + int cur_mb_pair = mb_nr >> 1; + currMB->mbAddrA = 2 * (cur_mb_pair - 1); + currMB->mbAddrB = 2 * (cur_mb_pair - dec_picture->PicWidthInMbs); + currMB->mbAddrC = 2 * (cur_mb_pair - dec_picture->PicWidthInMbs + 1); + currMB->mbAddrD = 2 * (cur_mb_pair - dec_picture->PicWidthInMbs - 1); + + currMB->mbAvailA = (Boolean) (mb_is_available(currMB->mbAddrA, currMB) && ((PicPos[cur_mb_pair ].x)!=0)); + currMB->mbAvailB = (Boolean) (mb_is_available(currMB->mbAddrB, currMB)); + currMB->mbAvailC = (Boolean) (mb_is_available(currMB->mbAddrC, currMB) && ((PicPos[cur_mb_pair + 1].x)!=0)); + currMB->mbAvailD = (Boolean) (mb_is_available(currMB->mbAddrD, currMB) && ((PicPos[cur_mb_pair ].x)!=0)); + } + else + { + BlockPos *p_pic_pos = &PicPos[mb_nr ]; + currMB->mbAddrA = mb_nr - 1; + currMB->mbAddrD = currMB->mbAddrA - dec_picture->PicWidthInMbs; + currMB->mbAddrB = currMB->mbAddrD + 1; + currMB->mbAddrC = currMB->mbAddrB + 1; + + + currMB->mbAvailA = (Boolean) (mb_is_available(currMB->mbAddrA, currMB) && ((p_pic_pos->x)!=0)); + currMB->mbAvailD = (Boolean) (mb_is_available(currMB->mbAddrD, currMB) && ((p_pic_pos->x)!=0)); + currMB->mbAvailC = (Boolean) (mb_is_available(currMB->mbAddrC, currMB) && (((p_pic_pos + 1)->x)!=0)); + currMB->mbAvailB = (Boolean) (mb_is_available(currMB->mbAddrB, currMB)); + } + + currMB->mb_left = (currMB->mbAvailA) ? &(currSlice->mb_data[currMB->mbAddrA]) : NULL; + currMB->mb_up = (currMB->mbAvailB) ? &(currSlice->mb_data[currMB->mbAddrB]) : NULL; +} + +/*! + ************************************************************************ + * \brief + * Checks the availability of neighboring macroblocks of + * the current macroblock for prediction and context determination; + ************************************************************************ + */ +void CheckAvailabilityOfNeighborsNormal(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + StorablePicture *dec_picture = currSlice->dec_picture; //p_Vid->dec_picture; + const int mb_nr = currMB->mbAddrX; + BlockPos *PicPos = currMB->p_Vid->PicPos; + + BlockPos *p_pic_pos = &PicPos[mb_nr ]; + currMB->mbAddrA = mb_nr - 1; + currMB->mbAddrD = currMB->mbAddrA - dec_picture->PicWidthInMbs; + currMB->mbAddrB = currMB->mbAddrD + 1; + currMB->mbAddrC = currMB->mbAddrB + 1; + + + currMB->mbAvailA = (Boolean) (mb_is_available(currMB->mbAddrA, currMB) && ((p_pic_pos->x)!=0)); + currMB->mbAvailD = (Boolean) (mb_is_available(currMB->mbAddrD, currMB) && ((p_pic_pos->x)!=0)); + currMB->mbAvailC = (Boolean) (mb_is_available(currMB->mbAddrC, currMB) && (((p_pic_pos + 1)->x)!=0)); + currMB->mbAvailB = (Boolean) (mb_is_available(currMB->mbAddrB, currMB)); + + + currMB->mb_left = (currMB->mbAvailA) ? &(currSlice->mb_data[currMB->mbAddrA]) : NULL; + currMB->mb_up = (currMB->mbAvailB) ? &(currSlice->mb_data[currMB->mbAddrB]) : NULL; +} + +/*! + ************************************************************************ + * \brief + * Checks the availability of neighboring macroblocks of + * the current macroblock for prediction and context determination; + ************************************************************************ + */ +void CheckAvailabilityOfNeighborsMBAFF(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + StorablePicture *dec_picture = currSlice->dec_picture; //p_Vid->dec_picture; + const int mb_nr = currMB->mbAddrX; + BlockPos *PicPos = currMB->p_Vid->PicPos; + + int cur_mb_pair = mb_nr >> 1; + currMB->mbAddrA = 2 * (cur_mb_pair - 1); + currMB->mbAddrB = 2 * (cur_mb_pair - dec_picture->PicWidthInMbs); + currMB->mbAddrC = 2 * (cur_mb_pair - dec_picture->PicWidthInMbs + 1); + currMB->mbAddrD = 2 * (cur_mb_pair - dec_picture->PicWidthInMbs - 1); + + currMB->mbAvailA = (Boolean) (mb_is_available(currMB->mbAddrA, currMB) && ((PicPos[cur_mb_pair ].x)!=0)); + currMB->mbAvailB = (Boolean) (mb_is_available(currMB->mbAddrB, currMB)); + currMB->mbAvailC = (Boolean) (mb_is_available(currMB->mbAddrC, currMB) && ((PicPos[cur_mb_pair + 1].x)!=0)); + currMB->mbAvailD = (Boolean) (mb_is_available(currMB->mbAddrD, currMB) && ((PicPos[cur_mb_pair ].x)!=0)); + + currMB->mb_left = (currMB->mbAvailA) ? &(currSlice->mb_data[currMB->mbAddrA]) : NULL; + currMB->mb_up = (currMB->mbAvailB) ? &(currSlice->mb_data[currMB->mbAddrB]) : NULL; +} + + +/*! + ************************************************************************ + * \brief + * returns the x and y macroblock coordinates for a given MbAddress + ************************************************************************ + */ +void get_mb_block_pos_normal (BlockPos *PicPos, int mb_addr, short *x, short *y) +{ + BlockPos *pPos = &PicPos[ mb_addr ]; + *x = (short) pPos->x; + *y = (short) pPos->y; +} + +/*! + ************************************************************************ + * \brief + * returns the x and y macroblock coordinates for a given MbAddress + * for mbaff type slices + ************************************************************************ + */ +void get_mb_block_pos_mbaff (BlockPos *PicPos, int mb_addr, short *x, short *y) +{ + BlockPos *pPos = &PicPos[ mb_addr >> 1 ]; + *x = (short) pPos->x; + *y = (short) ((pPos->y << 1) + (mb_addr & 0x01)); +} + +/*! + ************************************************************************ + * \brief + * returns the x and y sample coordinates for a given MbAddress + ************************************************************************ + */ +void get_mb_pos (VideoParameters *p_Vid, int mb_addr, int mb_size[2], short *x, short *y) +{ + p_Vid->get_mb_block_pos(p_Vid->PicPos, mb_addr, x, y); + + (*x) = (short) ((*x) * mb_size[0]); + (*y) = (short) ((*y) * mb_size[1]); +} + + +/*! + ************************************************************************ + * \brief + * get neighbouring positions for non-aff coding + * \param currMB + * current macroblock + * \param xN + * input x position + * \param yN + * input y position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void getNonAffNeighbour(Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix) +{ + int maxW = mb_size[0], maxH = mb_size[1]; + + if (xN < 0) + { + if (yN < 0) + { + pix->mb_addr = currMB->mbAddrD; + pix->available = currMB->mbAvailD; + } + else if (yN < maxH) + { + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + } + else + { + pix->available = FALSE; + } + } + else if (xN < maxW) + { + if (yN < 0) + { + pix->mb_addr = currMB->mbAddrB; + pix->available = currMB->mbAvailB; + } + else if (yN < maxH) + { + pix->mb_addr = currMB->mbAddrX; + pix->available = TRUE; + } + else + { + pix->available = FALSE; + } + } + else if ((xN >= maxW) && (yN < 0)) + { + pix->mb_addr = currMB->mbAddrC; + pix->available = currMB->mbAvailC; + } + else + { + pix->available = FALSE; + } + + if (pix->available || currMB->DeblockCall) + { + BlockPos *CurPos = &(currMB->p_Vid->PicPos[ pix->mb_addr ]); + pix->x = (short) (xN & (maxW - 1)); + pix->y = (short) (yN & (maxH - 1)); + pix->pos_x = (short) (pix->x + CurPos->x * maxW); + pix->pos_y = (short) (pix->y + CurPos->y * maxH); + } +} + +/*! + ************************************************************************ + * \brief + * get neighboring positions for aff coding + * \param currMB + * current macroblock + * \param xN + * input x position + * \param yN + * input y position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void getAffNeighbour(Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int maxW, maxH; + int yM = -1; + + maxW = mb_size[0]; + maxH = mb_size[1]; + + // initialize to "not available" + pix->available = FALSE; + + if(yN > (maxH - 1)) + { + return; + } + if (xN > (maxW - 1) && yN >= 0 && yN < maxH) + { + return; + } + + if (xN < 0) + { + if (yN < 0) + { + if(!currMB->mb_field) + { + // frame + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrD + 1; + pix->available = currMB->mbAvailD; + yM = yN; + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + yM = yN; + } + else + { + (pix->mb_addr)++; + yM = (yN + maxH) >> 1; + } + } + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrD; + pix->available = currMB->mbAvailD; + if (currMB->mbAvailD) + { + if(!p_Vid->mb_data[currMB->mbAddrD].mb_field) + { + (pix->mb_addr)++; + yM = 2 * yN; + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrD+1; + pix->available = currMB->mbAvailD; + yM = yN; + } + } + } + else + { // xN < 0 && yN >= 0 + if (yN >= 0 && yN mb_field) + { + // frame + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + yM = yN; + } + else + { + (pix->mb_addr)+= ((yN & 0x01) != 0); + yM = yN >> 1; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + (pix->mb_addr)++; + yM = yN; + } + else + { + (pix->mb_addr)+= ((yN & 0x01) != 0); + yM = (yN + maxH) >> 1; + } + } + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + if (yN < (maxH >> 1)) + { + yM = yN << 1; + } + else + { + (pix->mb_addr)++; + yM = (yN << 1 ) - maxH; + } + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + if (yN < (maxH >> 1)) + { + yM = (yN << 1) + 1; + } + else + { + (pix->mb_addr)++; + yM = (yN << 1 ) + 1 - maxH; + } + } + else + { + (pix->mb_addr)++; + yM = yN; + } + } + } + } + } + } + } + else + { // xN >= 0 + if (xN >= 0 && xN < maxW) + { + if (yN<0) + { + if (!currMB->mb_field) + { + //frame + if ((currMB->mbAddrX & 0x01) == 0) + { + //top + pix->mb_addr = currMB->mbAddrB; + // for the deblocker if the current MB is a frame and the one above is a field + // then the neighbor is the top MB of the pair + if (currMB->mbAvailB) + { + if (!(currMB->DeblockCall == 1 && (p_Vid->mb_data[currMB->mbAddrB]).mb_field)) + pix->mb_addr += 1; + } + + pix->available = currMB->mbAvailB; + yM = yN; + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrX - 1; + pix->available = TRUE; + yM = yN; + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrB; + pix->available = currMB->mbAvailB; + if (currMB->mbAvailB) + { + if(!p_Vid->mb_data[currMB->mbAddrB].mb_field) + { + (pix->mb_addr)++; + yM = 2* yN; + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrB + 1; + pix->available = currMB->mbAvailB; + yM = yN; + } + } + } + else + { + // yN >=0 + // for the deblocker if this is the extra edge then do this special stuff + if (yN == 0 && currMB->DeblockCall == 2) + { + pix->mb_addr = currMB->mbAddrB + 1; + pix->available = TRUE; + yM = yN - 1; + } + + else if ((yN >= 0) && (yN mb_addr = currMB->mbAddrX; + pix->available = TRUE; + yM = yN; + } + } + } + else + { // xN >= maxW + if(yN < 0) + { + if (!currMB->mb_field) + { + // frame + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrC + 1; + pix->available = currMB->mbAvailC; + yM = yN; + } + else + { + // bottom + pix->available = FALSE; + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrC; + pix->available = currMB->mbAvailC; + if (currMB->mbAvailC) + { + if(!p_Vid->mb_data[currMB->mbAddrC].mb_field) + { + (pix->mb_addr)++; + yM = 2* yN; + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrC + 1; + pix->available = currMB->mbAvailC; + yM = yN; + } + } + } + } + } + if (pix->available || currMB->DeblockCall) + { + pix->x = (short) (xN & (maxW - 1)); + pix->y = (short) (yM & (maxH - 1)); + get_mb_pos(p_Vid, pix->mb_addr, mb_size, &(pix->pos_x), &(pix->pos_y)); + pix->pos_x = pix->pos_x + pix->x; + pix->pos_y = pix->pos_y + pix->y; + } +} + + +/*! + ************************************************************************ + * \brief + * get neighboring 4x4 block + * \param currMB + * current macroblock + * \param block_x + * input x block position + * \param block_y + * input y block position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void get4x4Neighbour (Macroblock *currMB, int block_x, int block_y, int mb_size[2], PixelPos *pix) +{ + currMB->p_Vid->getNeighbour(currMB, block_x, block_y, mb_size, pix); + + if (pix->available) + { + pix->x >>= 2; + pix->y >>= 2; + pix->pos_x >>= 2; + pix->pos_y >>= 2; + } +} + +/*! + ************************************************************************ + * \brief + * get neighboring 4x4 block + * \param currMB + * current macroblock + * \param block_x + * input x block position + * \param block_y + * input y block position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void get4x4NeighbourBase (Macroblock *currMB, int block_x, int block_y, int mb_size[2], PixelPos *pix) +{ + currMB->p_Vid->getNeighbour(currMB, block_x, block_y, mb_size, pix); + + if (pix->available) + { + pix->x >>= 2; + pix->y >>= 2; + } +} diff --git a/ldecod/src/mb_prediction.c b/ldecod/src/mb_prediction.c new file mode 100644 index 0000000..55dfc4f --- /dev/null +++ b/ldecod/src/mb_prediction.c @@ -0,0 +1,1300 @@ +/*! +************************************************************************************* +* \file mb_prediction.c +* +* \brief +* Macroblock prediction functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +************************************************************************************* +*/ + +#include "contributors.h" + +#include "block.h" +#include "global.h" +#include "mbuffer.h" +#include "elements.h" +#include "errorconcealment.h" +#include "macroblock.h" +#include "fmo.h" +#include "cabac.h" +#include "vlc.h" +#include "image.h" +#include "mb_access.h" +#include "biaridecod.h" +#include "transform8x8.h" +#include "transform.h" +#include "mc_prediction.h" +#include "quant.h" +#include "intra4x4_pred.h" +#include "intra8x8_pred.h" +#include "intra16x16_pred.h" +#include "mv_prediction.h" +#include "mb_prediction.h" + +extern int get_colocated_info_8x8 (Macroblock *currMB, StorablePicture *list1, int i, int j); +extern int get_colocated_info_4x4 (Macroblock *currMB, StorablePicture *list1, int i, int j); + + +int mb_pred_intra4x4(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + int yuv = dec_picture->chroma_format_idc - 1; + int i=0, j=0,k, j4=0,i4=0; + int j_pos, i_pos; + int ioff,joff; + int block8x8; // needed for ABT + currMB->itrans_4x4 = (currMB->is_lossless == FALSE) ? itrans4x4 : Inv_Residual_trans_4x4; + + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + for (k = block8x8 * 4; k < block8x8 * 4 + 4; k ++) + { + i = (decode_block_scan[k] & 3); + j = ((decode_block_scan[k] >> 2) & 3); + + ioff = (i << 2); + joff = (j << 2); + i4 = currMB->block_x + i; + j4 = currMB->block_y + j; + j_pos = j4 * BLOCK_SIZE; + i_pos = i4 * BLOCK_SIZE; + + // PREDICTION + //===== INTRA PREDICTION ===== + if (currSlice->intra_pred_4x4(currMB, curr_plane, ioff,joff,i4,j4) == SEARCH_SYNC) /* make 4x4 prediction block mpr from given prediction p_Vid->mb_mode */ + return SEARCH_SYNC; /* bit error */ + // =============== 4x4 itrans ================ + // ------------------------------------------- + currMB->itrans_4x4 (currMB, curr_plane, ioff, joff); + + copy_image_data_4x4(&currImg[j_pos], &currSlice->mb_rec[curr_plane][joff], i_pos, ioff); + } + } + + // chroma decoding ******************************************************* + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + intra_cr_decoding(currMB, yuv); + } + + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + + +int mb_pred_intra16x16(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + int yuv = dec_picture->chroma_format_idc - 1; + + currMB->p_Slice->intra_pred_16x16(currMB, curr_plane, currMB->i16mode); + currMB->ipmode_DPCM = (char) currMB->i16mode; //For residual DPCM + // =============== 4x4 itrans ================ + // ------------------------------------------- + iMBtrans4x4(currMB, curr_plane, 0); + + // chroma decoding ******************************************************* + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + intra_cr_decoding(currMB, yuv); + } + + currMB->p_Slice->is_reset_coeff = FALSE; + return 1; +} + +int mb_pred_intra8x8(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + int yuv = dec_picture->chroma_format_idc - 1; + + int block8x8; // needed for ABT + currMB->itrans_8x8 = (currMB->is_lossless == FALSE) ? itrans8x8 : Inv_Residual_trans_8x8; + + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + //=========== 8x8 BLOCK TYPE ============ + int ioff = (block8x8 & 0x01) << 3; + int joff = (block8x8 >> 1 ) << 3; + + //PREDICTION + currSlice->intra_pred_8x8(currMB, curr_plane, ioff, joff); + if (currMB->cbp & (1 << block8x8)) + currMB->itrans_8x8 (currMB, curr_plane, ioff,joff); // use inverse integer transform and make 8x8 block m7 from prediction block mpr + else + icopy8x8(currMB, curr_plane, ioff,joff); + + copy_image_data_8x8(&currImg[currMB->pix_y + joff], &currSlice->mb_rec[curr_plane][joff], currMB->pix_x + ioff, ioff); + } + // chroma decoding ******************************************************* + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + intra_cr_decoding(currMB, yuv); + } + + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + + +static void set_chroma_vector(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + if (!currSlice->mb_aff_frame_flag) + { + if(currSlice->structure == TOP_FIELD) + { + int k,l; + for (l = LIST_0; l <= (LIST_1); l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + if(p_Vid->structure != currSlice->listX[l][k]->structure) + currSlice->chroma_vector_adjustment[l][k] = -2; + else + currSlice->chroma_vector_adjustment[l][k] = 0; + } + } + } + else if(currSlice->structure == BOTTOM_FIELD) + { + int k,l; + for (l = LIST_0; l <= (LIST_1); l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + if (p_Vid->structure != currSlice->listX[l][k]->structure) + currSlice->chroma_vector_adjustment[l][k] = 2; + else + currSlice->chroma_vector_adjustment[l][k] = 0; + } + } + } + else + { + int k,l; + for (l = LIST_0; l <= (LIST_1); l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + currSlice->chroma_vector_adjustment[l][k] = 0; + } + } + } + } + else + { + int mb_nr = (currMB->mbAddrX & 0x01); + int k,l; + + ////////////////////////// + // find out the correct list offsets + if (currMB->mb_field) + { + int list_offset = currMB->list_offset; + + for (l = LIST_0 + list_offset; l <= (LIST_1 + list_offset); l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + if(mb_nr == 0 && currSlice->listX[l][k]->structure == BOTTOM_FIELD) + currSlice->chroma_vector_adjustment[l][k] = -2; + else if(mb_nr == 1 && currSlice->listX[l][k]->structure == TOP_FIELD) + currSlice->chroma_vector_adjustment[l][k] = 2; + else + currSlice->chroma_vector_adjustment[l][k] = 0; + } + } + } + else + { + for (l = LIST_0; l <= (LIST_1); l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + currSlice->chroma_vector_adjustment[l][k] = 0; + } + } + } + } + + currSlice->max_mb_vmv_r = (currSlice->structure != FRAME || ( currMB->mb_field )) ? p_Vid->max_vmv_r >> 1 : p_Vid->max_vmv_r; +} + +int mb_pred_skip(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + //! Edited by Joao Carreira + currMB->p_Vid->n_SKIP++; + + set_chroma_vector(currMB); + + perform_mc(currMB, curr_plane, dec_picture, LIST_0, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + copy_image_data_16x16(&currImg[currMB->pix_y], currSlice->mb_pred[curr_plane], currMB->pix_x, 0); + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + + copy_image_data(&dec_picture->imgUV[0][currMB->pix_c_y], currSlice->mb_pred[1], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + copy_image_data(&dec_picture->imgUV[1][currMB->pix_c_y], currSlice->mb_pred[2], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + } + return 1; +} + +int mb_pred_sp_skip(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + set_chroma_vector(currMB); + + perform_mc(currMB, curr_plane, dec_picture, LIST_0, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + iTransform(currMB, curr_plane, 1); + return 1; +} + +int mb_pred_p_inter8x8(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + int block8x8; // needed for ABT + int i=0, j=0,k; + + Slice *currSlice = currMB->p_Slice; + int smb = currSlice->slice_type == SP_SLICE && (currMB->is_intra_block == FALSE); + + set_chroma_vector(currMB); + + for (block8x8=0; block8x8<4; block8x8++) + { + int mv_mode = currMB->b8mode[block8x8]; + int pred_dir = currMB->b8pdir[block8x8]; + + int k_start = (block8x8 << 2); + int k_inc = (mv_mode == SMB8x4) ? 2 : 1; + int k_end = (mv_mode == SMB8x8) ? k_start + 1 : ((mv_mode == SMB4x4) ? k_start + 4 : k_start + k_inc + 1); + + int block_size_x = ( mv_mode == SMB8x4 || mv_mode == SMB8x8 ) ? SMB_BLOCK_SIZE : BLOCK_SIZE; + int block_size_y = ( mv_mode == SMB4x8 || mv_mode == SMB8x8 ) ? SMB_BLOCK_SIZE : BLOCK_SIZE; + + for (k = k_start; k < k_end; k += k_inc) + { + i = (decode_block_scan[k] & 3); + j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, block_size_x, block_size_y); + } + } + + iTransform(currMB, curr_plane, smb); + + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + +int mb_pred_p_inter16x16(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + int smb = (currSlice->slice_type == SP_SLICE); + + set_chroma_vector(currMB); + perform_mc(currMB, curr_plane, dec_picture, currMB->b8pdir[0], 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + iTransform(currMB, curr_plane, smb); + + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + +int mb_pred_p_inter16x8(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + int smb = (currSlice->slice_type == SP_SLICE); + + set_chroma_vector(currMB); + + perform_mc(currMB, curr_plane, dec_picture, currMB->b8pdir[0], 0, 0, MB_BLOCK_SIZE, BLOCK_SIZE_8x8); + perform_mc(currMB, curr_plane, dec_picture, currMB->b8pdir[2], 0, 2, MB_BLOCK_SIZE, BLOCK_SIZE_8x8); + iTransform(currMB, curr_plane, smb); + + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + +int mb_pred_p_inter8x16(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + Slice *currSlice = currMB->p_Slice; + int smb = (currSlice->slice_type == SP_SLICE); + + set_chroma_vector(currMB); + + perform_mc(currMB, curr_plane, dec_picture, currMB->b8pdir[0], 0, 0, BLOCK_SIZE_8x8, MB_BLOCK_SIZE); + perform_mc(currMB, curr_plane, dec_picture, currMB->b8pdir[1], 2, 0, BLOCK_SIZE_8x8, MB_BLOCK_SIZE); + iTransform(currMB, curr_plane, smb); + + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + +static inline void update_neighbor_mvs(PicMotionParams **motion, const PicMotionParams *mv_info, int i4) +{ + (*motion++)[i4 + 1] = *mv_info; + (*motion )[i4 ] = *mv_info; + (*motion )[i4 + 1] = *mv_info; +} + +int mb_pred_b_d8x8temporal(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + short ref_idx; + int refList; + + int k, i, j, i4, j4, j6; + int block8x8; // needed for ABT + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams *mv_info = NULL, *colocated = NULL; + + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + set_chroma_vector(currMB); + + //printf("currMB %d\n", currMB->mbAddrX); + for (block8x8=0; block8x8<4; block8x8++) + { + int pred_dir = currMB->b8pdir[block8x8]; + + int k_start = (block8x8 << 2); + int k_end = k_start + 1; + + for (k = k_start; k < k_start + BLOCK_MULTIPLE; k ++) + { + + i = (decode_block_scan[k] & 3); + j = ((decode_block_scan[k] >> 2) & 3); + i4 = currMB->block_x + i; + j4 = currMB->block_y + j; + j6 = currMB->block_y_aff + j; + mv_info = &dec_picture->mv_info[j4][i4]; + colocated = &list1[0]->mv_info[RSD(j6)][RSD(i4)]; + if(currMB->p_Vid->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = &list1[0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(j6)][RSD(i4)]; + if(currSlice->mb_aff_frame_flag /*&& (!p_Vid->active_sps->frame_mbs_only_flag || p_Vid->active_sps->direct_8x8_inference_flag)*/) + { + assert(p_Vid->active_sps->direct_8x8_inference_flag); + if(!currMB->mb_field && ((currSlice->listX[LIST_1][0]->iCodingType==FRAME_MB_PAIR_CODING && currSlice->listX[LIST_1][0]->motion.mb_field[currMB->mbAddrX]) || + (currSlice->listX[LIST_1][0]->iCodingType==FIELD_CODING))) + { + if (iabs(dec_picture->poc - currSlice->listX[LIST_1+4][0]->poc)> iabs(dec_picture->poc -currSlice->listX[LIST_1+2][0]->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &currSlice->listX[LIST_1+2][0]->mv_info[RSD(j6)>>1][RSD(i4)] : &currSlice->listX[LIST_1+2][0]->mv_info[j6>>1][i4]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &currSlice->listX[LIST_1+4][0]->mv_info[RSD(j6)>>1][RSD(i4)] : &currSlice->listX[LIST_1+4][0]->mv_info[j6>>1][i4]; + } + } + } + else if(/*!currSlice->mb_aff_frame_flag &&*/ !p_Vid->active_sps->frame_mbs_only_flag && + (!currSlice->field_pic_flag && currSlice->listX[LIST_1][0]->iCodingType!=FRAME_CODING)) + { + if (iabs(dec_picture->poc - list1[0]->bottom_field->poc)> iabs(dec_picture->poc -list1[0]->top_field->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->top_field->mv_info[RSD(j6)>>1][RSD(i4)] : &list1[0]->top_field->mv_info[j6>>1][i4]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->bottom_field->mv_info[RSD(j6)>>1][RSD(i4)] : &list1[0]->bottom_field->mv_info[j6>>1][i4]; + } + } + else if(!p_Vid->active_sps->frame_mbs_only_flag && currSlice->field_pic_flag && currSlice->structure!=list1[0]->structure && list1[0]->coded_frame) + { + if (currSlice->structure == TOP_FIELD) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->frame->top_field->mv_info[RSD(j6)][RSD(i4)] : &list1[0]->frame->top_field->mv_info[j6][i4]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->frame->bottom_field->mv_info[RSD(j6)][RSD(i4)] : &list1[0]->frame->bottom_field->mv_info[j6][i4]; + } + } + + + assert (pred_dir<=2); + + refList = (colocated->ref_idx[LIST_0]== -1 ? LIST_1 : LIST_0); + ref_idx = colocated->ref_idx[refList]; + + if( colocated->ref_pic[refList] == NULL ) + { + ref_idx = -1; + } + + if(ref_idx==-1) // co-located is intra mode + { + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = 0; + } + else // co-located skip or inter mode + { + int mapped_idx=0; + int iref; + if( (currSlice->mb_aff_frame_flag && ( (currMB->mb_field && colocated->ref_pic[refList]->structure==FRAME) || + (!currMB->mb_field && colocated->ref_pic[refList]->structure!=FRAME))) || + (!currSlice->mb_aff_frame_flag && ((currSlice->field_pic_flag==0 && colocated->ref_pic[refList]->structure!=FRAME) + ||(currSlice->field_pic_flag==1 && colocated->ref_pic[refList]->structure==FRAME))) ) + { + for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]);iref++) + { + if(currSlice->listX[LIST_0 + list_offset][iref]->top_field == colocated->ref_pic[refList] || + currSlice->listX[LIST_0 + list_offset][iref]->bottom_field == colocated->ref_pic[refList] || + currSlice->listX[LIST_0 + list_offset][iref]->frame == colocated->ref_pic[refList]) + { + if ((currSlice->field_pic_flag==1) && (currSlice->listX[LIST_0 + list_offset][iref]->structure != currSlice->structure)) + { + mapped_idx=INVALIDINDEX; + } + else + { + mapped_idx = iref; + break; + } + } + else //! invalid index. Default to zero even though this case should not happen + { + mapped_idx=INVALIDINDEX; + } + } + } + else + { + for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]);iref++) + { + if(currSlice->listX[LIST_0 + list_offset][iref] == colocated->ref_pic[refList]) + { + mapped_idx = iref; + break; + } + else //! invalid index. Default to zero even though this case should not happen + { + mapped_idx=INVALIDINDEX; + } + } + } + + if(INVALIDINDEX != mapped_idx) + { + int mv_scale = currSlice->mvscale[LIST_0 + list_offset][mapped_idx]; + int mv_y = colocated->mv[refList].mv_y; + if((currSlice->mb_aff_frame_flag && !currMB->mb_field && colocated->ref_pic[refList]->structure!=FRAME) || + (!currSlice->mb_aff_frame_flag && currSlice->field_pic_flag==0 && colocated->ref_pic[refList]->structure!=FRAME) ) + mv_y *= 2; + else if((currSlice->mb_aff_frame_flag && currMB->mb_field && colocated->ref_pic[refList]->structure==FRAME) || + (!currSlice->mb_aff_frame_flag && currSlice->field_pic_flag==1 && colocated->ref_pic[refList]->structure==FRAME) ) + mv_y /= 2; + + //! In such case, an array is needed for each different reference. + if (mv_scale == 9999 || currSlice->listX[LIST_0 + list_offset][mapped_idx]->is_long_term) + { + mv_info->mv[LIST_0].mv_x = colocated->mv[refList].mv_x; + mv_info->mv[LIST_0].mv_y = (short) mv_y; + mv_info->mv[LIST_1] = zero_mv; + } + else + { + mv_info->mv[LIST_0].mv_x = (short) ((mv_scale * colocated->mv[refList].mv_x + 128 ) >> 8); + mv_info->mv[LIST_0].mv_y = (short) ((mv_scale * mv_y/*colocated->mv[refList].mv_y*/ + 128 ) >> 8); + + mv_info->mv[LIST_1].mv_x = (short) (mv_info->mv[LIST_0].mv_x - colocated->mv[refList].mv_x); + mv_info->mv[LIST_1].mv_y = (short) (mv_info->mv[LIST_0].mv_y - mv_y/*colocated->mv[refList].mv_y*/); + } + + mv_info->ref_idx[LIST_0] = (char) mapped_idx; //colocated->ref_idx[refList]; + mv_info->ref_idx[LIST_1] = 0; + } + else if (INVALIDINDEX == mapped_idx) + { + error("temporal direct error: colocated block has ref that is unavailable",-1111); + } + + } + // store reference picture ID determined by direct mode + mv_info->ref_pic[LIST_0] = list0[(short)mv_info->ref_idx[LIST_0]]; + mv_info->ref_pic[LIST_1] = list1[(short)mv_info->ref_idx[LIST_1]]; + } + + for (k = k_start; k < k_end; k ++) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, SMB_BLOCK_SIZE, SMB_BLOCK_SIZE); + } + } + + if (currMB->cbp == 0) + { + copy_image_data_16x16(&currImg[currMB->pix_y], currSlice->mb_pred[curr_plane], currMB->pix_x, 0); + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + copy_image_data(&dec_picture->imgUV[0][currMB->pix_c_y], currSlice->mb_pred[1], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + copy_image_data(&dec_picture->imgUV[1][currMB->pix_c_y], currSlice->mb_pred[2], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + } + } + else + { + iTransform(currMB, curr_plane, 0); + currSlice->is_reset_coeff = FALSE; + } + return 1; +} + +int mb_pred_b_d4x4temporal(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + short ref_idx; + int refList; + + int k; + int block8x8; // needed for ABT + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + set_chroma_vector(currMB); + + for (block8x8=0; block8x8<4; block8x8++) + { + int pred_dir = currMB->b8pdir[block8x8]; + + int k_start = (block8x8 << 2); + int k_end = k_start + BLOCK_MULTIPLE; + + for (k = k_start; k < k_end; k ++) + { + + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int j6 = currMB->block_y_aff + j; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + PicMotionParams *colocated = &list1[0]->mv_info[j6][i4]; + if(currMB->p_Vid->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = &list1[0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(j6)][RSD(i4)]; + assert (pred_dir<=2); + + refList = (colocated->ref_idx[LIST_0]== -1 ? LIST_1 : LIST_0); + ref_idx = colocated->ref_idx[refList]; + + if(ref_idx==-1) // co-located is intra mode + { + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = 0; + } + else // co-located skip or inter mode + { + int mapped_idx=0; + int iref; + + for (iref=0;irefnum_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]);iref++) + { + if(currSlice->listX[LIST_0 + list_offset][iref] == colocated->ref_pic[refList]) + { + mapped_idx=iref; + break; + } + else //! invalid index. Default to zero even though this case should not happen + { + mapped_idx=INVALIDINDEX; + } + } + if (INVALIDINDEX == mapped_idx) + { + error("temporal direct error: colocated block has ref that is unavailable",-1111); + } + else + { + int mv_scale = currSlice->mvscale[LIST_0 + list_offset][mapped_idx]; + + //! In such case, an array is needed for each different reference. + if (mv_scale == 9999 || currSlice->listX[LIST_0+list_offset][mapped_idx]->is_long_term) + { + mv_info->mv[LIST_0] = colocated->mv[refList]; + mv_info->mv[LIST_1] = zero_mv; + } + else + { + mv_info->mv[LIST_0].mv_x = (short) ((mv_scale * colocated->mv[refList].mv_x + 128 ) >> 8); + mv_info->mv[LIST_0].mv_y = (short) ((mv_scale * colocated->mv[refList].mv_y + 128 ) >> 8); + + mv_info->mv[LIST_1].mv_x = (short) (mv_info->mv[LIST_0].mv_x - colocated->mv[refList].mv_x); + mv_info->mv[LIST_1].mv_y = (short) (mv_info->mv[LIST_0].mv_y - colocated->mv[refList].mv_y); + } + + mv_info->ref_idx[LIST_0] = (char) mapped_idx; //colocated->ref_idx[refList]; + mv_info->ref_idx[LIST_1] = 0; + } + } + // store reference picture ID determined by direct mode + mv_info->ref_pic[LIST_0] = list0[(short)mv_info->ref_idx[LIST_0]]; + mv_info->ref_pic[LIST_1] = list1[(short)mv_info->ref_idx[LIST_1]]; + } + + for (k = k_start; k < k_end; k ++) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, BLOCK_SIZE, BLOCK_SIZE); + + } + } + + if (currMB->cbp == 0) + { + copy_image_data_16x16(&currImg[currMB->pix_y], currSlice->mb_pred[curr_plane], currMB->pix_x, 0); + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + copy_image_data(&dec_picture->imgUV[0][currMB->pix_c_y], currSlice->mb_pred[1], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + copy_image_data(&dec_picture->imgUV[1][currMB->pix_c_y], currSlice->mb_pred[2], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + } + } + else + { + iTransform(currMB, curr_plane, 0); + currSlice->is_reset_coeff = FALSE; + } + + return 1; +} + + +int mb_pred_b_d8x8spatial(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + char l0_rFrame = -1, l1_rFrame = -1; + MotionVector pmvl0 = zero_mv, pmvl1 = zero_mv; + int i4, j4; + int block8x8; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PicMotionParams *mv_info; + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + int pred_dir = 0; + + set_chroma_vector(currMB); + + prepare_direct_params(currMB, dec_picture, &pmvl0, &pmvl1, &l0_rFrame, &l1_rFrame); + + if (l0_rFrame == 0 || l1_rFrame == 0) + { + int is_not_moving; + + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + int k_start = (block8x8 << 2); + + int i = (decode_block_scan[k_start] & 3); + int j = ((decode_block_scan[k_start] >> 2) & 3); + i4 = currMB->block_x + i; + j4 = currMB->block_y + j; + + //Edited by Joao Carreira->Debug + if( currMB->p_Vid->dec_picture->poc==10 && currMB->p_Vid->dec_picture->view_id==1 && + i4 == 208 && j4 == 140) + { + int a = 0; + } + + + + is_not_moving = (get_colocated_info_8x8(currMB, list1[0], i4, currMB->block_y_aff + j) == 0); + + mv_info = &dec_picture->mv_info[j4][i4]; + + //===== DIRECT PREDICTION ===== + if (l1_rFrame == -1) + { + if (is_not_moving) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = -1; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + pred_dir = 0; + } + else if (l0_rFrame == -1) + { + if (is_not_moving) + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + pred_dir = 1; + } + else + { + if (l0_rFrame == 0 && ((is_not_moving))) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->ref_idx[LIST_0] = l0_rFrame; + } + + if (l1_rFrame == 0 && ((is_not_moving))) + { + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + pred_dir = 2; + } + + update_neighbor_mvs(&dec_picture->mv_info[j4], mv_info, i4); + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, SMB_BLOCK_SIZE, SMB_BLOCK_SIZE); + } + } + else + { + //===== DIRECT PREDICTION ===== + if (l0_rFrame < 0 && l1_rFrame < 0) + { + pred_dir = 2; + for (j4 = currMB->block_y; j4 < currMB->block_y + BLOCK_MULTIPLE; j4 += 2) + { + for (i4 = currMB->block_x; i4 < currMB->block_x + BLOCK_MULTIPLE; i4 += 2) + { + mv_info = &dec_picture->mv_info[j4][i4]; + + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = 0; + + update_neighbor_mvs(&dec_picture->mv_info[j4], mv_info, i4); + } + } + } + else if (l1_rFrame == -1) + { + pred_dir = 0; + + for (j4 = currMB->block_y; j4 < currMB->block_y + BLOCK_MULTIPLE; j4 += 2) + { + for (i4 = currMB->block_x; i4 < currMB->block_x + BLOCK_MULTIPLE; i4 += 2) + { + mv_info = &dec_picture->mv_info[j4][i4]; + + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + + update_neighbor_mvs(&dec_picture->mv_info[j4], mv_info, i4); + } + } + } + else if (l0_rFrame == -1) + { + pred_dir = 1; + for (j4 = currMB->block_y; j4 < currMB->block_y + BLOCK_MULTIPLE; j4 += 2) + { + for (i4 = currMB->block_x; i4 < currMB->block_x + BLOCK_MULTIPLE; i4 += 2) + { + mv_info = &dec_picture->mv_info[j4][i4]; + + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + + update_neighbor_mvs(&dec_picture->mv_info[j4], mv_info, i4); + } + } + } + else + { + pred_dir = 2; + + for (j4 = currMB->block_y; j4 < currMB->block_y + BLOCK_MULTIPLE; j4 += 2) + { + for (i4 = currMB->block_x; i4 < currMB->block_x + BLOCK_MULTIPLE; i4 += 2) + { + mv_info = &dec_picture->mv_info[j4][i4]; + + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = l1_rFrame; + + update_neighbor_mvs(&dec_picture->mv_info[j4], mv_info, i4); + } + } + } + // Now perform Motion Compensation + perform_mc(currMB, curr_plane, dec_picture, pred_dir, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + } + + if (currMB->cbp == 0) + { + copy_image_data_16x16(&currImg[currMB->pix_y], currSlice->mb_pred[curr_plane], currMB->pix_x, 0); + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + copy_image_data(&dec_picture->imgUV[0][currMB->pix_c_y], currSlice->mb_pred[1], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + copy_image_data(&dec_picture->imgUV[1][currMB->pix_c_y], currSlice->mb_pred[2], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + } + } + else + { + iTransform(currMB, curr_plane, 0); + currSlice->is_reset_coeff = FALSE; + } + + return 1; +} + + +int mb_pred_b_d4x4spatial(Macroblock *currMB, ColorPlane curr_plane, imgpel **currImg, StorablePicture *dec_picture) +{ + char l0_rFrame = -1, l1_rFrame = -1; + MotionVector pmvl0 = zero_mv, pmvl1 = zero_mv; + int k; + int block8x8; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PicMotionParams *mv_info; + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + int pred_dir = 0; + + set_chroma_vector(currMB); + + prepare_direct_params(currMB, dec_picture, &pmvl0, &pmvl1, &l0_rFrame, &l1_rFrame); + + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + int k_start = (block8x8 << 2); + int k_end = k_start + BLOCK_MULTIPLE; + + for (k = k_start; k < k_end; k ++) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + + mv_info = &dec_picture->mv_info[j4][i4]; + //===== DIRECT PREDICTION ===== + if (l0_rFrame == 0 || l1_rFrame == 0) + { + int is_not_moving = (get_colocated_info_4x4(currMB, list1[0], i4, currMB->block_y_aff + j) == 0); + + if (l1_rFrame == -1) + { + if (is_not_moving) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = -1; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + pred_dir = 0; + } + else if (l0_rFrame == -1) + { + if (is_not_moving) + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + pred_dir = 1; + } + else + { + if (l0_rFrame == 0 && ((is_not_moving))) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->ref_idx[LIST_0] = l0_rFrame; + } + + if (l1_rFrame == 0 && ((is_not_moving))) + { + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + pred_dir = 2; + } + } + else + { + mv_info = &dec_picture->mv_info[j4][i4]; + + if (l0_rFrame < 0 && l1_rFrame < 0) + { + pred_dir = 2; + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = 0; + } + else if (l1_rFrame == -1) + { + pred_dir = 0; + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + else if (l0_rFrame == -1) + { + pred_dir = 1; + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + else + { + pred_dir = 2; + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + } + + for (k = k_start; k < k_end; k ++) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, BLOCK_SIZE, BLOCK_SIZE); + } + } + + if (currMB->cbp == 0) + { + copy_image_data_16x16(&currImg[currMB->pix_y], currSlice->mb_pred[curr_plane], currMB->pix_x, 0); + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + copy_image_data(&dec_picture->imgUV[0][currMB->pix_c_y], currSlice->mb_pred[1], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + copy_image_data(&dec_picture->imgUV[1][currMB->pix_c_y], currSlice->mb_pred[2], currMB->pix_c_x, 0, p_Vid->mb_size[1][0], p_Vid->mb_size[1][1]); + } + } + else + { + iTransform(currMB, curr_plane, 0); + currSlice->is_reset_coeff = FALSE; + } + + return 1; +} + +int mb_pred_b_inter8x8(Macroblock *currMB, ColorPlane curr_plane, StorablePicture *dec_picture) +{ + char l0_rFrame = -1, l1_rFrame = -1; + MotionVector pmvl0 = zero_mv, pmvl1 = zero_mv; + int block_size_x, block_size_y; + int k; + int block8x8; // needed for ABT + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int list_offset = currMB->list_offset; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + set_chroma_vector(currMB); + + // prepare direct modes + if (currSlice->direct_spatial_mv_pred_flag && (!(currMB->b8mode[0] && currMB->b8mode[1] && currMB->b8mode[2] && currMB->b8mode[3]))) + prepare_direct_params(currMB, dec_picture, &pmvl0, &pmvl1, &l0_rFrame, &l1_rFrame); + + for (block8x8=0; block8x8<4; block8x8++) + { + int mv_mode = currMB->b8mode[block8x8]; + int pred_dir = currMB->b8pdir[block8x8]; + + if ( mv_mode != 0 ) + { + int k_start = (block8x8 << 2); + int k_inc = (mv_mode == SMB8x4) ? 2 : 1; + int k_end = (mv_mode == SMB8x8) ? k_start + 1 : ((mv_mode == SMB4x4) ? k_start + 4 : k_start + k_inc + 1); + + block_size_x = ( mv_mode == SMB8x4 || mv_mode == SMB8x8 ) ? SMB_BLOCK_SIZE : BLOCK_SIZE; + block_size_y = ( mv_mode == SMB4x8 || mv_mode == SMB8x8 ) ? SMB_BLOCK_SIZE : BLOCK_SIZE; + + for (k = k_start; k < k_end; k += k_inc) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, block_size_x, block_size_y); + } + } + else + { + int k_start = (block8x8 << 2); + int k_end = k_start; + + if (p_Vid->active_sps->direct_8x8_inference_flag) + { + block_size_x = SMB_BLOCK_SIZE; + block_size_y = SMB_BLOCK_SIZE; + k_end ++; + } + else + { + block_size_x = BLOCK_SIZE; + block_size_y = BLOCK_SIZE; + k_end += BLOCK_MULTIPLE; + } + + // Prepare mvs (needed for deblocking and mv prediction + if (currSlice->direct_spatial_mv_pred_flag) + { + for (k = k_start; k < k_start + BLOCK_MULTIPLE; k ++) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + + assert (pred_dir<=2); + + //===== DIRECT PREDICTION ===== + // motion information should be already set + if (mv_info->ref_idx[LIST_1] == -1) + { + pred_dir = 0; + } + else if (mv_info->ref_idx[LIST_0] == -1) + { + pred_dir = 1; + } + else + { + pred_dir = 2; + } + } + } + else + { + for (k = k_start; k < k_start + BLOCK_MULTIPLE; k ++) + { + + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + + assert (pred_dir<=2); + + // store reference picture ID determined by direct mode + mv_info->ref_pic[LIST_0] = list0[(short)mv_info->ref_idx[LIST_0]]; + mv_info->ref_pic[LIST_1] = list1[(short)mv_info->ref_idx[LIST_1]]; + } + } + + for (k = k_start; k < k_end; k ++) + { + int i = (decode_block_scan[k] & 3); + int j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, curr_plane, dec_picture, pred_dir, i, j, block_size_x, block_size_y); + } + } + } + + iTransform(currMB, curr_plane, 0); + if (currMB->cbp != 0) + currSlice->is_reset_coeff = FALSE; + return 1; +} + +/*! +************************************************************************ +* \brief +* Copy IPCM coefficients to decoded picture buffer and set parameters for this MB +* (for IPCM CABAC and IPCM CAVLC 28/11/2003) +* +* \author +* Dong Wang +************************************************************************ +*/ + +int mb_pred_ipcm(Macroblock *currMB) +{ + int i, j, k; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + + //Copy coefficients to decoded picture buffer + //IPCM coefficients are stored in currSlice->cof which is set in function read_IPCM_coeffs_from_NAL() + + for(i = 0; i < MB_BLOCK_SIZE; ++i) + { + for(j = 0;j < MB_BLOCK_SIZE ; ++j) + { + dec_picture->imgY[currMB->pix_y + i][currMB->pix_x + j] = (imgpel) currSlice->cof[0][i][j]; + } + } + + if ((dec_picture->chroma_format_idc != YUV400) && (p_Vid->separate_colour_plane_flag == 0)) + { + for (k = 0; k < 2; ++k) + { + for(i = 0; i < p_Vid->mb_cr_size_y; ++i) + { + for(j = 0;j < p_Vid->mb_cr_size_x; ++j) + { + dec_picture->imgUV[k][currMB->pix_c_y+i][currMB->pix_c_x + j] = (imgpel) currSlice->cof[k + 1][i][j]; + } + } + } + } + + // for deblocking filter + update_qp(currMB, 0); + + // for CAVLC: Set the nz_coeff to 16. + // These parameters are to be used in CAVLC decoding of neighbour blocks + memset(p_Vid->nz_coeff[currMB->mbAddrX][0][0], 16, 3 * BLOCK_PIXELS * sizeof(byte)); + + // for CABAC decoding of MB skip flag + currMB->skip_flag = 0; + + //for deblocking filter CABAC + currMB->s_cbp[0].blk = 0xFFFF; + + //For CABAC decoding of Dquant + currSlice->last_dquant = 0; + currSlice->is_reset_coeff = FALSE; + currSlice->is_reset_coeff_cr = FALSE; + return 1; +} + diff --git a/ldecod/src/mb_read.c b/ldecod/src/mb_read.c new file mode 100644 index 0000000..569159e --- /dev/null +++ b/ldecod/src/mb_read.c @@ -0,0 +1,2230 @@ +/*! + *********************************************************************** + * \file macroblock.c + * + * \brief + * Decode a Macroblock + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langøy + * - Rickard Sjoberg + * - Jani Lainema + * - Sebastian Purreiter + * - Thomas Wedi + * - Detlev Marpe + * - Gabi Blaettermann + * - Ye-Kui Wang + * - Lowell Winger + * - Alexis Michael Tourapis + *********************************************************************** +*/ + +#include "contributors.h" + +#include + +#include "block.h" +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_mvc.h" +#include "elements.h" +//#include "errorconcealment.h" +#include "macroblock.h" +#include "fmo.h" +#include "cabac.h" +#include "vlc.h" +#include "image.h" +#include "mb_access.h" +#include "biaridecod.h" +#include "transform.h" +#include "mc_prediction.h" +#include "quant.h" +#include "mv_prediction.h" +#include "mb_prediction.h" +#include "fast_memory.h" +#include "filehandle.h" + +#if TRACE +#define TRACE_STRING(s) strncpy(currSE.tracestring, s, TRACESTRING_SIZE) +#define TRACE_DECBITS(i) dectracebitcnt(1) +#define TRACE_printf(s) sprintf(type, "%s", s); +#define TRACE_STRING_P(s) strncpy(currSE->tracestring, s, TRACESTRING_SIZE) +#else +#define TRACE_STRING(s) +#define TRACE_DECBITS(i) +#define TRACE_printf(s) +#define TRACE_STRING_P(s) +#endif + +extern void set_read_comp_coeff_cabac (Macroblock *currMB); +extern void set_read_comp_coeff_cavlc (Macroblock *currMB); + +static inline void update_pixel_pos8(PixelPos *pos_block, const PixelPos *pos_mb, int pos) +{ + *pos_block = *pos_mb; + if (pos_block->available) + { + if (pos == 1) + { + pos_block->pos_x += 2; + } + else if (pos == 2) + { + pos_block->pos_y += 2; + } + else if (pos == 3) + { + pos_block->pos_y += 2; + pos_block->pos_x += 2; + } + } +} + +/*! + ************************************************************************ + * \brief + * Read Intra 8x8 Prediction modes + * + ************************************************************************ + */ +static void read_ipred_8x8_modes_mbaff(Macroblock *currMB) +{ + int b8, bi, bj, bx, by, dec; + SyntaxElement currSE; + DataPartition *dP; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + VideoParameters *p_Vid = currMB->p_Vid; + + int mostProbableIntraPredMode; + int upIntraPredMode; + int leftIntraPredMode; + + PixelPos left_block, top_block; + + currSE.type = SE_INTRAPREDMODE; + + TRACE_STRING("intra4x4_pred_mode"); + dP = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + if (!(p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag)) + currSE.reading = readIntraPredMode_CABAC; + + for(b8 = 0; b8 < 4; ++b8) //loop 8x8 blocks + { + by = (b8 & 0x02); + bj = currMB->block_y + by; + + bx = ((b8 & 0x01) << 1); + bi = currMB->block_x + bx; + //get from stream + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + readSyntaxElement_Intra4x4PredictionMode(&currSE, dP->bitstream); + else + { + currSE.context = (b8 << 2); + dP->readSyntaxElement(currMB, &currSE, dP); + } + + get4x4Neighbour(currMB, (bx << 2) - 1, (by << 2), p_Vid->mb_size[IS_LUMA], &left_block); + get4x4Neighbour(currMB, (bx << 2), (by << 2) - 1, p_Vid->mb_size[IS_LUMA], &top_block ); + + //get from array and decode + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + left_block.available = left_block.available ? currSlice->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? currSlice->intra_block[top_block.mb_addr] : 0; + } + + upIntraPredMode = (top_block.available ) ? currSlice->ipredmode[top_block.pos_y ][top_block.pos_x ] : -1; + leftIntraPredMode = (left_block.available) ? currSlice->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableIntraPredMode = (upIntraPredMode < 0 || leftIntraPredMode < 0) ? DC_PRED : upIntraPredMode < leftIntraPredMode ? upIntraPredMode : leftIntraPredMode; + + dec = (currSE.value1 == -1) ? mostProbableIntraPredMode : currSE.value1 + (currSE.value1 >= mostProbableIntraPredMode); + + //set + //loop 4x4s in the subblock for 8x8 prediction setting + currSlice->ipredmode[bj ][bi ] = (byte) dec; + currSlice->ipredmode[bj ][bi + 1] = (byte) dec; + currSlice->ipredmode[bj + 1][bi ] = (byte) dec; + currSlice->ipredmode[bj + 1][bi + 1] = (byte) dec; + } +} + +/*! + ************************************************************************ + * \brief + * Read Intra 8x8 Prediction modes + * + ************************************************************************ + */ +static void read_ipred_8x8_modes(Macroblock *currMB) +{ + int b8, bi, bj, bx, by, dec; + SyntaxElement currSE; + DataPartition *dP; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + VideoParameters *p_Vid = currMB->p_Vid; + + int mostProbableIntraPredMode; + int upIntraPredMode; + int leftIntraPredMode; + + PixelPos left_mb, top_mb; + PixelPos left_block, top_block; + + currSE.type = SE_INTRAPREDMODE; + + TRACE_STRING("intra4x4_pred_mode"); + dP = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + if (!(p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag)) + currSE.reading = readIntraPredMode_CABAC; + + get4x4Neighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &left_mb); + get4x4Neighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &top_mb ); + + for(b8 = 0; b8 < 4; ++b8) //loop 8x8 blocks + { + + + by = (b8 & 0x02); + bj = currMB->block_y + by; + + bx = ((b8 & 0x01) << 1); + bi = currMB->block_x + bx; + + //get from stream + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + readSyntaxElement_Intra4x4PredictionMode(&currSE, dP->bitstream); + else + { + currSE.context = (b8 << 2); + dP->readSyntaxElement(currMB, &currSE, dP); + } + + get4x4Neighbour(currMB, (bx<<2) - 1, (by<<2), p_Vid->mb_size[IS_LUMA], &left_block); + get4x4Neighbour(currMB, (bx<<2), (by<<2) - 1, p_Vid->mb_size[IS_LUMA], &top_block ); + + //get from array and decode + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + left_block.available = left_block.available ? currSlice->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? currSlice->intra_block[top_block.mb_addr] : 0; + } + + upIntraPredMode = (top_block.available ) ? currSlice->ipredmode[top_block.pos_y ][top_block.pos_x ] : -1; + leftIntraPredMode = (left_block.available) ? currSlice->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableIntraPredMode = (upIntraPredMode < 0 || leftIntraPredMode < 0) ? DC_PRED : upIntraPredMode < leftIntraPredMode ? upIntraPredMode : leftIntraPredMode; + + dec = (currSE.value1 == -1) ? mostProbableIntraPredMode : currSE.value1 + (currSE.value1 >= mostProbableIntraPredMode); + + //set + //loop 4x4s in the subblock for 8x8 prediction setting + currSlice->ipredmode[bj ][bi ] = (byte) dec; + currSlice->ipredmode[bj ][bi + 1] = (byte) dec; + currSlice->ipredmode[bj + 1][bi ] = (byte) dec; + currSlice->ipredmode[bj + 1][bi + 1] = (byte) dec; + } +} + +/*! + ************************************************************************ + * \brief + * Read Intra 4x4 Prediction modes + * + ************************************************************************ + */ +static void read_ipred_4x4_modes_mbaff(Macroblock *currMB) +{ + int b8,i,j,bi,bj,bx,by; + SyntaxElement currSE; + DataPartition *dP; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + VideoParameters *p_Vid = currMB->p_Vid; + BlockPos *PicPos = p_Vid->PicPos; + + int ts, ls; + int mostProbableIntraPredMode; + int upIntraPredMode; + int leftIntraPredMode; + + PixelPos left_block, top_block; + + currSE.type = SE_INTRAPREDMODE; + + TRACE_STRING("intra4x4_pred_mode"); + dP = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + if (!(p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag)) + currSE.reading = readIntraPredMode_CABAC; + + for(b8 = 0; b8 < 4; ++b8) //loop 8x8 blocks + { + for(j = 0; j < 2; j++) //loop subblocks + { + by = (b8 & 0x02) + j; + bj = currMB->block_y + by; + + for(i = 0; i < 2; i++) + { + bx = ((b8 & 1) << 1) + i; + bi = currMB->block_x + bx; + //get from stream + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + readSyntaxElement_Intra4x4PredictionMode(&currSE, dP->bitstream); + else + { + currSE.context=(b8<<2) + (j<<1) +i; + dP->readSyntaxElement(currMB, &currSE, dP); + } + + get4x4Neighbour(currMB, (bx<<2) - 1, (by<<2), p_Vid->mb_size[IS_LUMA], &left_block); + get4x4Neighbour(currMB, (bx<<2), (by<<2) - 1, p_Vid->mb_size[IS_LUMA], &top_block ); + + //get from array and decode + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + left_block.available = left_block.available ? currSlice->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? currSlice->intra_block[top_block.mb_addr] : 0; + } + + // !! KS: not sure if the following is still correct... + ts = ls = 0; // Check to see if the neighboring block is SI + if (currSlice->slice_type == SI_SLICE) // need support for MBINTLC1 + { + if (left_block.available) + if (currSlice->siblock [PicPos[left_block.mb_addr].y][PicPos[left_block.mb_addr].x]) + ls=1; + + if (top_block.available) + if (currSlice->siblock [PicPos[top_block.mb_addr].y][PicPos[top_block.mb_addr].x]) + ts=1; + } + + upIntraPredMode = (top_block.available &&(ts == 0)) ? currSlice->ipredmode[top_block.pos_y ][top_block.pos_x ] : -1; + leftIntraPredMode = (left_block.available &&(ls == 0)) ? currSlice->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableIntraPredMode = (upIntraPredMode < 0 || leftIntraPredMode < 0) ? DC_PRED : upIntraPredMode < leftIntraPredMode ? upIntraPredMode : leftIntraPredMode; + + currSlice->ipredmode[bj][bi] = (byte) ((currSE.value1 == -1) ? mostProbableIntraPredMode : currSE.value1 + (currSE.value1 >= mostProbableIntraPredMode)); + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Read Intra 4x4 Prediction modes + * + ************************************************************************ + */ +static void read_ipred_4x4_modes(Macroblock *currMB) +{ + int b8,i,j,bi,bj,bx,by; + SyntaxElement currSE; + DataPartition *dP; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + VideoParameters *p_Vid = currMB->p_Vid; + BlockPos *PicPos = p_Vid->PicPos; + + int ts, ls; + int mostProbableIntraPredMode; + int upIntraPredMode; + int leftIntraPredMode; + + PixelPos left_mb, top_mb; + PixelPos left_block, top_block; + + currSE.type = SE_INTRAPREDMODE; + + TRACE_STRING("intra4x4_pred_mode"); + dP = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + if (!(p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag)) + currSE.reading = readIntraPredMode_CABAC; + + get4x4Neighbour(currMB, -1, 0, p_Vid->mb_size[IS_LUMA], &left_mb); + get4x4Neighbour(currMB, 0, -1, p_Vid->mb_size[IS_LUMA], &top_mb ); + + for(b8 = 0; b8 < 4; ++b8) //loop 8x8 blocks + { + for(j = 0; j < 2; j++) //loop subblocks + { + by = (b8 & 0x02) + j; + bj = currMB->block_y + by; + + for(i = 0; i < 2; i++) + { + bx = ((b8 & 1) << 1) + i; + bi = currMB->block_x + bx; + //get from stream + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + readSyntaxElement_Intra4x4PredictionMode(&currSE, dP->bitstream); + else + { + currSE.context=(b8<<2) + (j<<1) +i; + dP->readSyntaxElement(currMB, &currSE, dP); + } + + get4x4Neighbour(currMB, (bx<<2) - 1, (by<<2), p_Vid->mb_size[IS_LUMA], &left_block); + get4x4Neighbour(currMB, (bx<<2), (by<<2) - 1, p_Vid->mb_size[IS_LUMA], &top_block ); + + //get from array and decode + + if (p_Vid->active_pps->constrained_intra_pred_flag) + { + left_block.available = left_block.available ? currSlice->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? currSlice->intra_block[top_block.mb_addr] : 0; + } + + // !! KS: not sure if the following is still correct... + ts = ls = 0; // Check to see if the neighboring block is SI + if (currSlice->slice_type == SI_SLICE) // need support for MBINTLC1 + { + if (left_block.available) + if (currSlice->siblock [PicPos[left_block.mb_addr].y][PicPos[left_block.mb_addr].x]) + ls=1; + + if (top_block.available) + if (currSlice->siblock [PicPos[top_block.mb_addr].y][PicPos[top_block.mb_addr].x]) + ts=1; + } + + upIntraPredMode = (top_block.available &&(ts == 0)) ? currSlice->ipredmode[top_block.pos_y ][top_block.pos_x ] : -1; + leftIntraPredMode = (left_block.available &&(ls == 0)) ? currSlice->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableIntraPredMode = (upIntraPredMode < 0 || leftIntraPredMode < 0) ? DC_PRED : upIntraPredMode < leftIntraPredMode ? upIntraPredMode : leftIntraPredMode; + + currSlice->ipredmode[bj][bi] = (byte) ((currSE.value1 == -1) ? mostProbableIntraPredMode : currSE.value1 + (currSE.value1 >= mostProbableIntraPredMode)); + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Read Intra Prediction modes + * + ************************************************************************ + */ +static void read_ipred_modes(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + StorablePicture *dec_picture = currSlice->dec_picture; + + if (currSlice->mb_aff_frame_flag) + { + if (currMB->mb_type == I8MB) + read_ipred_8x8_modes_mbaff(currMB); + else if (currMB->mb_type == I4MB) + read_ipred_4x4_modes_mbaff(currMB); + } + else + { + if (currMB->mb_type == I8MB) + read_ipred_8x8_modes(currMB); + else if (currMB->mb_type == I4MB) + read_ipred_4x4_modes(currMB); + } + + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444)) + { + SyntaxElement currSE; + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + VideoParameters *p_Vid = currMB->p_Vid; + + currSE.type = SE_INTRAPREDMODE; + TRACE_STRING("intra_chroma_pred_mode"); + dP = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC || dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + else + currSE.reading = readCIPredMode_CABAC; + + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->c_ipred_mode = (char) currSE.value1; + + if (currMB->c_ipred_mode < DC_PRED_8 || currMB->c_ipred_mode > PLANE_8) + { + error("illegal chroma intra pred mode!\n", 600); + } + } +} + + +static inline void reset_mbs(Macroblock *currMB) +{ + currMB->slice_nr = -1; + currMB->ei_flag = 1; + currMB->dpl_flag = 0; +} + +static inline void reset_mv_info(PicMotionParams *mv_info, int slice_no) +{ + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = -1; + mv_info->slice_no = slice_no; +} + +static inline void reset_mv_info_list(PicMotionParams *mv_info, int list, int slice_no) +{ + mv_info->ref_pic[list] = NULL; + mv_info->mv[list] = zero_mv; + mv_info->ref_idx[list] = -1; + mv_info->slice_no = slice_no; +} + +/*! + ************************************************************************ + * \brief + * init macroblock for skip mode. Only L1 info needs to be reset + ************************************************************************ + */ +static void init_macroblock_basic(Macroblock *currMB) +{ + int j, i; + PicMotionParams **mv_info = &currMB->p_Slice->dec_picture->mv_info[currMB->block_y]; //&p_Vid->dec_picture->mv_info[currMB->block_y]; + int slice_no = currMB->p_Slice->current_slice_nr; + // reset vectors and pred. modes + for(j = 0; j < BLOCK_SIZE; ++j) + { + i = currMB->block_x; + reset_mv_info_list(*mv_info + (i++), LIST_1, slice_no); + reset_mv_info_list(*mv_info + (i++), LIST_1, slice_no); + reset_mv_info_list(*mv_info + (i++), LIST_1, slice_no); + reset_mv_info_list(*(mv_info++) + i, LIST_1, slice_no); + } +} + +/*! + ************************************************************************ + * \brief + * init macroblock (direct) + ************************************************************************ + */ +static void init_macroblock_direct(Macroblock *currMB) +{ + int slice_no = currMB->p_Slice->current_slice_nr; + PicMotionParams **mv_info = &currMB->p_Slice->dec_picture->mv_info[currMB->block_y]; + int i, j; + + set_read_comp_coeff_cabac(currMB); + set_read_comp_coeff_cavlc(currMB); + i = currMB->block_x; + for(j = 0; j < BLOCK_SIZE; ++j) + { + (*mv_info+i)->slice_no = slice_no; + (*mv_info+i+1)->slice_no = slice_no; + (*mv_info+i+2)->slice_no = slice_no; + (*(mv_info++)+i+3)->slice_no = slice_no; + } +} + + +/*! + ************************************************************************ + * \brief + * init macroblock + ************************************************************************ + */ +static void init_macroblock(Macroblock *currMB) +{ + int j, i; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **mv_info = &currSlice->dec_picture->mv_info[currMB->block_y]; + int slice_no = currSlice->current_slice_nr; + // reset vectors and pred. modes + + for(j = 0; j < BLOCK_SIZE; ++j) + { + i = currMB->block_x; + reset_mv_info(*mv_info + (i++), slice_no); + reset_mv_info(*mv_info + (i++), slice_no); + reset_mv_info(*mv_info + (i++), slice_no); + reset_mv_info(*(mv_info++) + i, slice_no); + } + + set_read_comp_coeff_cabac(currMB); + set_read_comp_coeff_cavlc(currMB); +} + +static void concealIPCMcoeffs(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + StorablePicture *dec_picture = currSlice->dec_picture; + int i, j, k; + + for(i=0;icof[0][i][j] = p_Vid->dc_pred_value_comp[0]; + //currSlice->fcf[0][i][j] = p_Vid->dc_pred_value_comp[0]; + } + } + + if ((dec_picture->chroma_format_idc != YUV400) && (p_Vid->separate_colour_plane_flag == 0)) + { + for (k = 0; k < 2; ++k) + { + for(i=0;imb_cr_size_y;++i) + { + for(j=0;jmb_cr_size_x;++j) + { + currSlice->cof[k][i][j] = p_Vid->dc_pred_value_comp[k]; + //currSlice->fcf[k][i][j] = p_Vid->dc_pred_value_comp[k]; + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Initialize decoding engine after decoding an IPCM macroblock + * (for IPCM CABAC 28/11/2003) + * + * \author + * Dong Wang + ************************************************************************ + */ +static void init_decoding_engine_IPCM(Slice *currSlice) +{ + Bitstream *currStream; + int ByteStartPosition; + int PartitionNumber; + int i; + + if(currSlice->dp_mode==PAR_DP_1) + PartitionNumber=1; + else if(currSlice->dp_mode==PAR_DP_3) + PartitionNumber=3; + else + { + printf("Partition Mode is not supported\n"); + exit(1); + } + + for(i=0;ipartArr[i].bitstream; + ByteStartPosition = currStream->read_len; + + arideco_start_decoding (&currSlice->partArr[i].de_cabac, currStream->streamBuffer, ByteStartPosition, &currStream->read_len); + } +} + +/*! + ************************************************************************ + * \brief + * Read IPCM pcm_alignment_zero_bit and pcm_byte[i] from stream to currSlice->cof + * (for IPCM CABAC and IPCM CAVLC) + * + * \author + * Dong Wang + ************************************************************************ + */ +static void read_IPCM_coeffs_from_NAL(Slice *currSlice, struct datapartition_dec *dP) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + + StorablePicture *dec_picture = currSlice->dec_picture; + SyntaxElement currSE; + int i,j; + + //For CABAC, we don't need to read bits to let stream byte aligned + // because we have variable for integer bytes position + if(p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CABAC) + { + readIPCM_CABAC(currSlice, dP); + init_decoding_engine_IPCM(currSlice); + } + else + { + //read bits to let stream byte aligned + + if(((dP->bitstream->frame_bitoffset) & 0x07) != 0) + { + TRACE_STRING("pcm_alignment_zero_bit"); + currSE.len = (8 - ((dP->bitstream->frame_bitoffset) & 0x07)); + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + + //read luma and chroma IPCM coefficients + currSE.len=p_Vid->bitdepth_luma; + TRACE_STRING("pcm_sample_luma"); + + for(i=0;ibitstream); + currSlice->cof[0][i][j] = currSE.value1; + //currSlice->fcf[0][i][j] = currSE.value1; + } + } + currSE.len=p_Vid->bitdepth_chroma; + if ((dec_picture->chroma_format_idc != YUV400) && (p_Vid->separate_colour_plane_flag == 0)) + { + TRACE_STRING("pcm_sample_chroma (u)"); + for(i=0;imb_cr_size_y;++i) + { + for(j=0;jmb_cr_size_x;++j) + { + readSyntaxElement_FLC(&currSE, dP->bitstream); + currSlice->cof[1][i][j] = currSE.value1; + //currSlice->fcf[1][i][j] = currSE.value1; + } + } + TRACE_STRING("pcm_sample_chroma (v)"); + for(i=0;imb_cr_size_y;++i) + { + for(j=0;jmb_cr_size_x;++j) + { + readSyntaxElement_FLC(&currSE, dP->bitstream); + currSlice->cof[2][i][j] = currSE.value1; + //currSlice->fcf[2][i][j] = currSE.value1; + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Sets mode for 8x8 block + ************************************************************************ + */ +static inline void SetB8Mode (Macroblock* currMB, int value, int i) +{ + Slice* currSlice = currMB->p_Slice; + static const char p_v2b8 [ 5] = {4, 5, 6, 7, IBLOCK}; + static const char p_v2pd [ 5] = {0, 0, 0, 0, -1}; + static const char b_v2b8 [14] = {0, 4, 4, 4, 5, 6, 5, 6, 5, 6, 7, 7, 7, IBLOCK}; + static const char b_v2pd [14] = {2, 0, 1, 2, 0, 0, 1, 1, 2, 2, 0, 1, 2, -1}; + + if (currSlice->slice_type==B_SLICE) + { + currMB->b8mode[i] = b_v2b8[value]; + currMB->b8pdir[i] = b_v2pd[value]; + } + else + { + currMB->b8mode[i] = p_v2b8[value]; + currMB->b8pdir[i] = p_v2pd[value]; + } +} + +static inline void reset_coeffs(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + + // CAVLC + if (p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CAVLC) + fast_memset(p_Vid->nz_coeff[currMB->mbAddrX][0][0], 0, 3 * BLOCK_PIXELS * sizeof(byte)); +} + +static inline void field_flag_inference(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + if (currMB->mbAvailA) + { + currMB->mb_field = p_Vid->mb_data[currMB->mbAddrA].mb_field; + } + else + { + // check top macroblock pair + currMB->mb_field = currMB->mbAvailB ? p_Vid->mb_data[currMB->mbAddrB].mb_field : FALSE; + } +} + + +void skip_macroblock(Macroblock *currMB) +{ + MotionVector pred_mv; + int zeroMotionAbove; + int zeroMotionLeft; + PixelPos mb[4]; // neighbor blocks + int i, j; + int a_mv_y = 0; + int a_ref_idx = 0; + int b_mv_y = 0; + int b_ref_idx = 0; + int img_block_y = currMB->block_y; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int list_offset = LIST_0 + currMB->list_offset; + StorablePicture *dec_picture = currSlice->dec_picture; + MotionVector *a_mv = NULL; + MotionVector *b_mv = NULL; + + get_neighbors(currMB, mb, 0, 0, MB_BLOCK_SIZE); + if (currSlice->mb_aff_frame_flag == 0) + { + if (mb[0].available) + { + a_mv = &dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].mv[LIST_0]; + a_mv_y = a_mv->mv_y; + a_ref_idx = dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0]; + } + + if (mb[1].available) + { + b_mv = &dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].mv[LIST_0]; + b_mv_y = b_mv->mv_y; + b_ref_idx = dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0]; + } + } + else + { + if (mb[0].available) + { + a_mv = &dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].mv[LIST_0]; + a_mv_y = a_mv->mv_y; + a_ref_idx = dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0]; + + if (currMB->mb_field && !p_Vid->mb_data[mb[0].mb_addr].mb_field) + { + a_mv_y /=2; + a_ref_idx *=2; + } + if (!currMB->mb_field && p_Vid->mb_data[mb[0].mb_addr].mb_field) + { + a_mv_y *=2; + a_ref_idx >>=1; + } + } + + if (mb[1].available) + { + b_mv = &dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].mv[LIST_0]; + b_mv_y = b_mv->mv_y; + b_ref_idx = dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0]; + + if (currMB->mb_field && !p_Vid->mb_data[mb[1].mb_addr].mb_field) + { + b_mv_y /=2; + b_ref_idx *=2; + } + if (!currMB->mb_field && p_Vid->mb_data[mb[1].mb_addr].mb_field) + { + b_mv_y *=2; + b_ref_idx >>=1; + } + } + } + + zeroMotionLeft = !mb[0].available ? 1 : a_ref_idx==0 && a_mv->mv_x == 0 && a_mv_y==0 ? 1 : 0; + zeroMotionAbove = !mb[1].available ? 1 : b_ref_idx==0 && b_mv->mv_x == 0 && b_mv_y==0 ? 1 : 0; + + currMB->cbp = 0; + reset_coeffs(currMB); + + if (zeroMotionAbove || zeroMotionLeft) + { + PicMotionParams **dec_mv_info = &dec_picture->mv_info[img_block_y]; + StorablePicture *cur_pic = currSlice->listX[list_offset][0]; + PicMotionParams *mv_info = NULL; + + for(j = 0; j < BLOCK_SIZE; ++j) + { + for(i = currMB->block_x; i < currMB->block_x + BLOCK_SIZE; ++i) + { + mv_info = &dec_mv_info[j][i]; + mv_info->ref_pic[LIST_0] = cur_pic; + mv_info->mv [LIST_0] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + } + } + } + else + { + PicMotionParams **dec_mv_info = &dec_picture->mv_info[img_block_y]; + PicMotionParams *mv_info = NULL; + StorablePicture *cur_pic = currSlice->listX[list_offset][0]; + currMB->GetMVPredictor (currMB, mb, &pred_mv, 0, dec_picture->mv_info, LIST_0, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + // Set first block line (position img_block_y) + for(j = 0; j < BLOCK_SIZE; ++j) + { + for(i = currMB->block_x; i < currMB->block_x + BLOCK_SIZE; ++i) + { + mv_info = &dec_mv_info[j][i]; + mv_info->ref_pic[LIST_0] = cur_pic; + mv_info->mv [LIST_0] = pred_mv; + mv_info->ref_idx[LIST_0] = 0; + } + } + } +} +/*! + ************************************************************************ + * \brief + * read and set skip macroblock information + ************************************************************************ + */ +static void read_skip_macroblock(Macroblock *currMB) +{ + currMB->luma_transform_size_8x8_flag = FALSE; + + if(currMB->p_Vid->active_pps->constrained_intra_pred_flag) + { + int mb_nr = currMB->mbAddrX; + currMB->p_Slice->intra_block[mb_nr] = 0; + } + + //--- init macroblock data --- + init_macroblock_basic(currMB); + + skip_macroblock(currMB); +} + +/*! + ************************************************************************ + * \brief + * read and set intra (other than 4x4/8x8) mode macroblock information + ************************************************************************ + */ +static void read_intra_macroblock(Macroblock *currMB) +{ + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + //============= Transform Size Flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + currMB->luma_transform_size_8x8_flag = FALSE; + + //--- init macroblock data --- + init_macroblock(currMB); + + // intra prediction modes for a macroblock 4x4 ********************************************** + read_ipred_modes(currMB); + + // read CBP and Coeffs *************************************************************** + currMB->p_Slice->read_CBP_and_coeffs_from_NAL (currMB); +} + + +/*! + ************************************************************************ + * \brief + * read and set intra (4x4/8x8) mode macroblock information (CAVLC) + ************************************************************************ + */ +static void read_intra4x4_macroblock_cavlc(Macroblock *currMB, const byte *partMap) +{ + Slice *currSlice = currMB->p_Slice; + //============= Transform Size Flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + if (currSlice->Transform8x8Mode) + { + SyntaxElement currSE; + DataPartition *dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.type = SE_HEADER; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + + if (currMB->luma_transform_size_8x8_flag) + { + currMB->mb_type = I8MB; + memset(&currMB->b8mode, I8MB, 4 * sizeof(char)); + memset(&currMB->b8pdir, -1, 4 * sizeof(char)); + } + } + else + { + currMB->luma_transform_size_8x8_flag = FALSE; + } + + //--- init macroblock data --- + init_macroblock(currMB); + + // intra prediction modes for a macroblock 4x4 ********************************************** + read_ipred_modes(currMB); + + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); +} + +/*! + ************************************************************************ + * \brief + * read and set intra (4x4/8x8) mode macroblock information (CAVLC) + ************************************************************************ + */ +static void read_intra4x4_macroblock_cabac(Macroblock *currMB, const byte *partMap) +{ + Slice *currSlice = currMB->p_Slice; + //============= Transform Size Flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + if (currSlice->Transform8x8Mode) + { + SyntaxElement currSE; + DataPartition *dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.type = SE_HEADER; + currSE.reading = readMB_transform_size_flag_CABAC; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + if (dP->bitstream->ei_flag) + { + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + dP->readSyntaxElement(currMB, &currSE, dP); + } + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + + if (currMB->luma_transform_size_8x8_flag) + { + currMB->mb_type = I8MB; + memset(&currMB->b8mode, I8MB, 4 * sizeof(char)); + memset(&currMB->b8pdir, -1, 4 * sizeof(char)); + } + } + else + { + currMB->luma_transform_size_8x8_flag = FALSE; + } + + //--- init macroblock data --- + init_macroblock(currMB); + + // intra prediction modes for a macroblock 4x4 ********************************************** + read_ipred_modes(currMB); + + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); +} + + +/*! + ************************************************************************ + * \brief + * read and set generic (non skip/direct and P8x8) inter + * mode macroblock information + ************************************************************************ + */ +static void read_inter_macroblock(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + currMB->luma_transform_size_8x8_flag = FALSE; + + if(currMB->p_Vid->active_pps->constrained_intra_pred_flag) + { + int mb_nr = currMB->mbAddrX; + currSlice->intra_block[mb_nr] = 0; + } + + //--- init macroblock data --- + init_macroblock(currMB); + + // read inter frame vector data ********************************************************* + currSlice->read_motion_info_from_NAL (currMB); + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); +} + +/*! + ************************************************************************ + * \brief + * read and set I_PCM mode macroblock information + ************************************************************************ + */ +static void read_i_pcm_macroblock(Macroblock *currMB, const byte *partMap) +{ + Slice *currSlice = currMB->p_Slice; + currMB->NoMbPartLessThan8x8Flag = TRUE; + currMB->luma_transform_size_8x8_flag = FALSE; + + //--- init macroblock data --- + init_macroblock(currMB); + + //read pcm_alignment_zero_bit and pcm_byte[i] + + // here dP is assigned with the same dP as SE_MBTYPE, because IPCM syntax is in the + // same category as MBTYPE + if ( currSlice->dp_mode && currSlice->dpB_NotPresent ) + { + concealIPCMcoeffs(currMB); + } + else + { + DataPartition *dP = &(currSlice->partArr[partMap[SE_LUM_DC_INTRA]]); + read_IPCM_coeffs_from_NAL(currSlice, dP); + } +} + +/*! + ************************************************************************ + * \brief + * read and set P8x8 mode macroblock information + ************************************************************************ + */ +static void read_P8x8_macroblock(Macroblock *currMB, DataPartition *dP, SyntaxElement *currSE) +{ + int i; + Slice *currSlice = currMB->p_Slice; + //====== READ 8x8 SUB-PARTITION MODES (modes of 8x8 blocks) and Intra VBST block modes ====== + currMB->NoMbPartLessThan8x8Flag = TRUE; + currMB->luma_transform_size_8x8_flag = FALSE; + + for (i = 0; i < 4; ++i) + { + TRACE_STRING_P("sub_mb_type"); + dP->readSyntaxElement (currMB, currSE, dP); + SetB8Mode (currMB, currSE->value1, i); + + //set NoMbPartLessThan8x8Flag for P8x8 mode + currMB->NoMbPartLessThan8x8Flag &= (currMB->b8mode[i] == 0 && currSlice->active_sps->direct_8x8_inference_flag) || + (currMB->b8mode[i] == 4); + } + + //--- init macroblock data --- + init_macroblock (currMB); + currSlice->read_motion_info_from_NAL (currMB); + + if(currMB->p_Vid->active_pps->constrained_intra_pred_flag) + { + int mb_nr = currMB->mbAddrX; + currSlice->intra_block[mb_nr] = 0; + } + + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); +} + +/*! + ************************************************************************ + * \brief + * Get the syntax elements from the NAL + ************************************************************************ + */ +static void read_one_macroblock_i_slice_cavlc(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + + SyntaxElement currSE; + int mb_nr = currMB->mbAddrX; + + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + currMB->mb_field = ((mb_nr&0x01) == 0)? FALSE : currSlice->mb_data[mb_nr-1].mb_field; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + currSE.mapping = linfo_ue; + + // read MB aff + if (currSlice->mb_aff_frame_flag && (mb_nr&0x01)==0) + { + TRACE_STRING("mb_field_decoding_flag"); + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + currMB->mb_field = (Boolean) currSE.value1; + } + + // read MB type + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + + motion->mb_field[mb_nr] = (byte) currMB->mb_field; + + currMB->block_y_aff = ((currSlice->mb_aff_frame_flag) && (currMB->mb_field)) ? (mb_nr&0x01) ? (currMB->block_y - 4)>>1 : currMB->block_y >> 1 : currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + if(currMB->mb_type == IPCM) + { + read_i_pcm_macroblock(currMB, partMap); + } + else if (currMB->mb_type == I4MB) + { + read_intra4x4_macroblock_cavlc(currMB, partMap); + } + else // all other modes + { + read_intra_macroblock(currMB); + } + return; +} + +/*! + ************************************************************************ + * \brief + * Get the syntax elements from the NAL + ************************************************************************ + */ +static void read_one_macroblock_i_slice_cabac(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + + SyntaxElement currSE; + int mb_nr = currMB->mbAddrX; + + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + currMB->mb_field = ((mb_nr&0x01) == 0)? FALSE : currSlice->mb_data[mb_nr-1].mb_field; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + + // read MB aff + if (currSlice->mb_aff_frame_flag && (mb_nr&0x01)==0) + { + TRACE_STRING("mb_field_decoding_flag"); + if (dP->bitstream->ei_flag) + { + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + currSE.reading = readFieldModeInfo_CABAC; + dP->readSyntaxElement(currMB, &currSE, dP); + } + currMB->mb_field = (Boolean) currSE.value1; + } + + CheckAvailabilityOfNeighborsCABAC(currMB); + + // read MB type + TRACE_STRING("mb_type"); + currSE.reading = readMB_typeInfo_CABAC_i_slice; + dP->readSyntaxElement(currMB, &currSE, dP); + + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + + motion->mb_field[mb_nr] = (byte) currMB->mb_field; + + currMB->block_y_aff = ((currSlice->mb_aff_frame_flag) && (currMB->mb_field)) ? (mb_nr&0x01) ? (currMB->block_y - 4)>>1 : currMB->block_y >> 1 : currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + if(currMB->mb_type == IPCM) + { + read_i_pcm_macroblock(currMB, partMap); + } + else if (currMB->mb_type == I4MB) + { + //============= Transform Size Flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + if (currSlice->Transform8x8Mode) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.reading = readMB_transform_size_flag_CABAC; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + if (dP->bitstream->ei_flag) + { + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + dP->readSyntaxElement(currMB, &currSE, dP); + } + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + + if (currMB->luma_transform_size_8x8_flag) + { + currMB->mb_type = I8MB; + memset(&currMB->b8mode, I8MB, 4 * sizeof(char)); + memset(&currMB->b8pdir, -1, 4 * sizeof(char)); + } + } + else + { + currMB->luma_transform_size_8x8_flag = FALSE; + } + + //--- init macroblock data --- + init_macroblock(currMB); + + // intra prediction modes for a macroblock 4x4 ********************************************** + read_ipred_modes(currMB); + + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); + } + else // all other modes + { + read_intra_macroblock(currMB); + } + return; +} + +/*! + ************************************************************************ + * \brief + * Get the syntax elements from the NAL + ************************************************************************ + */ +static void read_one_macroblock_p_slice_cavlc(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + SyntaxElement currSE; + int mb_nr = currMB->mbAddrX; + + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + + if (currSlice->mb_aff_frame_flag == 0) + { + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + currMB->mb_field = FALSE; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + currSE.mapping = linfo_ue; + + // VLC Non-Intra + if(currSlice->cod_counter == -1) + { + TRACE_STRING("mb_skip_run"); + dP->readSyntaxElement(currMB, &currSE, dP); + currSlice->cod_counter = currSE.value1; + } + + if (currSlice->cod_counter==0) + { + // read MB type + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + ++(currSE.value1); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + currSlice->cod_counter--; + currMB->skip_flag = 0; + } + else + { + currSlice->cod_counter--; + currMB->mb_type = 0; + currMB->ei_flag = 0; + currMB->skip_flag = 1; + } + //update the list offset; + currMB->list_offset = 0; + + motion->mb_field[mb_nr] = (byte) FALSE; + + currMB->block_y_aff = currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + } + else + { + VideoParameters *p_Vid = currMB->p_Vid; + + Macroblock *topMB = NULL; + int prevMbSkipped = 0; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + if (mb_nr&0x01) + { + topMB= &p_Vid->mb_data[mb_nr-1]; + prevMbSkipped = (topMB->mb_type == 0); + } + else + prevMbSkipped = 0; + + currMB->mb_field = ((mb_nr&0x01) == 0)? FALSE : p_Vid->mb_data[mb_nr-1].mb_field; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + currSE.mapping = linfo_ue; + + // VLC Non-Intra + if(currSlice->cod_counter == -1) + { + TRACE_STRING("mb_skip_run"); + dP->readSyntaxElement(currMB, &currSE, dP); + currSlice->cod_counter = currSE.value1; + } + + if (currSlice->cod_counter==0) + { + // read MB aff + if ((((mb_nr&0x01)==0) || ((mb_nr&0x01) && prevMbSkipped))) + { + TRACE_STRING("mb_field_decoding_flag"); + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + currMB->mb_field = (Boolean) currSE.value1; + } + + // read MB type + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + ++(currSE.value1); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + currSlice->cod_counter--; + currMB->skip_flag = 0; + } + else + { + currSlice->cod_counter--; + currMB->mb_type = 0; + currMB->ei_flag = 0; + currMB->skip_flag = 1; + + // read field flag of bottom block + if(currSlice->cod_counter == 0 && ((mb_nr&0x01) == 0)) + { + TRACE_STRING("mb_field_decoding_flag (of coded bottom mb)"); + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + dP->bitstream->frame_bitoffset--; + TRACE_DECBITS(1); + currMB->mb_field = (Boolean) currSE.value1; + } + else if (currSlice->cod_counter > 0 && ((mb_nr & 0x01) == 0)) + { + // check left macroblock pair first + if (mb_is_available(mb_nr - 2, currMB) && ((mb_nr % (p_Vid->PicWidthInMbs * 2))!=0)) + { + currMB->mb_field = p_Vid->mb_data[mb_nr-2].mb_field; + } + else + { + // check top macroblock pair + if (mb_is_available(mb_nr - 2*p_Vid->PicWidthInMbs, currMB)) + { + currMB->mb_field = p_Vid->mb_data[mb_nr-2*p_Vid->PicWidthInMbs].mb_field; + } + else + currMB->mb_field = FALSE; + } + } + } + //update the list offset; + currMB->list_offset = (currMB->mb_field)? ((mb_nr&0x01)? 4: 2): 0; + + motion->mb_field[mb_nr] = (byte) currMB->mb_field; + + currMB->block_y_aff = (currMB->mb_field) ? (mb_nr&0x01) ? (currMB->block_y - 4)>>1 : currMB->block_y >> 1 : currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + + if(currMB->mb_field) + { + currSlice->num_ref_idx_active[LIST_0] <<=1; + currSlice->num_ref_idx_active[LIST_1] <<=1; + } + } + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + if (currMB->mb_type == IPCM) // I_PCM mode + { + read_i_pcm_macroblock(currMB, partMap); + } + else if (currMB->mb_type == I4MB) + { + read_intra4x4_macroblock_cavlc(currMB, partMap); + } + else if (currMB->mb_type == P8x8) + { + currSE.type = SE_MBTYPE; + currSE.mapping = linfo_ue; + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + read_P8x8_macroblock(currMB, dP, &currSE); + } + else if (currMB->mb_type == PSKIP) + { + read_skip_macroblock(currMB); + } + else if (currMB->is_intra_block) // all other intra modes + { + read_intra_macroblock(currMB); + } + else // all other remaining modes + { + read_inter_macroblock(currMB); + } + + + return; +} + +/*! + ************************************************************************ + * \brief + * Get the syntax elements from the NAL + ************************************************************************ + */ +static void read_one_macroblock_p_slice_cabac(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int mb_nr = currMB->mbAddrX; + SyntaxElement currSE; + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + + if (currSlice->mb_aff_frame_flag == 0) + { + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + currMB->mb_field = FALSE; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + + CheckAvailabilityOfNeighborsCABAC(currMB); + TRACE_STRING("mb_skip_flag"); + currSE.reading = read_skip_flag_CABAC_p_slice; + dP->readSyntaxElement(currMB, &currSE, dP); + + currMB->mb_type = (short) currSE.value1; + currMB->skip_flag = (char) (!(currSE.value1)); + + if (!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + + // read MB type + if (currMB->mb_type != 0 ) + { + currSE.reading = readMB_typeInfo_CABAC_p_slice; + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + } + + motion->mb_field[mb_nr] = (byte) FALSE; + currMB->block_y_aff = currMB->block_y; + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + currSlice->interpret_mb_mode(currMB); + } + else + { + Macroblock *topMB = NULL; + int prevMbSkipped = 0; + int check_bottom, read_bottom, read_top; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + if (mb_nr&0x01) + { + topMB= &p_Vid->mb_data[mb_nr-1]; + prevMbSkipped = (topMB->mb_type == 0); + } + else + prevMbSkipped = 0; + + currMB->mb_field = ((mb_nr&0x01) == 0)? FALSE : p_Vid->mb_data[mb_nr-1].mb_field; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + + // read MB skip_flag + if (((mb_nr&0x01) == 0||prevMbSkipped)) + field_flag_inference(currMB); + + CheckAvailabilityOfNeighborsCABAC(currMB); + TRACE_STRING("mb_skip_flag"); + currSE.reading = read_skip_flag_CABAC_p_slice; + dP->readSyntaxElement(currMB, &currSE, dP); + + currMB->mb_type = (short) currSE.value1; + currMB->skip_flag = (char) (!(currSE.value1)); + + if (!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + + // read MB AFF + check_bottom=read_bottom=read_top=0; + if ((mb_nr&0x01)==0) + { + check_bottom = currMB->skip_flag; + read_top = !check_bottom; + } + else + { + read_bottom = (topMB->skip_flag && (!currMB->skip_flag)); + } + + if (read_bottom || read_top) + { + TRACE_STRING("mb_field_decoding_flag"); + currSE.reading = readFieldModeInfo_CABAC; + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_field = (Boolean) currSE.value1; + } + + if (check_bottom) + check_next_mb_and_get_field_mode_CABAC_p_slice(currSlice, &currSE, dP); + + //update the list offset; + currMB->list_offset = (currMB->mb_field)? ((mb_nr&0x01)? 4: 2): 0; + + //if (currMB->mb_type != 0 ) + CheckAvailabilityOfNeighborsCABAC(currMB); + + // read MB type + if (currMB->mb_type != 0 ) + { + currSE.reading = readMB_typeInfo_CABAC_p_slice; + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + } + + motion->mb_field[mb_nr] = (byte) currMB->mb_field; + + currMB->block_y_aff = (currMB->mb_field) ? (mb_nr&0x01) ? (currMB->block_y - 4)>>1 : currMB->block_y >> 1 : currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + + if(currMB->mb_field) + { + currSlice->num_ref_idx_active[LIST_0] <<=1; + currSlice->num_ref_idx_active[LIST_1] <<=1; + } + } + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + if (currMB->mb_type == IPCM) // I_PCM mode + { + read_i_pcm_macroblock(currMB, partMap); + } + else if (currMB->mb_type == I4MB) + { + read_intra4x4_macroblock_cabac(currMB, partMap); + } + else if (currMB->mb_type == P8x8) + { + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + currSE.type = SE_MBTYPE; + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + else + currSE.reading = readB8_typeInfo_CABAC_p_slice; + + read_P8x8_macroblock(currMB, dP, &currSE); + } + else if (currMB->mb_type == PSKIP) + { + read_skip_macroblock (currMB); + } + else if (currMB->is_intra_block == TRUE) // all other intra modes + { + read_intra_macroblock(currMB); + } + else // all other remaining modes + { + read_inter_macroblock(currMB); + } + + return; +} + +/*! + ************************************************************************ + * \brief + * Get the syntax elements from the NAL + ************************************************************************ + */ +static void read_one_macroblock_b_slice_cavlc(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int mb_nr = currMB->mbAddrX; + DataPartition *dP; + SyntaxElement currSE; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + + if (currSlice->mb_aff_frame_flag == 0) + { + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + currMB->mb_field = FALSE; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + currSE.mapping = linfo_ue; + + if(currSlice->cod_counter == -1) + { + TRACE_STRING("mb_skip_run"); + dP->readSyntaxElement(currMB, &currSE, dP); + currSlice->cod_counter = currSE.value1; + } + if (currSlice->cod_counter==0) + { + // read MB type + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + currSlice->cod_counter--; + currMB->skip_flag = 0; + } + else + { + currSlice->cod_counter--; + currMB->mb_type = 0; + currMB->ei_flag = 0; + currMB->skip_flag = 1; + + } + //update the list offset; + currMB->list_offset = 0; + + motion->mb_field[mb_nr] = FALSE; + currMB->block_y_aff = currMB->block_y; + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + } + else + { + Macroblock *topMB = NULL; + int prevMbSkipped = 0; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + if (mb_nr&0x01) + { + topMB= &p_Vid->mb_data[mb_nr-1]; + prevMbSkipped = topMB->skip_flag; + } + else + prevMbSkipped = 0; + + currMB->mb_field = ((mb_nr&0x01) == 0)? FALSE : p_Vid->mb_data[mb_nr-1].mb_field; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + currSE.mapping = linfo_ue; + + if(currSlice->cod_counter == -1) + { + TRACE_STRING("mb_skip_run"); + dP->readSyntaxElement(currMB, &currSE, dP); + currSlice->cod_counter = currSE.value1; + } + if (currSlice->cod_counter==0) + { + // read MB aff + if ((((mb_nr&0x01)==0) || ((mb_nr&0x01) && prevMbSkipped))) + { + TRACE_STRING("mb_field_decoding_flag"); + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + currMB->mb_field = (Boolean) currSE.value1; + } + + // read MB type + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + currSlice->cod_counter--; + currMB->skip_flag = 0; + } + else + { + currSlice->cod_counter--; + currMB->mb_type = 0; + currMB->ei_flag = 0; + currMB->skip_flag = 1; + + // read field flag of bottom block + if(currSlice->cod_counter == 0 && ((mb_nr&0x01) == 0)) + { + TRACE_STRING("mb_field_decoding_flag (of coded bottom mb)"); + currSE.len = (int64) 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + dP->bitstream->frame_bitoffset--; + TRACE_DECBITS(1); + currMB->mb_field = (Boolean) currSE.value1; + } + else if (currSlice->cod_counter > 0 && ((mb_nr & 0x01) == 0)) + { + // check left macroblock pair first + if (mb_is_available(mb_nr - 2, currMB) && ((mb_nr % (p_Vid->PicWidthInMbs * 2))!=0)) + { + currMB->mb_field = p_Vid->mb_data[mb_nr-2].mb_field; + } + else + { + // check top macroblock pair + if (mb_is_available(mb_nr - 2*p_Vid->PicWidthInMbs, currMB)) + { + currMB->mb_field = p_Vid->mb_data[mb_nr-2*p_Vid->PicWidthInMbs].mb_field; + } + else + currMB->mb_field = FALSE; + } + } + } + //update the list offset; + currMB->list_offset = (currMB->mb_field)? ((mb_nr&0x01)? 4: 2): 0; + + motion->mb_field[mb_nr] = (byte) currMB->mb_field; + + currMB->block_y_aff = (currMB->mb_field) ? (mb_nr&0x01) ? (currMB->block_y - 4)>>1 : currMB->block_y >> 1 : currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + + if(currSlice->mb_aff_frame_flag) + { + if(currMB->mb_field) + { + currSlice->num_ref_idx_active[LIST_0] <<=1; + currSlice->num_ref_idx_active[LIST_1] <<=1; + } + } + } + + if (currMB->mb_type == IPCM) + { + read_i_pcm_macroblock(currMB, partMap); + } + else if (currMB->mb_type == I4MB) + { + read_intra4x4_macroblock_cavlc(currMB, partMap); + } + else if (currMB->mb_type == P8x8) + { + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + currSE.type = SE_MBTYPE; + currSE.mapping = linfo_ue; + + read_P8x8_macroblock(currMB, dP, &currSE); + } + else if (currMB->mb_type == BSKIP_DIRECT) + { + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = (!(currSlice->active_sps->direct_8x8_inference_flag))? FALSE: TRUE; + + currMB->luma_transform_size_8x8_flag = FALSE; + + if(p_Vid->active_pps->constrained_intra_pred_flag) + { + currSlice->intra_block[mb_nr] = 0; + } + + //--- init macroblock data --- + init_macroblock_direct(currMB); + + if (currSlice->cod_counter >= 0) + { + currMB->cbp = 0; + reset_coeffs(currMB); + } + else + { + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); + } + } + else if (currMB->is_intra_block == TRUE) // all other intra modes + { + read_intra_macroblock(currMB); + } + else // all other remaining modes + { + read_inter_macroblock(currMB); + } + + return; +} + +/*! + ************************************************************************ + * \brief + * Get the syntax elements from the NAL + ************************************************************************ + */ +static void read_one_macroblock_b_slice_cabac(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int mb_nr = currMB->mbAddrX; + SyntaxElement currSE; + + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + + if (currSlice->mb_aff_frame_flag == 0) + { + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + currMB->mb_field = FALSE; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + + CheckAvailabilityOfNeighborsCABAC(currMB); + TRACE_STRING("mb_skip_flag"); + currSE.reading = read_skip_flag_CABAC_b_slice; + dP->readSyntaxElement(currMB, &currSE, dP); + + currMB->mb_type = (short) currSE.value1; + currMB->skip_flag = (char) (!(currSE.value1)); + + currMB->cbp = currSE.value2; + + if (!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + + if (currSE.value1 == 0 && currSE.value2 == 0) + currSlice->cod_counter=0; + + // read MB type + if (currMB->mb_type != 0 ) + { + currSE.reading = readMB_typeInfo_CABAC_b_slice; + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + } + + motion->mb_field[mb_nr] = (byte) FALSE; + currMB->block_y_aff = currMB->block_y; + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + currSlice->interpret_mb_mode(currMB); + } + else + { + Macroblock *topMB = NULL; + int prevMbSkipped = 0; + int check_bottom, read_bottom, read_top; + StorablePicture *dec_picture = currSlice->dec_picture; + PicMotionParamsOld *motion = &dec_picture->motion; + + if (mb_nr&0x01) + { + topMB= &p_Vid->mb_data[mb_nr-1]; + prevMbSkipped = topMB->skip_flag; + } + else + prevMbSkipped = 0; + + currMB->mb_field = ((mb_nr&0x01) == 0)? FALSE : p_Vid->mb_data[mb_nr-1].mb_field; + + update_qp(currMB, currSlice->qp); + currSE.type = SE_MBTYPE; + + // read MB mode ***************************************************************** + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + + // read MB skip_flag + if (((mb_nr&0x01) == 0||prevMbSkipped)) + field_flag_inference(currMB); + + CheckAvailabilityOfNeighborsCABAC(currMB); + TRACE_STRING("mb_skip_flag"); + currSE.reading = read_skip_flag_CABAC_b_slice; + dP->readSyntaxElement(currMB, &currSE, dP); + + currMB->mb_type = (short) currSE.value1; + currMB->skip_flag = (char) (!(currSE.value1)); + + currMB->cbp = currSE.value2; + + if (!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + + if (currSE.value1 == 0 && currSE.value2 == 0) + currSlice->cod_counter=0; + + // read MB AFF + check_bottom=read_bottom=read_top=0; + if ((mb_nr & 0x01) == 0) + { + check_bottom = currMB->skip_flag; + read_top = !check_bottom; + } + else + { + read_bottom = (topMB->skip_flag && (!currMB->skip_flag)); + } + + if (read_bottom || read_top) + { + TRACE_STRING("mb_field_decoding_flag"); + currSE.reading = readFieldModeInfo_CABAC; + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_field = (Boolean) currSE.value1; + } + if (check_bottom) + check_next_mb_and_get_field_mode_CABAC_b_slice(currSlice, &currSE, dP); + + //update the list offset; + currMB->list_offset = (currMB->mb_field)? ((mb_nr&0x01)? 4: 2): 0; + //if (currMB->mb_type != 0 ) + CheckAvailabilityOfNeighborsCABAC(currMB); + + // read MB type + if (currMB->mb_type != 0 ) + { + currSE.reading = readMB_typeInfo_CABAC_b_slice; + TRACE_STRING("mb_type"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->mb_type = (short) currSE.value1; + if(!dP->bitstream->ei_flag) + currMB->ei_flag = 0; + } + + + motion->mb_field[mb_nr] = (byte) currMB->mb_field; + + currMB->block_y_aff = (currMB->mb_field) ? (mb_nr&0x01) ? (currMB->block_y - 4)>>1 : currMB->block_y >> 1 : currMB->block_y; + + currSlice->siblock[currMB->mb.y][currMB->mb.x] = 0; + + currSlice->interpret_mb_mode(currMB); + + if(currMB->mb_field) + { + currSlice->num_ref_idx_active[LIST_0] <<=1; + currSlice->num_ref_idx_active[LIST_1] <<=1; + } + } + + if(currMB->mb_type == IPCM) + { + read_i_pcm_macroblock(currMB, partMap); + } + else if (currMB->mb_type == I4MB) + { + read_intra4x4_macroblock_cabac(currMB, partMap); + } + else if (currMB->mb_type == P8x8) + { + dP = &(currSlice->partArr[partMap[SE_MBTYPE]]); + currSE.type = SE_MBTYPE; + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_ue; + else + currSE.reading = readB8_typeInfo_CABAC_b_slice; + + read_P8x8_macroblock(currMB, dP, &currSE); + } + else if (currMB->mb_type == BSKIP_DIRECT) + { + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = (!(currSlice->active_sps->direct_8x8_inference_flag))? FALSE: TRUE; + + //============= Transform Size Flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + currMB->luma_transform_size_8x8_flag = FALSE; + + if(p_Vid->active_pps->constrained_intra_pred_flag) + { + currSlice->intra_block[mb_nr] = 0; + } + + //--- init macroblock data --- + init_macroblock_direct(currMB); + + if (currSlice->cod_counter >= 0) + { + currSlice->is_reset_coeff = TRUE; + currMB->cbp = 0; + currSlice->cod_counter = -1; + } + else + { + // read CBP and Coeffs *************************************************************** + currSlice->read_CBP_and_coeffs_from_NAL (currMB); + } + } + else if (currMB->is_intra_block == TRUE) // all other intra modes + { + read_intra_macroblock(currMB); + } + else // all other remaining modes + { + read_inter_macroblock(currMB); + } + + return; +} + + +void setup_read_macroblock(Slice *currSlice) +{ + if (currSlice->p_Vid->active_pps->entropy_coding_mode_flag == (Boolean) CABAC) + { + switch (currSlice->slice_type) + { + case P_SLICE: + case SP_SLICE: + currSlice->read_one_macroblock = read_one_macroblock_p_slice_cabac; + break; + case B_SLICE: + currSlice->read_one_macroblock = read_one_macroblock_b_slice_cabac; + break; + case I_SLICE: + case SI_SLICE: + currSlice->read_one_macroblock = read_one_macroblock_i_slice_cabac; + break; + default: + printf("Unsupported slice type\n"); + break; + } + } + else + { + switch (currSlice->slice_type) + { + case P_SLICE: + case SP_SLICE: + currSlice->read_one_macroblock = read_one_macroblock_p_slice_cavlc; + break; + case B_SLICE: + currSlice->read_one_macroblock = read_one_macroblock_b_slice_cavlc; + break; + case I_SLICE: + case SI_SLICE: + currSlice->read_one_macroblock = read_one_macroblock_i_slice_cavlc; + break; + default: + printf("Unsupported slice type\n"); + break; + } + } +} diff --git a/ldecod/src/mbuffer.c b/ldecod/src/mbuffer.c new file mode 100644 index 0000000..6aea307 --- /dev/null +++ b/ldecod/src/mbuffer.c @@ -0,0 +1,3512 @@ + +/*! +*********************************************************************** +* \file +* mbuffer.c +* +* \brief +* Frame buffer functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Karsten Suehring +* - Alexis Tourapis +* - Jill Boyce +* - Saurav K Bandyopadhyay +* - Zhenyu Wu +* - Yuwen He +*********************************************************************** +*/ + +#include + +#include "global.h" +#include "erc_api.h" +#include "header.h" +#include "image.h" +#include "mbuffer.h" +#include "mbuffer_common.h" +#include "memalloc.h" +#include "output.h" +#include "mbuffer_mvc.h" +#include "fast_memory.h" +#include "input.h" + +#include "ferc_api.h" + +static void insert_picture_in_dpb (VideoParameters *p_Vid, FrameStore* fs, StorablePicture* p); +static int output_one_frame_from_dpb (DecodedPictureBuffer *p_Dpb); +static void gen_field_ref_ids (VideoParameters *p_Vid, StorablePicture *p); + +#define MAX_LIST_SIZE 33 + + + +void dump_ref_lists(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + unsigned int i; +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if((currSlice->listXsize[0]>0) || (currSlice->listXsize[1]>0)) + printf("\n *** Dump Ref Lists *** CurPOC: %d | ViewID:%d ***\n", currSlice->ThisPOC, currSlice->view_id); + if(currSlice->listXsize[0]>0) + { + printf(" ** %s Ref Pic List 0 ** \n", currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, GetViewIdx(p_Vid, currSlice->listX[0][i]->view_id) ); + if( currSlice->view_id != currSlice->listX[0][i]->view_id ) + printf("i"); + printf("\n"); + } + } + if(currSlice->listXsize[1]>0) + { + printf(" ** %s Ref Pic List 1 **\n", currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[1]); i++) //ref list 1 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d", i, currSlice->listX[1][i]->poc, currSlice->listX[1][i]->pic_num, GetViewIdx(p_Vid, currSlice->listX[1][i]->view_id) ); + if( currSlice->view_id != currSlice->listX[1][i]->view_id ) + printf("i"); + printf("\n"); + } + } + } +#endif + fflush(stdout); +} + +/*! +************************************************************************ +* \brief +* Print out list of pictures in DPB. Used for debug purposes. +************************************************************************ +*/ +void dump_dpb(DecodedPictureBuffer *p_Dpb) +{ + unsigned i; + + for (i=0; iused_size;i++) + { + printf("("); + printf("fn=%d ", p_Dpb->fs[i]->frame_num); + if (p_Dpb->fs[i]->is_used & 1) + { + if (p_Dpb->fs[i]->top_field) + printf("T: poc=%d ", p_Dpb->fs[i]->top_field->poc); + else + printf("T: poc=%d ", p_Dpb->fs[i]->frame->top_poc); + } + if (p_Dpb->fs[i]->is_used & 2) + { + if (p_Dpb->fs[i]->bottom_field) + printf("B: poc=%d ", p_Dpb->fs[i]->bottom_field->poc); + else + printf("B: poc=%d ", p_Dpb->fs[i]->frame->bottom_poc); + } + if (p_Dpb->fs[i]->is_used == 3) + printf("F: poc=%d ", p_Dpb->fs[i]->frame->poc); + printf("G: poc=%d) ", p_Dpb->fs[i]->poc); + if (p_Dpb->fs[i]->is_reference) printf ("ref (%d) ", p_Dpb->fs[i]->is_reference); + if (p_Dpb->fs[i]->is_long_term) printf ("lt_ref (%d) ", p_Dpb->fs[i]->is_reference); + if (p_Dpb->fs[i]->is_output) printf ("out "); + if (p_Dpb->fs[i]->is_used == 3) + { + if (p_Dpb->fs[i]->frame->non_existing) printf ("ne "); + } +#if (MVC_EXTENSION_ENABLE) + if (p_Dpb->fs[i]->is_reference) + printf ("view_id (%d) ", p_Dpb->fs[i]->view_id); +#endif + printf ("\n"); + } +} + +/*! +************************************************************************ +* \brief +* Returns the size of the dpb depending on level and picture size +* +* +************************************************************************ +*/ +int getDpbSize(VideoParameters *p_Vid, seq_parameter_set_rbsp_t *active_sps) +{ + int pic_size = (active_sps->pic_width_in_mbs_minus1 + 1) * (active_sps->pic_height_in_map_units_minus1 + 1) * (active_sps->frame_mbs_only_flag?1:2) * 384; + + int size = 0; + + switch (active_sps->level_idc) + { + case 9: + size = 152064; + break; + case 10: + size = 152064; + break; + case 11: + if (!is_FREXT_profile(active_sps->profile_idc) && (active_sps->constrained_set3_flag == 1)) + size = 152064; + else + size = 345600; + break; + case 12: + size = 912384; + break; + case 13: + size = 912384; + break; + case 20: + size = 912384; + break; + case 21: + size = 1824768; + break; + case 22: + size = 3110400; + break; + case 30: + size = 3110400; + break; + case 31: + size = 6912000; + break; + case 32: + size = 7864320; + break; + case 40: + size = 12582912; + break; + case 41: + size = 12582912; + break; + case 42: + size = 13369344; + break; + case 50: + size = 42393600; + break; + case 51: + size = 70778880; + break; + default: + error ("undefined level", 500); + break; + } + + size /= pic_size; + if(p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) + { + int num_views = p_Vid->active_subset_sps->num_views_minus1+1; + size = imin(2*size, imax(1, RoundLog2(num_views))*16)/num_views; + } + else + size = imin( size, 16); + + if (active_sps->vui_parameters_present_flag && active_sps->vui_seq_parameters.bitstream_restriction_flag) + { + int size_vui; + if ((int)active_sps->vui_seq_parameters.max_dec_frame_buffering > size) + { + error ("max_dec_frame_buffering larger than MaxDpbSize", 500); + } + size_vui = imax (1, active_sps->vui_seq_parameters.max_dec_frame_buffering); +#ifdef _DEBUG + if(size_vui < size) + { + printf("Warning: max_dec_frame_buffering(%d) is less than DPB size(%d) calculated from Profile/Level.\n", size_vui, size); + } +#endif + size = size_vui; + } + + return size; +} + +/*! +************************************************************************ +* \brief +* Check then number of frames marked "used for reference" and break +* if maximum is exceeded +* +************************************************************************ +*/ +void check_num_ref(DecodedPictureBuffer *p_Dpb) +{ + if ((int)(p_Dpb->ltref_frames_in_buffer + p_Dpb->ref_frames_in_buffer ) > imax(1, p_Dpb->num_ref_frames)) + { + error ("Max. number of reference frames exceeded. Invalid stream.", 500); + } +} + + +/*! +************************************************************************ +* \brief +* Allocate memory for decoded picture buffer and initialize with sane values. +* +************************************************************************ +*/ +void init_dpb(VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb, int type) +{ + unsigned i; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + p_Dpb->p_Vid = p_Vid; + if (p_Dpb->init_done) + { + free_dpb(p_Dpb); + } + + p_Dpb->size = getDpbSize(p_Vid, active_sps) + p_Vid->p_Inp->dpb_plus[type==2? 1: 0]; + p_Dpb->num_ref_frames = active_sps->num_ref_frames; + +#if (MVC_EXTENSION_ENABLE) + if ((unsigned int)active_sps->max_dec_frame_buffering < active_sps->num_ref_frames) +#else + if (p_Dpb->size < active_sps->num_ref_frames) +#endif + { + error ("DPB size at specified level is smaller than the specified number of reference frames. This is not allowed.\n", 1000); + } + + p_Dpb->used_size = 0; + p_Dpb->last_picture = NULL; + + p_Dpb->ref_frames_in_buffer = 0; + p_Dpb->ltref_frames_in_buffer = 0; + + p_Dpb->fs = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs) + no_mem_exit("init_dpb: p_Dpb->fs"); + + p_Dpb->fs_ref = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ref) + no_mem_exit("init_dpb: p_Dpb->fs_ref"); + + p_Dpb->fs_ltref = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ltref) + no_mem_exit("init_dpb: p_Dpb->fs_ltref"); + +#if (MVC_EXTENSION_ENABLE) + //! Edited by Joao Carreira + if( p_Vid->p_Inp->DecodeAllLayers && p_Vid->active_subset_sps) + p_Dpb->size_ilref = p_Vid->active_subset_sps->num_views_minus1; + else + p_Dpb->size_ilref = 1; + + p_Dpb->fs_ilref = calloc(p_Dpb->size_ilref, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ilref) + no_mem_exit("init_dpb: p_Dpb->fs_ilref"); + +#endif + +for (i = 0; i < p_Dpb->size; i++) +{ + p_Dpb->fs[i] = alloc_frame_store(); + p_Dpb->fs_ref[i] = NULL; + p_Dpb->fs_ltref[i] = NULL; + p_Dpb->fs[i]->layer_id = MVC_INIT_VIEW_ID; +#if (MVC_EXTENSION_ENABLE) + p_Dpb->fs[i]->view_id = MVC_INIT_VIEW_ID; + p_Dpb->fs[i]->inter_view_flag[0] = p_Dpb->fs[i]->inter_view_flag[1] = 0; + p_Dpb->fs[i]->anchor_pic_flag[0] = p_Dpb->fs[i]->anchor_pic_flag[1] = 0; +#endif +} +#if (MVC_EXTENSION_ENABLE) +//! Edited by Joao Carreira +if (type == 2) +{ + for (i=0; iactive_subset_sps->num_views_minus1+1-1; i++) + { + p_Dpb->fs_ilref[i] = alloc_frame_store(); + // These may need some cleanups + p_Dpb->fs_ilref[i]->view_id = MVC_INIT_VIEW_ID; + p_Dpb->fs_ilref[i]->inter_view_flag[0] = p_Dpb->fs_ilref[i]->inter_view_flag[1] = 0; + p_Dpb->fs_ilref[i]->anchor_pic_flag[0] = p_Dpb->fs_ilref[i]->anchor_pic_flag[1] = 0; + // given that this is in a different buffer, do we even need proc_flag anymore? + } +} +else + p_Dpb->fs_ilref[0] = NULL; +#endif + +/* +for (i = 0; i < 6; i++) +{ +currSlice->listX[i] = calloc(MAX_LIST_SIZE, sizeof (StorablePicture*)); // +1 for reordering +if (NULL==currSlice->listX[i]) +no_mem_exit("init_dpb: currSlice->listX[i]"); +} +*/ +/* allocate a dummy storable picture */ +if(!p_Vid->no_reference_picture) +{ + p_Vid->no_reference_picture = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + p_Vid->no_reference_picture->top_field = p_Vid->no_reference_picture; + p_Vid->no_reference_picture->bottom_field = p_Vid->no_reference_picture; + p_Vid->no_reference_picture->frame = p_Vid->no_reference_picture; +} +p_Dpb->last_output_poc = INT_MIN; + +#if (MVC_EXTENSION_ENABLE) +p_Dpb->last_output_view_id = -1; +#endif + +p_Vid->last_has_mmco_5 = 0; + +p_Dpb->init_done = 1; + +} + +void re_init_dpb(VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb, int type) +{ + int i; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + int iDpbSize; + + iDpbSize = getDpbSize(p_Vid, active_sps)+p_Vid->p_Inp->dpb_plus[type==2? 1: 0]; + p_Dpb->num_ref_frames = active_sps->num_ref_frames; + if( iDpbSize > (int)p_Dpb->size) + { +#if (MVC_EXTENSION_ENABLE) + if ((unsigned int)active_sps->max_dec_frame_buffering < active_sps->num_ref_frames) +#else + if (p_Dpb->size < active_sps->num_ref_frames) +#endif + { + error ("DPB size at specified level is smaller than the specified number of reference frames. This is not allowed.\n", 1000); + } + + p_Dpb->fs = realloc(p_Dpb->fs, iDpbSize * sizeof (FrameStore*)); + if (NULL==p_Dpb->fs) + no_mem_exit("re_init_dpb: p_Dpb->fs"); + + p_Dpb->fs_ref = realloc(p_Dpb->fs_ref, iDpbSize * sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ref) + no_mem_exit("re_init_dpb: p_Dpb->fs_ref"); + + p_Dpb->fs_ltref = realloc(p_Dpb->fs_ltref, iDpbSize * sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ltref) + no_mem_exit("re_init_dpb: p_Dpb->fs_ltref"); + +#if (MVC_EXTENSION_ENABLE) + if(!p_Dpb->fs_ilref) + { + //! Edited by Joao Carreira + p_Dpb->size_ilref = p_Vid->active_subset_sps->num_views_minus1; + p_Dpb->fs_ilref = calloc(p_Dpb->size_ilref, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ilref) + no_mem_exit("init_dpb: p_Dpb->fs_ilref"); + } +#endif + + for (i = p_Dpb->size; i < iDpbSize; i++) + { + p_Dpb->fs[i] = alloc_frame_store(); + p_Dpb->fs_ref[i] = NULL; + p_Dpb->fs_ltref[i] = NULL; +#if (MVC_EXTENSION_ENABLE) + p_Dpb->fs[i]->view_id = MVC_INIT_VIEW_ID; + p_Dpb->fs[i]->inter_view_flag[0] = p_Dpb->fs[i]->inter_view_flag[1] = 0; + p_Dpb->fs[i]->anchor_pic_flag[0] = p_Dpb->fs[i]->anchor_pic_flag[1] = 0; +#endif + } + + +#if (MVC_EXTENSION_ENABLE) + //! Edited by Joao Carreira + if (type == 2) + { + for (i=0; iactive_subset_sps->num_views_minus1; i++) + { + if(!p_Dpb->fs_ilref[i]) + { + p_Dpb->fs_ilref[i] = alloc_frame_store(); + // These may need some cleanups + p_Dpb->fs_ilref[i]->view_id = MVC_INIT_VIEW_ID; + p_Dpb->fs_ilref[i]->inter_view_flag[0] = p_Dpb->fs_ilref[i]->inter_view_flag[1] = 0; + p_Dpb->fs_ilref[i]->anchor_pic_flag[0] = p_Dpb->fs_ilref[i]->anchor_pic_flag[1] = 0; + // given that this is in a different buffer, do we even need proc_flag anymore? + } + } + } + else + p_Dpb->fs_ilref[0] = NULL; +#endif + + p_Dpb->size = iDpbSize; + p_Dpb->last_output_poc = INT_MIN; +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = -1; +#endif + p_Dpb->init_done = 1; + + } +} + +/*! +************************************************************************ +* \brief +* Free memory for decoded picture buffer. +************************************************************************ +*/ +void free_dpb(DecodedPictureBuffer *p_Dpb) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + if (p_Dpb->fs) + { + for (i=0; isize; i++) + { + free_frame_store(p_Dpb->fs[i]); + } + free (p_Dpb->fs); + p_Dpb->fs=NULL; + } + + if (p_Dpb->fs_ref) + { + free (p_Dpb->fs_ref); + } + if (p_Dpb->fs_ltref) + { + free (p_Dpb->fs_ltref); + } + +#if (MVC_EXTENSION_ENABLE) + if (p_Dpb->fs_ilref) + { + for (i=0; isize_ilref; i++) + { + if( p_Dpb->fs_ilref[i] ) + free_frame_store(p_Dpb->fs_ilref[i]); + } + free (p_Dpb->fs_ilref); + p_Dpb->fs_ilref=NULL; + } + + p_Dpb->last_output_view_id = -1; +#endif + + p_Dpb->last_output_poc = INT_MIN; + + p_Dpb->init_done = 0; + + if(p_Vid->no_reference_picture) + { + free_storable_picture(p_Vid->no_reference_picture); + p_Vid->no_reference_picture = NULL; + } +} + + +/*! +************************************************************************ +* \brief +* Allocate memory for decoded picture buffer frame stores and initialize with sane values. +* +* \return +* the allocated FrameStore structure +************************************************************************ +*/ +FrameStore* alloc_frame_store(void) +{ + FrameStore *f; + + f = calloc (1, sizeof(FrameStore)); + if (NULL==f) + no_mem_exit("alloc_frame_store: f"); + + f->is_used = 0; + f->is_reference = 0; + f->is_long_term = 0; + f->is_orig_reference = 0; + + f->is_output = 0; + + f->frame = NULL;; + f->top_field = NULL; + f->bottom_field = NULL; + + return f; +} + +void alloc_pic_motion(PicMotionParamsOld *motion, int size_y, int size_x) +{ + motion->mb_field = calloc (size_y * size_x, sizeof(byte)); + if (motion->mb_field == NULL) + no_mem_exit("alloc_storable_picture: motion->mb_field"); +} + +/*! +************************************************************************ +* \brief +* Allocate memory for a stored picture. +* +* \param p_Vid +* VideoParameters +* \param structure +* picture structure +* \param size_x +* horizontal luma size +* \param size_y +* vertical luma size +* \param size_x_cr +* horizontal chroma size +* \param size_y_cr +* vertical chroma size +* +* \return +* the allocated StorablePicture structure +************************************************************************ +*/ +StorablePicture* alloc_storable_picture(VideoParameters *p_Vid, PictureStructure structure, int size_x, int size_y, int size_x_cr, int size_y_cr, int is_output) +{ + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + StorablePicture *s; + int nplane; + + //printf ("Allocating (%s) picture (x=%d, y=%d, x_cr=%d, y_cr=%d)\n", (type == FRAME)?"FRAME":(type == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", size_x, size_y, size_x_cr, size_y_cr); + + s = (StorablePicture *) calloc (1, sizeof(StorablePicture)); + if (NULL==s) + no_mem_exit("alloc_storable_picture: s"); + + if (structure!=FRAME) + { + size_y /= 2; + size_y_cr /= 2; + } + + s->PicSizeInMbs = (size_x*size_y)/256; + s->imgUV = NULL; + + get_mem2Dpel_pad (&(s->imgY), size_y, size_x, p_Vid->iLumaPadY, p_Vid->iLumaPadX); + s->iLumaStride = size_x+2*p_Vid->iLumaPadX; + s->iLumaExpandedHeight = size_y+2*p_Vid->iLumaPadY; + + if (active_sps->chroma_format_idc != YUV400) + { + get_mem3Dpel_pad(&(s->imgUV), 2, size_y_cr, size_x_cr, p_Vid->iChromaPadY, p_Vid->iChromaPadX); + } + + s->iChromaStride =size_x_cr + 2*p_Vid->iChromaPadX; + s->iChromaExpandedHeight = size_y_cr + 2*p_Vid->iChromaPadY; + s->iLumaPadY = p_Vid->iLumaPadY; + s->iLumaPadX = p_Vid->iLumaPadX; + s->iChromaPadY = p_Vid->iChromaPadY; + s->iChromaPadX = p_Vid->iChromaPadX; + + s->separate_colour_plane_flag = p_Vid->separate_colour_plane_flag; + + get_mem2Dmp ( &s->mv_info, (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + alloc_pic_motion( &s->motion , (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplaneJVmv_info[nplane], (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + alloc_pic_motion(&s->JVmotion[nplane] , (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + } + } + + s->pic_num = 0; + s->frame_num = 0; + s->long_term_frame_idx = 0; + s->long_term_pic_num = 0; + s->used_for_reference = 0; + s->is_long_term = 0; + s->non_existing = 0; + s->is_output = 0; + s->max_slice_id = 0; +#if (MVC_EXTENSION_ENABLE) + s->view_id = -1; +#endif + + s->structure=structure; + + s->size_x = size_x; + s->size_y = size_y; + s->size_x_cr = size_x_cr; + s->size_y_cr = size_y_cr; + s->size_x_m1 = size_x - 1; + s->size_y_m1 = size_y - 1; + s->size_x_cr_m1 = size_x_cr - 1; + s->size_y_cr_m1 = size_y_cr - 1; + + s->top_field = p_Vid->no_reference_picture; + s->bottom_field = p_Vid->no_reference_picture; + s->frame = p_Vid->no_reference_picture; + + s->dec_ref_pic_marking_buffer = NULL; + + //! Edited by Joao Carreira + s->PicSlice = NULL; + s->have_concealed_reference = 0; + s->disparity = NULL; + + s->coded_frame = 0; + s->mb_aff_frame_flag = 0; + + s->top_poc = s->bottom_poc = s->poc = 0; + s->seiHasTone_mapping = 0; + + if(!p_Vid->active_sps->frame_mbs_only_flag && structure != FRAME) + { + int i, j; + for(j = 0; j < MAX_NUM_SLICES; j++) + { + for (i = 0; i < 2; i++) + { + s->listX[j][i] = (StorablePicture **) calloc(MAX_LIST_SIZE, sizeof (StorablePicture*)); // +1 for reordering + if (NULL==s->listX[j][i]) + no_mem_exit("alloc_storable_picture: s->listX[i]"); + } + } + } + + s->disparity = NULL; + + return s; +} + +/*! +************************************************************************ +* \brief +* Free frame store memory. +* +* \param p_Vid +* VideoParameters +* \param f +* FrameStore to be freed +* +************************************************************************ +*/ +void free_frame_store(FrameStore* f) +{ + if (f) + { + if (f->frame) + { + free_storable_picture(f->frame); + f->frame=NULL; + } + if (f->top_field) + { + free_storable_picture(f->top_field); + f->top_field=NULL; + } + if (f->bottom_field) + { + free_storable_picture(f->bottom_field); + f->bottom_field=NULL; + } + free(f); + } +} + +void free_pic_motion(PicMotionParamsOld *motion) +{ + if (motion->mb_field) + { + free(motion->mb_field); + motion->mb_field = NULL; + } +} + + +/*! +************************************************************************ +* \brief +* Free picture memory. +* +* \param p +* Picture to be freed +* +************************************************************************ +*/ +void free_storable_picture(StorablePicture* p) +{ + int nplane; + if (p) + { + /* Edited by Joao Carreira */ + if( p->disparity ) + { + free_storable_picture( p->disparity ); + } + + if (p->mv_info) + { + free_mem2Dmp(p->mv_info); + p->mv_info = NULL; + } + free_pic_motion(&p->motion); + + if( (p->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplaneJVmv_info[nplane]) + { + free_mem2Dmp(p->JVmv_info[nplane]); + p->JVmv_info[nplane] = NULL; + } + free_pic_motion(&p->JVmotion[nplane]); + } + } + + if (p->imgY) + { + free_mem2Dpel_pad(p->imgY, p->iLumaPadY, p->iLumaPadX); + p->imgY = NULL; + } + + if (p->imgUV) + { + free_mem3Dpel_pad(p->imgUV, 2, p->iChromaPadY, p->iChromaPadX); + p->imgUV=NULL; + } + + + if (p->seiHasTone_mapping) + free(p->tone_mapping_lut); + + { + int i, j; + for(j = 0; j < MAX_NUM_SLICES; j++) + { + for(i=0; i<2; i++) + { + if(p->listX[j][i]) + { + free(p->listX[j][i]); + p->listX[j][i] = NULL; + } + } + } + } + free(p); + p = NULL; + } +} + +/*! +************************************************************************ +* \brief +* mark FrameStore unused for reference +* +************************************************************************ +*/ +void unmark_for_reference(FrameStore* fs) +{ + if (fs->is_used & 1) + { + if (fs->top_field) + { + fs->top_field->used_for_reference = 0; + } + } + if (fs->is_used & 2) + { + if (fs->bottom_field) + { + fs->bottom_field->used_for_reference = 0; + } + } + if (fs->is_used == 3) + { + if (fs->top_field && fs->bottom_field) + { + fs->top_field->used_for_reference = 0; + fs->bottom_field->used_for_reference = 0; + } + fs->frame->used_for_reference = 0; + } + + fs->is_reference = 0; + + if(fs->frame) + { + free_pic_motion(&fs->frame->motion); + } + + if (fs->top_field) + { + free_pic_motion(&fs->top_field->motion); + } + + if (fs->bottom_field) + { + free_pic_motion(&fs->bottom_field->motion); + } +} + + +/*! +************************************************************************ +* \brief +* mark FrameStore unused for reference and reset long term flags +* +************************************************************************ +*/ +void unmark_for_long_term_reference(FrameStore* fs) +{ + if (fs->is_used & 1) + { + if (fs->top_field) + { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + } + } + if (fs->is_used & 2) + { + if (fs->bottom_field) + { + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + } + if (fs->is_used == 3) + { + if (fs->top_field && fs->bottom_field) + { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + fs->frame->used_for_reference = 0; + fs->frame->is_long_term = 0; + } + + fs->is_reference = 0; + fs->is_long_term = 0; +} + + + +void update_pic_num(Slice *currSlice) +{ + unsigned int i; + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int add_top = 0, add_bottom = 0; + int max_frame_num = 1 << (active_sps->log2_max_frame_num_minus4 + 4); + + if (currSlice->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if ( p_Dpb->fs_ref[i]->is_used==3 ) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if( p_Dpb->fs_ref[i]->frame_num > currSlice->frame_num ) + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num - max_frame_num; + } + else + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num; + } + p_Dpb->fs_ref[i]->frame->pic_num = p_Dpb->fs_ref[i]->frame_num_wrap; + } + } + } + // update long_term_pic_num + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + p_Dpb->fs_ltref[i]->frame->long_term_pic_num = p_Dpb->fs_ltref[i]->frame->long_term_frame_idx; + } + } + } + } + else + { + if (currSlice->structure == TOP_FIELD) + { + add_top = 1; + add_bottom = 0; + } + else + { + add_top = 0; + add_bottom = 1; + } + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference) + { + if( p_Dpb->fs_ref[i]->frame_num > currSlice->frame_num ) + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num - max_frame_num; + } + else + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num; + } + if (p_Dpb->fs_ref[i]->is_reference & 1) + { + p_Dpb->fs_ref[i]->top_field->pic_num = (2 * p_Dpb->fs_ref[i]->frame_num_wrap) + add_top; + } + if (p_Dpb->fs_ref[i]->is_reference & 2) + { + p_Dpb->fs_ref[i]->bottom_field->pic_num = (2 * p_Dpb->fs_ref[i]->frame_num_wrap) + add_bottom; + } + } + } + // update long_term_pic_num + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_long_term & 1) + { + p_Dpb->fs_ltref[i]->top_field->long_term_pic_num = 2 * p_Dpb->fs_ltref[i]->top_field->long_term_frame_idx + add_top; + } + if (p_Dpb->fs_ltref[i]->is_long_term & 2) + { + p_Dpb->fs_ltref[i]->bottom_field->long_term_pic_num = 2 * p_Dpb->fs_ltref[i]->bottom_field->long_term_frame_idx + add_bottom; + } + } + } +} +/*! +************************************************************************ +* \brief +* Initialize reference lists depending on current slice type +* +************************************************************************ +*/ +void init_lists_i_slice(Slice *currSlice) +{ + +#if (MVC_EXTENSION_ENABLE) + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; +#endif + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; +} + +/*! +************************************************************************ +* \brief +* Initialize reference lists for a P Slice +* +************************************************************************ +*/ +void init_lists_p_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i; + + int list0idx = 0; + int listltidx = 0; + + FrameStore **fs_list0; + FrameStore **fs_listlt; + +#if (MVC_EXTENSION_ENABLE) + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; +#endif + + if (currSlice->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference) && (!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + // order list 0 by PicNum + qsort((void *)currSlice->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc); + currSlice->listXsize[0] = (char) list0idx; + //printf("listX[0] (PicNum): "); for (i=0; ilistX[0][i]->pic_num);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = (char) list0idx; + } + else + { + fs_list0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list0) + no_mem_exit("init_lists: fs_list0"); + fs_listlt = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_listlt) + no_mem_exit("init_lists: fs_listlt"); + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + + qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_frame_num_desc); + + //printf("fs_list0 (FrameNum): "); for (i=0; iframe_num_wrap);} printf("\n"); + + currSlice->listXsize[0] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, list0idx, currSlice->listX[0], &currSlice->listXsize[0], 0); + + //printf("listX[0] (PicNum): "); for (i=0; i < currSlice->listXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->pic_num);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + fs_listlt[listltidx++]=p_Dpb->fs_ltref[i]; + } + + qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[0], &currSlice->listXsize[0], 1); + + free(fs_list0); + free(fs_listlt); + } + currSlice->listXsize[1] = 0; + + + // set max size + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + + // set the unused list entries to NULL + for (i=currSlice->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[0][i] = p_Vid->no_reference_picture; + } + for (i=currSlice->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[1][i] = p_Vid->no_reference_picture; + } + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if(currSlice->listXsize[0]>0) + { + printf("\n"); + printf(" ** (CurViewID:%d %d) %s Ref Pic List 0 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + } +#endif +#endif +} + + +/*! +************************************************************************ +* \brief +* Initialize reference lists for a B Slice +* +************************************************************************ +*/ +void init_lists_b_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i; + int j; + + int list0idx = 0; + int list0idx_1 = 0; + int listltidx = 0; + + FrameStore **fs_list0; + FrameStore **fs_list1; + FrameStore **fs_listlt; + +#if (MVC_EXTENSION_ENABLE) + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; +#endif + + { + // B-Slice + if (currSlice->structure == FRAME) + { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if (currSlice->framepoc >= p_Dpb->fs_ref[i]->frame->poc) //!KS use >= for error concealment + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + } + qsort((void *)currSlice->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_poc_desc); + + //get the backward reference picture (POC>current POC) in list0; + list0idx_1 = list0idx; + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if (currSlice->framepoc < p_Dpb->fs_ref[i]->frame->poc) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + } + qsort((void *)&currSlice->listX[0][list0idx_1], list0idx-list0idx_1, sizeof(StorablePicture*), compare_pic_by_poc_asc); + + for (j=0; jlistX[1][list0idx-list0idx_1+j]=currSlice->listX[0][j]; + } + for (j=list0idx_1; jlistX[1][j-list0idx_1]=currSlice->listX[0][j]; + } + + currSlice->listXsize[0] = currSlice->listXsize[1] = (char) list0idx; + + //printf("listX[0] (PicNum): "); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->pic_num);} printf("\n"); + //printf("listX[1] (PicNum): "); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->pic_num);} printf("\n"); + //printf("currSlice->listX[0] currPoc=%d (Poc): ", p_Vid->framepoc); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->poc);} printf("\n"); + //printf("currSlice->listX[1] currPoc=%d (Poc): ", p_Vid->framepoc); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->poc);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + currSlice->listX[0][list0idx] = p_Dpb->fs_ltref[i]->frame; + currSlice->listX[1][list0idx++] = p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + qsort((void *)&currSlice->listX[1][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = currSlice->listXsize[1] = (char) list0idx; + } + else + { + fs_list0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list0) + no_mem_exit("init_lists: fs_list0"); + fs_list1 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list1) + no_mem_exit("init_lists: fs_list1"); + fs_listlt = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_listlt) + no_mem_exit("init_lists: fs_listlt"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 1; + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used) + { + if (currSlice->ThisPOC >= p_Dpb->fs_ref[i]->poc) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_poc_desc); + list0idx_1 = list0idx; + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used) + { + if (currSlice->ThisPOC < p_Dpb->fs_ref[i]->poc) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)&fs_list0[list0idx_1], list0idx-list0idx_1, sizeof(FrameStore*), compare_fs_by_poc_asc); + + for (j=0; jThisPOC); for (i=0; ipoc);} printf("\n"); + //printf("fs_list1 currPoc=%d (Poc): ", currSlice->ThisPOC); for (i=0; ipoc);} printf("\n"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, list0idx, currSlice->listX[0], &currSlice->listXsize[0], 0); + gen_pic_list_from_frame_list(currSlice->structure, fs_list1, list0idx, currSlice->listX[1], &currSlice->listXsize[1], 0); + + //printf("currSlice->listX[0] currPoc=%d (Poc): ", p_Vid->framepoc); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->poc);} printf("\n"); + //printf("currSlice->listX[1] currPoc=%d (Poc): ", p_Vid->framepoc); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->poc);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + fs_listlt[listltidx++]=p_Dpb->fs_ltref[i]; + } + + qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[0], &currSlice->listXsize[0], 1); + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[1], &currSlice->listXsize[1], 1); + + free(fs_list0); + free(fs_list1); + free(fs_listlt); + } + } + + if ((currSlice->listXsize[0] == currSlice->listXsize[1]) && (currSlice->listXsize[0] > 1)) + { + // check if lists are identical, if yes swap first two elements of currSlice->listX[1] + int diff=0; + for (j = 0; j< currSlice->listXsize[0]; j++) + { + if (currSlice->listX[0][j] != currSlice->listX[1][j]) + { + diff = 1; + break; + } + } + if (!diff) + { + StorablePicture *tmp_s = currSlice->listX[1][0]; + currSlice->listX[1][0]=currSlice->listX[1][1]; + currSlice->listX[1][1]=tmp_s; + } + } + + // set max size + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + + // set the unused list entries to NULL + for (i=currSlice->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[0][i] = p_Vid->no_reference_picture; + } + for (i=currSlice->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[1][i] = p_Vid->no_reference_picture; + } + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if((currSlice->listXsize[0]>0) || (currSlice->listXsize[1]>0)) + printf("\n"); + if(currSlice->listXsize[0]>0) + { + printf(" ** (CurViewID:%d %d) %s Ref Pic List 0 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + if(currSlice->listXsize[1]>0) + { + printf(" ** (CurViewID:%d %d) %s Ref Pic List 1 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[1]); i++) //ref list 1 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[1][i]->poc, currSlice->listX[1][i]->pic_num, currSlice->listX[1][i]->view_id); + } + } + } +#endif +#endif +} + +/*! +************************************************************************ +* \brief +* Initialize listX[2..5] from lists 0 and 1 +* listX[2]: list0 for current_field==top +* listX[3]: list1 for current_field==top +* listX[4]: list0 for current_field==bottom +* listX[5]: list1 for current_field==bottom +* +************************************************************************ +*/ +void init_mbaff_lists(VideoParameters *p_Vid, Slice *currSlice) +{ + unsigned j; + int i; + + for (i=2;i<6;i++) + { + for (j=0; jlistX[i][j] = p_Vid->no_reference_picture; + } + currSlice->listXsize[i]=0; + } + + for (i = 0; i < currSlice->listXsize[0]; i++) + { + currSlice->listX[2][2*i ] = currSlice->listX[0][i]->top_field; + currSlice->listX[2][2*i+1] = currSlice->listX[0][i]->bottom_field; + currSlice->listX[4][2*i ] = currSlice->listX[0][i]->bottom_field; + currSlice->listX[4][2*i+1] = currSlice->listX[0][i]->top_field; + } + currSlice->listXsize[2] = currSlice->listXsize[4] = currSlice->listXsize[0] * 2; + + for (i = 0; i < currSlice->listXsize[1]; i++) + { + currSlice->listX[3][2*i ] = currSlice->listX[1][i]->top_field; + currSlice->listX[3][2*i+1] = currSlice->listX[1][i]->bottom_field; + currSlice->listX[5][2*i ] = currSlice->listX[1][i]->bottom_field; + currSlice->listX[5][2*i+1] = currSlice->listX[1][i]->top_field; + } + currSlice->listXsize[3] = currSlice->listXsize[5] = currSlice->listXsize[1] * 2; +} + +/*! +************************************************************************ +* \brief +* Returns short term pic with given picNum +* +************************************************************************ +*/ +StorablePicture* get_short_term_pic(Slice *currSlice, DecodedPictureBuffer *p_Dpb, int picNum) +{ + unsigned i; + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + { + if (currSlice->structure == FRAME) + { + if (p_Dpb->fs_ref[i]->is_reference == 3) + if ((!p_Dpb->fs_ref[i]->frame->is_long_term)&&(p_Dpb->fs_ref[i]->frame->pic_num == picNum)) + return p_Dpb->fs_ref[i]->frame; + } + else + { + if (p_Dpb->fs_ref[i]->is_reference & 1) + if ((!p_Dpb->fs_ref[i]->top_field->is_long_term)&&(p_Dpb->fs_ref[i]->top_field->pic_num == picNum)) + return p_Dpb->fs_ref[i]->top_field; + if (p_Dpb->fs_ref[i]->is_reference & 2) + if ((!p_Dpb->fs_ref[i]->bottom_field->is_long_term)&&(p_Dpb->fs_ref[i]->bottom_field->pic_num == picNum)) + return p_Dpb->fs_ref[i]->bottom_field; + } + } + + return currSlice->p_Vid->no_reference_picture; +} + + + +#if (!MVC_EXTENSION_ENABLE) +/*! +************************************************************************ +* \brief +* Reordering process for short-term reference pictures +* +************************************************************************ +*/ +static void reorder_short_term(Slice *currSlice, int cur_list, int num_ref_idx_lX_active_minus1, int picNumLX, int *refIdxLX) +{ + StorablePicture **RefPicListX = currSlice->listX[cur_list]; + int cIdx, nIdx; + + StorablePicture *picLX; + + picLX = get_short_term_pic(currSlice, currSlice->p_Dpb, picNumLX); + + for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ ) + { + if (RefPicListX[ cIdx ]) + if( (RefPicListX[ cIdx ]->is_long_term ) || (RefPicListX[ cIdx ]->pic_num != picNumLX )) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } +} + + +/*! +************************************************************************ +* \brief +* Reordering process for long-term reference pictures +* +************************************************************************ +*/ +static void reorder_long_term(Slice *currSlice, StorablePicture **RefPicListX, int num_ref_idx_lX_active_minus1, int LongTermPicNum, int *refIdxLX) +{ + int cIdx, nIdx; + + StorablePicture *picLX; + + picLX = get_long_term_pic(currSlice, currSlice->p_Dpb, LongTermPicNum); + + for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ ) + { + if (RefPicListX[ cIdx ]) + { + if( (!RefPicListX[ cIdx ]->is_long_term ) || (RefPicListX[ cIdx ]->long_term_pic_num != LongTermPicNum )) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } + } +} +#endif + +/*! +************************************************************************ +* \brief +* Reordering process for reference picture lists +* +************************************************************************ +*/ +void reorder_ref_pic_list(Slice *currSlice, int cur_list) +{ + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[cur_list]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[cur_list]; + int *long_term_pic_idx = currSlice->long_term_pic_idx[cur_list]; + int num_ref_idx_lX_active_minus1 = currSlice->num_ref_idx_active[cur_list] - 1; + + VideoParameters *p_Vid = currSlice->p_Vid; + int i; + + int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX; + int refIdxLX = 0; + + if (p_Vid->structure==FRAME) + { + maxPicNum = p_Vid->max_frame_num; + currPicNum = currSlice->frame_num; + } + else + { + maxPicNum = 2 * p_Vid->max_frame_num; + currPicNum = 2 * currSlice->frame_num + 1; + } + + picNumLXPred = currPicNum; + + for (i=0; modification_of_pic_nums_idc[i]!=3; i++) + { + if (modification_of_pic_nums_idc[i]>3) + error ("Invalid modification_of_pic_nums_idc command", 500); + + if (modification_of_pic_nums_idc[i] < 2) + { + if (modification_of_pic_nums_idc[i] == 0) + { + if( picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) < 0 ) + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) + maxPicNum; + else + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ); + } + else // (modification_of_pic_nums_idc[i] == 1) + { + if( picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) >= maxPicNum ) + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) - maxPicNum; + else + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ); + } + picNumLXPred = picNumLXNoWrap; + + if( picNumLXNoWrap > currPicNum ) + picNumLX = picNumLXNoWrap - maxPicNum; + else + picNumLX = picNumLXNoWrap; + +#if (MVC_EXTENSION_ENABLE) + reorder_short_term(currSlice, cur_list, num_ref_idx_lX_active_minus1, picNumLX, &refIdxLX, -1); +#else + reorder_short_term(currSlice, cur_list, num_ref_idx_lX_active_minus1, picNumLX, &refIdxLX); +#endif + } + else //(modification_of_pic_nums_idc[i] == 2) + { +#if (MVC_EXTENSION_ENABLE) + reorder_long_term(currSlice, currSlice->listX[cur_list], num_ref_idx_lX_active_minus1, long_term_pic_idx[i], &refIdxLX, -1); +#else + reorder_long_term(currSlice, currSlice->listX[cur_list], num_ref_idx_lX_active_minus1, long_term_pic_idx[i], &refIdxLX); +#endif + } + + } + // that's a definition + currSlice->listXsize[cur_list] = (char) (num_ref_idx_lX_active_minus1 + 1); +} + + + + +/*! +************************************************************************ +* \brief +* Perform Memory management for idr pictures +* +************************************************************************ +*/ +void idr_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + uint32 i; + + if (p->no_output_of_prior_pics_flag) + { + // free all stored pictures + for (i=0; iused_size; i++) + { + // reset all reference settings + free_frame_store(p_Dpb->fs[i]); + p_Dpb->fs[i] = alloc_frame_store(); + } + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + { + p_Dpb->fs_ref[i]=NULL; + } + for (i=0; iltref_frames_in_buffer; i++) + { + p_Dpb->fs_ltref[i]=NULL; + } + p_Dpb->used_size=0; + } + else + { + flush_dpb(p_Dpb); + } + p_Dpb->last_picture = NULL; + + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + p_Dpb->last_output_poc = INT_MIN; + + if (p->long_term_reference_flag) + { + p_Dpb->max_long_term_pic_idx = 0; + p->is_long_term = 1; + p->long_term_frame_idx = 0; + } + else + { + p_Dpb->max_long_term_pic_idx = -1; + p->is_long_term = 0; + } + +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = -1; +#endif + + //! Error Concealment Function + fercResetPOCInDpb(p_Dpb); + +} + +/*! +************************************************************************ +* \brief +* Perform Sliding window decoded reference picture marking process +* +************************************************************************ +*/ +void sliding_window_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + uint32 i; + + assert (!p->idr_flag); + + // if this is a reference pic with sliding window, unmark first ref frame + if (p_Dpb->ref_frames_in_buffer == imax(1, p_Dpb->num_ref_frames) - p_Dpb->ltref_frames_in_buffer) + { + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term))) + { + unmark_for_reference(p_Dpb->fs[i]); + update_ref_list(p_Dpb); + break; + } + } + } + + p->is_long_term = 0; +} + + +/*! +************************************************************************ +* \brief +* Perform Adaptive memory control decoded reference picture marking process +************************************************************************ +*/ +static void adaptive_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + DecRefPicMarking_t *tmp_drpm; + VideoParameters *p_Vid = p_Dpb->p_Vid; + + p_Vid->last_has_mmco_5 = 0; + + assert (!p->idr_flag); + assert (p->adaptive_ref_pic_buffering_flag); + + while (p->dec_ref_pic_marking_buffer) + { + tmp_drpm = p->dec_ref_pic_marking_buffer; + switch (tmp_drpm->memory_management_control_operation) + { + case 0: + if (tmp_drpm->Next != NULL) + { + error ("memory_management_control_operation = 0 not last operation in buffer", 500); + } + break; + case 1: + mm_unmark_short_term_for_reference(p_Dpb, p, tmp_drpm->difference_of_pic_nums_minus1); + update_ref_list(p_Dpb); + break; + case 2: + mm_unmark_long_term_for_reference(p_Dpb, p, tmp_drpm->long_term_pic_num); + update_ltref_list(p_Dpb); + break; + case 3: + mm_assign_long_term_frame_idx(p_Dpb, p, tmp_drpm->difference_of_pic_nums_minus1, tmp_drpm->long_term_frame_idx); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + break; + case 4: + mm_update_max_long_term_frame_idx (p_Dpb, tmp_drpm->max_long_term_frame_idx_plus1); + update_ltref_list(p_Dpb); + break; + case 5: + mm_unmark_all_short_term_for_reference(p_Dpb); + mm_unmark_all_long_term_for_reference(p_Dpb); + p_Vid->last_has_mmco_5 = 1; + break; + case 6: + mm_mark_current_picture_long_term(p_Dpb, p, tmp_drpm->long_term_frame_idx); + check_num_ref(p_Dpb); + break; + default: + error ("invalid memory_management_control_operation in buffer", 500); + } + p->dec_ref_pic_marking_buffer = tmp_drpm->Next; + free (tmp_drpm); + } + if ( p_Vid->last_has_mmco_5 ) + { + p->pic_num = p->frame_num = 0; + + switch (p->structure) + { + case TOP_FIELD: + { + //p->poc = p->top_poc = p_Vid->toppoc =0; + p->poc = p->top_poc = 0; + break; + } + case BOTTOM_FIELD: + { + //p->poc = p->bottom_poc = p_Vid->bottompoc = 0; + p->poc = p->bottom_poc = 0; + break; + } + case FRAME: + { + p->top_poc -= p->poc; + p->bottom_poc -= p->poc; + + //p_Vid->toppoc = p->top_poc; + //p_Vid->bottompoc = p->bottom_poc; + + p->poc = imin (p->top_poc, p->bottom_poc); + //p_Vid->framepoc = p->poc; + break; + } + } + //currSlice->ThisPOC = p->poc; +#if (MVC_EXTENSION_ENABLE) + if(p->view_id == 0) + { + + flush_dpb(p_Vid->p_Dpb_layer[1]); + flush_dpb(p_Vid->p_Dpb_layer[0]); + } + else + { + flush_dpb(p_Dpb); + } +#else + flush_dpb(p_Dpb); +#endif + } +} + + +/*! +************************************************************************ +* \brief +* Store a picture in DPB. This includes cheking for space in DPB and +* flushing frames. +* If we received a frame, we need to check for a new store, if we +* got a field, check if it's the second field of an already allocated +* store. +* +* \param p_Vid +* VideoParameters +* \param p +* Picture to be stored +* +************************************************************************ +*/ +void store_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + int poc, pos; + // picture error concealment + + // diagnostics + //printf ("Storing (%s) non-ref pic with frame_num #%d\n", (p->type == FRAME)?"FRAME":(p->type == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", p->pic_num); + // if frame, check for new store, + assert (p!=NULL); + + p_Vid->last_has_mmco_5=0; + p_Vid->last_pic_bottom_field = (p->structure == BOTTOM_FIELD); + + if (p->idr_flag) + { +#if (MVC_EXTENSION_ENABLE) + if( p_Vid->p_Inp->DecodeAllLayers && p_Vid->conceal_mode != NONE_CONCEAL && p_Vid->active_subset_sps ) + { + int i; + for( i=1; i < p_Vid->active_subset_sps->num_views_minus1+1; i++ ) + { + if( p_Vid->p_Dpb_layer[i] ) + idr_memory_management(p_Vid->p_Dpb_layer[i], p); + } + } +#endif + idr_memory_management(p_Dpb, p); + } + else + { + // adaptive memory management + if (p->used_for_reference && (p->adaptive_ref_pic_buffering_flag)) + adaptive_memory_management(p_Dpb, p); + } + + if ((p->structure==TOP_FIELD)||(p->structure==BOTTOM_FIELD)) + { + // check for frame store with same pic_number + if (p_Dpb->last_picture) + { + if ((int)p_Dpb->last_picture->frame_num == p->pic_num) + { + if (((p->structure==TOP_FIELD)&&(p_Dpb->last_picture->is_used==2))||((p->structure==BOTTOM_FIELD)&&(p_Dpb->last_picture->is_used==1))) + { + if ((p->used_for_reference && (p_Dpb->last_picture->is_orig_reference!=0))|| + (!p->used_for_reference && (p_Dpb->last_picture->is_orig_reference==0))) + { + insert_picture_in_dpb(p_Vid, p_Dpb->last_picture, p); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); +#if DUMP_DPB + dump_dpb(p_Dpb); +#endif + p_Dpb->last_picture = NULL; + return; + } + } + } + } + } + + // this is a frame or a field which has no stored complementary field + + // sliding window, if necessary + if ((!p->idr_flag)&&(p->used_for_reference && (!p->adaptive_ref_pic_buffering_flag))) + { + sliding_window_memory_management(p_Dpb, p); + } + + // first try to remove unused frames + if (p_Dpb->used_size==p_Dpb->size) + { + // picture error concealment + if( p_Vid->conceal_mode != NONE_CONCEAL) + fercConcealLostNonRefFrames(p_Dpb, 2); + + remove_unused_frame_from_dpb(p_Dpb); + } + + // then output frames until one can be removed + while (p_Dpb->used_size == p_Dpb->size) + { + // non-reference frames may be output directly + if (!p->used_for_reference) + { + get_smallest_poc(p_Dpb, &poc, &pos); + if ((-1==pos) || (p->poc < poc)) + { +#if (_DEBUG && MVC_EXTENSION_ENABLE) + if((p_Vid->profile_idc >= MVC_HIGH)) + printf("Display order might not be correct, %d, %d\n", p->view_id, p->poc); + dump_dpb(p_Dpb); +#endif +#if (MVC_EXTENSION_ENABLE) + direct_output(p_Vid, p, p_Vid->p_out_mvc[p_Dpb->layer_id]); +#else + direct_output(p_Vid, p, p_Vid->p_out); +#endif + return; + } + } + // flush a frame + output_one_frame_from_dpb(p_Dpb); + } + + // check for duplicate frame number in short term reference buffer + if ((p->used_for_reference)&&(!p->is_long_term)) + { + for (i=0; iref_frames_in_buffer; i++) + { +#if (MVC_EXTENSION_ENABLE) + if (p_Dpb->fs_ref[i]->frame_num == p->frame_num && p_Dpb->fs_ref[i]->view_id == p->view_id ) +#else + if (p_Dpb->fs_ref[i]->frame_num == p->frame_num ) +#endif + { + error("duplicate frame_num in short-term reference picture buffer", 500); + } + } + } + // store at end of buffer + insert_picture_in_dpb(p_Vid, p_Dpb->fs[p_Dpb->used_size],p); + + // picture error concealment + if (p->idr_flag) + { + p_Vid->earlier_missing_poc = INT_MAX; + } + + if (p->structure != FRAME) + { + p_Dpb->last_picture = p_Dpb->fs[p_Dpb->used_size]; + } + else + { + p_Dpb->last_picture = NULL; + } + + p_Dpb->used_size++; + + + //! Error Concealment Function + fercAddPOC2Dpb( p_Dpb , p->poc ); + + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + + check_num_ref(p_Dpb); +#if DUMP_DPB + dump_dpb(p_Dpb); +#endif +} + + +/*! +************************************************************************ +* \brief +* Insert the picture into the DPB. A free DPB position is necessary +* for frames, . +* +* \param p_Vid +* VideoParameters +* \param fs +* FrameStore into which the picture will be inserted +* \param p +* StorablePicture to be inserted +* +************************************************************************ +*/ +static void insert_picture_in_dpb(VideoParameters *p_Vid, FrameStore* fs, StorablePicture* p) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + // printf ("insert (%s) pic with frame_num #%d, poc %d\n", (p->structure == FRAME)?"FRAME":(p->structure == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", p->pic_num, p->poc); + assert (p!=NULL); + assert (fs!=NULL); + switch (p->structure) + { + case FRAME: + fs->frame = p; + fs->is_used = 3; + if (p->used_for_reference) + { + fs->is_reference = 3; + fs->is_orig_reference = 3; + if (p->is_long_term) + { + fs->is_long_term = 3; + fs->long_term_frame_idx = p->long_term_frame_idx; + } + } + fs->layer_id = p->layer_id; +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; + fs->inter_view_flag[0] = fs->inter_view_flag[1] = p->inter_view_flag; + fs->anchor_pic_flag[0] = fs->anchor_pic_flag[1] = p->anchor_pic_flag; +#endif + // generate field views + dpb_split_field(p_Vid, fs); + break; + case TOP_FIELD: + fs->top_field = p; + fs->is_used |= 1; + fs->layer_id = p->layer_id; +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; + fs->inter_view_flag[0] = p->inter_view_flag; + fs->anchor_pic_flag[0] = p->anchor_pic_flag; +#endif + if (p->used_for_reference) + { + fs->is_reference |= 1; + fs->is_orig_reference |= 1; + if (p->is_long_term) + { + fs->is_long_term |= 1; + fs->long_term_frame_idx = p->long_term_frame_idx; + } + } + if (fs->is_used == 3) + { + // generate frame view + dpb_combine_field(p_Vid, fs); + } + else + { + fs->poc = p->poc; + } + gen_field_ref_ids(p_Vid, p); + break; + case BOTTOM_FIELD: + fs->bottom_field = p; + fs->is_used |= 2; + fs->layer_id = p->layer_id; +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; + fs->inter_view_flag[1] = p->inter_view_flag; + fs->anchor_pic_flag[1] = p->anchor_pic_flag; +#endif + if (p->used_for_reference) + { + fs->is_reference |= 2; + fs->is_orig_reference |= 2; + if (p->is_long_term) + { + fs->is_long_term |= 2; + fs->long_term_frame_idx = p->long_term_frame_idx; + } + } + if (fs->is_used == 3) + { + // generate frame view + dpb_combine_field(p_Vid, fs); + } + else + { + fs->poc = p->poc; + } + gen_field_ref_ids(p_Vid, p); + break; + } + //! Edited by Joao Carreira + fs->frame_no = p->frame_no; + fs->frame_num = p->pic_num; + fs->recovery_frame = p->recovery_frame; + + fs->is_output = p->is_output; + + /* + if (fs->is_used==3) + { + calculate_frame_no(p_Vid, p); + if (-1 != p_Vid->p_ref && !p_Inp->silent) + find_snr(p_Vid, fs->frame, &p_Vid->p_ref); + } + */ +} + + +/*! +************************************************************************ +* \brief +* remove one frame from DPB +************************************************************************ +*/ +void remove_frame_from_dpb(DecodedPictureBuffer *p_Dpb, int pos) +{ + FrameStore* fs = p_Dpb->fs[pos]; + FrameStore* tmp; + unsigned i; + + //! Error Concealment Function + fercSlindingWindowsOnceFrameRemoved( p_Dpb , fs->frame->poc ); + + //printf ("remove frame with frame_num #%d\n", fs->frame_num); + switch (fs->is_used) + { + case 3: + free_storable_picture(fs->frame); + free_storable_picture(fs->top_field); + free_storable_picture(fs->bottom_field); + fs->frame=NULL; + fs->top_field=NULL; + fs->bottom_field=NULL; + break; + case 2: + free_storable_picture(fs->bottom_field); + fs->bottom_field=NULL; + break; + case 1: + free_storable_picture(fs->top_field); + fs->top_field=NULL; + break; + case 0: + break; + default: + error("invalid frame store type",500); + } + fs->is_used = 0; + fs->is_long_term = 0; + fs->is_reference = 0; + fs->is_orig_reference = 0; + + // move empty framestore to end of buffer + tmp = p_Dpb->fs[pos]; + + for (i=pos; iused_size-1;i++) + { + p_Dpb->fs[i] = p_Dpb->fs[i+1]; + } + p_Dpb->fs[p_Dpb->used_size-1] = tmp; + p_Dpb->used_size--; +} + + + + +/*! +************************************************************************ +* \brief +* Output one picture stored in the DPB. +************************************************************************ +*/ +static int output_one_frame_from_dpb(DecodedPictureBuffer *p_Dpb) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + int poc, pos; + //diagnostics + + if (p_Dpb->used_size < 1) + { + error("Cannot output frame, DPB empty.",150); + } + + // find smallest POC + get_smallest_poc(p_Dpb, &poc, &pos); + + if(pos==-1) + { + return 0; + } + + // call the output function + // printf ("output frame with frame_num #%d, poc %d (dpb. p_Dpb->size=%d, p_Dpb->used_size=%d)\n", p_Dpb->fs[pos]->frame_num, p_Dpb->fs[pos]->frame->poc, p_Dpb->size, p_Dpb->used_size); + + // picture error concealment + if(p_Vid->conceal_mode != 0) + { +#if (MVC_EXTENSION_ENABLE) + fercWriteConcealedLostNonRefFrames(p_Dpb, p_Dpb->fs[pos]->poc, p_Dpb->fs[pos]->view_id); +#else + fercWriteConcealedLostNonRefFrames(p_Dpb, poc, 0); +#endif + +#if( CONCEAL_REMAINING_FRAMES ) + if (p_Vid->p_Inp->IDR_Period != 0) + { //conceal the remaining frames + fercConcealRemainingLostFrames(p_Dpb, p_Dpb->fs[pos]); + } +#endif + } + + // JVT-P072 ends + +#if (MVC_EXTENSION_ENABLE) + write_stored_frame(p_Vid, p_Dpb->fs[pos], p_Vid->p_out_mvc[GetViewIdx(p_Vid, p_Dpb->layer_id)]); +#else + write_stored_frame(p_Vid, p_Dpb->fs[pos], p_Vid->p_out); +#endif + + + + // picture error concealment + if(p_Vid->conceal_mode == 0) + { + if (p_Dpb->last_output_poc >= poc) + { + error ("output POC must be in ascending order", 150); + } + } + + p_Dpb->last_output_poc = poc; + + // free frame store and move empty store to end of buffer + if (!is_used_for_reference(p_Dpb->fs[pos])) + { + remove_frame_from_dpb(p_Dpb, pos); + } + return 1; +} + + + +/*! +************************************************************************ +* \brief +* All stored picture are output. Should be called to empty the buffer +************************************************************************ +*/ +void flush_dpb(DecodedPictureBuffer *p_Dpb) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + uint32 i; + + // diagnostics + // printf("Flush remaining frames from the dpb. p_Dpb->size=%d, p_Dpb->used_size=%d\n",p_Dpb->size,p_Dpb->used_size); + if(!p_Dpb->init_done) + return; + + if( p_Vid->conceal_mode != NONE_CONCEAL) + fercConcealLostNonRefFrames(p_Dpb, 0); + + // mark all frames unused + for (i=0; iused_size; i++) + { +#if MVC_EXTENSION_ENABLE + assert( p_Dpb->fs[i]->view_id == p_Dpb->layer_id); +#endif + unmark_for_reference (p_Dpb->fs[i]); + } + + while (remove_unused_frame_from_dpb(p_Dpb)) ; + + // output frames in POC order + while (p_Dpb->used_size && output_one_frame_from_dpb(p_Dpb)) ; + + p_Dpb->last_output_poc = INT_MIN; +} + +#if (MVC_EXTENSION_ENABLE) +void flush_dpbs(DecodedPictureBuffer **p_Dpb_layers, int nLayers) +{ + VideoParameters *p_Vid = p_Dpb_layers[0]->p_Vid; + DecodedPictureBuffer *p_Dpb; + int i, j, used_size; + + // diagnostics + // printf("Flush remaining frames from the dpb. p_Dpb->size=%d, p_Dpb->used_size=%d\n",p_Dpb->size,p_Dpb->used_size); + + // if(p_Vid->conceal_mode == 0) + + + // mark all frames unused + for(j=0; jconceal_mode != NONE_CONCEAL ) + fercConcealLostNonRefFrames(p_Dpb, 0); + + if(p_Dpb->init_done) + { + for (i=0; i<(int)p_Dpb->used_size; i++) + { + unmark_for_reference (p_Dpb->fs[i]); + } + while (remove_unused_frame_from_dpb(p_Dpb)) ; + } + } + // output frames in POC order + used_size = p_Dpb_layers[0]->used_size; + for(j=1; jinit_done) + { + if(p_Dpb->used_size && (p_Dpb->used_size != used_size)) + { + assert(!"DPB used_size is not equal!"); + } + if((int)p_Dpb->used_size > used_size) + { + used_size = (int)p_Dpb->used_size; + } + } + } + while (used_size) + { + for(j=0; jused_size) + output_one_frame_from_dpb(p_Dpb); + } + used_size--; + } + for(j=0; jlast_output_poc = INT_MIN; + } +} +#endif + +static void gen_field_ref_ids(VideoParameters *p_Vid, StorablePicture *p) +{ + int i,j; + //! Generate Frame parameters from field information. + + //copy the list; + for(j=0; jiSliceNumOfCurrPic; j++) + { + if(p->listX[j][LIST_0]) + { + p->listXsize[j][LIST_0] = p_Vid->ppSliceList[j]->listXsize[LIST_0]; + for(i=0; ilistXsize[j][LIST_0]; i++) + p->listX[j][LIST_0][i] = p_Vid->ppSliceList[j]->listX[LIST_0][i]; + } + if(p->listX[j][LIST_1]) + { + p->listXsize[j][LIST_1] = p_Vid->ppSliceList[j]->listXsize[LIST_1]; + for(i=0; ilistXsize[j][LIST_1]; i++) + p->listX[j][LIST_1][i] = p_Vid->ppSliceList[j]->listX[LIST_1][i]; + } + } +} + +/*! +************************************************************************ +* \brief +* Extract top field from a frame +************************************************************************ +*/ +void dpb_split_field(VideoParameters *p_Vid, FrameStore *fs) +{ + int i, j, ii, jj, jj4; + int idiv,jdiv; + int currentmb; + int twosz16 = 2 * (fs->frame->size_x >> 4); + StorablePicture *fs_top = NULL, *fs_btm = NULL; + StorablePicture *frame = fs->frame; + + fs->poc = frame->poc; + + if (!frame->frame_mbs_only_flag) + { + fs_top = fs->top_field = alloc_storable_picture(p_Vid, TOP_FIELD, frame->size_x, frame->size_y, frame->size_x_cr, frame->size_y_cr, 1); + fs_btm = fs->bottom_field = alloc_storable_picture(p_Vid, BOTTOM_FIELD, frame->size_x, frame->size_y, frame->size_x_cr, frame->size_y_cr, 1); + + for (i = 0; i < (frame->size_y >> 1); i++) + { + memcpy(fs_top->imgY[i], frame->imgY[i*2], frame->size_x*sizeof(imgpel)); + } + + for (i = 0; i< (frame->size_y_cr >> 1); i++) + { + memcpy(fs_top->imgUV[0][i], frame->imgUV[0][i*2], frame->size_x_cr*sizeof(imgpel)); + memcpy(fs_top->imgUV[1][i], frame->imgUV[1][i*2], frame->size_x_cr*sizeof(imgpel)); + } + + for (i = 0; i < (frame->size_y>>1); i++) + { + memcpy(fs_btm->imgY[i], frame->imgY[i*2 + 1], frame->size_x*sizeof(imgpel)); + } + + for (i = 0; i < (frame->size_y_cr>>1); i++) + { + memcpy(fs_btm->imgUV[0][i], frame->imgUV[0][i*2 + 1], frame->size_x_cr*sizeof(imgpel)); + memcpy(fs_btm->imgUV[1][i], frame->imgUV[1][i*2 + 1], frame->size_x_cr*sizeof(imgpel)); + } + + fs_top->poc = frame->top_poc; + fs_btm->poc = frame->bottom_poc; + +#if (MVC_EXTENSION_ENABLE) + fs_top->view_id = frame->view_id; + fs_btm->view_id = frame->view_id; +#endif + + fs_top->frame_poc = frame->frame_poc; + + fs_top->bottom_poc = fs_btm->bottom_poc = frame->bottom_poc; + fs_top->top_poc = fs_btm->top_poc = frame->top_poc; + fs_btm->frame_poc = frame->frame_poc; + + fs_top->used_for_reference = fs_btm->used_for_reference + = frame->used_for_reference; + fs_top->is_long_term = fs_btm->is_long_term + = frame->is_long_term; + fs->long_term_frame_idx = fs_top->long_term_frame_idx + = fs_btm->long_term_frame_idx + = frame->long_term_frame_idx; + + fs_top->coded_frame = fs_btm->coded_frame = 1; + fs_top->mb_aff_frame_flag = fs_btm->mb_aff_frame_flag + = frame->mb_aff_frame_flag; + + frame->top_field = fs_top; + frame->bottom_field = fs_btm; + frame->frame = frame; + fs_top->bottom_field = fs_btm; + fs_top->frame = frame; + fs_top->top_field = fs_top; + fs_btm->top_field = fs_top; + fs_btm->frame = frame; + fs_btm->bottom_field = fs_btm; + +#if (MVC_EXTENSION_ENABLE) + fs_top->view_id = fs_btm->view_id = fs->view_id; + fs_top->inter_view_flag = fs->inter_view_flag[0]; + fs_btm->inter_view_flag = fs->inter_view_flag[1]; +#endif + + fs_top->chroma_format_idc = fs_btm->chroma_format_idc = frame->chroma_format_idc; + fs_top->iCodingType = fs_btm->iCodingType = frame->iCodingType; + if(frame->used_for_reference) + { + pad_dec_picture(p_Vid, fs_top); + pad_dec_picture(p_Vid, fs_btm); + } + } + else + { + fs->top_field = NULL; + fs->bottom_field = NULL; + frame->top_field = NULL; + frame->bottom_field = NULL; + frame->frame = frame; + } + + if (!frame->frame_mbs_only_flag) + { + if (frame->mb_aff_frame_flag) + { + PicMotionParamsOld *frm_motion = &frame->motion; + for (j=0 ; j< (frame->size_y >> 3); j++) + { + jj = (j >> 2)*8 + (j & 0x03); + jj4 = jj + 4; + jdiv = (j >> 1); + for (i=0 ; i < (frame->size_x>>2); i++) + { + idiv = (i >> 2); + + currentmb = twosz16*(jdiv >> 1)+ (idiv)*2 + (jdiv & 0x01); + // Assign field mvs attached to MB-Frame buffer to the proper buffer + if (frm_motion->mb_field[currentmb]) + { + fs_btm->mv_info[j][i].mv[LIST_0] = frame->mv_info[jj4][i].mv[LIST_0]; + fs_btm->mv_info[j][i].mv[LIST_1] = frame->mv_info[jj4][i].mv[LIST_1]; + fs_btm->mv_info[j][i].ref_idx[LIST_0] = frame->mv_info[jj4][i].ref_idx[LIST_0]; + if(fs_btm->mv_info[j][i].ref_idx[LIST_0] >=0) + fs_btm->mv_info[j][i].ref_pic[LIST_0] = p_Vid->ppSliceList[frame->mv_info[jj4][i].slice_no]->listX[4][(short) fs_btm->mv_info[j][i].ref_idx[LIST_0]]; + else + fs_btm->mv_info[j][i].ref_pic[LIST_0] = NULL; + fs_btm->mv_info[j][i].ref_idx[LIST_1] = frame->mv_info[jj4][i].ref_idx[LIST_1]; + if(fs_btm->mv_info[j][i].ref_idx[LIST_1] >=0) + fs_btm->mv_info[j][i].ref_pic[LIST_1] = p_Vid->ppSliceList[frame->mv_info[jj4][i].slice_no]->listX[5][(short) fs_btm->mv_info[j][i].ref_idx[LIST_1]]; + else + fs_btm->mv_info[j][i].ref_pic[LIST_1] = NULL; + + fs_top->mv_info[j][i].mv[LIST_0] = frame->mv_info[jj][i].mv[LIST_0]; + fs_top->mv_info[j][i].mv[LIST_1] = frame->mv_info[jj][i].mv[LIST_1]; + fs_top->mv_info[j][i].ref_idx[LIST_0] = frame->mv_info[jj][i].ref_idx[LIST_0]; + if(fs_top->mv_info[j][i].ref_idx[LIST_0] >=0) + fs_top->mv_info[j][i].ref_pic[LIST_0] = p_Vid->ppSliceList[frame->mv_info[jj][i].slice_no]->listX[2][(short) fs_top->mv_info[j][i].ref_idx[LIST_0]]; + else + fs_top->mv_info[j][i].ref_pic[LIST_0] = NULL; + fs_top->mv_info[j][i].ref_idx[LIST_1] = frame->mv_info[jj][i].ref_idx[LIST_1]; + if(fs_top->mv_info[j][i].ref_idx[LIST_1] >=0) + fs_top->mv_info[j][i].ref_pic[LIST_1] = p_Vid->ppSliceList[frame->mv_info[jj][i].slice_no]->listX[3][(short) fs_top->mv_info[j][i].ref_idx[LIST_1]]; + else + fs_top->mv_info[j][i].ref_pic[LIST_1] = NULL; + } + } + } + } + + //! Generate field MVs from Frame MVs + for (j=0 ; j < (frame->size_y >> 3) ; j++) + { + jj = 2* RSD(j); + jdiv = (j >> 1); + for (i=0 ; i < (frame->size_x >> 2) ; i++) + { + ii = RSD(i); + idiv = (i >> 2); + + currentmb = twosz16 * (jdiv >> 1)+ (idiv)*2 + (jdiv & 0x01); + + if (!frame->mb_aff_frame_flag || !frame->motion.mb_field[currentmb]) + { + fs_top->mv_info[j][i].mv[LIST_0] = fs_btm->mv_info[j][i].mv[LIST_0] = frame->mv_info[jj][ii].mv[LIST_0]; + fs_top->mv_info[j][i].mv[LIST_1] = fs_btm->mv_info[j][i].mv[LIST_1] = frame->mv_info[jj][ii].mv[LIST_1]; + + // Scaling of references is done here since it will not affect spatial direct (2*0 =0) + if (frame->mv_info[jj][ii].ref_idx[LIST_0] == -1) + { + fs_top->mv_info[j][i].ref_idx[LIST_0] = fs_btm->mv_info[j][i].ref_idx[LIST_0] = - 1; + fs_top->mv_info[j][i].ref_pic[LIST_0] = fs_btm->mv_info[j][i].ref_pic[LIST_0] = NULL; + } + else + { + fs_top->mv_info[j][i].ref_idx[LIST_0] = fs_btm->mv_info[j][i].ref_idx[LIST_0] = frame->mv_info[jj][ii].ref_idx[LIST_0]; + fs_top->mv_info[j][i].ref_pic[LIST_0] = fs_btm->mv_info[j][i].ref_pic[LIST_0] = p_Vid->ppSliceList[frame->mv_info[jj][ii].slice_no]->listX[LIST_0][(short) frame->mv_info[jj][ii].ref_idx[LIST_0]]; + } + + if (frame->mv_info[jj][ii].ref_idx[LIST_1] == -1) + { + fs_top->mv_info[j][i].ref_idx[LIST_1] = fs_btm->mv_info[j][i].ref_idx[LIST_1] = - 1; + fs_top->mv_info[j][i].ref_pic[LIST_1] = fs_btm->mv_info[j][i].ref_pic[LIST_1] = NULL; + } + else + { + fs_top->mv_info[j][i].ref_idx[LIST_1] = fs_btm->mv_info[j][i].ref_idx[LIST_1] = frame->mv_info[jj][ii].ref_idx[LIST_1]; + fs_top->mv_info[j][i].ref_pic[LIST_1] = fs_btm->mv_info[j][i].ref_pic[LIST_1] = p_Vid->ppSliceList[frame->mv_info[jj][ii].slice_no]->listX[LIST_1][(short) frame->mv_info[jj][ii].ref_idx[LIST_1]]; + } + } + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Generate a frame from top and bottom fields, +* YUV components and display information only +************************************************************************ +*/ +void dpb_combine_field_yuv(VideoParameters *p_Vid, FrameStore *fs) +{ + int i, j; + + if (!fs->frame) + { + fs->frame = alloc_storable_picture(p_Vid, FRAME, fs->top_field->size_x, fs->top_field->size_y*2, fs->top_field->size_x_cr, fs->top_field->size_y_cr*2, 1); + } + + for (i=0; itop_field->size_y; i++) + { + memcpy(fs->frame->imgY[i*2], fs->top_field->imgY[i] , fs->top_field->size_x * sizeof(imgpel)); // top field + memcpy(fs->frame->imgY[i*2 + 1], fs->bottom_field->imgY[i], fs->bottom_field->size_x * sizeof(imgpel)); // bottom field + } + + for (j = 0; j < 2; j++) + { + for (i=0; itop_field->size_y_cr; i++) + { + memcpy(fs->frame->imgUV[j][i*2], fs->top_field->imgUV[j][i], fs->top_field->size_x_cr*sizeof(imgpel)); + memcpy(fs->frame->imgUV[j][i*2 + 1], fs->bottom_field->imgUV[j][i], fs->bottom_field->size_x_cr*sizeof(imgpel)); + } + } + fs->poc=fs->frame->poc =fs->frame->frame_poc = imin (fs->top_field->poc, fs->bottom_field->poc); + + fs->bottom_field->frame_poc=fs->top_field->frame_poc=fs->frame->poc; + + fs->bottom_field->top_poc=fs->frame->top_poc=fs->top_field->poc; + fs->top_field->bottom_poc=fs->frame->bottom_poc=fs->bottom_field->poc; + + fs->frame->used_for_reference = (fs->top_field->used_for_reference && fs->bottom_field->used_for_reference ); + fs->frame->is_long_term = (fs->top_field->is_long_term && fs->bottom_field->is_long_term ); + + if (fs->frame->is_long_term) + fs->frame->long_term_frame_idx = fs->long_term_frame_idx; + + fs->frame->top_field = fs->top_field; + fs->frame->bottom_field = fs->bottom_field; + fs->frame->frame = fs->frame; + + fs->frame->coded_frame = 0; + + fs->frame->chroma_format_idc = fs->top_field->chroma_format_idc; + fs->frame->frame_cropping_flag = fs->top_field->frame_cropping_flag; + if (fs->frame->frame_cropping_flag) + { + fs->frame->frame_crop_top_offset = fs->top_field->frame_crop_top_offset; + fs->frame->frame_crop_bottom_offset = fs->top_field->frame_crop_bottom_offset; + fs->frame->frame_crop_left_offset = fs->top_field->frame_crop_left_offset; + fs->frame->frame_crop_right_offset = fs->top_field->frame_crop_right_offset; + } + + fs->top_field->frame = fs->bottom_field->frame = fs->frame; + fs->top_field->top_field = fs->top_field; + fs->top_field->bottom_field = fs->bottom_field; + fs->bottom_field->top_field = fs->top_field; + fs->bottom_field->bottom_field = fs->bottom_field; + if(fs->top_field->used_for_reference || fs->bottom_field->used_for_reference) + { + pad_dec_picture(p_Vid, fs->frame); + } + +} + + +/*! +************************************************************************ +* \brief +* Generate a frame from top and bottom fields +************************************************************************ +*/ +void dpb_combine_field(VideoParameters *p_Vid, FrameStore *fs) +{ + int i,j, jj, jj4, k, l; + + dpb_combine_field_yuv(p_Vid, fs); + +#if (MVC_EXTENSION_ENABLE) + fs->frame->view_id = fs->view_id; +#endif + fs->frame->iCodingType = fs->top_field->iCodingType; //FIELD_CODING; + //! Use inference flag to remap mvs/references + + //! Generate Frame parameters from field information. + + for (j=0 ; j < (fs->top_field->size_y >> 2) ; j++) + { + jj = (j<<1); + jj4 = jj + 1; + for (i=0 ; i< (fs->top_field->size_x >> 2) ; i++) + { + fs->frame->mv_info[jj][i].mv[LIST_0] = fs->top_field->mv_info[j][i].mv[LIST_0]; + fs->frame->mv_info[jj][i].mv[LIST_1] = fs->top_field->mv_info[j][i].mv[LIST_1]; + + fs->frame->mv_info[jj][i].ref_idx[LIST_0] = fs->top_field->mv_info[j][i].ref_idx[LIST_0]; + fs->frame->mv_info[jj][i].ref_idx[LIST_1] = fs->top_field->mv_info[j][i].ref_idx[LIST_1]; + + /* bug: top field list doesnot exist.*/ + l = fs->top_field->mv_info[j][i].slice_no; + k = fs->top_field->mv_info[j][i].ref_idx[LIST_0]; + fs->frame->mv_info[jj][i].ref_pic[LIST_0] = k>=0? fs->top_field->listX[l][LIST_0][k]: NULL; + k = fs->top_field->mv_info[j][i].ref_idx[LIST_1]; + fs->frame->mv_info[jj][i].ref_pic[LIST_1] = k>=0? fs->top_field->listX[l][LIST_1][k]: NULL; + + //! association with id already known for fields. + fs->frame->mv_info[jj4][i].mv[LIST_0] = fs->bottom_field->mv_info[j][i].mv[LIST_0]; + fs->frame->mv_info[jj4][i].mv[LIST_1] = fs->bottom_field->mv_info[j][i].mv[LIST_1]; + + fs->frame->mv_info[jj4][i].ref_idx[LIST_0] = fs->bottom_field->mv_info[j][i].ref_idx[LIST_0]; + fs->frame->mv_info[jj4][i].ref_idx[LIST_1] = fs->bottom_field->mv_info[j][i].ref_idx[LIST_1]; + l = fs->bottom_field->mv_info[j][i].slice_no; + + k = fs->bottom_field->mv_info[j][i].ref_idx[LIST_0]; + fs->frame->mv_info[jj4][i].ref_pic[LIST_0] = k>=0? fs->bottom_field->listX[l][LIST_0][k]: NULL; + k = fs->bottom_field->mv_info[j][i].ref_idx[LIST_1]; + fs->frame->mv_info[jj4][i].ref_pic[LIST_1] = k>=0? fs->bottom_field->listX[l][LIST_1][k]: NULL; + } + } +} + + +/*! +************************************************************************ +* \brief +* Allocate memory for buffering of reference picture reordering commands +************************************************************************ +*/ +void alloc_ref_pic_list_reordering_buffer(Slice *currSlice) +{ + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + int size = currSlice->num_ref_idx_active[LIST_0] + 1; + if ((currSlice->modification_of_pic_nums_idc[LIST_0] = calloc(size ,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: modification_of_pic_nums_idc_l0"); + if ((currSlice->abs_diff_pic_num_minus1[LIST_0] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_pic_num_minus1_l0"); + if ((currSlice->long_term_pic_idx[LIST_0] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: long_term_pic_idx_l0"); +#if (MVC_EXTENSION_ENABLE) + if ((currSlice->abs_diff_view_idx_minus1[LIST_0] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_view_idx_minus1_l0"); +#endif + } + else + { + currSlice->modification_of_pic_nums_idc[LIST_0] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_0] = NULL; + currSlice->long_term_pic_idx[LIST_0] = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->abs_diff_view_idx_minus1[LIST_0] = NULL; +#endif + } + + if (currSlice->slice_type == B_SLICE) + { + int size = currSlice->num_ref_idx_active[LIST_1] + 1; + if ((currSlice->modification_of_pic_nums_idc[LIST_1] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: modification_of_pic_nums_idc_l1"); + if ((currSlice->abs_diff_pic_num_minus1[LIST_1] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_pic_num_minus1_l1"); + if ((currSlice->long_term_pic_idx[LIST_1] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: long_term_pic_idx_l1"); +#if (MVC_EXTENSION_ENABLE) + if ((currSlice->abs_diff_view_idx_minus1[LIST_1] = calloc(size,sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_view_idx_minus1_l1"); +#endif + } + else + { + currSlice->modification_of_pic_nums_idc[LIST_1] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_1] = NULL; + currSlice->long_term_pic_idx[LIST_1] = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->abs_diff_view_idx_minus1[LIST_1] = NULL; +#endif + } +} + + +/*! +************************************************************************ +* \brief +* Free memory for buffering of reference picture reordering commands +************************************************************************ +*/ +void free_ref_pic_list_reordering_buffer(Slice *currSlice) +{ + if (currSlice->modification_of_pic_nums_idc[LIST_0]) + free(currSlice->modification_of_pic_nums_idc[LIST_0]); + if (currSlice->abs_diff_pic_num_minus1[LIST_0]) + free(currSlice->abs_diff_pic_num_minus1[LIST_0]); + if (currSlice->long_term_pic_idx[LIST_0]) + free(currSlice->long_term_pic_idx[LIST_0]); + + currSlice->modification_of_pic_nums_idc[LIST_0] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_0] = NULL; + currSlice->long_term_pic_idx[LIST_0] = NULL; + + if (currSlice->modification_of_pic_nums_idc[LIST_1]) + free(currSlice->modification_of_pic_nums_idc[LIST_1]); + if (currSlice->abs_diff_pic_num_minus1[LIST_1]) + free(currSlice->abs_diff_pic_num_minus1[LIST_1]); + if (currSlice->long_term_pic_idx[LIST_1]) + free(currSlice->long_term_pic_idx[LIST_1]); + + currSlice->modification_of_pic_nums_idc[LIST_1] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_1] = NULL; + currSlice->long_term_pic_idx[LIST_1] = NULL; + +#if (MVC_EXTENSION_ENABLE) + if (currSlice->abs_diff_view_idx_minus1[LIST_0]) + free(currSlice->abs_diff_view_idx_minus1[LIST_0]); + currSlice->abs_diff_view_idx_minus1[LIST_0] = NULL; + if (currSlice->abs_diff_view_idx_minus1[LIST_1]) + free(currSlice->abs_diff_view_idx_minus1[LIST_1]); + currSlice->abs_diff_view_idx_minus1[LIST_1] = NULL; +#endif +} + +/*! +************************************************************************ +* \brief +* Tian Dong +* June 13, 2002, Modified on July 30, 2003 +* +* If a gap in frame_num is found, try to fill the gap +* \param p_Vid +* VideoParameters structure +* +************************************************************************ +*/ +void fill_frame_num_gap(VideoParameters *p_Vid, Slice *currSlice) +{ + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int CurrFrameNum; + int UnusedShortTermFrameNum; + StorablePicture *picture = NULL; + int tmp1 = currSlice->delta_pic_order_cnt[0]; + int tmp2 = currSlice->delta_pic_order_cnt[1]; + currSlice->delta_pic_order_cnt[0] = currSlice->delta_pic_order_cnt[1] = 0; + + printf("A gap in frame number is found, try to fill it.\n"); + +#if (MVC_EXTENSION_ENABLE) + UnusedShortTermFrameNum = (p_Vid->pre_frame_num[currSlice->view_id] + 1) % p_Vid->max_frame_num; +#else + UnusedShortTermFrameNum = (p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num; +#endif + CurrFrameNum = currSlice->frame_num; //p_Vid->frame_num; + + while (CurrFrameNum != UnusedShortTermFrameNum) + { + picture = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 1); + picture->coded_frame = 1; + picture->pic_num = UnusedShortTermFrameNum; + picture->frame_num = UnusedShortTermFrameNum; + picture->non_existing = 1; + picture->is_output = 1; + picture->used_for_reference = 1; + picture->adaptive_ref_pic_buffering_flag = 0; +#if (MVC_EXTENSION_ENABLE) + picture->view_id = currSlice->view_id; +#endif + + currSlice->frame_num = UnusedShortTermFrameNum; + if (active_sps->pic_order_cnt_type!=0) + { + decode_poc(p_Vid, p_Vid->ppSliceList[0]); + } + picture->top_poc = currSlice->toppoc; + picture->bottom_poc = currSlice->bottompoc; + picture->frame_poc = currSlice->framepoc; + picture->poc = currSlice->framepoc; + + store_picture_in_dpb(currSlice->p_Dpb, picture); + + picture=NULL; +#if (MVC_EXTENSION_ENABLE) + p_Vid->pre_frame_num[currSlice->view_id] = UnusedShortTermFrameNum; +#else + p_Vid->pre_frame_num = UnusedShortTermFrameNum; +#endif + UnusedShortTermFrameNum = (UnusedShortTermFrameNum + 1) % p_Vid->max_frame_num; + } + currSlice->delta_pic_order_cnt[0] = tmp1; + currSlice->delta_pic_order_cnt[1] = tmp2; + currSlice->frame_num = CurrFrameNum; +} + + +/*! +************************************************************************ +* \brief +* Compute co-located motion info +* +************************************************************************ +*/ +void compute_colocated (Slice *currSlice, StorablePicture **listX[6]) +{ + int i, j; + + VideoParameters *p_Vid = currSlice->p_Vid; + + if (currSlice->direct_spatial_mv_pred_flag == 0) + { + for (j = 0; j < 2 + (currSlice->mb_aff_frame_flag * 4); j += 2) + { + for (i = 0; i < currSlice->listXsize[j];i++) + { + int prescale, iTRb, iTRp; + + if (j==0) + { + iTRb = iClip3( -128, 127, p_Vid->dec_picture->poc - listX[LIST_0 + j][i]->poc ); + } + else if (j == 2) + { + iTRb = iClip3( -128, 127, p_Vid->dec_picture->top_poc - listX[LIST_0 + j][i]->poc ); + } + else + { + iTRb = iClip3( -128, 127, p_Vid->dec_picture->bottom_poc - listX[LIST_0 + j][i]->poc ); + } + + iTRp = iClip3( -128, 127, listX[LIST_1 + j][0]->poc - listX[LIST_0 + j][i]->poc); + + if (iTRp!=0) + { + prescale = ( 16384 + iabs( iTRp / 2 ) ) / iTRp; + currSlice->mvscale[j][i] = iClip3( -1024, 1023, ( iTRb * prescale + 32 ) >> 6 ) ; + } + else + { + currSlice->mvscale[j][i] = 9999; + } + } + } + } +} + + +#if (MVC_EXTENSION_ENABLE) +int GetMaxDecFrameBuffering(VideoParameters *p_Vid) +{ + int i, j, iMax, iMax_1 = 0, iMax_2 = 0; + subset_seq_parameter_set_rbsp_t *curr_subset_sps; + seq_parameter_set_rbsp_t *curr_sps; + + curr_subset_sps = p_Vid->SubsetSeqParSet; + curr_sps = p_Vid->SeqParSet; + for(i=0; iValid && curr_subset_sps->sps.seq_parameter_set_id < MAXSPS) + { + j = curr_subset_sps->sps.max_dec_frame_buffering; + + if (curr_subset_sps->sps.vui_parameters_present_flag && curr_subset_sps->sps.vui_seq_parameters.bitstream_restriction_flag) + { + if ((int)curr_subset_sps->sps.vui_seq_parameters.max_dec_frame_buffering > j) + { + error ("max_dec_frame_buffering larger than MaxDpbSize", 500); + } + j = imax (1, curr_subset_sps->sps.vui_seq_parameters.max_dec_frame_buffering); + } + + if(j > iMax_2) + iMax_2 = j; + } + + if(curr_sps->Valid) + { + j = curr_sps->max_dec_frame_buffering; + + if (curr_sps->vui_parameters_present_flag && curr_sps->vui_seq_parameters.bitstream_restriction_flag) + { + if ((int)curr_sps->vui_seq_parameters.max_dec_frame_buffering > j) + { + error ("max_dec_frame_buffering larger than MaxDpbSize", 500); + } + j = imax (1, curr_sps->vui_seq_parameters.max_dec_frame_buffering); + } + + if(j > iMax_1) + iMax_1 = j; + } + curr_subset_sps++; + curr_sps++; + } + + if (iMax_1 > 0 && iMax_2 > 0) + iMax = iMax_1 + iMax_2; + else + iMax = (iMax_1 >0? iMax_1*2 : iMax_2*2); + return iMax; +} + +static int is_view_id_in_ref_view_list(int view_id, int *ref_view_id, int num_ref_views) +{ + int i; + for(i=0; ip_Vid; + int iVOIdx = curr_view_id; + int pic_avail; + int poc = 0; + int fld_idx; + int num_ref_views, *ref_view_id; + FrameStore *fs = p_Dpb->fs_ilref[0]; + int i; + + if(iVOIdx <0) + printf("Error: iVOIdx: %d is not less than 0\n", iVOIdx); + + if(anchor_pic_flag) + { + num_ref_views = list_idx? p_Vid->active_subset_sps->num_anchor_refs_l1[iVOIdx] : p_Vid->active_subset_sps->num_anchor_refs_l0[iVOIdx]; + ref_view_id = list_idx? p_Vid->active_subset_sps->anchor_ref_l1[iVOIdx]:p_Vid->active_subset_sps->anchor_ref_l0[iVOIdx]; + } + else + { + num_ref_views = list_idx? p_Vid->active_subset_sps->num_non_anchor_refs_l1[iVOIdx] : p_Vid->active_subset_sps->num_non_anchor_refs_l0[iVOIdx]; + ref_view_id = list_idx? p_Vid->active_subset_sps->non_anchor_ref_l1[iVOIdx]:p_Vid->active_subset_sps->non_anchor_ref_l0[iVOIdx]; + } + + // if(num_ref_views <= 0) + // printf("Error: iNumOfRefViews: %d is not larger than 0\n", num_ref_views); + + if(currPicStructure == BOTTOM_FIELD) + fld_idx = 1; + else + fld_idx = 0; + + for(i=0;iused_size_il;i++) + { + FrameStore *fs = p_Dpb->fs_ilref[i]; + if(currPicStructure==FRAME) + { + pic_avail = (fs->is_used == 3); + if (pic_avail) + poc = fs->frame->poc; + } + else if(currPicStructure==TOP_FIELD) + { + pic_avail = fs->is_used & 1; + if (pic_avail) + poc = fs->top_field->poc; + } + else if(currPicStructure==BOTTOM_FIELD) + { + pic_avail = fs->is_used & 2; + if (pic_avail) + poc = fs->bottom_field->poc; + } + else + pic_avail =0; + + if(pic_avail && fs->inter_view_flag[fld_idx]) + { + if(poc == currPOC) + { + //int real_view = GetViewIdx(p_Vid, fs->view_id); + //! Edited by Joao Carreira - + if(is_view_id_in_ref_view_list( GetViewIdx(p_Vid, fs->view_id), ref_view_id, num_ref_views)) + { + //add one inter-view reference; + list[*listXsize] = fs; + //next; + (*listXsize)++; + } + } + } + } +} + +#endif + +void process_picture_in_dpb_s(VideoParameters *p_Vid, StorablePicture *p_pic) +{ + //InputParameters *p_Inp = p_Vid->p_Inp; + ImageData *p_img_out = &p_Vid->tempData3; + imgpel*** d_img; + int i; + + if(p_Vid->tempData3.frm_data[0] == NULL) + init_img_data( p_Vid, &(p_Vid->tempData3), p_Vid->active_sps); + + if (p_pic->structure == FRAME) + { + d_img = p_img_out->frm_data; + } + else //If reference picture is a field, then frm_data will actually contain field data and therefore top/bottom stride is set accordingly. + { + if (p_pic->structure == TOP_FIELD) + { + d_img = p_img_out->top_data; + } + else + { + d_img = p_img_out->bot_data; + } + } + + for(i=0; isize_y; i++) + memcpy(d_img[0][i], p_pic->imgY[i], p_pic->size_x*sizeof(imgpel)); + if (p_Vid->yuv_format != YUV400) + { + for(i=0; isize_y_cr; i++) + memcpy(d_img[1][i], p_pic->imgUV[0][i], p_pic->size_x_cr * sizeof(imgpel)); + for(i=0; isize_y_cr; i++) + memcpy(d_img[2][i], p_pic->imgUV[1][i], p_pic->size_x_cr * sizeof(imgpel)); + } +} + +int init_img_data(VideoParameters *p_Vid, ImageData *p_ImgData, seq_parameter_set_rbsp_t *sps) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int memory_size = 0; + int nplane; + + // allocate memory for reference frame buffers: p_ImgData->frm_data + p_ImgData->format = p_Inp->output; + p_ImgData->format.width[0] = p_Vid->width; + p_ImgData->format.width[1] = p_Vid->width_cr; + p_ImgData->format.width[2] = p_Vid->width_cr; + p_ImgData->format.height[0] = p_Vid->height; + p_ImgData->format.height[1] = p_Vid->height_cr; + p_ImgData->format.height[2] = p_Vid->height_cr; + p_ImgData->format.yuv_format = (ColorFormat) sps->chroma_format_idc; + p_ImgData->format.auto_crop_bottom = p_Inp->output.auto_crop_bottom; + p_ImgData->format.auto_crop_right = p_Inp->output.auto_crop_right; + p_ImgData->format.auto_crop_bottom_cr = p_Inp->output.auto_crop_bottom_cr; + p_ImgData->format.auto_crop_right_cr = p_Inp->output.auto_crop_right_cr; + p_ImgData->frm_stride[0] = p_Vid->width; + p_ImgData->frm_stride[1] = p_ImgData->frm_stride[2] = p_Vid->width_cr; + p_ImgData->top_stride[0] = p_ImgData->bot_stride[0] = p_ImgData->frm_stride[0] << 1; + p_ImgData->top_stride[1] = p_ImgData->top_stride[2] = p_ImgData->bot_stride[1] = p_ImgData->bot_stride[2] = p_ImgData->frm_stride[1] << 1; + + if( sps->separate_colour_plane_flag ) + { + for( nplane=0; nplane < MAX_PLANE; nplane++ ) + { + memory_size += get_mem2Dpel(&(p_ImgData->frm_data[nplane]), p_Vid->height, p_Vid->width); + } + } + else + { + memory_size += get_mem2Dpel(&(p_ImgData->frm_data[0]), p_Vid->height, p_Vid->width); + + if (p_Vid->yuv_format != YUV400) + { + int i, j, k; + memory_size += get_mem2Dpel(&(p_ImgData->frm_data[1]), p_Vid->height_cr, p_Vid->width_cr); + memory_size += get_mem2Dpel(&(p_ImgData->frm_data[2]), p_Vid->height_cr, p_Vid->width_cr); + + if (sizeof(imgpel) == sizeof(unsigned char)) + { + for (k = 1; k < 3; k++) + fast_memset(p_ImgData->frm_data[k][0], 128, p_Vid->height_cr * p_Vid->width_cr * sizeof(imgpel)); + } + else + { + imgpel mean_val; + + for (k = 1; k < 3; k++) + { + mean_val = (imgpel) ((p_Vid->max_pel_value_comp[k] + 1) >> 1); + + for (j = 0; j < p_Vid->height_cr; j++) + { + for (i = 0; i < p_Vid->width_cr; i++) + p_ImgData->frm_data[k][j][i] = mean_val; + } + } + } + } + } + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + // allocate memory for field reference frame buffers + memory_size += init_top_bot_planes(p_ImgData->frm_data[0], p_Vid->height, &(p_ImgData->top_data[0]), &(p_ImgData->bot_data[0])); + + if (p_Vid->yuv_format != YUV400) + { + memory_size += 4*(sizeof(imgpel**)); + + memory_size += init_top_bot_planes(p_ImgData->frm_data[1], p_Vid->height_cr, &(p_ImgData->top_data[1]), &(p_ImgData->bot_data[1])); + memory_size += init_top_bot_planes(p_ImgData->frm_data[2], p_Vid->height_cr, &(p_ImgData->top_data[2]), &(p_ImgData->bot_data[2])); + } + } + + return memory_size; +} + +void free_img_data(VideoParameters *p_Vid, ImageData *p_ImgData) +{ + if ( p_Vid->separate_colour_plane_flag ) + { + int nplane; + + for( nplane=0; nplanefrm_data[nplane]) + { + free_mem2Dpel(p_ImgData->frm_data[nplane]); // free ref frame buffers + p_ImgData->frm_data[nplane] = NULL; + } + } + } + else + { + if (p_ImgData->frm_data[0]) + { + free_mem2Dpel(p_ImgData->frm_data[0]); // free ref frame buffers + p_ImgData->frm_data[0] = NULL; + } + + if (p_ImgData->format.yuv_format != YUV400) + { + if (p_ImgData->frm_data[1]) + { + free_mem2Dpel(p_ImgData->frm_data[1]); + p_ImgData->frm_data[1] = NULL; + } + if (p_ImgData->frm_data[2]) + { + free_mem2Dpel(p_ImgData->frm_data[2]); + p_ImgData->frm_data[2] = NULL; + } + } + } + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + free_top_bot_planes(p_ImgData->top_data[0], p_ImgData->bot_data[0]); + + if (p_ImgData->format.yuv_format != YUV400) + { + free_top_bot_planes(p_ImgData->top_data[1], p_ImgData->bot_data[1]); + free_top_bot_planes(p_ImgData->top_data[2], p_ImgData->bot_data[2]); + } + } +} + +static inline void copy_img_data(imgpel *out_img, imgpel *in_img, int ostride, int istride, unsigned int size_y, unsigned int size_x) +{ + unsigned int i; + for(i = 0; i < size_y; i++) + { + fast_memcpy(out_img, in_img, size_x); + out_img += ostride; + in_img += istride; + } +} + +/*! +************************************************************************ +* \brief +* Remove a picture from DPB which is no longer needed. +************************************************************************ +*/ +#if !MVC_EXTENSION_ENABLE +int remove_unused_proc_pic_from_dpb(DecodedPictureBuffer *p_Dpb) +{ + assert(!"The function is not available\n"); + return 0; +} +#endif + +/*! +************************************************************************ +* \brief +* Store a processed picture in DPB. This includes cheking for space in DPB and +* flushing frames. +* If we received a frame, we need to check for a new store, if we +* got a field, check if it's the second field of an already allocated +* store. +* +* \param p_Vid +* VideoParameters +* \param p +* Picture to be stored +* +************************************************************************ +*/ +#if (MVC_EXTENSION_ENABLE) +void check_for_previous_interview_frames(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + int i; + FrameStore *fs; + if(p_Dpb->used_size_il > 0 ) + { + for(i=0;iused_size_il;i++) + { + fs = p_Dpb->fs_ilref[i]; + if( fs->is_used==3) + { + //checking; +#ifdef _DEBUG + if(p->structure==FRAME) + assert(fs->frame->frame_poc != p->poc); + else if(p->structure==TOP_FIELD) + assert(fs->top_field->top_poc != p->poc); + else if(p->structure==BOTTOM_FIELD) + assert(fs->bottom_field->bottom_poc != p->poc); +#endif + if(fs->frame) + { + free_storable_picture(fs->frame); + fs->frame = NULL; + } + if(fs->top_field) + { + free_storable_picture(fs->top_field); + fs->top_field = NULL; + } + if(fs->bottom_field) + { + free_storable_picture(fs->bottom_field); + fs->bottom_field = NULL; + } + fs->is_used = 0; + fs->is_reference = 0; + + } + + } + } + p_Dpb->used_size_il=0; +} +void store_proc_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + FrameStore *fs = p_Dpb->fs_ilref[p_Dpb->used_size_il]; + + if(p_Dpb->used_size_il == p_Vid->active_subset_sps->num_views_minus1 ) + { + fs = p_Dpb->fs_ilref[p_Dpb->used_size_il-1]; + if( fs->is_used==3) + { + //checking; +#ifdef _DEBUG + if(p->structure==FRAME) + assert(fs->frame->frame_poc != p->poc); + else if(p->structure==TOP_FIELD) + assert(fs->top_field->top_poc != p->poc); + else if(p->structure==BOTTOM_FIELD) + assert(fs->bottom_field->bottom_poc != p->poc); +#endif + if(fs->frame) + { + free_storable_picture(fs->frame); + fs->frame = NULL; + } + if(fs->top_field) + { + free_storable_picture(fs->top_field); + fs->top_field = NULL; + } + if(fs->bottom_field) + { + free_storable_picture(fs->bottom_field); + fs->bottom_field = NULL; + } + fs->is_used = 0; + fs->is_reference = 0; + p_Dpb->used_size_il--; + } + } +#ifdef _DEBUG + if(fs->is_used>0) + { + //checking; + if(p->structure==FRAME) + assert(fs->frame == NULL); + else if(p->structure==TOP_FIELD) + assert(fs->top_field == NULL); + else if(p->structure==BOTTOM_FIELD) + assert(fs->bottom_field == NULL); + } +#endif + + insert_picture_in_dpb(p_Vid, fs, p); + if((p->structure==FRAME && fs->is_used == 3) || (p->structure!=FRAME && fs->is_used && fs->is_used <3)) + p_Dpb->used_size_il++; +} + +/*! +************************************************************************ +* \brief +* Clone an encoded frame picture structure +************************************************************************ +*/ +StorablePicture * clone_storable_picture( VideoParameters *p_Vid, StorablePicture *p_pic ) +{ + int i, j; + int nplane; + int *istride = NULL; + int ostride[2]; + imgpel ***img_in = NULL; + + StorablePicture *p_stored_pic = alloc_storable_picture (p_Vid, (PictureStructure) p_Vid->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, 0); + + p_stored_pic->pic_num = p_pic->pic_num; + p_stored_pic->frame_num = p_pic->frame_num; + p_stored_pic->long_term_frame_idx = p_pic->long_term_frame_idx; + p_stored_pic->long_term_pic_num = p_pic->long_term_pic_num; + //p_stored_pic->used_for_reference = p_pic->used_for_reference; + p_stored_pic->is_long_term = 0; + p_stored_pic->non_existing = p_pic->non_existing; + p_stored_pic->max_slice_id = p_pic->max_slice_id; + p_stored_pic->structure = p_pic->structure; + p_stored_pic->size_x = p_pic->size_x; + p_stored_pic->size_y = p_pic->size_y; + p_stored_pic->size_x_cr = p_pic->size_x_cr; + p_stored_pic->size_y_cr = p_pic->size_y_cr; + p_stored_pic->size_x_m1 = p_pic->size_x - 1; + p_stored_pic->size_y_m1 = p_pic->size_y - 1; + p_stored_pic->size_x_cr_m1 = p_pic->size_x_cr - 1; + p_stored_pic->size_y_cr_m1 = p_pic->size_y_cr - 1; + + p_stored_pic->mb_aff_frame_flag = p_pic->mb_aff_frame_flag; + p_stored_pic->seiHasTone_mapping = p_pic->seiHasTone_mapping; + p_stored_pic->frame_no = p_pic->frame_no; + p_stored_pic->poc = p_pic->poc; + p_stored_pic->top_poc = p_pic->top_poc; + p_stored_pic->bottom_poc = p_pic->bottom_poc; + p_stored_pic->frame_poc = p_pic->frame_poc; + p_stored_pic->pic_num = p_pic->pic_num; + p_stored_pic->frame_num = p_pic->frame_num; + p_stored_pic->coded_frame = 1; + p_stored_pic->qp = p_pic->qp; + p_stored_pic->slice_qp_delta = p_pic->slice_qp_delta; + p_stored_pic->chroma_qp_offset[0] = p_pic->chroma_qp_offset[0]; + p_stored_pic->chroma_qp_offset[1] = p_pic->chroma_qp_offset[1]; + + p_stored_pic->slice_type = p_pic->slice_type; + p_stored_pic->idr_flag = p_pic->idr_flag; + p_stored_pic->no_output_of_prior_pics_flag = p_pic->no_output_of_prior_pics_flag; + p_stored_pic->long_term_reference_flag = 0; + p_stored_pic->adaptive_ref_pic_buffering_flag = 0; + p_stored_pic->dec_ref_pic_marking_buffer = NULL; + p_stored_pic->PicWidthInMbs = p_pic->PicWidthInMbs; + p_stored_pic->recovery_frame = p_pic->recovery_frame; + p_stored_pic->chroma_format_idc = p_pic->chroma_format_idc; + p_stored_pic->frame_mbs_only_flag = p_pic->frame_mbs_only_flag; + p_stored_pic->frame_cropping_flag = p_pic->frame_cropping_flag; + + /* Edited by Joao Carreira */ + p_stored_pic->concealed_pic = p_pic->concealed_pic; + + + if (p_stored_pic->frame_cropping_flag) + { + p_stored_pic->frame_crop_left_offset = p_pic->frame_crop_left_offset; + p_stored_pic->frame_crop_right_offset = p_pic->frame_crop_right_offset; + p_stored_pic->frame_crop_top_offset = p_pic->frame_crop_top_offset; + p_stored_pic->frame_crop_bottom_offset = p_pic->frame_crop_bottom_offset; + } + + // store BL reconstruction + //memcpy((void *)p_stored_pic->imgY[0], (void *)p_Vid->tempData3.frm_data[0][0], p_pic->size_x * p_pic->size_y * sizeof(imgpel)); + + ostride[0] = p_stored_pic->iLumaStride; + ostride[1] = p_stored_pic->iChromaStride; + if (p_stored_pic->structure == FRAME) + { + istride = p_Vid->tempData3.frm_stride; + img_in = p_Vid->tempData3.frm_data; + } + else if (p_stored_pic->structure == TOP_FIELD) + { + istride = p_Vid->tempData3.top_stride; + img_in = p_Vid->tempData3.top_data; + } + else + { + istride = p_Vid->tempData3.bot_stride; + img_in = p_Vid->tempData3.bot_data; + } + + copy_img_data(&p_stored_pic->imgY[0][0], &img_in[0][0][0], ostride[0], istride[0], p_pic->size_y, p_pic->size_x * sizeof(imgpel)); + + pad_buf(*p_stored_pic->imgY, p_stored_pic->size_x, p_stored_pic->size_y, p_stored_pic->iLumaStride, p_Vid->iLumaPadX, p_Vid->iLumaPadY); + + if (p_Vid->active_sps->chroma_format_idc != YUV400) + { + //memcpy((void *)p_stored_pic->imgUV[0][0], (void *)p_Vid->tempData3.frm_data[1][0], p_pic->size_x_cr * p_pic->size_y_cr * sizeof(imgpel)); + //memcpy((void *)p_stored_pic->imgUV[1][0], (void *)p_Vid->tempData3.frm_data[2][0], p_pic->size_x_cr * p_pic->size_y_cr * sizeof(imgpel)); + copy_img_data(&p_stored_pic->imgUV[0][0][0], &img_in[1][0][0], ostride[1], istride[1], p_pic->size_y_cr, p_pic->size_x_cr*sizeof(imgpel)); + pad_buf(*p_stored_pic->imgUV[0], p_stored_pic->size_x_cr, p_stored_pic->size_y_cr, p_stored_pic->iChromaStride, p_Vid->iChromaPadX, p_Vid->iChromaPadY); + copy_img_data(&p_stored_pic->imgUV[1][0][0], &img_in[2][0][0], ostride[1], istride[2], p_pic->size_y_cr, p_pic->size_x_cr*sizeof(imgpel)); + pad_buf(*p_stored_pic->imgUV[1], p_stored_pic->size_x_cr, p_stored_pic->size_y_cr, p_stored_pic->iChromaStride, p_Vid->iChromaPadX, p_Vid->iChromaPadY); + } + + for (j = 0; j < (p_pic->size_y >> BLOCK_SHIFT); j++) + { + //PicMotionParams *mv_info = p_stored_pic->mv_info[j]; + char *ref_idx = p_stored_pic->mv_info[j][0].ref_idx; + for (i = 0; i < (p_pic->size_x >> BLOCK_SHIFT); i++) + { + //*((short *)&((mv_info++)->ref_idx[LIST_0])) = -1; + *((short *) ref_idx) = -1; + ref_idx += sizeof(PicMotionParams); + } + } + + if( (p_Vid->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplanesize_y >> BLOCK_SHIFT); j++) + { + for (i = 0; i < (p_pic->size_x >> BLOCK_SHIFT); i++) + { + p_stored_pic->JVmv_info[nplane][j][i].ref_idx[LIST_0] = -1; + p_stored_pic->JVmv_info[nplane][j][i].ref_idx[LIST_1] = -1; + } + } + } + } + + // MVC-related parameters + p_stored_pic->inter_view_flag = p_pic->inter_view_flag; + p_stored_pic->anchor_pic_flag = 0; + p_stored_pic->view_id = p_pic->view_id; + p_stored_pic->layer_id = p_pic->layer_id; + p_stored_pic->proc_flag = 1; + p_stored_pic->is_output = 1; + p_stored_pic->used_for_reference = 1; + + return p_stored_pic; +} +#endif + + diff --git a/ldecod/src/mbuffer_mvc.c b/ldecod/src/mbuffer_mvc.c new file mode 100644 index 0000000..a699f36 --- /dev/null +++ b/ldecod/src/mbuffer_mvc.c @@ -0,0 +1,859 @@ +/*! + *********************************************************************** + * \file + * mbuffer_mvc.c + * + * \brief + * Frame buffer functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Athanasios Leontaris + * - Karsten Suehring + * - Alexis Tourapis + * - Yuwen He + *********************************************************************** + */ + +#include + +#include "global.h" +#include "header.h" +#include "image.h" +#include "mbuffer.h" +#include "mbuffer_common.h" +#include "mbuffer_mvc.h" +#include "memalloc.h" +#include "output.h" + +#if (MVC_EXTENSION_ENABLE) + +/*! + ************************************************************************ + * \brief + * Reordering process for short-term reference pictures + * + ************************************************************************ + */ +void reorder_short_term(Slice *currSlice, int cur_list, int num_ref_idx_lX_active_minus1, int picNumLX, int *refIdxLX, int currViewID) +{ + StorablePicture **RefPicListX = currSlice->listX[cur_list]; + int cIdx, nIdx; + + StorablePicture *picLX; + + picLX = get_short_term_pic(currSlice, currSlice->p_Dpb, picNumLX); + + for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ ) + if (RefPicListX[ cIdx ]) + { + if( (RefPicListX[ cIdx ]->is_long_term ) || (RefPicListX[ cIdx ]->pic_num != picNumLX ) || + ( currViewID != -1 && RefPicListX[ cIdx ]->layer_id != currViewID ) + ) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } +} + + +/*! + ************************************************************************ + * \brief + * Reordering process for long-term reference pictures + * + ************************************************************************ + */ +void reorder_long_term(Slice *currSlice, StorablePicture **RefPicListX, int num_ref_idx_lX_active_minus1, int LongTermPicNum, int *refIdxLX, int currViewID) +{ + int cIdx, nIdx; + + StorablePicture *picLX; + + picLX = get_long_term_pic(currSlice, currSlice->p_Dpb, LongTermPicNum); + + for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ ) + { + if (RefPicListX[ cIdx ]) + { + if( (!RefPicListX[ cIdx ]->is_long_term ) || (RefPicListX[ cIdx ]->long_term_pic_num != LongTermPicNum ) || + ( currViewID != -1 && RefPicListX[ cIdx ]->layer_id != currViewID ) + ) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } + } +} + +/*! + ************************************************************************ + * \brief + * Returns inter-view prediction pic with given targetViewID + * + ************************************************************************ + */ +static StorablePicture* get_inter_view_pic(VideoParameters *p_Vid, Slice *currSlice, int targetViewID, int currPOC, int listidx) +{ + unsigned i; + unsigned int listinterview_size; + FrameStore **fs_listinterview; + + if (listidx == 0) + { + fs_listinterview = currSlice->fs_listinterview0; + listinterview_size = currSlice->listinterviewidx0; + } + else + { + fs_listinterview = currSlice->fs_listinterview1; + listinterview_size = currSlice->listinterviewidx1; + } + + for(i=0; ilayer_id == GetVOIdx( p_Vid, targetViewID )) + { + if(p_Vid->structure==FRAME && fs_listinterview[i]->frame->poc == currPOC) + { + return fs_listinterview[i]->frame; + } + else if(p_Vid->structure==TOP_FIELD && fs_listinterview[i]->top_field->poc == currPOC) + { + return fs_listinterview[i]->top_field; + } + else if(p_Vid->structure==BOTTOM_FIELD && fs_listinterview[i]->bottom_field->poc == currPOC) + { + return fs_listinterview[i]->bottom_field; + } + } + } + + return NULL; +} + +/*! + ************************************************************************ + * \brief + * Generates a alternating field list from a given FrameStore inter-view list + * + ************************************************************************ + */ +static void gen_pic_list_from_frame_interview_list(PictureStructure currStructure, FrameStore **fs_list, int list_idx, StorablePicture **list, char *list_size) +{ + int i; + + if (currStructure == TOP_FIELD) + { + for (i=0; itop_field; + (*list_size)++; + } + } + if (currStructure == BOTTOM_FIELD) + { + for (i=0; ibottom_field; + (*list_size)++; + } + } +} + + +/*! +************************************************************************ +* \brief +* Initialize reference lists depending on current slice type +* +************************************************************************ +*/ +void init_lists_i_slice_mvc(Slice *currSlice) +{ + //VideoParameters *p_Vid = currSlice->p_Vid; + + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; +} + +/*! +************************************************************************ +* \brief +* Initialize reference lists for a P Slice +* +************************************************************************ +*/ +void init_lists_p_slice_mvc(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + int view_id = currSlice->view_id; + unsigned int i; + + int list0idx = 0; + int listltidx = 0; + + FrameStore **fs_list0; + FrameStore **fs_listlt; + + int currPOC = currSlice->ThisPOC; + int anchor_pic_flag = currSlice->anchor_pic_flag; + + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; + + if (currSlice->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + // order list 0 by PicNum + qsort((void *)currSlice->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc); + currSlice->listXsize[0] = (char) list0idx; + //printf("listX[0] (PicNum): "); for (i=0; ilistX[0][i]->pic_num);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + currSlice->listX[0][list0idx++]=p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = (char) list0idx; + } + else + { + fs_list0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list0) + no_mem_exit("init_lists: fs_list0"); + fs_listlt = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_listlt) + no_mem_exit("init_lists: fs_listlt"); + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + + qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_frame_num_desc); + + //printf("fs_list0 (FrameNum): "); for (i=0; iframe_num_wrap);} printf("\n"); + + currSlice->listXsize[0] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, list0idx, currSlice->listX[0], &currSlice->listXsize[0], 0); + + //printf("listX[0] (PicNum): "); for (i=0; i < currSlice->listXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->pic_num);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + fs_listlt[listltidx++]=p_Dpb->fs_ltref[i]; + } + + qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[0], &currSlice->listXsize[0], 1); + + free(fs_list0); + free(fs_listlt); + } + + currSlice->listXsize[1] = 0; + +#if !SIMULCAST_ENABLE + if (currSlice->svc_extension_flag == 0) + { + int curr_view_id = currSlice->layer_id; + currSlice->fs_listinterview0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==currSlice->fs_listinterview0) + no_mem_exit("init_lists: fs_listinterview0"); + list0idx = currSlice->listXsize[0]; + if (currSlice->structure == FRAME) + { + //append_interview_list(p_Vid->p_Dpb_layer[1], 0, 0, currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_view_id, anchor_pic_flag); + append_interview_list(p_Dpb, 0, 0, currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_view_id, anchor_pic_flag); + for (i=0; i<(unsigned int)currSlice->listinterviewidx0; i++) + { + currSlice->listX[0][list0idx++]=currSlice->fs_listinterview0[i]->frame; + } + currSlice->listXsize[0] = (char) list0idx; + } + else + { + //append_interview_list(p_Vid->p_Dpb_layer[1], currSlice->structure, 0, currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_view_id, anchor_pic_flag); + append_interview_list(p_Dpb, currSlice->structure, 0, currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_view_id, anchor_pic_flag); + gen_pic_list_from_frame_interview_list(currSlice->structure, currSlice->fs_listinterview0, currSlice->listinterviewidx0, currSlice->listX[0], &currSlice->listXsize[0]); + } + } +#endif + // set max size + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + + // set the unused list entries to NULL + for (i=currSlice->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[0][i] = p_Vid->no_reference_picture; + } + for (i=currSlice->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[1][i] = p_Vid->no_reference_picture; + } + + #if PRINTREFLIST + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if(currSlice->listXsize[0]>0) + { + printf("\n"); + printf(" ** (CurViewID:%d %d) %s Ref Pic List 0 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + } + #endif +} + +/*! + ************************************************************************ + * \brief + * Initialize reference lists for a B Slice + * + ************************************************************************ + */ +void init_lists_b_slice_mvc(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i; + int j; + + int list0idx = 0; + int list0idx_1 = 0; + int listltidx = 0; + + FrameStore **fs_list0; + FrameStore **fs_list1; + FrameStore **fs_listlt; + + int currPOC = currSlice->ThisPOC; + int anchor_pic_flag = currSlice->anchor_pic_flag; + + currSlice->listinterviewidx0 = 0; + currSlice->listinterviewidx1 = 0; + + { + // B-Slice + if (currSlice->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if (currSlice->framepoc >= p_Dpb->fs_ref[i]->frame->poc) //!KS use >= for error concealment + // if (p_Vid->framepoc > p_Dpb->fs_ref[i]->frame->poc) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + } + qsort((void *)currSlice->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_poc_desc); + list0idx_1 = list0idx; + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if (currSlice->framepoc < p_Dpb->fs_ref[i]->frame->poc) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + } + qsort((void *)&currSlice->listX[0][list0idx_1], list0idx-list0idx_1, sizeof(StorablePicture*), compare_pic_by_poc_asc); + + for (j=0; jlistX[1][list0idx-list0idx_1+j]=currSlice->listX[0][j]; + } + for (j=list0idx_1; jlistX[1][j-list0idx_1]=currSlice->listX[0][j]; + } + + currSlice->listXsize[0] = currSlice->listXsize[1] = (char) list0idx; + + // printf("currSlice->listX[0] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->poc);} printf("\n"); + // printf("currSlice->listX[1] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->poc);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + currSlice->listX[0][list0idx] = p_Dpb->fs_ltref[i]->frame; + currSlice->listX[1][list0idx++] = p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + qsort((void *)&currSlice->listX[1][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = currSlice->listXsize[1] = (char) list0idx; + } + else + { + fs_list0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list0) + no_mem_exit("init_lists: fs_list0"); + fs_list1 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list1) + no_mem_exit("init_lists: fs_list1"); + fs_listlt = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_listlt) + no_mem_exit("init_lists: fs_listlt"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 1; + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used) + { + if (currSlice->ThisPOC >= p_Dpb->fs_ref[i]->poc) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_poc_desc); + list0idx_1 = list0idx; + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used) + { + if (currSlice->ThisPOC < p_Dpb->fs_ref[i]->poc) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)&fs_list0[list0idx_1], list0idx-list0idx_1, sizeof(FrameStore*), compare_fs_by_poc_asc); + + for (j=0; jThisPOC); for (i=0; ipoc);} printf("\n"); + // printf("fs_list1 currPoc=%d (Poc): ", currSlice->ThisPOC); for (i=0; ipoc);} printf("\n"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, list0idx, currSlice->listX[0], &currSlice->listXsize[0], 0); + gen_pic_list_from_frame_list(currSlice->structure, fs_list1, list0idx, currSlice->listX[1], &currSlice->listXsize[1], 0); + + // printf("currSlice->listX[0] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->poc);} printf("\n"); + // printf("currSlice->listX[1] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->poc);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + fs_listlt[listltidx++]=p_Dpb->fs_ltref[i]; + } + + qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[0], &currSlice->listXsize[0], 1); + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[1], &currSlice->listXsize[1], 1); + + free(fs_list0); + free(fs_list1); + free(fs_listlt); + } + } + + if ((currSlice->listXsize[0] == currSlice->listXsize[1]) && (currSlice->listXsize[0] > 1)) + { + // check if lists are identical, if yes swap first two elements of currSlice->listX[1] + int diff=0; + for (j = 0; j< currSlice->listXsize[0]; j++) + { + if (currSlice->listX[0][j] != currSlice->listX[1][j]) + { + diff = 1; + break; + } + } + if (!diff) + { + StorablePicture *tmp_s = currSlice->listX[1][0]; + currSlice->listX[1][0]=currSlice->listX[1][1]; + currSlice->listX[1][1]=tmp_s; + } + } + // set max size + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + +#if !SIMULCAST_ENABLE + if (currSlice->svc_extension_flag == 0) + { + int curr_view_id = currSlice->view_id; + // B-Slice + currSlice->fs_listinterview0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==currSlice->fs_listinterview0) + no_mem_exit("init_lists: fs_listinterview0"); + currSlice->fs_listinterview1 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==currSlice->fs_listinterview1) + no_mem_exit("init_lists: fs_listinterview1"); + list0idx = currSlice->listXsize[0]; + + if (currSlice->structure == FRAME) + { + append_interview_list( + p_Vid->p_Dpb_layer[curr_view_id], + 0, 0, currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_view_id, anchor_pic_flag); + append_interview_list( + p_Vid->p_Dpb_layer[curr_view_id], + 0, 1, currSlice->fs_listinterview1, &currSlice->listinterviewidx1, currPOC, curr_view_id, anchor_pic_flag); + for (i=0; i<(unsigned int)currSlice->listinterviewidx0; i++) + { + currSlice->listX[0][list0idx++]=currSlice->fs_listinterview0[i]->frame; + } + currSlice->listXsize[0] = (char) list0idx; + list0idx = currSlice->listXsize[1]; + for (i=0; i<(unsigned int)currSlice->listinterviewidx1; i++) + { + currSlice->listX[1][list0idx++] = currSlice->fs_listinterview1[i]->frame; + } + currSlice->listXsize[1] = (char) list0idx; + } + else + { + append_interview_list( + p_Vid->p_Dpb_layer[1], + currSlice->structure, 0, currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_view_id, anchor_pic_flag); + gen_pic_list_from_frame_interview_list(currSlice->structure, currSlice->fs_listinterview0, currSlice->listinterviewidx0, currSlice->listX[0], &currSlice->listXsize[0]); + append_interview_list( + p_Vid->p_Dpb_layer[1], + currSlice->structure, 1, currSlice->fs_listinterview1, &currSlice->listinterviewidx1, currPOC, curr_view_id, anchor_pic_flag); + gen_pic_list_from_frame_interview_list(currSlice->structure, currSlice->fs_listinterview1, currSlice->listinterviewidx1, currSlice->listX[1], &currSlice->listXsize[1]); + } + } +#endif + + + // set the unused list entries to NULL + for (i=currSlice->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[0][i] = p_Vid->no_reference_picture; + } + for (i=currSlice->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[1][i] = p_Vid->no_reference_picture; + } +#if PRINTREFLIST + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if((currSlice->listXsize[0]>0) || (currSlice->listXsize[1]>0)) + printf("\n"); + if(currSlice->listXsize[0]>0) + { + printf(" ** (CurViewID:%d %d) %s Ref Pic List 0 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + if(currSlice->listXsize[1]>0) + { + printf(" ** (CurViewID:%d %d) %s Ref Pic List 1 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[1]); i++) //ref list 1 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[1][i]->poc, currSlice->listX[1][i]->pic_num, currSlice->listX[1][i]->view_id); + } + } + } +#endif +} + + +/*! + ************************************************************************ + * \brief + * Reordering process for inter-view reference pictures + * + ************************************************************************ + */ +static void reorder_interview(VideoParameters *p_Vid, Slice *currSlice, StorablePicture **RefPicListX, int num_ref_idx_lX_active_minus1, int *refIdxLX, int targetViewID, int currPOC, int listidx) +{ + int cIdx, nIdx; + StorablePicture *picLX; + + picLX = get_inter_view_pic(p_Vid, currSlice, targetViewID, currPOC, listidx); + + if (picLX) + { + for( cIdx = num_ref_idx_lX_active_minus1+1; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= num_ref_idx_lX_active_minus1+1; cIdx++ ) + { + if((GetViewIdx( p_Vid, RefPicListX[cIdx]->view_id ) != targetViewID) || (RefPicListX[cIdx]->poc != currPOC)) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } + } +} + +/*! + ************************************************************************ + * \brief + * Reordering process for MVC reference picture lists + * + ************************************************************************ + */ +void reorder_ref_pic_list_mvc(Slice *currSlice, int cur_list, int **anchor_ref, int **non_anchor_ref, int view_id, int anchor_pic_flag, int currPOC, int listidx) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[cur_list]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[cur_list]; + int *long_term_pic_idx = currSlice->long_term_pic_idx[cur_list]; + int num_ref_idx_lX_active_minus1 = currSlice->num_ref_idx_active[cur_list] - 1; + int *abs_diff_view_idx_minus1 = currSlice->abs_diff_view_idx_minus1[cur_list]; + + int i; + + int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX; + int picViewIdxLX, targetViewID; + int refIdxLX = 0; + int maxViewIdx =0; + int curr_VOIdx = -1; + int picViewIdxLXPred=-1; + + if (p_Vid->structure==FRAME) + { + maxPicNum = p_Vid->max_frame_num; + currPicNum = currSlice->frame_num; + } + else + { + maxPicNum = 2 * p_Vid->max_frame_num; + currPicNum = 2 * currSlice->frame_num + 1; + } + + if(currSlice->svc_extension_flag==0) + { + curr_VOIdx = view_id; + maxViewIdx = get_maxViewIdx(p_Vid, view_id, anchor_pic_flag, 0); + picViewIdxLXPred=-1; + } + + picNumLXPred = currPicNum; + + for (i=0; modification_of_pic_nums_idc[i]!=3; i++) + { + if (modification_of_pic_nums_idc[i] > 5) + error ("Invalid modification_of_pic_nums_idc command", 500); + + if (modification_of_pic_nums_idc[i] < 2) + { + if (modification_of_pic_nums_idc[i] == 0) + { + if( picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) < 0 ) + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) + maxPicNum; + else + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ); + } + else // (modification_of_pic_nums_idc[i] == 1) + { + if( picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) >= maxPicNum ) + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) - maxPicNum; + else + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ); + } + picNumLXPred = picNumLXNoWrap; + + if( picNumLXNoWrap > currPicNum ) + picNumLX = picNumLXNoWrap - maxPicNum; + else + picNumLX = picNumLXNoWrap; + + reorder_short_term(currSlice, cur_list, num_ref_idx_lX_active_minus1, picNumLX, &refIdxLX, view_id); + } + else if (modification_of_pic_nums_idc[i] == 2) //(modification_of_pic_nums_idc[i] == 2) + { + reorder_long_term(currSlice, currSlice->listX[cur_list], num_ref_idx_lX_active_minus1, long_term_pic_idx[i], &refIdxLX, view_id); + } + else + { + if(modification_of_pic_nums_idc[i] == 4) //(modification_of_pic_nums_idc[i] == 4) + { + picViewIdxLX = picViewIdxLXPred - (abs_diff_view_idx_minus1[i] + 1); + if( picViewIdxLX <0) + picViewIdxLX += maxViewIdx; + } + else //(modification_of_pic_nums_idc[i] == 5) + { + picViewIdxLX = picViewIdxLXPred + (abs_diff_view_idx_minus1[i] + 1); + if( picViewIdxLX >= maxViewIdx) + picViewIdxLX -= maxViewIdx; + } + picViewIdxLXPred = picViewIdxLX; + + if (anchor_pic_flag) + targetViewID = anchor_ref[curr_VOIdx][picViewIdxLX]; + else + targetViewID = non_anchor_ref[curr_VOIdx][picViewIdxLX]; + + reorder_interview(p_Vid, currSlice, currSlice->listX[cur_list], num_ref_idx_lX_active_minus1, &refIdxLX, targetViewID, currPOC, listidx); + } + } + // that's a definition + currSlice->listXsize[cur_list] = (char) (num_ref_idx_lX_active_minus1 + 1); +} + +void reorder_lists_mvc(Slice * currSlice, int currPOC) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + + if ((currSlice->slice_type != I_SLICE)&&(currSlice->slice_type != SI_SLICE)) + { + if (currSlice->ref_pic_list_reordering_flag[LIST_0]) + { + reorder_ref_pic_list_mvc(currSlice, LIST_0, + p_Vid->active_subset_sps->anchor_ref_l0, + p_Vid->active_subset_sps->non_anchor_ref_l0, + currSlice->view_id, currSlice->anchor_pic_flag, currPOC, 0); + } + if (p_Vid->no_reference_picture == currSlice->listX[0][currSlice->num_ref_idx_active[LIST_0]-1]) + { + if (p_Vid->non_conforming_stream) + printf("RefPicList0[ %d ] is equal to 'no reference picture'\n", currSlice->num_ref_idx_active[LIST_0] - 1); + else + error("RefPicList0[ num_ref_idx_l0_active_minus1 ] in MVC layer is equal to 'no reference picture', invalid bitstream",500); + } + // that's a definition + currSlice->listXsize[0] = (char)currSlice->num_ref_idx_active[LIST_0]; + } + if (currSlice->slice_type == B_SLICE) + { + if (currSlice->ref_pic_list_reordering_flag[LIST_1]) + { + reorder_ref_pic_list_mvc(currSlice, LIST_1, + p_Vid->active_subset_sps->anchor_ref_l1, + p_Vid->active_subset_sps->non_anchor_ref_l1, + currSlice->view_id, currSlice->anchor_pic_flag, currPOC, 1); + } + if (p_Vid->no_reference_picture == currSlice->listX[1][currSlice->num_ref_idx_active[LIST_1]-1]) + { + if (p_Vid->non_conforming_stream) + printf("RefPicList1[ %d ] is equal to 'no reference picture'\n", currSlice->num_ref_idx_active[LIST_1] - 1); + else + error("RefPicList1[ num_ref_idx_l1_active_minus1 ] is equal to 'no reference picture', invalid bitstream",500); + } + // that's a definition + currSlice->listXsize[1] = (char)currSlice->num_ref_idx_active[LIST_1]; + } + + free_ref_pic_list_reordering_buffer(currSlice); + + if ( currSlice->slice_type == P_SLICE ) + { +#if PRINTREFLIST + unsigned int i; + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if(currSlice->listXsize[0]>0) + { + printf("\n"); + printf(" ** (FinalViewID:%d %d) %s Ref Pic List 0 ****\n", currSlice->view_id, currSlice->ThisPOC, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + } +#endif + } + else if ( currSlice->slice_type == B_SLICE ) + { +#if PRINTREFLIST + unsigned int i; + // print out for debug purpose + if((p_Vid->profile_idc == MVC_HIGH || p_Vid->profile_idc == STEREO_HIGH) && currSlice->current_slice_nr==0) + { + if((currSlice->listXsize[0]>0) || (currSlice->listXsize[1]>0)) + printf("\n"); + if(currSlice->listXsize[0]>0) + { + printf(" ** (FinalViewID:%d) %s Ref Pic List 0 ****\n", currSlice->view_id, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + if(currSlice->listXsize[1]>0) + { + printf(" ** (FinalViewID:%d) %s Ref Pic List 1 ****\n", currSlice->view_id, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[1]); i++) //ref list 1 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[1][i]->poc, currSlice->listX[1][i]->pic_num, currSlice->listX[1][i]->view_id); + } + } + } +#endif + } +} + +#endif + diff --git a/ldecod/src/mc_direct.c b/ldecod/src/mc_direct.c new file mode 100644 index 0000000..35b34cc --- /dev/null +++ b/ldecod/src/mc_direct.c @@ -0,0 +1,709 @@ + +/*! + ************************************************************************************* + * \file mc_direct.c + * + * \brief + * Direct Prediction functions + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * - Yuwen He + * + ************************************************************************************* + */ +#include "global.h" +#include "block.h" +#include "mc_prediction.h" +#include "mbuffer.h" +#include "mb_access.h" +#include "macroblock.h" +#include "memalloc.h" + +static void update_direct_mv_info_temporal(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int j,k; + int partmode = ((currMB->mb_type == P8x8) ? 4 : currMB->mb_type); + int step_h0 = BLOCK_STEP [partmode][0]; + int step_v0 = BLOCK_STEP [partmode][1]; + + int i0, j0, j6; + + int j4, i4; + StorablePicture *dec_picture = currSlice->dec_picture; + + int list_offset = currMB->list_offset; // ((currSlice->mb_aff_frame_flag)&&(currMB->mb_field))? (mb_nr&0x01) ? 4 : 2 : 0; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + Boolean has_direct = (currMB->b8mode[0] == 0) | (currMB->b8mode[1] == 0) | (currMB->b8mode[2] == 0) | (currMB->b8mode[3] == 0); + + if (has_direct) + { + int mv_scale = 0; + + for (k = 0; k < 4; ++k) // Scan all blocks + { + if (currMB->b8mode[k] == 0) + { + currMB->b8pdir[k] = 2; + for(j0 = 2 * (k >> 1); j0 < 2 * (k >> 1) + 2; j0 += step_v0) + { + for(i0 = currMB->block_x + 2*(k & 0x01); i0 < currMB->block_x + 2 * (k & 0x01)+2; i0 += step_h0) + { + PicMotionParams *colocated; + int refList; + int ref_idx; + int mapped_idx = -1, iref; + + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->mv_info[RSD(currMB->block_y_aff + j0)][RSD(i0)] : &list1[0]->mv_info[currMB->block_y_aff + j0][i0]; + if(currSlice->mb_aff_frame_flag) + { + assert(p_Vid->active_sps->direct_8x8_inference_flag); + if(!currMB->mb_field && ((currSlice->listX[LIST_1][0]->iCodingType==FRAME_MB_PAIR_CODING && currSlice->listX[LIST_1][0]->motion.mb_field[currMB->mbAddrX]) || + (currSlice->listX[LIST_1][0]->iCodingType==FIELD_CODING))) + { + if (iabs(dec_picture->poc - currSlice->listX[LIST_1+4][0]->poc)> iabs(dec_picture->poc -currSlice->listX[LIST_1+2][0]->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &currSlice->listX[LIST_1+2][0]->mv_info[RSD(currMB->block_y_aff + j0)>>1][RSD(i0)] : &currSlice->listX[LIST_1+2][0]->mv_info[(currMB->block_y_aff + j0)>>1][i0]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &currSlice->listX[LIST_1+4][0]->mv_info[RSD(currMB->block_y_aff + j0)>>1][RSD(i0)] : &currSlice->listX[LIST_1+4][0]->mv_info[(currMB->block_y_aff + j0)>>1][i0]; + } + } + } + else if(!p_Vid->active_sps->frame_mbs_only_flag && !currSlice->field_pic_flag && currSlice->listX[LIST_1][0]->iCodingType != FRAME_CODING) + { + if (iabs(dec_picture->poc - list1[0]->bottom_field->poc)> iabs(dec_picture->poc -list1[0]->top_field->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->top_field->mv_info[RSD(currMB->block_y_aff + j0)>>1][RSD(i0)] : &list1[0]->top_field->mv_info[(currMB->block_y_aff + j0)>>1][i0]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->bottom_field->mv_info[RSD(currMB->block_y_aff + j0)>>1][RSD(i0)] : &list1[0]->bottom_field->mv_info[(currMB->block_y_aff + j0)>>1][i0]; + } + } + else if(!p_Vid->active_sps->frame_mbs_only_flag && currSlice->field_pic_flag && currSlice->structure!=list1[0]->structure && list1[0]->coded_frame) + { + if (currSlice->structure == TOP_FIELD) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->frame->top_field->mv_info[RSD(currMB->block_y_aff + j0)][RSD(i0)] : &list1[0]->frame->top_field->mv_info[currMB->block_y_aff + j0][i0]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->frame->bottom_field->mv_info[RSD(currMB->block_y_aff + j0)][RSD(i0)] : &list1[0]->frame->bottom_field->mv_info[currMB->block_y_aff + j0][i0]; + } + } + + refList = colocated->ref_idx[LIST_0 ]== -1 ? LIST_1 : LIST_0; + ref_idx = colocated->ref_idx[refList]; + + if (colocated->ref_pic[refList] == NULL) + { + ref_idx = -1; + } + if (ref_idx == -1) + { + for (j4 = currMB->block_y + j0; j4 < currMB->block_y + j0 + step_v0; ++j4) + { + for (i4 = i0; i4 < i0 + step_h0; ++i4) + { + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv [LIST_0] = zero_mv; + mv_info->mv [LIST_1] = zero_mv; + mv_info->ref_idx [LIST_0] = 0; + mv_info->ref_idx [LIST_1] = 0; + } + } + } + else + { + if( (currSlice->mb_aff_frame_flag && ( (currMB->mb_field && colocated->ref_pic[refList]->structure==FRAME) || + (!currMB->mb_field && colocated->ref_pic[refList]->structure!=FRAME))) || + (!currSlice->mb_aff_frame_flag && ((currSlice->field_pic_flag==0 && colocated->ref_pic[refList]->structure!=FRAME)|| + (currSlice->field_pic_flag==1 && colocated->ref_pic[refList]->structure==FRAME))) ) + { + //! Frame with field co-located + for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]); ++iref) + { + if (currSlice->listX[LIST_0 + list_offset][iref]->top_field == colocated->ref_pic[refList] || + currSlice->listX[LIST_0 + list_offset][iref]->bottom_field == colocated->ref_pic[refList] || + currSlice->listX[LIST_0 + list_offset][iref]->frame == colocated->ref_pic[refList] ) + { + if ((currSlice->field_pic_flag==1) && (currSlice->listX[LIST_0 + list_offset][iref]->structure != currSlice->structure)) + { + mapped_idx=INVALIDINDEX; + } + else + { + mapped_idx = iref; + break; + } + } + else //! invalid index. Default to zero even though this case should not happen + mapped_idx=INVALIDINDEX; + } + } + else + { + for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]); ++iref) + { + if (currSlice->listX[LIST_0 + list_offset][iref] == colocated->ref_pic[refList]) + { + mapped_idx=iref; + break; + } + else //! invalid index. Default to zero even though this case should not happen + mapped_idx=INVALIDINDEX; + } + } + + if (mapped_idx != INVALIDINDEX) + { + for (j = j0; j < j0 + step_v0; ++j) + { + j4 = currMB->block_y + j; + j6 = currMB->block_y_aff + j; + + for (i4 = i0; i4 < i0 + step_h0; ++i4) + { + PicMotionParams *colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->mv_info[RSD(j6)][RSD(i4)] : &list1[0]->mv_info[j6][i4]; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + int mv_y; + if(currSlice->mb_aff_frame_flag /*&& (!p_Vid->active_sps->frame_mbs_only_flag || p_Vid->active_sps->direct_8x8_inference_flag)*/) + { + if(!currMB->mb_field && ((currSlice->listX[LIST_1][0]->iCodingType==FRAME_MB_PAIR_CODING && currSlice->listX[LIST_1][0]->motion.mb_field[currMB->mbAddrX]) || + (currSlice->listX[LIST_1][0]->iCodingType==FIELD_CODING))) + { + if (iabs(dec_picture->poc - currSlice->listX[LIST_1+4][0]->poc)> iabs(dec_picture->poc -currSlice->listX[LIST_1+2][0]->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &currSlice->listX[LIST_1+2][0]->mv_info[RSD(j6)>>1][RSD(i4)] : &currSlice->listX[LIST_1+2][0]->mv_info[j6>>1][i4]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &currSlice->listX[LIST_1+4][0]->mv_info[RSD(j6)>>1][RSD(i4)] : &currSlice->listX[LIST_1+4][0]->mv_info[j6>>1][i4]; + } + } + } + else if(/*!currSlice->mb_aff_frame_flag &&*/ !p_Vid->active_sps->frame_mbs_only_flag && !currSlice->field_pic_flag && currSlice->listX[LIST_1][0]->iCodingType!=FRAME_CODING) + { + if (iabs(dec_picture->poc - list1[0]->bottom_field->poc)> iabs(dec_picture->poc -list1[0]->top_field->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->top_field->mv_info[RSD(j6)>>1][RSD(i4)] : &list1[0]->top_field->mv_info[(j6)>>1][i4]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->bottom_field->mv_info[RSD(j6)>>1][RSD(i4)] : &list1[0]->bottom_field->mv_info[(j6)>>1][i4]; + } + } + else if(!p_Vid->active_sps->frame_mbs_only_flag && currSlice->field_pic_flag && currSlice->structure!=list1[0]->structure && list1[0]->coded_frame) + { + if (currSlice->structure == TOP_FIELD) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->frame->top_field->mv_info[RSD(j6)][RSD(i4)] : &list1[0]->frame->top_field->mv_info[j6][i4]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + &list1[0]->frame->bottom_field->mv_info[RSD(j6)][RSD(i4)] : &list1[0]->frame->bottom_field->mv_info[j6][i4]; + } + } + + mv_y = colocated->mv[refList].mv_y; + if((currSlice->mb_aff_frame_flag && !currMB->mb_field && colocated->ref_pic[refList]->structure!=FRAME) || + (!currSlice->mb_aff_frame_flag && currSlice->field_pic_flag==0 && colocated->ref_pic[refList]->structure!=FRAME)) + mv_y *= 2; + else if((currSlice->mb_aff_frame_flag && currMB->mb_field && colocated->ref_pic[refList]->structure==FRAME) || + (!currSlice->mb_aff_frame_flag && currSlice->field_pic_flag==1 && colocated->ref_pic[refList]->structure==FRAME)) + mv_y /= 2; + + mv_scale = currSlice->mvscale[LIST_0 + list_offset][mapped_idx]; + + mv_info->ref_idx [LIST_0] = (char) mapped_idx; + mv_info->ref_idx [LIST_1] = 0; + + mv_info->ref_pic[LIST_0] = list0[mapped_idx]; + mv_info->ref_pic[LIST_1] = list1[0]; + + if (mv_scale == 9999 || currSlice->listX[LIST_0+list_offset][mapped_idx]->is_long_term) + { + mv_info->mv[LIST_0].mv_x = colocated->mv[refList].mv_x; + mv_info->mv[LIST_0].mv_y = (short) mv_y; + mv_info->mv[LIST_1] = zero_mv; + } + else + { + mv_info->mv[LIST_0].mv_x = (short) ((mv_scale * colocated->mv[refList].mv_x + 128 ) >> 8); + mv_info->mv[LIST_0].mv_y = (short) ((mv_scale * mv_y/*colocated->mv[refList].mv_y*/ + 128 ) >> 8); + mv_info->mv[LIST_1].mv_x = (short) (mv_info->mv[LIST_0].mv_x - colocated->mv[refList].mv_x); + mv_info->mv[LIST_1].mv_y = (short) (mv_info->mv[LIST_0].mv_y - mv_y/*colocated->mv[refList].mv_y*/); + } + } + } + } + else if (INVALIDINDEX == mapped_idx) + { + error("temporal direct error: colocated block has ref that is unavailable",-1111); + } + } + } + } + } + } + } +} + + +static inline void update_neighbor_mvs(PicMotionParams **motion, const PicMotionParams *mv_info, int i4) +{ + (*motion++)[i4 + 1] = *mv_info; + (*motion )[i4 ] = *mv_info; + (*motion )[i4 + 1] = *mv_info; +} + +/*! +************************************************************************************* +* \brief +* Colocated info <= direct_inference is disabled. +************************************************************************************* +*/ +int get_colocated_info_4x4(Macroblock *currMB, StorablePicture *list1, int i, int j) +{ + if (list1->is_long_term) + return 1; + else + { + PicMotionParams *fs = &list1->mv_info[j][i]; + + int moving = !((( + (fs->ref_idx[LIST_0] == 0) + && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) + || ((fs->ref_idx[LIST_0] == -1) + && (fs->ref_idx[LIST_1] == 0) + && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); + + return moving; + } +} + +/*! +************************************************************************************* +* \brief +* Temporary function for colocated info when direct_inference is enabled. Will be replaced with +* function that will access directly motion information +************************************************************************************* +*/ +int get_colocated_info_8x8(Macroblock *currMB, StorablePicture *list1, int i, int j) +{ + if (list1->is_long_term) + return 1; + else + { + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + if( (currSlice->mb_aff_frame_flag) || + (!p_Vid->active_sps->frame_mbs_only_flag && ((!currSlice->structure && list1->iCodingType == FIELD_CODING)||(currSlice->structure!=list1->structure && list1->coded_frame)))) + { + int jj = RSD(j); + int ii = RSD(i); + int jdiv = (jj>>1); + int moving; + PicMotionParams *fs = &list1->mv_info[jj][ii]; + + if(currSlice->field_pic_flag && currSlice->structure!=list1->structure && list1->coded_frame) + { + if(currSlice->structure == TOP_FIELD) + fs = list1->top_field->mv_info[jj] + ii; + else + fs = list1->bottom_field->mv_info[jj] + ii; + } + else + { + if( (currSlice->mb_aff_frame_flag && ((!currMB->mb_field && list1->motion.mb_field[currMB->mbAddrX]) || + (!currMB->mb_field && list1->iCodingType == FIELD_CODING))) + || (!currSlice->mb_aff_frame_flag)) + { + if (iabs(currSlice->dec_picture->poc - list1->bottom_field->poc)> iabs(currSlice->dec_picture->poc -list1->top_field->poc) ) + { + fs = list1->top_field->mv_info[jdiv] + ii; + } + else + { + fs = list1->bottom_field->mv_info[jdiv] + ii; + } + } + } + moving = !((((fs->ref_idx[LIST_0] == 0) + && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) + || ((fs->ref_idx[LIST_0] == -1) + && (fs->ref_idx[LIST_1] == 0) + && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); + return moving; + } + else + { + PicMotionParams *fs = &list1->mv_info[RSD(j)][RSD(i)]; + int moving; + if(currMB->p_Vid->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + fs = &list1->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(j)][RSD(i)]; + moving= !((((fs->ref_idx[LIST_0] == 0) + && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) + || ((fs->ref_idx[LIST_0] == -1) + && (fs->ref_idx[LIST_1] == 0) + && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); + return moving; + } + } +} + + +static void update_direct_mv_info_spatial_8x8(Macroblock *currMB) +{ + Boolean has_direct = (currMB->b8mode[0] == 0) | (currMB->b8mode[1] == 0) | (currMB->b8mode[2] == 0) | (currMB->b8mode[3] == 0); + + if (has_direct) + { + //VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int i,j,k; + + int j4, i4; + StorablePicture *dec_picture = currSlice->dec_picture; + + int list_offset = currMB->list_offset; // ((currSlice->mb_aff_frame_flag)&&(currMB->mb_field))? (mb_nr&0x01) ? 4 : 2 : 0; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + char l0_rFrame, l1_rFrame; + MotionVector pmvl0, pmvl1; + int is_not_moving; + PicMotionParams *mv_info = NULL; + + prepare_direct_params(currMB, dec_picture, &pmvl0, &pmvl1, &l0_rFrame, &l1_rFrame); + + for (k = 0; k < 4; ++k) + { + if (currMB->b8mode[k] == 0) + { + i = 2 * (k & 0x01); + j = 2 * (k >> 1); + + //j6 = currMB->block_y_aff + j; + j4 = currMB->block_y + j; + i4 = currMB->block_x + i; + + mv_info = &dec_picture->mv_info[j4][i4]; + + is_not_moving = (get_colocated_info_8x8(currMB, list1[0], i4, currMB->block_y_aff + j) == 0); + + if (is_not_moving && (l0_rFrame == 0 || l1_rFrame == 0)) + { + if (l1_rFrame == -1) + { + if (l0_rFrame == 0) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = -1; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + } + else if (l0_rFrame == -1) + { + if (l1_rFrame == 0) + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + else + { + if (l0_rFrame == 0) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + } + else + { + mv_info->ref_pic[LIST_1] = list1[(short) l0_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->ref_idx[LIST_0] = l0_rFrame; + } + + if (l1_rFrame == 0) + { + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + } + else + { + if (l0_rFrame < 0 && l1_rFrame < 0) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = 0; + } + else if (l0_rFrame < 0) + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + else if (l1_rFrame < 0) + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + update_neighbor_mvs(&dec_picture->mv_info[j4], mv_info, i4); + } + } + } +} + +static void update_direct_mv_info_spatial_4x4(Macroblock *currMB) +{ + Boolean has_direct = (currMB->b8mode[0] == 0) | (currMB->b8mode[1] == 0) | (currMB->b8mode[2] == 0) | (currMB->b8mode[3] == 0); + + if (has_direct) + { + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int i,j,k; + + int j4, i4; + StorablePicture *dec_picture = p_Vid->dec_picture; + + int list_offset = currMB->list_offset; // ((currSlice->mb_aff_frame_flag)&&(currMB->mb_field))? (mb_nr&0x01) ? 4 : 2 : 0; + StorablePicture **list0 = currSlice->listX[LIST_0 + list_offset]; + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + char l0_rFrame, l1_rFrame; + MotionVector pmvl0, pmvl1; + + prepare_direct_params(currMB, dec_picture, &pmvl0, &pmvl1, &l0_rFrame, &l1_rFrame); + for (k = 0; k < 4; ++k) + { + if (currMB->b8mode[k] == 0) + { + + i = 2 * (k & 0x01); + for(j = 2 * (k >> 1); j < 2 * (k >> 1)+2;++j) + { + j4 = currMB->block_y + j; + + for(i4 = currMB->block_x + i; i4 < currMB->block_x + i + 2; ++i4) + { + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + //===== DIRECT PREDICTION ===== + if (l0_rFrame == 0 || l1_rFrame == 0) + { + int is_not_moving = (get_colocated_info_4x4(currMB, list1[0], i4, currMB->block_y_aff + j) == 0); + + if (l1_rFrame == -1) + { + if (is_not_moving) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = -1; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + } + else if (l0_rFrame == -1) + { + if (is_not_moving) + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + else + { + if (l0_rFrame == 0 && ((is_not_moving))) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->ref_idx[LIST_0] = l0_rFrame; + } + + if (l1_rFrame == 0 && ((is_not_moving))) + { + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_1] = 0; + } + else + { + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + } + else + { + mv_info = &dec_picture->mv_info[j4][i4]; + + if (l0_rFrame < 0 && l1_rFrame < 0) + { + mv_info->ref_pic[LIST_0] = list0[0]; + mv_info->ref_pic[LIST_1] = list1[0]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = 0; + mv_info->ref_idx[LIST_1] = 0; + } + else if (l1_rFrame == -1) + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = NULL; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = zero_mv; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = -1; + } + else if (l0_rFrame == -1) + { + mv_info->ref_pic[LIST_0] = NULL; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = zero_mv; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = -1; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + else + { + mv_info->ref_pic[LIST_0] = list0[(short) l0_rFrame]; + mv_info->ref_pic[LIST_1] = list1[(short) l1_rFrame]; + mv_info->mv[LIST_0] = pmvl0; + mv_info->mv[LIST_1] = pmvl1; + mv_info->ref_idx[LIST_0] = l0_rFrame; + mv_info->ref_idx[LIST_1] = l1_rFrame; + } + } + } + } + } + } + } +} + + +void update_direct_types(Slice *currSlice) +{ + if (currSlice->active_sps->direct_8x8_inference_flag) + currSlice->update_direct_mv_info = currSlice->direct_spatial_mv_pred_flag ? update_direct_mv_info_spatial_8x8 : update_direct_mv_info_temporal; + else + currSlice->update_direct_mv_info = currSlice->direct_spatial_mv_pred_flag ? update_direct_mv_info_spatial_4x4 : update_direct_mv_info_temporal; +} diff --git a/ldecod/src/mc_prediction.c b/ldecod/src/mc_prediction.c new file mode 100644 index 0000000..1fa4580 --- /dev/null +++ b/ldecod/src/mc_prediction.c @@ -0,0 +1,1802 @@ + +/*! +************************************************************************************* +* \file mc_prediction.c +* +* \brief +* Functions for motion compensated prediction +* +* \author +* Main contributors (see contributors.h for copyright, +* address and affiliation details) +* - Alexis Michael Tourapis +* - Chris Vogt +* +************************************************************************************* +*/ +#include "global.h" +#include "block.h" +#include "mc_prediction.h" +#include "mbuffer.h" +#include "mb_access.h" +#include "macroblock.h" +#include "memalloc.h" +#include "dec_statistics.h" + +#include "ferc_api.h" + + +int allocate_pred_mem(Slice *currSlice) +{ + int alloc_size = 0; + alloc_size += get_mem2Dpel(&currSlice->tmp_block_l0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + alloc_size += get_mem2Dpel(&currSlice->tmp_block_l1, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + alloc_size += get_mem2Dpel(&currSlice->tmp_block_l2, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + alloc_size += get_mem2Dpel(&currSlice->tmp_block_l3, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + alloc_size += get_mem2Dint(&currSlice->tmp_res, MB_BLOCK_SIZE + 5, MB_BLOCK_SIZE + 5); + return (alloc_size); +} + +void free_pred_mem(Slice *currSlice) +{ + free_mem2Dint(currSlice->tmp_res); + free_mem2Dpel(currSlice->tmp_block_l0); + free_mem2Dpel(currSlice->tmp_block_l1); + free_mem2Dpel(currSlice->tmp_block_l2); + free_mem2Dpel(currSlice->tmp_block_l3); +} + +static const int COEF[6] = { 1, -5, 20, 20, -5, 1 }; + +/*! +************************************************************************ +* \brief +* block single list prediction +************************************************************************ +*/ +static void mc_prediction(imgpel **mb_pred, imgpel **block, int block_size_y, int block_size_x, int ioff) +{ + + int j; + + for (j = 0; j < block_size_y; j++) + { + memcpy(&mb_pred[j][ioff], block[j], block_size_x * sizeof(imgpel)); + } +} + +/*! +************************************************************************ +* \brief +* block single list weighted prediction +************************************************************************ +*/ +static void weighted_mc_prediction(imgpel **mb_pred, + imgpel **block, + int block_size_y, + int block_size_x, + int ioff, + int wp_scale, + int wp_offset, + int weight_denom, + int color_clip) +{ + int i, j; + int result; + + for(j = 0; j < block_size_y; j++) + { + for(i = 0; i < block_size_x; i++) + { + result = rshift_rnd((wp_scale * block[j][i]), weight_denom) + wp_offset; + mb_pred[j][i + ioff] = (imgpel)iClip3(0, color_clip, result); + } + } +} + + + +/*! +************************************************************************ +* \brief +* block bi-prediction +************************************************************************ +*/ +void bi_prediction(imgpel **mb_pred, imgpel **block_l0, imgpel **block_l1, + int block_size_y, int block_size_x, int ioff) +{ + imgpel *mpr = &mb_pred[0][ioff]; + imgpel *b0 = block_l0[0]; + imgpel *b1 = block_l1[0]; + int ii, jj; + int row_inc = MB_BLOCK_SIZE - block_size_x; + for(jj = 0;jj < block_size_y;jj++) + { + // unroll the loop + for(ii = 0; ii < block_size_x; ii += 2) + { + *(mpr++) = (imgpel)(((*(b0++) + *(b1++)) + 1) >> 1); + *(mpr++) = (imgpel)(((*(b0++) + *(b1++)) + 1) >> 1); + } + mpr += row_inc; + b0 += row_inc; + b1 += row_inc; + } +} + + + +/*! +************************************************************************ +* \brief +* block weighted biprediction +************************************************************************ +*/ +static void weighted_bi_prediction(imgpel *mb_pred, + imgpel *block_l0, + imgpel *block_l1, + int block_size_y, + int block_size_x, + int wp_scale_l0, + int wp_scale_l1, + int wp_offset, + int weight_denom, + int color_clip) +{ + int i, j, result; + int row_inc = MB_BLOCK_SIZE - block_size_x; + + for(j = 0; j < block_size_y; j++) + { + for(i = 0; i < block_size_x; i++) + { + result = rshift_rnd_sf((wp_scale_l0 * *(block_l0++) + wp_scale_l1 * *(block_l1++)), weight_denom); + + *(mb_pred++) = (imgpel) iClip1(color_clip, result + wp_offset); + } + mb_pred += row_inc; + block_l0 += row_inc; + block_l1 += row_inc; + } +} + +/*! +************************************************************************ +* \brief +* Integer positions +************************************************************************ +*/ +static void get_block_00(imgpel *block, imgpel *cur_img, int span, int block_size_y) +{ + // fastest to just move an entire block, since block is a temp block is a 256 byte block (16x16) + // writes 2 lines of 16 imgpel 1 to 8 times depending in block_size_y + int j; + + for (j = 0; j < block_size_y; j += 2) + { + memcpy(block, cur_img, MB_BLOCK_SIZE * sizeof(imgpel)); + block += MB_BLOCK_SIZE; + cur_img += span; + memcpy(block, cur_img, MB_BLOCK_SIZE * sizeof(imgpel)); + block += MB_BLOCK_SIZE; + cur_img += span; + } +} + + +/*! +************************************************************************ +* \brief +* Qpel (1,0) horizontal +************************************************************************ +*/ +static void get_luma_10(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos , int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + + for (j = 0; j < block_size_y; j++) + { + cur_line = &(cur_imgY[j][x_pos]); + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + } +} + +/*! +************************************************************************ +* \brief +* Half horizontal +************************************************************************ +*/ +static void get_luma_20(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos , int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int i, j; + int result; + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } +} + +/*! +************************************************************************ +* \brief +* Qpel (3,0) horizontal +************************************************************************ +*/ +static void get_luma_30(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos , int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + + for (j = 0; j < block_size_y; j++) + { + cur_line = &(cur_imgY[j][x_pos + 1]); + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + } +} + +/*! +************************************************************************ +* \brief +* Qpel vertical (0, 1) +************************************************************************ +*/ +static void get_luma_01(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + int jj = 0; + p0 = &(cur_imgY[ - 2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + cur_line = &(cur_imgY[jj++][x_pos]); + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + p0 = p1 - block_size_x; + } +} + + +/*! +************************************************************************ +* \brief +* Half vertical +************************************************************************ +*/ +static void get_luma_02(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int i, j; + int result; + p0 = &(cur_imgY[ - 2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + p0 = p1 - block_size_x; + } +} + + +/*! +************************************************************************ +* \brief +* Qpel vertical (0, 3) +************************************************************************ +*/ +static void get_luma_03(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + int jj = 1; + + p0 = &(cur_imgY[ -2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + cur_line = &(cur_imgY[jj++][x_pos]); + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + p0 = p1 - block_size_x; + } +} + +/*! +************************************************************************ +* \brief +* Hpel horizontal, Qpel vertical (2, 1) +************************************************************************ +*/ +static void get_luma_21(imgpel **block, imgpel **cur_imgY, int **tmp_res, int block_size_y, int block_size_x, int x_pos, int max_imgpel_value) +{ + int i, j; + /* Vertical & horizontal interpolation */ + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + int jj = -2; + + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + } + + jj = 2; + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res[jj++]; + x0 = tmp_res[j ]; + x1 = tmp_res[j + 1]; + x2 = tmp_res[j + 2]; + x3 = tmp_res[j + 3]; + x4 = tmp_res[j + 4]; + x5 = tmp_res[j + 5]; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) - 5 * (*x1++ + *x4++) + 20 * (*x2++ + *x3++); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16) >> 5)) + 1 )>> 1); + orig_line++; + } + } +} + +/*! +************************************************************************ +* \brief +* Hpel horizontal, Hpel vertical (2, 2) +************************************************************************ +*/ +static void get_luma_22(imgpel **block, imgpel **cur_imgY, int **tmp_res, int block_size_y, int block_size_x, int x_pos, int max_imgpel_value) +{ + int i, j; + /* Vertical & horizontal interpolation */ + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + int jj = - 2; + + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + } + + for (j = 0; j < block_size_y; j++) + { + x0 = tmp_res[j ]; + x1 = tmp_res[j + 1]; + x2 = tmp_res[j + 2]; + x3 = tmp_res[j + 3]; + x4 = tmp_res[j + 4]; + x5 = tmp_res[j + 5]; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) - 5 * (*x1++ + *x4++) + 20 * (*x2++ + *x3++); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + } + } +} + +/*! +************************************************************************ +* \brief +* Hpel horizontal, Qpel vertical (2, 3) +************************************************************************ +*/ +static void get_luma_23(imgpel **block, imgpel **cur_imgY, int **tmp_res, int block_size_y, int block_size_x, int x_pos, int max_imgpel_value) +{ + int i, j; + /* Vertical & horizontal interpolation */ + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + int jj = -2; + + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + } + + jj = 3; + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res[jj++]; + x0 = tmp_res[j ]; + x1 = tmp_res[j + 1]; + x2 = tmp_res[j + 2]; + x3 = tmp_res[j + 3]; + x4 = tmp_res[j + 4]; + x5 = tmp_res[j + 5]; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) - 5 * (*x1++ + *x4++) + 20 * (*x2++ + *x3++); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16) >> 5)) + 1 )>> 1); + orig_line++; + } + } +} + +/*! +************************************************************************ +* \brief +* Qpel horizontal, Hpel vertical (1, 2) +************************************************************************ +*/ +static void get_luma_12(imgpel **block, imgpel **cur_imgY, int **tmp_res, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + p0 = &(cur_imgY[ -2][x_pos - 2]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x + 5; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + p0 = p1 - (block_size_x + 5); + } + + for (j = 0; j < block_size_y; j++) + { + tmp_line = &tmp_res[j][2]; + orig_line = block[j]; + x0 = tmp_res[j]; + x1 = x0 + 1; + x2 = x1 + 1; + x3 = x2 + 1; + x4 = x3 + 1; + x5 = x4 + 1; + + for (i = 0; i < block_size_x; i++) + { + result = (*(x0++) + *(x5++)) - 5 * (*(x1++) + *(x4++)) + 20 * (*(x2++) + *(x3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16)>>5))+1)>>1); + orig_line ++; + } + } +} + + +/*! +************************************************************************ +* \brief +* Qpel horizontal, Hpel vertical (3, 2) +************************************************************************ +*/ +static void get_luma_32(imgpel **block, imgpel **cur_imgY, int **tmp_res, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + p0 = &(cur_imgY[ -2][x_pos - 2]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x + 5; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + p0 = p1 - (block_size_x + 5); + } + + for (j = 0; j < block_size_y; j++) + { + tmp_line = &tmp_res[j][3]; + orig_line = block[j]; + x0 = tmp_res[j]; + x1 = x0 + 1; + x2 = x1 + 1; + x3 = x2 + 1; + x4 = x3 + 1; + x5 = x4 + 1; + + for (i = 0; i < block_size_x; i++) + { + result = (*(x0++) + *(x5++)) - 5 * (*(x1++) + *(x4++)) + 20 * (*(x2++) + *(x3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16)>>5))+1)>>1); + orig_line ++; + } + } +} + +/*! +************************************************************************ +* \brief +* Qpel horizontal, Qpel vertical (3, 3) +************************************************************************ +*/ +static void get_luma_33(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 1; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos + 1]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + + + +/*! +************************************************************************ +* \brief +* Qpel horizontal, Qpel vertical (1, 1) +************************************************************************ +*/ +static void get_luma_11(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 0; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + +/*! +************************************************************************ +* \brief +* Qpel horizontal, Qpel vertical (1, 3) +************************************************************************ +*/ +static void get_luma_13(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + /* Diagonal interpolation */ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 1; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + +/*! +************************************************************************ +* \brief +* Qpel horizontal, Qpel vertical (3, 1) +************************************************************************ +*/ +static void get_luma_31(imgpel **block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + /* Diagonal interpolation */ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 0; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos + 1]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + +/*! +************************************************************************ +* \brief +* Interpolation of 1/4 subpixel +************************************************************************ +*/ +void get_block_luma(StorablePicture *curr_ref, int x_pos, int y_pos, int block_size_x, int block_size_y, imgpel **block, + int shift_x, int maxold_x, int maxold_y, int **tmp_res, int max_imgpel_value, imgpel no_ref_value, Macroblock *currMB) +{ + if (curr_ref->no_ref) { + //printf("list[ref_frame] is equal to 'no reference picture' before RAP\n"); + memset(block[0],no_ref_value,block_size_y * block_size_x * sizeof(imgpel)); + } + else + { + imgpel **cur_imgY = (currMB->p_Vid->separate_colour_plane_flag && currMB->p_Slice->colour_plane_id>PLANE_Y)? curr_ref->imgUV[currMB->p_Slice->colour_plane_id-1] : curr_ref->cur_imgY; + int dx = (x_pos & 3); + int dy = (y_pos & 3); + x_pos >>= 2; + y_pos >>= 2; + x_pos = iClip3(-18, maxold_x+2, x_pos); + y_pos = iClip3(-10, maxold_y+2, y_pos); + + if (dx == 0 && dy == 0) + get_block_00(&block[0][0], &cur_imgY[y_pos][x_pos], curr_ref->iLumaStride, block_size_y); + else + { /* other positions */ + if (dy == 0) /* No vertical interpolation */ + { + if (dx == 1) + get_luma_10(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, max_imgpel_value); + else if (dx == 2) + get_luma_20(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, max_imgpel_value); + else + get_luma_30(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, max_imgpel_value); + } + else if (dx == 0) /* No horizontal interpolation */ + { + if (dy == 1) + get_luma_01(block, &cur_imgY[y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + else if (dy == 2) + get_luma_02(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + else + get_luma_03(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + } + else if (dx == 2) /* Vertical & horizontal interpolation */ + { + if (dy == 1) + get_luma_21(block, &cur_imgY[ y_pos], tmp_res, block_size_y, block_size_x, x_pos, max_imgpel_value); + else if (dy == 2) + get_luma_22(block, &cur_imgY[ y_pos], tmp_res, block_size_y, block_size_x, x_pos, max_imgpel_value); + else + get_luma_23(block, &cur_imgY[ y_pos], tmp_res, block_size_y, block_size_x, x_pos, max_imgpel_value); + } + else if (dy == 2) + { + if (dx == 1) + get_luma_12(block, &cur_imgY[ y_pos], tmp_res, block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + else + get_luma_32(block, &cur_imgY[ y_pos], tmp_res, block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + } + else + { + if (dx == 1) + { + if (dy == 1) + get_luma_11(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + else + get_luma_13(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + } + else + { + if (dy == 1) + get_luma_31(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + else + get_luma_33(block, &cur_imgY[ y_pos], block_size_y, block_size_x, x_pos, shift_x, max_imgpel_value); + } + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Chroma (0,X) +************************************************************************ +*/ +static void get_chroma_0X(imgpel *block, imgpel *cur_img, int span, int block_size_y, int block_size_x, int w00, int w01, int total_scale) +{ + imgpel *cur_row = cur_img; + imgpel *nxt_row = cur_img + span; + + + imgpel *cur_line, *cur_line_p1; + imgpel *blk_line; + int result; + int i, j; + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_row; + cur_line_p1 = nxt_row; + blk_line = block; + block += 16; + cur_row = nxt_row; + nxt_row += span; + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *cur_line++ + w01 * *cur_line_p1++); + *(blk_line++) = (imgpel) rshift_rnd_sf(result, total_scale); + } + } +} + + +/*! +************************************************************************ +* \brief +* Chroma (X,0) +************************************************************************ +*/ +static void get_chroma_X0(imgpel *block, imgpel *cur_img, int span, int block_size_y, int block_size_x, int w00, int w10, int total_scale) +{ + imgpel *cur_row = cur_img; + + + imgpel *cur_line, *cur_line_p1; + imgpel *blk_line; + int result; + int i, j; + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_row; + cur_line_p1 = cur_line + 1; + blk_line = block; + block += 16; + cur_row += span; + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *cur_line++ + w10 * *cur_line_p1++); + //*(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + *(blk_line++) = (imgpel) rshift_rnd_sf(result, total_scale); + } + } +} + +/*! +************************************************************************ +* \brief +* Chroma (X,X) +************************************************************************ +*/ +static void get_chroma_XY(imgpel *block, imgpel *cur_img, int span, int block_size_y, int block_size_x, int w00, int w01, int w10, int w11, int total_scale) +{ + imgpel *cur_row = cur_img; + imgpel *nxt_row = cur_img + span; + + + { + imgpel *cur_line, *cur_line_p1; + imgpel *blk_line; + int result; + int i, j; + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_row; + cur_line_p1 = nxt_row; + blk_line = block; + block += 16; + cur_row = nxt_row; + nxt_row += span; + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *(cur_line++) + w01 * *(cur_line_p1++)); + result += (w10 * *(cur_line ) + w11 * *(cur_line_p1 )); + *(blk_line++) = (imgpel) rshift_rnd_sf(result, total_scale); + } + } + } +} + +static void get_block_chroma(StorablePicture *curr_ref, int x_pos, int y_pos, int subpel_x, int subpel_y, int maxold_x, int maxold_y, + int block_size_x, int vert_block_size, int shiftpel_x, int shiftpel_y, + imgpel *block1, imgpel *block2, int total_scale, imgpel no_ref_value, VideoParameters *p_Vid) +{ + imgpel *img1,*img2; + short dx,dy; + int span = curr_ref->iChromaStride; + if (curr_ref->no_ref) { + //printf("list[ref_frame] is equal to 'no reference picture' before RAP\n"); + memset(block1,no_ref_value,vert_block_size * block_size_x * sizeof(imgpel)); + memset(block2,no_ref_value,vert_block_size * block_size_x * sizeof(imgpel)); + } + else + { + dx = (short) (x_pos & subpel_x); + dy = (short) (y_pos & subpel_y); + x_pos = x_pos >> shiftpel_x; + y_pos = y_pos >> shiftpel_y; + //clip MV; + assert(vert_block_size <=p_Vid->iChromaPadY && block_size_x<=p_Vid->iChromaPadX); + x_pos = iClip3(-p_Vid->iChromaPadX, maxold_x, x_pos); //16 + y_pos = iClip3(-p_Vid->iChromaPadY, maxold_y, y_pos); //8 + img1 = &curr_ref->imgUV[0][y_pos][x_pos]; + img2 = &curr_ref->imgUV[1][y_pos][x_pos]; + + if (dx == 0 && dy == 0) + { + get_block_00(block1, img1, span, vert_block_size); + get_block_00(block2, img2, span, vert_block_size); + } + else + { + short dxcur = (short) (subpel_x + 1 - dx); + short dycur = (short) (subpel_y + 1 - dy); + short w00 = dxcur * dycur; + if (dx == 0) + { + short w01 = dxcur * dy; + get_chroma_0X(block1, img1, span, vert_block_size, block_size_x, w00, w01, total_scale); + get_chroma_0X(block2, img2, span, vert_block_size, block_size_x, w00, w01, total_scale); + } + else if (dy == 0) + { + short w10 = dx * dycur; + get_chroma_X0(block1, img1, span, vert_block_size, block_size_x, w00, w10, total_scale); + get_chroma_X0(block2, img2, span, vert_block_size, block_size_x, w00, w10, total_scale); + } + else + { + short w01 = dxcur * dy; + short w10 = dx * dycur; + short w11 = dx * dy; + get_chroma_XY(block1, img1, span, vert_block_size, block_size_x, w00, w01, w10, w11, total_scale); + get_chroma_XY(block2, img2, span, vert_block_size, block_size_x, w00, w01, w10, w11, total_scale); + } + } + } +} + +void intra_cr_decoding(Macroblock *currMB, int yuv) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + StorablePicture *dec_picture = currSlice->dec_picture; + imgpel **curUV; + int uv; + int b8,b4; + int ioff, joff; + int i,j; + + currSlice->intra_pred_chroma(currMB);// last argument is ignored, computes needed data for both uv channels + + for(uv = 0; uv < 2; uv++) + { + currMB->itrans_4x4 = (currMB->is_lossless == FALSE) ? itrans4x4 : itrans4x4_ls; + + curUV = dec_picture->imgUV[uv]; + + if(currMB->is_lossless) + { + if ((currMB->c_ipred_mode == VERT_PRED_8)||(currMB->c_ipred_mode == HOR_PRED_8)) + Inv_Residual_trans_Chroma(currMB, uv) ; + else + { + for(j=0;jmb_cr_size_y;j++) + for(i=0;imb_cr_size_x;i++) + currSlice->mb_rres [uv+1][j][i]=currSlice->cof[uv+1][j][i]; + } + } + + if ((!(currMB->mb_type == SI4MB) && (currMB->cbp >> 4)) ) + { + for (b8 = 0; b8 < (p_Vid->num_uv_blocks); b8++) + { + for(b4 = 0; b4 < 4; b4++) + { + joff = subblk_offset_y[yuv][b8][b4]; + ioff = subblk_offset_x[yuv][b8][b4]; + + currMB->itrans_4x4(currMB, (ColorPlane) (uv + 1), ioff, joff); + + copy_image_data_4x4(&curUV[currMB->pix_c_y + joff], &(currSlice->mb_rec[uv + 1][joff]), currMB->pix_c_x + ioff, ioff); + } + } + currSlice->is_reset_coeff_cr = FALSE; + } + else if (currMB->mb_type == SI4MB) + { + itrans_sp_cr(currMB, uv); + + for (joff = 0; joff < 8; joff += 4) + { + for(ioff = 0; ioff < 8;ioff+=4) + { + currMB->itrans_4x4(currMB, (ColorPlane) (uv + 1), ioff, joff); + + copy_image_data_4x4(&curUV[currMB->pix_c_y + joff], &(currSlice->mb_rec[uv + 1][joff]), currMB->pix_c_x + ioff, ioff); + } + } + currSlice->is_reset_coeff_cr = FALSE; + } + else + { + for (b8 = 0; b8 < (p_Vid->num_uv_blocks); b8++) + { + for(b4 = 0; b4 < 4; b4++) + { + joff = subblk_offset_y[yuv][b8][b4]; + ioff = subblk_offset_x[yuv][b8][b4]; + + copy_image_data_4x4(&curUV[currMB->pix_c_y + joff], &(currSlice->mb_pred[uv + 1][joff]), currMB->pix_c_x + ioff, ioff); + } + } + } + } +} + +static inline void set_direct_references(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info) +{ + if (mb->available) + { + char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; + *l0_rFrame = ref_idx[LIST_0]; + *l1_rFrame = ref_idx[LIST_1]; + } + else + { + *l0_rFrame = -1; + *l1_rFrame = -1; + } +} + + +static void set_direct_references_mb_field(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info, Macroblock *mb_data) +{ + if (mb->available) + { + char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; + if (mb_data[mb->mb_addr].mb_field) + { + *l0_rFrame = ref_idx[LIST_0]; + *l1_rFrame = ref_idx[LIST_1]; + } + else + { + *l0_rFrame = (ref_idx[LIST_0] < 0) ? ref_idx[LIST_0] : ref_idx[LIST_0] * 2; + *l1_rFrame = (ref_idx[LIST_1] < 0) ? ref_idx[LIST_1] : ref_idx[LIST_1] * 2; + } + } + else + { + *l0_rFrame = -1; + *l1_rFrame = -1; + } +} + +static void set_direct_references_mb_frame(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info, Macroblock *mb_data) +{ + if (mb->available) + { + char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; + if (mb_data[mb->mb_addr].mb_field) + { + *l0_rFrame = (ref_idx[LIST_0] >> 1); + *l1_rFrame = (ref_idx[LIST_1] >> 1); + } + else + { + *l0_rFrame = ref_idx[LIST_0]; + *l1_rFrame = ref_idx[LIST_1]; + } + } + else + { + *l0_rFrame = -1; + *l1_rFrame = -1; + } +} + +void prepare_direct_params(Macroblock *currMB, StorablePicture *dec_picture, MotionVector *pmvl0, MotionVector *pmvl1, char *l0_rFrame, char *l1_rFrame) +{ + Slice *currSlice = currMB->p_Slice; + char l0_refA, l0_refB, l0_refC; + char l1_refA, l1_refB, l1_refC; + PicMotionParams **mv_info = dec_picture->mv_info; + + PixelPos mb[4]; + + get_neighbors(currMB, mb, 0, 0, 16); + + if (!currSlice->mb_aff_frame_flag) + { + set_direct_references(&mb[0], &l0_refA, &l1_refA, mv_info); + set_direct_references(&mb[1], &l0_refB, &l1_refB, mv_info); + set_direct_references(&mb[2], &l0_refC, &l1_refC, mv_info); + } + else + { + VideoParameters *p_Vid = currMB->p_Vid; + if (currMB->mb_field) + { + set_direct_references_mb_field(&mb[0], &l0_refA, &l1_refA, mv_info, p_Vid->mb_data); + set_direct_references_mb_field(&mb[1], &l0_refB, &l1_refB, mv_info, p_Vid->mb_data); + set_direct_references_mb_field(&mb[2], &l0_refC, &l1_refC, mv_info, p_Vid->mb_data); + } + else + { + set_direct_references_mb_frame(&mb[0], &l0_refA, &l1_refA, mv_info, p_Vid->mb_data); + set_direct_references_mb_frame(&mb[1], &l0_refB, &l1_refB, mv_info, p_Vid->mb_data); + set_direct_references_mb_frame(&mb[2], &l0_refC, &l1_refC, mv_info, p_Vid->mb_data); + } + } + + *l0_rFrame = (char) imin(imin((unsigned char) l0_refA, (unsigned char) l0_refB), (unsigned char) l0_refC); + *l1_rFrame = (char) imin(imin((unsigned char) l1_refA, (unsigned char) l1_refB), (unsigned char) l1_refC); + + if (*l0_rFrame >=0) + currMB->GetMVPredictor (currMB, mb, pmvl0, *l0_rFrame, mv_info, LIST_0, 0, 0, 16, 16); + + if (*l1_rFrame >=0) + currMB->GetMVPredictor (currMB, mb, pmvl1, *l1_rFrame, mv_info, LIST_1, 0, 0, 16, 16); +} + +static void check_motion_vector_range(const MotionVector *mv, Slice *pSlice) +{ + if (mv->mv_x > 8191 || mv->mv_x < -8192) + { + printf("WARNING! Horizontal motion vector %d is out of allowed range {-8192, 8191} in picture %d, macroblock %d\n", mv->mv_x, pSlice->p_Vid->number, pSlice->current_mb_nr); + //error("invalid stream: too big horizontal motion vector", 500); + } + + if (mv->mv_y > (pSlice->max_mb_vmv_r - 1) || mv->mv_y < (-pSlice->max_mb_vmv_r)) + { + printf("WARNING! Vertical motion vector %d is out of allowed range {%d, %d} in picture %d, macroblock %d\n", mv->mv_y, (-pSlice->max_mb_vmv_r), (pSlice->max_mb_vmv_r - 1), pSlice->p_Vid->number, pSlice->current_mb_nr); + //error("invalid stream: too big vertical motion vector", 500); + } +} + +static inline int check_vert_mv(int llimit, int vec1_y,int rlimit) +{ + int y_pos = vec1_y >> 2; + if(y_pos < llimit || y_pos > rlimit) + return 1; + else + return 0; +} + +static void perform_mc_single_wp(Macroblock *currMB, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int i, int j, int block_size_x, int block_size_y) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + seq_parameter_set_rbsp_t *active_sps = currSlice->active_sps; + imgpel **tmp_block_l0 = currSlice->tmp_block_l0; + imgpel **tmp_block_l1 = currSlice->tmp_block_l1; + static const int mv_mul = 16; // 4 * 4 + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int type = currSlice->slice_type; + int chroma_format_idc = dec_picture->chroma_format_idc; + //===== Single List Prediction ===== + int ioff = (i << 2); + int joff = (j << 2); + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + short ref_idx = mv_info->ref_idx[pred_dir]; + short ref_idx_wp = ref_idx; + MotionVector *mv_array = &mv_info->mv[pred_dir]; + int list_offset = currMB->list_offset; + StorablePicture *list = currSlice->listX[list_offset + pred_dir][ref_idx]; + int vec1_x, vec1_y; + // vars for get_block_luma + int maxold_x = dec_picture->size_x_m1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1; + int shift_x = dec_picture->iLumaStride; + int **tmp_res = currSlice->tmp_res; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + imgpel no_ref_value = (imgpel) p_Vid->dc_pred_value_comp[pl]; + // + +#if ENABLE_DEC_STATS + p_Vid->dec_stats->histogram_mv[LIST_0][0][mv_array->mv_x]++; + p_Vid->dec_stats->histogram_mv[LIST_0][1][mv_array->mv_y]++; +#endif + + check_motion_vector_range(mv_array, currSlice); + vec1_x = i4 * mv_mul + mv_array->mv_x; + vec1_y = (currMB->block_y_aff + j) * mv_mul + mv_array->mv_y; + if(block_size_y > (p_Vid->iLumaPadY-4) && CheckVertMV(currMB, vec1_y, block_size_y)) + { + get_block_luma(list, vec1_x, vec1_y, block_size_x, BLOCK_SIZE_8x8, tmp_block_l0, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + get_block_luma(list, vec1_x, vec1_y+BLOCK_SIZE_8x8_SP, block_size_x, block_size_y-BLOCK_SIZE_8x8, tmp_block_l0+BLOCK_SIZE_8x8, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + } + else + get_block_luma(list, vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0,shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + + + { + int alpha_l0, wp_offset, wp_denom; + if (currMB->mb_field && ((p_Vid->active_pps->weighted_pred_flag&&(type==P_SLICE|| type == SP_SLICE))||(p_Vid->active_pps->weighted_bipred_idc==1 && (type==B_SLICE)))) + ref_idx_wp >>=1; + alpha_l0 = currSlice->wp_weight[pred_dir][ref_idx_wp][pl]; + wp_offset = currSlice->wp_offset[pred_dir][ref_idx_wp][pl]; + wp_denom = pl > 0 ? currSlice->chroma_log2_weight_denom : currSlice->luma_log2_weight_denom; + weighted_mc_prediction(&currSlice->mb_pred[pl][joff], tmp_block_l0, block_size_y, block_size_x, ioff, alpha_l0, wp_offset, wp_denom, max_imgpel_value); + } + + if ((chroma_format_idc != YUV400) && (chroma_format_idc != YUV444) ) + { + int ioff_cr,joff_cr,block_size_x_cr,block_size_y_cr; + int vec1_y_cr = vec1_y + ((active_sps->chroma_format_idc == 1)? currSlice->chroma_vector_adjustment[list_offset + pred_dir][ref_idx] : 0); + int total_scale = p_Vid->total_scale; + int maxold_x = dec_picture->size_x_cr_m1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y_cr >> 1) - 1 : dec_picture->size_y_cr_m1; + int chroma_log2_weight = currSlice->chroma_log2_weight_denom; + if (p_Vid->mb_cr_size_x == MB_BLOCK_SIZE) + { + ioff_cr = ioff; + block_size_x_cr = block_size_x; + } + else + { + ioff_cr = ioff >> 1; + block_size_x_cr = block_size_x >> 1; + } + if (p_Vid->mb_cr_size_y == MB_BLOCK_SIZE) + { + joff_cr = joff; + block_size_y_cr = block_size_y; + } + else + { + joff_cr = joff >> 1; + block_size_y_cr = block_size_y >> 1; + } + no_ref_value = (imgpel)p_Vid->dc_pred_value_comp[1]; + { + int *weight = currSlice->wp_weight[pred_dir][ref_idx_wp]; + int *offset = currSlice->wp_offset[pred_dir][ref_idx_wp]; + get_block_chroma(list,vec1_x,vec1_y_cr,p_Vid->subpel_x,p_Vid->subpel_y,maxold_x,maxold_y,block_size_x_cr,block_size_y_cr,p_Vid->shiftpel_x,p_Vid->shiftpel_y,&tmp_block_l0[0][0],&tmp_block_l1[0][0] ,total_scale,no_ref_value,p_Vid); + weighted_mc_prediction(&currSlice->mb_pred[1][joff_cr], tmp_block_l0, block_size_y_cr, block_size_x_cr, ioff_cr, weight[1], offset[1], chroma_log2_weight, p_Vid->max_pel_value_comp[1]); + weighted_mc_prediction(&currSlice->mb_pred[2][joff_cr], tmp_block_l1, block_size_y_cr, block_size_x_cr, ioff_cr, weight[2], offset[2], chroma_log2_weight, p_Vid->max_pel_value_comp[2]); + } + } +} + + +static void perform_mc_single(Macroblock *currMB, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int i, int j, int block_size_x, int block_size_y) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + seq_parameter_set_rbsp_t *active_sps = currSlice->active_sps; + imgpel **tmp_block_l0 = currSlice->tmp_block_l0; + imgpel **tmp_block_l1 = currSlice->tmp_block_l1; + static const int mv_mul = 16; // 4 * 4 + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int chroma_format_idc = dec_picture->chroma_format_idc; + //===== Single List Prediction ===== + int ioff = (i << 2); + int joff = (j << 2); + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + MotionVector *mv_array = &mv_info->mv[pred_dir]; + short ref_idx = mv_info->ref_idx[pred_dir]; + int list_offset = currMB->list_offset; + StorablePicture *list = currSlice->listX[list_offset + pred_dir][ref_idx]; + int vec1_x, vec1_y; + // vars for get_block_luma + int maxold_x = dec_picture->size_x_m1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1; + int shift_x = dec_picture->iLumaStride; + int **tmp_res = currSlice->tmp_res; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + imgpel no_ref_value = (imgpel) p_Vid->dc_pred_value_comp[pl]; + // +#if ENABLE_DEC_STATS + p_Vid->dec_stats->histogram_mv[LIST_0][0][mv_array->mv_x]++; + p_Vid->dec_stats->histogram_mv[LIST_0][1][mv_array->mv_y]++; +#endif + + //if (iabs(mv_array->mv_x) > 4 * 126 || iabs(mv_array->mv_y) > 4 * 126) + //printf("motion vector %d %d\n", mv_array->mv_x, mv_array->mv_y); + + check_motion_vector_range(mv_array, currSlice); + vec1_x = i4 * mv_mul + mv_array->mv_x; + vec1_y = (currMB->block_y_aff + j) * mv_mul + mv_array->mv_y; + + if (block_size_y > (p_Vid->iLumaPadY-4) && CheckVertMV(currMB, vec1_y, block_size_y)) + { + get_block_luma(list, vec1_x, vec1_y, block_size_x, BLOCK_SIZE_8x8, tmp_block_l0, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + get_block_luma(list, vec1_x, vec1_y+BLOCK_SIZE_8x8_SP, block_size_x, block_size_y-BLOCK_SIZE_8x8, tmp_block_l0+BLOCK_SIZE_8x8, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + } + else + get_block_luma(list, vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0,shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + + mc_prediction(&currSlice->mb_pred[pl][joff], tmp_block_l0, block_size_y, block_size_x, ioff); + + if ((chroma_format_idc != YUV400) && (chroma_format_idc != YUV444) ) + { + int ioff_cr,joff_cr,block_size_x_cr,block_size_y_cr; + int vec1_y_cr = vec1_y + ((active_sps->chroma_format_idc == 1)? currSlice->chroma_vector_adjustment[list_offset + pred_dir][ref_idx] : 0); + int total_scale = p_Vid->total_scale; + int maxold_x = dec_picture->size_x_cr_m1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y_cr >> 1) - 1 : dec_picture->size_y_cr_m1; + if (p_Vid->mb_cr_size_x == MB_BLOCK_SIZE) + { + ioff_cr = ioff; + block_size_x_cr = block_size_x; + } + else + { + ioff_cr = ioff >> 1; + block_size_x_cr = block_size_x >> 1; + } + if (p_Vid->mb_cr_size_y == MB_BLOCK_SIZE) + { + joff_cr = joff; + block_size_y_cr = block_size_y; + } + else + { + joff_cr = joff >> 1; + block_size_y_cr = block_size_y >> 1; + } + no_ref_value = (imgpel)p_Vid->dc_pred_value_comp[1]; + get_block_chroma(list,vec1_x,vec1_y_cr,p_Vid->subpel_x,p_Vid->subpel_y,maxold_x,maxold_y,block_size_x_cr,block_size_y_cr,p_Vid->shiftpel_x,p_Vid->shiftpel_y,&tmp_block_l0[0][0],&tmp_block_l1[0][0] ,total_scale,no_ref_value,p_Vid); + mc_prediction(&currSlice->mb_pred[1][joff_cr], tmp_block_l0, block_size_y_cr, block_size_x_cr, ioff_cr); + mc_prediction(&currSlice->mb_pred[2][joff_cr], tmp_block_l1, block_size_y_cr, block_size_x_cr, ioff_cr); + } +} + +static void perform_mc_bi_wp(Macroblock *currMB, ColorPlane pl, StorablePicture *dec_picture, int i, int j, int block_size_x, int block_size_y) +{ + static const int mv_mul = 16; + int vec1_x, vec1_y, vec2_x, vec2_y; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + int weighted_bipred_idc = p_Vid->active_pps->weighted_bipred_idc; + int block_y_aff = currMB->block_y_aff; + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int ioff = (i << 2); + int joff = (j << 2); + int chroma_format_idc = dec_picture->chroma_format_idc; + int list_offset = currMB->list_offset; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + MotionVector *l0_mv_array = &mv_info->mv[LIST_0]; + MotionVector *l1_mv_array = &mv_info->mv[LIST_1]; + short l0_refframe = mv_info->ref_idx[LIST_0]; + short l1_refframe = mv_info->ref_idx[LIST_1]; + int l0_ref_idx = (currMB->mb_field && weighted_bipred_idc == 1) ? l0_refframe >> 1: l0_refframe; + int l1_ref_idx = (currMB->mb_field && weighted_bipred_idc == 1) ? l1_refframe >> 1: l1_refframe; + + + /// WP Parameters + int wt_list_offset = (weighted_bipred_idc==2)? list_offset : 0; + int *weight0 = currSlice->wbp_weight[LIST_0 + wt_list_offset][l0_ref_idx][l1_ref_idx]; + int *weight1 = currSlice->wbp_weight[LIST_1 + wt_list_offset][l0_ref_idx][l1_ref_idx]; + int *offset0 = currSlice->wp_offset[LIST_0 + wt_list_offset][l0_ref_idx]; + int *offset1 = currSlice->wp_offset[LIST_1 + wt_list_offset][l1_ref_idx]; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1; + int pady = p_Vid->iLumaPadY; + int rlimit = maxold_y + pady - block_size_y - 2; + int llimit = 2 - pady; + int big_blocky = block_size_y > (pady - 4); + StorablePicture *list0 = currSlice->listX[LIST_0 + list_offset][l0_refframe]; + StorablePicture *list1 = currSlice->listX[LIST_1 + list_offset][l1_refframe]; + imgpel **tmp_block_l0 = currSlice->tmp_block_l0; + imgpel *block0 = tmp_block_l0[0]; + imgpel **tmp_block_l1 = currSlice->tmp_block_l1; + imgpel *block1 = tmp_block_l1[0]; + imgpel **tmp_block_l2 = currSlice->tmp_block_l2; + imgpel *block2 = tmp_block_l2[0]; + imgpel **tmp_block_l3 = currSlice->tmp_block_l3; + imgpel *block3 = tmp_block_l3[0]; + int wp_offset; + int wp_denom; + + // vars for get_block_luma + int maxold_x = dec_picture->size_x_m1; + int shift_x = dec_picture->iLumaStride; + int **tmp_res = currSlice->tmp_res; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + imgpel no_ref_value = (imgpel) p_Vid->dc_pred_value_comp[pl]; + + check_motion_vector_range(l0_mv_array, currSlice); + check_motion_vector_range(l1_mv_array, currSlice); + vec1_x = i4 * mv_mul + l0_mv_array->mv_x; + vec2_x = i4 * mv_mul + l1_mv_array->mv_x; + vec1_y = (block_y_aff + j) * mv_mul + l0_mv_array->mv_y; + vec2_y = (block_y_aff + j) * mv_mul + l1_mv_array->mv_y; + + if (big_blocky && check_vert_mv(llimit, vec1_y, rlimit)) + { + get_block_luma(list0, vec1_x, vec1_y, block_size_x, BLOCK_SIZE_8x8, tmp_block_l0, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + get_block_luma(list0, vec1_x, vec1_y+BLOCK_SIZE_8x8_SP, block_size_x, block_size_y-BLOCK_SIZE_8x8, tmp_block_l0+BLOCK_SIZE_8x8, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + } + else + get_block_luma(list0, vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0,shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + if (big_blocky && check_vert_mv(llimit, vec2_y,rlimit)) + { + get_block_luma(list1, vec2_x, vec2_y, block_size_x, BLOCK_SIZE_8x8, tmp_block_l1, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + get_block_luma(list1, vec2_x, vec2_y+BLOCK_SIZE_8x8_SP, block_size_x, block_size_y-BLOCK_SIZE_8x8, tmp_block_l1 + BLOCK_SIZE_8x8, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + } + else + get_block_luma(list1, vec2_x, vec2_y, block_size_x, block_size_y, tmp_block_l1,shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + + + wp_offset = ((offset0[pl] + offset1[pl] + 1) >>1); + wp_denom = pl > 0 ? currSlice->chroma_log2_weight_denom : currSlice->luma_log2_weight_denom; + weighted_bi_prediction(&currSlice->mb_pred[pl][joff][ioff], block0, block1, block_size_y, block_size_x, weight0[pl], weight1[pl], wp_offset, wp_denom + 1, max_imgpel_value); + + if ((chroma_format_idc != YUV400) && (chroma_format_idc != YUV444) ) + { + int ioff_cr, joff_cr,block_size_y_cr,block_size_x_cr,vec2_y_cr,vec1_y_cr; + int maxold_x = dec_picture->size_x_cr_m1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y_cr >> 1) - 1 : dec_picture->size_y_cr_m1; + int shiftpel_x = p_Vid->shiftpel_x; + int shiftpel_y = p_Vid->shiftpel_y; + int subpel_x = p_Vid->subpel_x; + int subpel_y = p_Vid->subpel_y; + int total_scale = p_Vid->total_scale; + int chroma_log2 = currSlice->chroma_log2_weight_denom + 1; + + if (p_Vid->mb_cr_size_x == MB_BLOCK_SIZE) + { + ioff_cr = ioff; + block_size_x_cr = block_size_x; + } + else + { + ioff_cr = ioff >> 1; + block_size_x_cr = block_size_x >> 1; + } + + if (p_Vid->mb_cr_size_y == MB_BLOCK_SIZE) + { + joff_cr = joff; + block_size_y_cr = block_size_y; + } + else + { + joff_cr = joff >> 1; + block_size_y_cr = block_size_y >> 1; + } + if (chroma_format_idc == 1) + { + vec1_y_cr = vec1_y + currSlice->chroma_vector_adjustment[LIST_0 + list_offset][l0_refframe]; + vec2_y_cr = vec2_y + currSlice->chroma_vector_adjustment[LIST_1 + list_offset][l1_refframe]; + } + else + { + vec1_y_cr = vec1_y; + vec2_y_cr = vec2_y; + } + no_ref_value = (imgpel)p_Vid->dc_pred_value_comp[1]; + + wp_offset = ((offset0[1] + offset1[1] + 1) >>1); + get_block_chroma(list0,vec1_x,vec1_y_cr,subpel_x,subpel_y,maxold_x,maxold_y,block_size_x_cr,block_size_y_cr,shiftpel_x,shiftpel_y,block0,block2 ,total_scale,no_ref_value,p_Vid); + get_block_chroma(list1,vec2_x,vec2_y_cr,subpel_x,subpel_y,maxold_x,maxold_y,block_size_x_cr,block_size_y_cr,shiftpel_x,shiftpel_y,block1,block3 ,total_scale,no_ref_value,p_Vid); + weighted_bi_prediction(&currSlice->mb_pred[1][joff_cr][ioff_cr],block0,block1,block_size_y_cr,block_size_x_cr,weight0[1],weight1[1],wp_offset,chroma_log2,p_Vid->max_pel_value_comp[1]); + wp_offset = ((offset0[2] + offset1[2] + 1) >>1); + weighted_bi_prediction(&currSlice->mb_pred[2][joff_cr][ioff_cr],block2,block3,block_size_y_cr,block_size_x_cr,weight0[2],weight1[2],wp_offset,chroma_log2,p_Vid->max_pel_value_comp[2]); + } +} + +static void perform_mc_bi(Macroblock *currMB, ColorPlane pl, StorablePicture *dec_picture, int i, int j, int block_size_x, int block_size_y) +{ + static const int mv_mul = 16; + int vec1_x=0, vec1_y=0, vec2_x=0, vec2_y=0; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + int block_y_aff = currMB->block_y_aff; + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int ioff = (i << 2); + int joff = (j << 2); + int chroma_format_idc = dec_picture->chroma_format_idc; + PicMotionParams *mv_info = &dec_picture->mv_info[j4][i4]; + MotionVector *l0_mv_array = &mv_info->mv[LIST_0]; + MotionVector *l1_mv_array = &mv_info->mv[LIST_1]; + short l0_refframe = mv_info->ref_idx[LIST_0]; + short l1_refframe = mv_info->ref_idx[LIST_1]; + int list_offset = currMB->list_offset; + + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y_m1; + int pady = p_Vid->iLumaPadY; + int rlimit = maxold_y + pady - block_size_y - 2; + int llimit = 2 - pady; + int big_blocky = block_size_y > (pady - 4); + StorablePicture *list0 = currSlice->listX[LIST_0 + list_offset][l0_refframe]; + StorablePicture *list1 = currSlice->listX[LIST_1 + list_offset][l1_refframe]; + imgpel **tmp_block_l0 = currSlice->tmp_block_l0; + imgpel *block0 = tmp_block_l0[0]; + imgpel **tmp_block_l1 = currSlice->tmp_block_l1; + imgpel *block1 = tmp_block_l1[0]; + imgpel **tmp_block_l2 = currSlice->tmp_block_l2; + imgpel *block2 = tmp_block_l2[0]; + imgpel **tmp_block_l3 = currSlice->tmp_block_l3; + imgpel *block3 = tmp_block_l3[0]; + // vars for get_block_luma + int maxold_x = dec_picture->size_x_m1; + int shift_x = dec_picture->iLumaStride; + int **tmp_res = currSlice->tmp_res; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + imgpel no_ref_value = (imgpel) p_Vid->dc_pred_value_comp[pl]; + check_motion_vector_range(l0_mv_array, currSlice); + check_motion_vector_range(l1_mv_array, currSlice); + vec1_x = i4 * mv_mul + l0_mv_array->mv_x; + vec2_x = i4 * mv_mul + l1_mv_array->mv_x; + vec1_y = (block_y_aff + j) * mv_mul + l0_mv_array->mv_y; + vec2_y = (block_y_aff + j) * mv_mul + l1_mv_array->mv_y; + if (big_blocky && check_vert_mv(llimit, vec1_y, rlimit)) + { + get_block_luma(list0, vec1_x, vec1_y, block_size_x, BLOCK_SIZE_8x8, tmp_block_l0, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + get_block_luma(list0, vec1_x, vec1_y+BLOCK_SIZE_8x8_SP, block_size_x, block_size_y-BLOCK_SIZE_8x8, tmp_block_l0+BLOCK_SIZE_8x8, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + } + else + get_block_luma(list0, vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0,shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + if (big_blocky && check_vert_mv(llimit, vec2_y,rlimit)) + { + get_block_luma(list1, vec2_x, vec2_y, block_size_x, BLOCK_SIZE_8x8, tmp_block_l1, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + get_block_luma(list1, vec2_x, vec2_y+BLOCK_SIZE_8x8_SP, block_size_x, block_size_y-BLOCK_SIZE_8x8, tmp_block_l1 + BLOCK_SIZE_8x8, shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + } + else + get_block_luma(list1, vec2_x, vec2_y, block_size_x, block_size_y, tmp_block_l1,shift_x,maxold_x,maxold_y,tmp_res,max_imgpel_value,no_ref_value, currMB); + bi_prediction(&currSlice->mb_pred[pl][joff],tmp_block_l0,tmp_block_l1, block_size_y, block_size_x, ioff); + + if ((chroma_format_idc != YUV400) && (chroma_format_idc != YUV444) ) + { + int ioff_cr, joff_cr,block_size_y_cr,block_size_x_cr,vec2_y_cr,vec1_y_cr; + int chroma_format_idc = p_Vid->active_sps->chroma_format_idc; + int maxold_x = dec_picture->size_x_cr_m1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y_cr >> 1) - 1 : dec_picture->size_y_cr_m1; + int shiftpel_x = p_Vid->shiftpel_x; + int shiftpel_y = p_Vid->shiftpel_y; + int subpel_x = p_Vid->subpel_x; + int subpel_y = p_Vid->subpel_y; + int total_scale = p_Vid->total_scale; + if (p_Vid->mb_cr_size_x == MB_BLOCK_SIZE) + { + ioff_cr = ioff; + block_size_x_cr = block_size_x; + } + else + { + ioff_cr = ioff >> 1; + block_size_x_cr = block_size_x >> 1; + } + if (p_Vid->mb_cr_size_y == MB_BLOCK_SIZE) + { + joff_cr = joff; + block_size_y_cr = block_size_y; + } + else + { + joff_cr = joff >> 1; + block_size_y_cr = block_size_y >> 1; + } + if (chroma_format_idc == 1) + { + vec1_y_cr = vec1_y + currSlice->chroma_vector_adjustment[LIST_0 + list_offset][l0_refframe]; + vec2_y_cr = vec2_y + currSlice->chroma_vector_adjustment[LIST_1 + list_offset][l1_refframe]; + } + else + { + vec1_y_cr = vec1_y; + vec2_y_cr = vec2_y; + } + no_ref_value = (imgpel)p_Vid->dc_pred_value_comp[1]; + get_block_chroma(list0,vec1_x,vec1_y_cr,subpel_x,subpel_y,maxold_x,maxold_y,block_size_x_cr,block_size_y_cr,shiftpel_x,shiftpel_y,block0,block2 ,total_scale,no_ref_value,p_Vid); + get_block_chroma(list1,vec2_x,vec2_y_cr,subpel_x,subpel_y,maxold_x,maxold_y,block_size_x_cr,block_size_y_cr,shiftpel_x,shiftpel_y,block1,block3 ,total_scale,no_ref_value,p_Vid); + bi_prediction(&currSlice->mb_pred[1][joff_cr],tmp_block_l0,tmp_block_l1, block_size_y_cr, block_size_x_cr, ioff_cr); + bi_prediction(&currSlice->mb_pred[2][joff_cr],tmp_block_l2,tmp_block_l3, block_size_y_cr, block_size_x_cr, ioff_cr); + } +} + +void perform_mc(Macroblock *currMB, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int i, int j, int block_size_x, int block_size_y) +{ + + Slice *currSlice = currMB->p_Slice; + assert (pred_dir<=2); + + /* Edited by joao Carreira */ + if( currMB->p_Vid->p_Inp->error_prop ) + ChangeInterViewPrediction(currMB, dec_picture, pred_dir, i, j, block_size_x, block_size_y ); + + if (pred_dir != 2) + { + if (currSlice->weighted_pred_flag) + perform_mc_single_wp(currMB, pl, dec_picture, pred_dir, i, j, block_size_x, block_size_y); + else + perform_mc_single(currMB, pl, dec_picture, pred_dir, i, j, block_size_x, block_size_y); + } + else + { + + if (currSlice->weighted_bipred_idc) + perform_mc_bi_wp(currMB, pl, dec_picture, i, j, block_size_x, block_size_y); + else + perform_mc_bi(currMB, pl, dec_picture, i, j, block_size_x, block_size_y); + } +} + + + diff --git a/ldecod/src/nal.c b/ldecod/src/nal.c new file mode 100644 index 0000000..ac9d00a --- /dev/null +++ b/ldecod/src/nal.c @@ -0,0 +1,120 @@ + +/*! + ************************************************************************ + * \file nal.c + * + * \brief + * Converts Encapsulated Byte Sequence Packets (EBSP) to Raw Byte + * Sequence Packets (RBSP), and then onto String Of Data Bits (SODB) + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Shankar L. Regunathan + * - Tobias Oelbaum +************************************************************************ + */ + +#include "contributors.h" +#include "global.h" + + /*! + ************************************************************************ + * \brief + * Converts RBSP to string of data bits + * \param streamBuffer + * pointer to buffer containing data + * \param last_byte_pos + * position of the last byte containing data. + * \return last_byte_pos + * position of the last byte pos. If the last-byte was entirely a stuffing byte, + * it is removed, and the last_byte_pos is updated. + * +************************************************************************/ + +int RBSPtoSODB(byte *streamBuffer, int last_byte_pos) +{ + int ctr_bit, bitoffset; + + bitoffset = 0; + //find trailing 1 + ctr_bit = (streamBuffer[last_byte_pos-1] & (0x01< 0x03)) + return -1; + //if cabac_zero_word is used, the final byte of this NAL unit(0x03) is discarded, and the last two bytes of RBSP must be 0x0000 + if(i == end_bytepos-1) + return j; + + ++i; + count = 0; + } + streamBuffer[j] = streamBuffer[i]; + if(streamBuffer[i] == 0x00) + ++count; + else + count = 0; + ++j; + } + + return j; +} diff --git a/ldecod/src/nalu.c b/ldecod/src/nalu.c new file mode 100644 index 0000000..983ba71 --- /dev/null +++ b/ldecod/src/nalu.c @@ -0,0 +1,187 @@ + +/*! +************************************************************************ +* \file nalu.c +* +* \brief +* Decoder NALU support functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Stephan Wenger +************************************************************************ +*/ + +#include "global.h" +#include "annexb.h" +#include "nalu.h" +#include "memalloc.h" +#include "rtp.h" +#if (MVC_EXTENSION_ENABLE) +#include "vlc.h" +#endif + +#include "stream_parser.h" + +/*! +************************************************************************************* +* \brief +* Converts a NALU to an RBSP +* +* \param +* nalu: nalu structure to be filled +* +* \return +* length of the RBSP in bytes +************************************************************************************* +*/ + +static int NALUtoRBSP (NALU_t *nalu) +{ + assert (nalu != NULL); + + nalu->len = EBSPtoRBSP (nalu->buf, nalu->len, 1) ; + + return nalu->len ; +} + +/*! +************************************************************************ +* \brief +* Read the next NAL unit (with error handling) +************************************************************************ +*/ +int read_next_nalu(VideoParameters *p_Vid, NALU_t *nalu) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int ret; + + do{ + switch( p_Inp->FileFormat ) + { + default: + case PAR_OF_ANNEXB: + ret = get_annex_b_NALU(p_Vid, nalu, p_Vid->annex_b); + break; + case PAR_OF_RTP: + ret = GetRTPNALU(p_Vid, nalu, p_Vid->BitStreamFile); + break; + } + + if (ret < 0) + { + snprintf(errortext, ET_SIZE, "Error while getting the NALU in file format %s, exit\n", p_Inp->FileFormat==PAR_OF_ANNEXB?"Annex B":"RTP"); + error (errortext, 601); + } + if (ret == 0) + { + //FreeNALU(nalu); + return 0; + } + + //In some cases, zero_byte shall be present. If current NALU is a VCL NALU, we can't tell + //whether it is the first VCL NALU at this point, so only non-VCL NAL unit is checked here. + CheckZeroByteNonVCL(p_Vid, nalu); + + ret = NALUtoRBSP(nalu); + + if (ret < 0) + error ("Invalid startcode emulation prevention found.", 602); + + // Got a NALU + if (nalu->forbidden_bit) + { + error ("Found NALU with forbidden_bit set, bit error?", 603); + } + + }while( !parse_nalu(p_Vid, nalu) ); + + return nalu->len; +} + +void CheckZeroByteNonVCL(VideoParameters *p_Vid, NALU_t *nalu) +{ + int CheckZeroByte=0; + + //This function deals only with non-VCL NAL units + if(nalu->nal_unit_type>=1&&nalu->nal_unit_type<=5) + return; + + //for SPS and PPS, zero_byte shall exist + if(nalu->nal_unit_type==NALU_TYPE_SPS || nalu->nal_unit_type==NALU_TYPE_PPS) + CheckZeroByte=1; + //check the possibility of the current NALU to be the start of a new access unit, according to 7.4.1.2.3 + if(nalu->nal_unit_type==NALU_TYPE_AUD || nalu->nal_unit_type==NALU_TYPE_SPS || + nalu->nal_unit_type==NALU_TYPE_PPS || nalu->nal_unit_type==NALU_TYPE_SEI || + (nalu->nal_unit_type>=13 && nalu->nal_unit_type<=18)) + { + if(p_Vid->LastAccessUnitExists) + { + p_Vid->LastAccessUnitExists=0; //deliver the last access unit to decoder + p_Vid->NALUCount=0; + } + } + p_Vid->NALUCount++; + //for the first NAL unit in an access unit, zero_byte shall exists + if(p_Vid->NALUCount==1) + CheckZeroByte=1; + if(CheckZeroByte && nalu->startcodeprefix_len==3) + { + printf("Warning: zero_byte shall exist\n"); + //because it is not a very serious problem, we do not exit here + } +} + +void CheckZeroByteVCL(VideoParameters *p_Vid, NALU_t *nalu) +{ + int CheckZeroByte=0; + + //This function deals only with VCL NAL units + if(!(nalu->nal_unit_type>=NALU_TYPE_SLICE && nalu->nal_unit_type <= NALU_TYPE_IDR)) + return; + + if(p_Vid->LastAccessUnitExists) + { + p_Vid->NALUCount=0; + } + p_Vid->NALUCount++; + //the first VCL NAL unit that is the first NAL unit after last VCL NAL unit indicates + //the start of a new access unit and hence the first NAL unit of the new access unit. (sounds like a tongue twister :-) + if(p_Vid->NALUCount == 1) + CheckZeroByte = 1; + p_Vid->LastAccessUnitExists = 1; + if(CheckZeroByte && nalu->startcodeprefix_len==3) + { + printf("warning: zero_byte shall exist\n"); + //because it is not a very serious problem, we do not exit here + } +} + +#if (MVC_EXTENSION_ENABLE) +void nal_unit_header_mvc_extension(NALUnitHeaderMVCExt_t *NaluHeaderMVCExt, Bitstream *s) +{ + //to be implemented; + NaluHeaderMVCExt->non_idr_flag = read_u_v (1, "non_idr_flag", s, &p_Dec->UsedBits); + NaluHeaderMVCExt->priority_id = read_u_v (6, "priority_id", s, &p_Dec->UsedBits); + NaluHeaderMVCExt->view_id = read_u_v (10, "view_id", s, &p_Dec->UsedBits); + NaluHeaderMVCExt->temporal_id = read_u_v (3, "temporal_id", s, &p_Dec->UsedBits); + NaluHeaderMVCExt->anchor_pic_flag = read_u_v (1, "anchor_pic_flag", s, &p_Dec->UsedBits); + NaluHeaderMVCExt->inter_view_flag = read_u_v (1, "inter_view_flag", s, &p_Dec->UsedBits); + NaluHeaderMVCExt->reserved_one_bit = read_u_v (1, "reserved_one_bit", s, &p_Dec->UsedBits); + if(NaluHeaderMVCExt->reserved_one_bit != 1) + { + printf("Nalu Header MVC Extension: reserved_one_bit is not 1!\n"); + } +} + +void nal_unit_header_svc_extension( void ) +{ + //to be implemented for Annex G; +} + +void prefix_nal_unit_svc( void ) +{ + //to be implemented for Annex G; +} + +#endif diff --git a/ldecod/src/output.c b/ldecod/src/output.c new file mode 100644 index 0000000..aa17fa3 --- /dev/null +++ b/ldecod/src/output.c @@ -0,0 +1,959 @@ + +/*! + ************************************************************************ + * \file output.c + * + * \brief + * Output an image and Trance support + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + ************************************************************************ + */ + +#include "contributors.h" + +#include "global.h" +#include "mbuffer.h" +#include "image.h" +#include "memalloc.h" +#include "sei.h" +#include "input.h" +#include "fast_memory.h" + +#if( DISPLAY_OUTPUTED_FRAMES ) +#include "debug_functions.h" +#endif + +static void write_out_picture(VideoParameters *p_Vid, StorablePicture *p, int p_out); +static void img2buf_byte (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom, int iOutStride); +static void img2buf_normal (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom, int iOutStride); +static void img2buf_endian (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom, int iOutStride); + + +/*! + ************************************************************************ + * \brief + * selects appropriate output function given system arch. and data + * \return + * + ************************************************************************ + */ +void init_output(CodingParameters *p_cps, int symbol_size_in_bytes) +{ + if (( sizeof(char) == sizeof (imgpel))) + { + if ( sizeof(char) == symbol_size_in_bytes) + p_cps->img2buf = img2buf_byte; + else + p_cps->img2buf = img2buf_normal; + } + else + { + if (testEndian()) + p_cps->img2buf = img2buf_endian; + else + p_cps->img2buf = img2buf_normal; + } +} + +/*! + ************************************************************************ + * \brief + * Convert image plane to temporary buffer for file writing + * \param imgX + * Pointer to image plane + * \param buf + * Buffer for file output + * \param size_x + * horizontal size + * \param size_y + * vertical size + * \param symbol_size_in_bytes + * number of bytes used per pel + * \param crop_left + * pixels to crop from left + * \param crop_right + * pixels to crop from right + * \param crop_top + * pixels to crop from top + * \param crop_bottom + * pixels to crop from bottom + ************************************************************************ + */ +static void img2buf_normal (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom, int iOutStride) +{ + int i,j; + + int twidth = size_x - crop_left - crop_right; + int theight = size_y - crop_top - crop_bottom; + + int size = 0; + + // sizeof (imgpel) > sizeof(char) + // little endian + if (sizeof (imgpel) < symbol_size_in_bytes) + { + // this should not happen. we should not have smaller imgpel than our source material. + size = sizeof (imgpel); + // clear buffer + for(j=0; j> 8) | ((tmp16&0xFF)<<8)); + memcpy(buf+((j-crop_left+((i-crop_top)*iOutStride))*2),&(ui16), 2); + } + break; + } + case 4: + { + for(i=crop_top;i>8) | ((tmp32&0xFF000000)>>24)); + memcpy(buf+((j-crop_left+((i-crop_top)*iOutStride))*4),&(ui32), 4); + } + break; + } + default: + { + error ("writing only to formats of 8, 16 or 32 bit allowed on big endian architecture", 500); + break; + } + } +} + + +#if (PAIR_FIELDS_IN_OUTPUT) + +void clear_picture(VideoParameters *p_Vid, StorablePicture *p); + +/*! + ************************************************************************ + * \brief + * output the pending frame buffer + * \param p_out + * Output file + ************************************************************************ + */ +void flush_pending_output(VideoParameters *p_Vid, int p_out) +{ + if (p_Vid->pending_output_state != FRAME) + { + write_out_picture(p_Vid, p_Vid->pending_output, p_out); + } + + if (p_Vid->pending_output->imgY) + { + free_mem2Dpel (p_Vid->pending_output->imgY); + p_Vid->pending_output->imgY=NULL; + } + if (p_Vid->pending_output->imgUV) + { + free_mem3Dpel (p_Vid->pending_output->imgUV); + p_Vid->pending_output->imgUV=NULL; + } + + p_Vid->pending_output_state = FRAME; +} + + +/*! + ************************************************************************ + * \brief + * Writes out a storable picture + * If the picture is a field, the output buffers the picture and tries + * to pair it with the next field. + * \param p + * Picture to be written + * \param p_out + * Output file + ************************************************************************ + */ +void write_picture(VideoParameters *p_Vid, StorablePicture *p, int p_out, int real_structure) +{ + int i, add; + + if (real_structure==FRAME) + { + + flush_pending_output(p_Vid, p_out); + write_out_picture(p_Vid, p, p_out); + return; + } + if (real_structure == p_Vid->pending_output_state) + { + flush_pending_output(p_Vid, p_out); + write_picture(p_Vid, p, p_out, real_structure); + return; + } + + if (p_Vid->pending_output_state == FRAME) + { + p_Vid->pending_output->size_x = p->size_x; + p_Vid->pending_output->size_y = p->size_y; + p_Vid->pending_output->size_x_cr = p->size_x_cr; + p_Vid->pending_output->size_y_cr = p->size_y_cr; + p_Vid->pending_output->chroma_format_idc = p->chroma_format_idc; + + p_Vid->pending_output->frame_mbs_only_flag = p->frame_mbs_only_flag; + p_Vid->pending_output->frame_cropping_flag = p->frame_cropping_flag; + if (p_Vid->pending_output->frame_cropping_flag) + { + p_Vid->pending_output->frame_crop_left_offset = p->frame_crop_left_offset; + p_Vid->pending_output->frame_crop_right_offset = p->frame_crop_right_offset; + p_Vid->pending_output->frame_crop_top_offset = p->frame_crop_top_offset; + p_Vid->pending_output->frame_crop_bottom_offset = p->frame_crop_bottom_offset; + } + + get_mem2Dpel (&(p_Vid->pending_output->imgY), p_Vid->pending_output->size_y, p_Vid->pending_output->size_x); + get_mem3Dpel (&(p_Vid->pending_output->imgUV), 2, p_Vid->pending_output->size_y_cr, p_Vid->pending_output->size_x_cr); + + clear_picture(p_Vid, p_Vid->pending_output); + + // copy first field + if (real_structure == TOP_FIELD) + { + add = 0; + } + else + { + add = 1; + } + + for (i=0; ipending_output->size_y; i+=2) + { + memcpy(p_Vid->pending_output->imgY[(i+add)], p->imgY[(i+add)], p->size_x * sizeof(imgpel)); + } + for (i=0; ipending_output->size_y_cr; i+=2) + { + memcpy(p_Vid->pending_output->imgUV[0][(i+add)], p->imgUV[0][(i+add)], p->size_x_cr * sizeof(imgpel)); + memcpy(p_Vid->pending_output->imgUV[1][(i+add)], p->imgUV[1][(i+add)], p->size_x_cr * sizeof(imgpel)); + } + p_Vid->pending_output_state = real_structure; + } + else + { + if ( (p_Vid->pending_output->size_x!=p->size_x) || (p_Vid->pending_output->size_y!= p->size_y) + || (p_Vid->pending_output->frame_mbs_only_flag != p->frame_mbs_only_flag) + || (p_Vid->pending_output->frame_cropping_flag != p->frame_cropping_flag) + || ( p_Vid->pending_output->frame_cropping_flag && + ( (p_Vid->pending_output->frame_crop_left_offset != p->frame_crop_left_offset) + ||(p_Vid->pending_output->frame_crop_right_offset != p->frame_crop_right_offset) + ||(p_Vid->pending_output->frame_crop_top_offset != p->frame_crop_top_offset) + ||(p_Vid->pending_output->frame_crop_bottom_offset != p->frame_crop_bottom_offset) + ) + ) + ) + { + flush_pending_output(p_Vid, p_out); + write_picture (p_Vid, p, p_out, real_structure); + return; + } + // copy second field + if (real_structure == TOP_FIELD) + { + add = 0; + } + else + { + add = 1; + } + + for (i=0; ipending_output->size_y; i+=2) + { + memcpy(p_Vid->pending_output->imgY[(i+add)], p->imgY[(i+add)], p->size_x * sizeof(imgpel)); + } + for (i=0; ipending_output->size_y_cr; i+=2) + { + memcpy(p_Vid->pending_output->imgUV[0][(i+add)], p->imgUV[0][(i+add)], p->size_x_cr * sizeof(imgpel)); + memcpy(p_Vid->pending_output->imgUV[1][(i+add)], p->imgUV[1][(i+add)], p->size_x_cr * sizeof(imgpel)); + } + + flush_pending_output(p_Vid, p_out); + } +} + +#else + +/*! + ************************************************************************ + * \brief + * Writes out a storable picture without doing any output modifications + * + * \param p_Vid + * image decoding parameters for current picture + * \param p + * Picture to be written + * \param p_out + * Output file + * \param real_structure + * real picture structure + ************************************************************************ + */ +void write_picture(VideoParameters *p_Vid, StorablePicture *p, int p_out, int real_structure) +{ +#if PRINT_OUTPUT_DPB_POC + if (!p_Vid->p_Inp->silent) + { + if (p->concealed_pic) + printf( "Output frame c%1d( frame_no: %2d poc: %3d view_id: %2d)\n", p->concealed_pic, p->frame_no , p->poc, p->view_id); + else + printf( "Output frame ( frame_no: %2d poc: %3d view_id: %2d)\n", p->frame_no , p->poc, p->view_id); + } +#endif + +#if( DISPLAY_OUTPUTED_FRAMES ) + showStorablePicture (p_Vid , p, 1, "Outputed Frame", 1000 / 30); +#endif + write_out_picture(p_Vid, p, p_out); +#if( MVC_EXTENSION_ENABLE ) + p_Vid->nFramesOut[p->view_id]++; +#else + p_Vid->nFramesOut++; +#endif +} + + +#endif + +static void allocate_p_dec_pic(VideoParameters *p_Vid, DecodedPicList *pDecPic, StorablePicture *p, int iLumaSize, int iFrameSize, int iLumaSizeX, int iLumaSizeY, int iChromaSizeX, int iChromaSizeY) +{ + int symbol_size_in_bytes = ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3); + + if(pDecPic->pY) + mem_free(pDecPic->pY); + pDecPic->iBufSize = iFrameSize; + pDecPic->pY = mem_malloc(pDecPic->iBufSize); + pDecPic->pU = pDecPic->pY+iLumaSize; + pDecPic->pV = pDecPic->pU + ((iFrameSize-iLumaSize)>>1); + //init; + pDecPic->iYUVFormat = p->chroma_format_idc; + pDecPic->iYUVStorageFormat = 0; + pDecPic->iBitDepth = p_Vid->pic_unit_bitsize_on_disk; + pDecPic->iWidth = iLumaSizeX; //p->size_x; + pDecPic->iHeight = iLumaSizeY; //p->size_y; + pDecPic->iYBufStride = iLumaSizeX*symbol_size_in_bytes; //p->size_x *symbol_size_in_bytes; + pDecPic->iUVBufStride = iChromaSizeX*symbol_size_in_bytes; //p->size_x_cr*symbol_size_in_bytes; +} + +/*! +************************************************************************ +* \brief +* Writes out a storable picture +* +* \param p_Vid +* image decoding parameters for current picture +* \param p +* Picture to be written +* \param p_out +* Output file +************************************************************************ +*/ +static void write_out_picture(VideoParameters *p_Vid, StorablePicture *p, int p_out) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + DecodedPicList *pDecPic; + + static const int SubWidthC [4]= { 1, 2, 2, 1}; + static const int SubHeightC [4]= { 1, 2, 1, 1}; + + int crop_left, crop_right, crop_top, crop_bottom; + int symbol_size_in_bytes = ((p_Vid->pic_unit_bitsize_on_disk+7) >> 3); + int rgb_output = p_Vid->p_EncodePar[p->layer_id]->rgb_output; //(p_Vid->active_sps->vui_seq_parameters.matrix_coefficients==0); + unsigned char *buf; + //int iPicSizeTab[4] = {2, 3, 4, 6}; + int iLumaSize, iFrameSize; + int iLumaSizeX, iLumaSizeY; + int iChromaSizeX, iChromaSizeY; + + int ret; + + if (p->non_existing) + return; + +#if (ENABLE_OUTPUT_TONEMAPPING) + // note: this tone-mapping is working for RGB format only. Sharp + if (p->seiHasTone_mapping && rgb_output) + { + //printf("output frame %d with tone model id %d\n", p->frame_num, p->tone_mapping_model_id); + symbol_size_in_bytes = (p->tonemapped_bit_depth>8)? 2 : 1; + tone_map(p->imgY, p->tone_mapping_lut, p->size_x, p->size_y); + tone_map(p->imgUV[0], p->tone_mapping_lut, p->size_x_cr, p->size_y_cr); + tone_map(p->imgUV[1], p->tone_mapping_lut, p->size_x_cr, p->size_y_cr); + } +#endif + + // should this be done only once? + if (p->frame_cropping_flag) + { + crop_left = SubWidthC [p->chroma_format_idc] * p->frame_crop_left_offset; + crop_right = SubWidthC [p->chroma_format_idc] * p->frame_crop_right_offset; + crop_top = SubHeightC[p->chroma_format_idc] * ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = SubHeightC[p->chroma_format_idc] * ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + iChromaSizeX = p->size_x_cr- p->frame_crop_left_offset -p->frame_crop_right_offset; + iChromaSizeY = p->size_y_cr - ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset -( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + iLumaSizeX = p->size_x - crop_left-crop_right; + iLumaSizeY = p->size_y - crop_top - crop_bottom; + iLumaSize = iLumaSizeX * iLumaSizeY * symbol_size_in_bytes; + iFrameSize = (iLumaSizeX * iLumaSizeY + 2 * (iChromaSizeX * iChromaSizeY)) * symbol_size_in_bytes; //iLumaSize*iPicSizeTab[p->chroma_format_idc]/2; + + //printf ("write frame size: %dx%d\n", p->size_x-crop_left-crop_right,p->size_y-crop_top-crop_bottom ); + + // We need to further cleanup this function + if (p_out == -1) + return; + + + + // KS: this buffer should actually be allocated only once, but this is still much faster than the previous version + pDecPic = get_one_avail_dec_pic_from_list(p_Vid->pDecOuputPic, 0, 0); + if( (pDecPic->pY == NULL) + || (pDecPic->iBufSize < iFrameSize) + ) + allocate_p_dec_pic(p_Vid, pDecPic, p, iLumaSize, iFrameSize, iLumaSizeX, iLumaSizeY, iChromaSizeX, iChromaSizeY); +#if (MVC_EXTENSION_ENABLE) + { + pDecPic->bValid = 1; + pDecPic->iViewId = p->view_id >=0 ? p->view_id : -1; + } +#else + pDecPic->bValid = 1; +#endif + + pDecPic->iPOC = p->frame_poc; + + if (NULL==pDecPic->pY) + { + no_mem_exit("write_out_picture: buf"); + } + + + if(rgb_output) + { + buf = malloc (p->size_x * p->size_y * symbol_size_in_bytes); + crop_left = p->frame_crop_left_offset; + crop_right = p->frame_crop_right_offset; + crop_top = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + + p_Vid->img2buf (p->imgUV[1], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom, pDecPic->iYBufStride); + if (p_out >= 0) + { + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to RGB file", 500); + } + } + + if (p->frame_cropping_flag) + { + crop_left = SubWidthC[p->chroma_format_idc] * p->frame_crop_left_offset; + crop_right = SubWidthC[p->chroma_format_idc] * p->frame_crop_right_offset; + crop_top = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + if(buf) + free(buf); + } + + buf = (pDecPic->bValid==1)? pDecPic->pY: pDecPic->pY+iLumaSizeX*symbol_size_in_bytes; + + p_Vid->img2buf (p->imgY, buf, p->size_x, p->size_y, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom, pDecPic->iYBufStride); + if(p_out >=0) + { + ret = write(p_out, buf, (p->size_y-crop_bottom-crop_top)*(p->size_x-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y-crop_bottom-crop_top)*(p->size_x-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + } + + if (p->chroma_format_idc!=YUV400) + { + crop_left = p->frame_crop_left_offset; + crop_right = p->frame_crop_right_offset; + crop_top = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + buf = (pDecPic->bValid==1)? pDecPic->pU : pDecPic->pU + iChromaSizeX*symbol_size_in_bytes; + p_Vid->img2buf (p->imgUV[0], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom, pDecPic->iUVBufStride); + if(p_out >= 0) + { + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)* symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)* symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + } + + if (!rgb_output) + { + buf = (pDecPic->bValid==1)? pDecPic->pV : pDecPic->pV + iChromaSizeX*symbol_size_in_bytes; + p_Vid->img2buf (p->imgUV[1], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom, pDecPic->iUVBufStride); + + if(p_out >= 0) + { + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + } + } + } + else + { + if (p_Inp->write_uv) + { + int i,j; + imgpel cr_val = (imgpel) (1<<(p_Vid->bitdepth_luma - 1)); + + get_mem3Dpel (&(p->imgUV), 1, p->size_y/2, p->size_x/2); + + for (j=0; jsize_y/2; j++) + { + for (i=0; isize_x/2; i++) + { + p->imgUV[0][j][i]=cr_val; + } + } + + // fake out U=V=128 to make a YUV 4:2:0 stream + buf = malloc (p->size_x*p->size_y*symbol_size_in_bytes); + p_Vid->img2buf (p->imgUV[0], buf, p->size_x/2, p->size_y/2, symbol_size_in_bytes, crop_left/2, crop_right/2, crop_top/2, crop_bottom/2, pDecPic->iYBufStride/2); + + ret = write(p_out, buf, symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2 ); + if (ret != (symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + ret = write(p_out, buf, symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2 ); + if (ret != (symbol_size_in_bytes * (p->size_y-crop_bottom-crop_top)/2 * (p->size_x-crop_right-crop_left)/2)) + { + error ("write_out_picture: error writing to YUV file", 500); + } + free(buf); + free_mem3Dpel(p->imgUV); + p->imgUV=NULL; + } + } + + //free(buf); + if(p_out >=0) + pDecPic->bValid = 0; + + // fsync(p_out); +} + +/*! + ************************************************************************ + * \brief + * Initialize output buffer for direct output + ************************************************************************ + */ +void init_out_buffer(VideoParameters *p_Vid) +{ + p_Vid->out_buffer = alloc_frame_store(); + +#if (PAIR_FIELDS_IN_OUTPUT) + p_Vid->pending_output = calloc (sizeof(StorablePicture), 1); + if (NULL==p_Vid->pending_output) no_mem_exit("init_out_buffer"); + p_Vid->pending_output->imgUV = NULL; + p_Vid->pending_output->imgY = NULL; +#endif +} + +/*! + ************************************************************************ + * \brief + * Uninitialize output buffer for direct output + ************************************************************************ + */ +void uninit_out_buffer(VideoParameters *p_Vid) +{ + free_frame_store(p_Vid->out_buffer); + p_Vid->out_buffer=NULL; +#if (PAIR_FIELDS_IN_OUTPUT) + flush_pending_output(p_Vid, p_Vid->p_out); + free (p_Vid->pending_output); +#endif +} + +/*! + ************************************************************************ + * \brief + * Initialize picture memory with (Y:0,U:128,V:128) + ************************************************************************ + */ +void clear_picture(VideoParameters *p_Vid, StorablePicture *p) +{ + int i,j; + + for(i=0;isize_y;i++) + { + for (j=0; jsize_x; j++) + p->imgY[i][j] = (imgpel) p_Vid->dc_pred_value_comp[0]; + } + for(i=0;isize_y_cr;i++) + { + for (j=0; jsize_x_cr; j++) + p->imgUV[0][i][j] = (imgpel) p_Vid->dc_pred_value_comp[1]; + } + for(i=0;isize_y_cr;i++) + { + for (j=0; jsize_x_cr; j++) + p->imgUV[1][i][j] = (imgpel) p_Vid->dc_pred_value_comp[2]; + } +} + +/*! + ************************************************************************ + * \brief + * Write out not paired direct output fields. A second empty field is generated + * and combined into the frame buffer. + * + * \param p_Vid + * image decoding parameters for current picture + * \param fs + * FrameStore that contains a single field + * \param p_out + * Output file + ************************************************************************ + */ +void write_unpaired_field(VideoParameters *p_Vid, FrameStore* fs, int p_out) +{ + StorablePicture *p; + assert (fs->is_used<3); + + if(fs->is_used & 0x01) + { + // we have a top field + // construct an empty bottom field + p = fs->top_field; + fs->bottom_field = alloc_storable_picture(p_Vid, BOTTOM_FIELD, p->size_x, 2*p->size_y, p->size_x_cr, 2*p->size_y_cr, 1); + fs->bottom_field->chroma_format_idc = p->chroma_format_idc; + clear_picture(p_Vid, fs->bottom_field); + dpb_combine_field_yuv(p_Vid, fs); +#if (MVC_EXTENSION_ENABLE) + fs->frame->view_id = fs->view_id; +#endif + write_picture (p_Vid, fs->frame, p_out, TOP_FIELD); + } + + if(fs->is_used & 0x02) + { + // we have a bottom field + // construct an empty top field + p = fs->bottom_field; + fs->top_field = alloc_storable_picture(p_Vid, TOP_FIELD, p->size_x, 2*p->size_y, p->size_x_cr, 2*p->size_y_cr, 1); + fs->top_field->chroma_format_idc = p->chroma_format_idc; + clear_picture(p_Vid, fs->top_field); + fs ->top_field->frame_cropping_flag = fs->bottom_field->frame_cropping_flag; + if(fs ->top_field->frame_cropping_flag) + { + fs ->top_field->frame_crop_top_offset = fs->bottom_field->frame_crop_top_offset; + fs ->top_field->frame_crop_bottom_offset = fs->bottom_field->frame_crop_bottom_offset; + fs ->top_field->frame_crop_left_offset = fs->bottom_field->frame_crop_left_offset; + fs ->top_field->frame_crop_right_offset = fs->bottom_field->frame_crop_right_offset; + } + dpb_combine_field_yuv(p_Vid, fs); +#if (MVC_EXTENSION_ENABLE) + fs->frame->view_id = fs->view_id; +#endif + write_picture (p_Vid, fs->frame, p_out, BOTTOM_FIELD); + } + + fs->is_used = 3; +} + +/*! + ************************************************************************ + * \brief + * Write out unpaired fields from output buffer. + * + * \param p_Vid + * image decoding parameters for current picture + * \param p_out + * Output file + ************************************************************************ + */ +void flush_direct_output(VideoParameters *p_Vid, int p_out) +{ + write_unpaired_field(p_Vid, p_Vid->out_buffer, p_out); + + free_storable_picture(p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; +} + + +/*! + ************************************************************************ + * \brief + * Write a frame (from FrameStore) + * + * \param p_Vid + * image decoding parameters for current picture + * \param fs + * FrameStore containing the frame + * \param p_out + * Output file + ************************************************************************ + */ +void write_stored_frame( VideoParameters *p_Vid, FrameStore *fs, int p_out) +{ + +#ifndef DISABLE_MB_DECODING + + if( fs->frame->frame_no >= INITAL_PFRAMES_LENGTH ) + { + if (fs->frame->concealed_pic > 0) + { + p_Vid->p_PFrames[fs->view_id][fs->frame->frame_no] = 0; + } + + if (fs->frame->have_concealed_reference == 1) + { + p_Vid->p_PFrames[fs->view_id][fs->frame->frame_no] = -1; + } + + if ( !(fs->frame->concealed_pic > 0 || fs->frame->have_concealed_reference == 1) ) + { + p_Vid->p_PFrames[fs->view_id][fs->frame->frame_no] = 1; + } + } + // make sure no direct output field is pending + flush_direct_output(p_Vid, p_out); + + if (fs->is_used<3) + { + write_unpaired_field(p_Vid, fs, p_out); + } + else + { + if (fs->recovery_frame) + p_Vid->recovery_flag = 1; + if ((!p_Vid->non_conforming_stream) || p_Vid->recovery_flag) + write_picture(p_Vid, fs->frame, p_out, FRAME); + } +#endif + + fs->is_output = 1; +} + +/*! + ************************************************************************ + * \brief + * Directly output a picture without storing it in the DPB. Fields + * are buffered before they are written to the file. + * + * \param p_Vid + * image decoding parameters for current picture + * \param p + * Picture for output + * \param p_out + * Output file + ************************************************************************ + */ +void direct_output(VideoParameters *p_Vid, StorablePicture *p, int p_out) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + if (p->structure==FRAME) + { + // we have a frame (or complementary field pair) + // so output it directly + flush_direct_output(p_Vid, p_out); + write_picture (p_Vid, p, p_out, FRAME); + //calculate_frame_no(p_Vid, p); + //if (-1 != p_Vid->p_ref && !p_Inp->silent) + // find_snr(p_Vid, p, &p_Vid->p_ref); + free_storable_picture(p); + return; + } + + if (p->structure == TOP_FIELD) + { + if (p_Vid->out_buffer->is_used &1) + flush_direct_output(p_Vid, p_out); + p_Vid->out_buffer->top_field = p; + p_Vid->out_buffer->is_used |= 1; + } + + if (p->structure == BOTTOM_FIELD) + { + if (p_Vid->out_buffer->is_used &2) + flush_direct_output(p_Vid, p_out); + p_Vid->out_buffer->bottom_field = p; + p_Vid->out_buffer->is_used |= 2; + } + + if (p_Vid->out_buffer->is_used == 3) + { + // we have both fields, so output them + dpb_combine_field_yuv(p_Vid, p_Vid->out_buffer); +#if (MVC_EXTENSION_ENABLE) + p_Vid->out_buffer->frame->view_id = p_Vid->out_buffer->view_id; +#endif + write_picture (p_Vid, p_Vid->out_buffer->frame, p_out, FRAME); + + //calculate_frame_no(p_Vid, p); + //if (-1 != p_Vid->p_ref && !p_Inp->silent) + // find_snr(p_Vid, p_Vid->out_buffer->frame, &p_Vid->p_ref); + + free_storable_picture(p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; + } +} + diff --git a/ldecod/src/parset.c b/ldecod/src/parset.c new file mode 100644 index 0000000..e7fa538 --- /dev/null +++ b/ldecod/src/parset.c @@ -0,0 +1,1604 @@ + +/*! + ************************************************************************ + * \file + * parset.c + * \brief + * Parameter Sets + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * + *********************************************************************** + */ + +#include "global.h" +#include "image.h" +#include "parsetcommon.h" +#include "parset.h" +#include "nalu.h" +#include "memalloc.h" +#include "fmo.h" +#include "cabac.h" +#include "vlc.h" +#include "mbuffer.h" +#include "erc_api.h" + +#if TRACE +#define SYMTRACESTRING(s) strncpy(sym->tracestring,s,TRACESTRING_SIZE) +#else +#define SYMTRACESTRING(s) // do nothing +#endif + +extern void init_frext(VideoParameters *p_Vid); + +// syntax for scaling list matrix values +void Scaling_List(int *scalingList, int sizeOfScalingList, Boolean *UseDefaultScalingMatrix, Bitstream *s) +{ + int j, scanj; + int delta_scale, lastScale, nextScale; + + lastScale = 8; + nextScale = 8; + + for(j=0; jUsedBits); + nextScale = (lastScale + delta_scale + 256) % 256; + *UseDefaultScalingMatrix = (Boolean) (scanj==0 && nextScale==0); + } + + scalingList[scanj] = (nextScale==0) ? lastScale:nextScale; + lastScale = scalingList[scanj]; + } +} +// fill sps with content of p + +int InterpretSPS (VideoParameters *p_Vid, DataPartition *p, seq_parameter_set_rbsp_t *sps) +{ + unsigned i; + unsigned n_ScalingList; + int reserved_zero; + Bitstream *s = p->bitstream; + + assert (p != NULL); + assert (p->bitstream != NULL); + assert (p->bitstream->streamBuffer != 0); + assert (sps != NULL); + + p_Dec->UsedBits = 0; + + sps->profile_idc = read_u_v (8, "SPS: profile_idc" , s, &p_Dec->UsedBits); + + if ((sps->profile_idc!=BASELINE ) && + (sps->profile_idc!=MAIN ) && + (sps->profile_idc!=EXTENDED ) && + (sps->profile_idc!=FREXT_HP ) && + (sps->profile_idc!=FREXT_Hi10P ) && + (sps->profile_idc!=FREXT_Hi422 ) && + (sps->profile_idc!=FREXT_Hi444 ) && + (sps->profile_idc!=FREXT_CAVLC444 ) +#if (MVC_EXTENSION_ENABLE) + && (sps->profile_idc!=MVC_HIGH) + && (sps->profile_idc!=STEREO_HIGH) +#endif + ) + { + printf("Invalid Profile IDC (%d) encountered. \n", sps->profile_idc); + return p_Dec->UsedBits; + } + + sps->constrained_set0_flag = read_u_1 ( "SPS: constrained_set0_flag" , s, &p_Dec->UsedBits); + sps->constrained_set1_flag = read_u_1 ( "SPS: constrained_set1_flag" , s, &p_Dec->UsedBits); + sps->constrained_set2_flag = read_u_1 ( "SPS: constrained_set2_flag" , s, &p_Dec->UsedBits); + sps->constrained_set3_flag = read_u_1 ( "SPS: constrained_set3_flag" , s, &p_Dec->UsedBits); +#if (MVC_EXTENSION_ENABLE) + sps->constrained_set4_flag = read_u_1 ( "SPS: constrained_set4_flag" , s, &p_Dec->UsedBits); + sps->constrained_set5_flag = read_u_1 ( "SPS: constrained_set5_flag" , s, &p_Dec->UsedBits); + reserved_zero = read_u_v (2, "SPS: reserved_zero_2bits" , s, &p_Dec->UsedBits); +#else + reserved_zero = read_u_v (4, "SPS: reserved_zero_4bits" , s, &p_Dec->UsedBits); +#endif + //assert (reserved_zero==0); + if (reserved_zero != 0) + { + printf("Warning, reserved_zero flag not equal to 0. Possibly new constrained_setX flag introduced.\n"); + } + + sps->level_idc = read_u_v (8, "SPS: level_idc" , s, &p_Dec->UsedBits); + + sps->seq_parameter_set_id = read_ue_v ("SPS: seq_parameter_set_id" , s, &p_Dec->UsedBits); + + // Fidelity Range Extensions stuff + sps->chroma_format_idc = 1; + sps->bit_depth_luma_minus8 = 0; + sps->bit_depth_chroma_minus8 = 0; + sps->lossless_qpprime_flag = 0; + sps->separate_colour_plane_flag = 0; + + if((sps->profile_idc==FREXT_HP ) || + (sps->profile_idc==FREXT_Hi10P) || + (sps->profile_idc==FREXT_Hi422) || + (sps->profile_idc==FREXT_Hi444) || + (sps->profile_idc==FREXT_CAVLC444) +#if (MVC_EXTENSION_ENABLE) + || (sps->profile_idc==MVC_HIGH) + || (sps->profile_idc==STEREO_HIGH) +#endif + ) + { + sps->chroma_format_idc = read_ue_v ("SPS: chroma_format_idc" , s, &p_Dec->UsedBits); + + if(sps->chroma_format_idc == YUV444) + { + sps->separate_colour_plane_flag = read_u_1 ("SPS: separate_colour_plane_flag" , s, &p_Dec->UsedBits); + } + + sps->bit_depth_luma_minus8 = read_ue_v ("SPS: bit_depth_luma_minus8" , s, &p_Dec->UsedBits); + sps->bit_depth_chroma_minus8 = read_ue_v ("SPS: bit_depth_chroma_minus8" , s, &p_Dec->UsedBits); + //checking; + if((sps->bit_depth_luma_minus8+8 > sizeof(imgpel)*8) || (sps->bit_depth_chroma_minus8+8> sizeof(imgpel)*8)) + error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500); + + sps->lossless_qpprime_flag = read_u_1 ("SPS: lossless_qpprime_y_zero_flag" , s, &p_Dec->UsedBits); + + sps->seq_scaling_matrix_present_flag = read_u_1 ( "SPS: seq_scaling_matrix_present_flag" , s, &p_Dec->UsedBits); + + if(sps->seq_scaling_matrix_present_flag) + { + n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12; + for(i=0; iseq_scaling_list_present_flag[i] = read_u_1 ( "SPS: seq_scaling_list_present_flag" , s, &p_Dec->UsedBits); + if(sps->seq_scaling_list_present_flag[i]) + { + if(i<6) + Scaling_List(sps->ScalingList4x4[i], 16, &sps->UseDefaultScalingMatrix4x4Flag[i], s); + else + Scaling_List(sps->ScalingList8x8[i-6], 64, &sps->UseDefaultScalingMatrix8x8Flag[i-6], s); + } + } + } + } + + sps->log2_max_frame_num_minus4 = read_ue_v ("SPS: log2_max_frame_num_minus4" , s, &p_Dec->UsedBits); + sps->pic_order_cnt_type = read_ue_v ("SPS: pic_order_cnt_type" , s, &p_Dec->UsedBits); + + if (sps->pic_order_cnt_type == 0) + sps->log2_max_pic_order_cnt_lsb_minus4 = read_ue_v ("SPS: log2_max_pic_order_cnt_lsb_minus4" , s, &p_Dec->UsedBits); + else if (sps->pic_order_cnt_type == 1) + { + sps->delta_pic_order_always_zero_flag = read_u_1 ("SPS: delta_pic_order_always_zero_flag" , s, &p_Dec->UsedBits); + sps->offset_for_non_ref_pic = read_se_v ("SPS: offset_for_non_ref_pic" , s, &p_Dec->UsedBits); + sps->offset_for_top_to_bottom_field = read_se_v ("SPS: offset_for_top_to_bottom_field" , s, &p_Dec->UsedBits); + sps->num_ref_frames_in_pic_order_cnt_cycle = read_ue_v ("SPS: num_ref_frames_in_pic_order_cnt_cycle" , s, &p_Dec->UsedBits); + for(i=0; inum_ref_frames_in_pic_order_cnt_cycle; i++) + sps->offset_for_ref_frame[i] = read_se_v ("SPS: offset_for_ref_frame[i]" , s, &p_Dec->UsedBits); + } + sps->num_ref_frames = read_ue_v ("SPS: num_ref_frames" , s, &p_Dec->UsedBits); + sps->gaps_in_frame_num_value_allowed_flag = read_u_1 ("SPS: gaps_in_frame_num_value_allowed_flag" , s, &p_Dec->UsedBits); + sps->pic_width_in_mbs_minus1 = read_ue_v ("SPS: pic_width_in_mbs_minus1" , s, &p_Dec->UsedBits); + sps->pic_height_in_map_units_minus1 = read_ue_v ("SPS: pic_height_in_map_units_minus1" , s, &p_Dec->UsedBits); + sps->frame_mbs_only_flag = read_u_1 ("SPS: frame_mbs_only_flag" , s, &p_Dec->UsedBits); + if (!sps->frame_mbs_only_flag) + { + sps->mb_adaptive_frame_field_flag = read_u_1 ("SPS: mb_adaptive_frame_field_flag" , s, &p_Dec->UsedBits); + } + //printf("interlace flags %d %d\n", sps->frame_mbs_only_flag, sps->mb_adaptive_frame_field_flag); + sps->direct_8x8_inference_flag = read_u_1 ("SPS: direct_8x8_inference_flag" , s, &p_Dec->UsedBits); + sps->frame_cropping_flag = read_u_1 ("SPS: frame_cropping_flag" , s, &p_Dec->UsedBits); + + if (sps->frame_cropping_flag) + { + sps->frame_crop_left_offset = read_ue_v ("SPS: frame_crop_left_offset" , s, &p_Dec->UsedBits); + sps->frame_crop_right_offset = read_ue_v ("SPS: frame_crop_right_offset" , s, &p_Dec->UsedBits); + sps->frame_crop_top_offset = read_ue_v ("SPS: frame_crop_top_offset" , s, &p_Dec->UsedBits); + sps->frame_crop_bottom_offset = read_ue_v ("SPS: frame_crop_bottom_offset" , s, &p_Dec->UsedBits); + } + sps->vui_parameters_present_flag = (Boolean) read_u_1 ("SPS: vui_parameters_present_flag" , s, &p_Dec->UsedBits); + + InitVUI(sps); + ReadVUI(p, sps); + + sps->Valid = TRUE; + return p_Dec->UsedBits; +} + +// fill subset_sps with content of p +#if (MVC_EXTENSION_ENABLE) +static int InterpretSubsetSPS (VideoParameters *p_Vid, DataPartition *p, int *curr_seq_set_id) +{ + subset_seq_parameter_set_rbsp_t *subset_sps; + unsigned int additional_extension2_flag; + Bitstream *s = p->bitstream; + seq_parameter_set_rbsp_t *sps = AllocSPS(); + + assert (p != NULL); + assert (p->bitstream != NULL); + assert (p->bitstream->streamBuffer != 0); + + InterpretSPS (p_Vid, p, sps); + get_max_dec_frame_buf_size(sps); + + *curr_seq_set_id = sps->seq_parameter_set_id; + subset_sps = p_Vid->SubsetSeqParSet + sps->seq_parameter_set_id; + if(subset_sps->Valid || subset_sps->num_views_minus1>=0) + { + if(memcmp(&subset_sps->sps, sps, sizeof (seq_parameter_set_rbsp_t)-sizeof(int))) + assert(0); + reset_subset_sps(subset_sps); + } + memcpy (&subset_sps->sps, sps, sizeof (seq_parameter_set_rbsp_t)); + + assert (subset_sps != NULL); + subset_sps->Valid = FALSE; + + /*if(subset_sps->sps.profile_idc == SCALABLE_BASELINE_PROFILE || subset_sps->sps.profile_idc == SCALABLE_HIGH_PROFILE) + { + printf("\nScalable profile is not supported yet!\n"); + } + else*/ + if( is_MVC_profile(subset_sps->sps.profile_idc)) + { + subset_sps->bit_equal_to_one = read_u_1("bit_equal_to_one", s, &p_Dec->UsedBits); + + if(subset_sps->bit_equal_to_one !=1 ) + { + printf("\nbit_equal_to_one is not equal to 1!\n"); + return p_Dec->UsedBits; + } + + seq_parameter_set_mvc_extension(subset_sps, s); + + subset_sps->mvc_vui_parameters_present_flag = read_u_1("mvc_vui_parameters_present_flag", s, &p_Dec->UsedBits); + if(subset_sps->mvc_vui_parameters_present_flag) + mvc_vui_parameters_extension(&(subset_sps->MVCVUIParams), s); + } + + additional_extension2_flag = read_u_1("additional_extension2_flag", s, &p_Dec->UsedBits); + if(additional_extension2_flag) + { + while (more_rbsp_data(s->streamBuffer, s->frame_bitoffset,s->bitstream_length)) + additional_extension2_flag = read_u_1("additional_extension2_flag", s, &p_Dec->UsedBits); + } + + if (subset_sps->sps.Valid) + subset_sps->Valid = TRUE; + + FreeSPS (sps); + return p_Dec->UsedBits; + +} +#endif + +void InitVUI(seq_parameter_set_rbsp_t *sps) +{ + sps->vui_seq_parameters.matrix_coefficients = 2; +} + + +int ReadVUI(DataPartition *p, seq_parameter_set_rbsp_t *sps) +{ + Bitstream *s = p->bitstream; + if (sps->vui_parameters_present_flag) + { + sps->vui_seq_parameters.aspect_ratio_info_present_flag = read_u_1 ("VUI: aspect_ratio_info_present_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.aspect_ratio_info_present_flag) + { + sps->vui_seq_parameters.aspect_ratio_idc = read_u_v ( 8, "VUI: aspect_ratio_idc" , s, &p_Dec->UsedBits); + if (255==sps->vui_seq_parameters.aspect_ratio_idc) + { + sps->vui_seq_parameters.sar_width = (unsigned short) read_u_v (16, "VUI: sar_width" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.sar_height = (unsigned short) read_u_v (16, "VUI: sar_height" , s, &p_Dec->UsedBits); + } + } + + sps->vui_seq_parameters.overscan_info_present_flag = read_u_1 ("VUI: overscan_info_present_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.overscan_info_present_flag) + { + sps->vui_seq_parameters.overscan_appropriate_flag = read_u_1 ("VUI: overscan_appropriate_flag" , s, &p_Dec->UsedBits); + } + + sps->vui_seq_parameters.video_signal_type_present_flag = read_u_1 ("VUI: video_signal_type_present_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.video_signal_type_present_flag) + { + sps->vui_seq_parameters.video_format = read_u_v ( 3,"VUI: video_format" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.video_full_range_flag = read_u_1 ( "VUI: video_full_range_flag" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.colour_description_present_flag = read_u_1 ( "VUI: color_description_present_flag" , s, &p_Dec->UsedBits); + if(sps->vui_seq_parameters.colour_description_present_flag) + { + sps->vui_seq_parameters.colour_primaries = read_u_v ( 8,"VUI: colour_primaries" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.transfer_characteristics = read_u_v ( 8,"VUI: transfer_characteristics" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.matrix_coefficients = read_u_v ( 8,"VUI: matrix_coefficients" , s, &p_Dec->UsedBits); + } + } + sps->vui_seq_parameters.chroma_location_info_present_flag = read_u_1 ( "VUI: chroma_loc_info_present_flag" , s, &p_Dec->UsedBits); + if(sps->vui_seq_parameters.chroma_location_info_present_flag) + { + sps->vui_seq_parameters.chroma_sample_loc_type_top_field = read_ue_v ( "VUI: chroma_sample_loc_type_top_field" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.chroma_sample_loc_type_bottom_field = read_ue_v ( "VUI: chroma_sample_loc_type_bottom_field" , s, &p_Dec->UsedBits); + } + sps->vui_seq_parameters.timing_info_present_flag = read_u_1 ("VUI: timing_info_present_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.timing_info_present_flag) + { + sps->vui_seq_parameters.num_units_in_tick = read_u_v (32,"VUI: num_units_in_tick" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.time_scale = read_u_v (32,"VUI: time_scale" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.fixed_frame_rate_flag = read_u_1 ( "VUI: fixed_frame_rate_flag" , s, &p_Dec->UsedBits); + } + sps->vui_seq_parameters.nal_hrd_parameters_present_flag = read_u_1 ("VUI: nal_hrd_parameters_present_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + { + ReadHRDParameters(p, &(sps->vui_seq_parameters.nal_hrd_parameters)); + } + sps->vui_seq_parameters.vcl_hrd_parameters_present_flag = read_u_1 ("VUI: vcl_hrd_parameters_present_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + { + ReadHRDParameters(p, &(sps->vui_seq_parameters.vcl_hrd_parameters)); + } + if (sps->vui_seq_parameters.nal_hrd_parameters_present_flag || sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + { + sps->vui_seq_parameters.low_delay_hrd_flag = read_u_1 ("VUI: low_delay_hrd_flag" , s, &p_Dec->UsedBits); + } + sps->vui_seq_parameters.pic_struct_present_flag = read_u_1 ("VUI: pic_struct_present_flag " , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.bitstream_restriction_flag = read_u_1 ("VUI: bitstream_restriction_flag" , s, &p_Dec->UsedBits); + if (sps->vui_seq_parameters.bitstream_restriction_flag) + { + sps->vui_seq_parameters.motion_vectors_over_pic_boundaries_flag = read_u_1 ("VUI: motion_vectors_over_pic_boundaries_flag", s, &p_Dec->UsedBits); + sps->vui_seq_parameters.max_bytes_per_pic_denom = read_ue_v ("VUI: max_bytes_per_pic_denom" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.max_bits_per_mb_denom = read_ue_v ("VUI: max_bits_per_mb_denom" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.log2_max_mv_length_horizontal = read_ue_v ("VUI: log2_max_mv_length_horizontal" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.log2_max_mv_length_vertical = read_ue_v ("VUI: log2_max_mv_length_vertical" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.num_reorder_frames = read_ue_v ("VUI: num_reorder_frames" , s, &p_Dec->UsedBits); + sps->vui_seq_parameters.max_dec_frame_buffering = read_ue_v ("VUI: max_dec_frame_buffering" , s, &p_Dec->UsedBits); + } + } + + return 0; +} + + +int ReadHRDParameters(DataPartition *p, hrd_parameters_t *hrd) +{ + Bitstream *s = p->bitstream; + unsigned int SchedSelIdx; + + hrd->cpb_cnt_minus1 = read_ue_v ( "VUI: cpb_cnt_minus1" , s, &p_Dec->UsedBits); + hrd->bit_rate_scale = read_u_v ( 4,"VUI: bit_rate_scale" , s, &p_Dec->UsedBits); + hrd->cpb_size_scale = read_u_v ( 4,"VUI: cpb_size_scale" , s, &p_Dec->UsedBits); + + for( SchedSelIdx = 0; SchedSelIdx <= hrd->cpb_cnt_minus1; SchedSelIdx++ ) + { + hrd->bit_rate_value_minus1[ SchedSelIdx ] = read_ue_v ( "VUI: bit_rate_value_minus1" , s, &p_Dec->UsedBits); + hrd->cpb_size_value_minus1[ SchedSelIdx ] = read_ue_v ( "VUI: cpb_size_value_minus1" , s, &p_Dec->UsedBits); + hrd->cbr_flag[ SchedSelIdx ] = read_u_1 ( "VUI: cbr_flag" , s, &p_Dec->UsedBits); + } + + hrd->initial_cpb_removal_delay_length_minus1 = read_u_v ( 5,"VUI: initial_cpb_removal_delay_length_minus1" , s, &p_Dec->UsedBits); + hrd->cpb_removal_delay_length_minus1 = read_u_v ( 5,"VUI: cpb_removal_delay_length_minus1" , s, &p_Dec->UsedBits); + hrd->dpb_output_delay_length_minus1 = read_u_v ( 5,"VUI: dpb_output_delay_length_minus1" , s, &p_Dec->UsedBits); + hrd->time_offset_length = read_u_v ( 5,"VUI: time_offset_length" , s, &p_Dec->UsedBits); + + return 0; +} + + +int InterpretPPS (VideoParameters *p_Vid, DataPartition *p, pic_parameter_set_rbsp_t *pps) +{ + unsigned i; + unsigned n_ScalingList; + int chroma_format_idc; + int NumberBitsPerSliceGroupId; + Bitstream *s = p->bitstream; + + assert (p != NULL); + assert (p->bitstream != NULL); + assert (p->bitstream->streamBuffer != 0); + assert (pps != NULL); + + p_Dec->UsedBits = 0; + + pps->pic_parameter_set_id = read_ue_v ("PPS: pic_parameter_set_id" , s, &p_Dec->UsedBits); + pps->seq_parameter_set_id = read_ue_v ("PPS: seq_parameter_set_id" , s, &p_Dec->UsedBits); + pps->entropy_coding_mode_flag = read_u_1 ("PPS: entropy_coding_mode_flag" , s, &p_Dec->UsedBits); + + //! Note: as per JVT-F078 the following bit is unconditional. If F078 is not accepted, then + //! one has to fetch the correct SPS to check whether the bit is present (hopefully there is + //! no consistency problem :-( + //! The current encoder code handles this in the same way. When you change this, don't forget + //! the encoder! StW, 12/8/02 + pps->bottom_field_pic_order_in_frame_present_flag = read_u_1 ("PPS: bottom_field_pic_order_in_frame_present_flag" , s, &p_Dec->UsedBits); + + pps->num_slice_groups_minus1 = read_ue_v ("PPS: num_slice_groups_minus1" , s, &p_Dec->UsedBits); + + // FMO stuff begins here + if (pps->num_slice_groups_minus1 > 0) + { + pps->slice_group_map_type = read_ue_v ("PPS: slice_group_map_type" , s, &p_Dec->UsedBits); + if (pps->slice_group_map_type == 0) + { + for (i=0; i<=pps->num_slice_groups_minus1; i++) + pps->run_length_minus1 [i] = read_ue_v ("PPS: run_length_minus1 [i]" , s, &p_Dec->UsedBits); + } + else if (pps->slice_group_map_type == 2) + { + for (i=0; inum_slice_groups_minus1; i++) + { + //! JVT-F078: avoid reference of SPS by using ue(v) instead of u(v) + pps->top_left [i] = read_ue_v ("PPS: top_left [i]" , s, &p_Dec->UsedBits); + pps->bottom_right [i] = read_ue_v ("PPS: bottom_right [i]" , s, &p_Dec->UsedBits); + } + } + else if (pps->slice_group_map_type == 3 || + pps->slice_group_map_type == 4 || + pps->slice_group_map_type == 5) + { + pps->slice_group_change_direction_flag = read_u_1 ("PPS: slice_group_change_direction_flag" , s, &p_Dec->UsedBits); + pps->slice_group_change_rate_minus1 = read_ue_v ("PPS: slice_group_change_rate_minus1" , s, &p_Dec->UsedBits); + } + else if (pps->slice_group_map_type == 6) + { + if (pps->num_slice_groups_minus1+1 >4) + NumberBitsPerSliceGroupId = 3; + else if (pps->num_slice_groups_minus1+1 > 2) + NumberBitsPerSliceGroupId = 2; + else + NumberBitsPerSliceGroupId = 1; + pps->pic_size_in_map_units_minus1 = read_ue_v ("PPS: pic_size_in_map_units_minus1" , s, &p_Dec->UsedBits); + if ((pps->slice_group_id = calloc (pps->pic_size_in_map_units_minus1+1, 1)) == NULL) + no_mem_exit ("InterpretPPS: slice_group_id"); + for (i=0; i<=pps->pic_size_in_map_units_minus1; i++) + pps->slice_group_id[i] = (byte) read_u_v (NumberBitsPerSliceGroupId, "slice_group_id[i]", s, &p_Dec->UsedBits); + } + } + + // End of FMO stuff + + pps->num_ref_idx_l0_default_active_minus1 = read_ue_v ("PPS: num_ref_idx_l0_default_active_minus1" , s, &p_Dec->UsedBits); + pps->num_ref_idx_l1_default_active_minus1 = read_ue_v ("PPS: num_ref_idx_l1_default_active_minus1" , s, &p_Dec->UsedBits); + pps->weighted_pred_flag = read_u_1 ("PPS: weighted_pred_flag" , s, &p_Dec->UsedBits); + pps->weighted_bipred_idc = read_u_v ( 2, "PPS: weighted_bipred_idc" , s, &p_Dec->UsedBits); + pps->pic_init_qp_minus26 = read_se_v ("PPS: pic_init_qp_minus26" , s, &p_Dec->UsedBits); + pps->pic_init_qs_minus26 = read_se_v ("PPS: pic_init_qs_minus26" , s, &p_Dec->UsedBits); + + pps->chroma_qp_index_offset = read_se_v ("PPS: chroma_qp_index_offset" , s, &p_Dec->UsedBits); + + pps->deblocking_filter_control_present_flag = read_u_1 ("PPS: deblocking_filter_control_present_flag" , s, &p_Dec->UsedBits); + pps->constrained_intra_pred_flag = read_u_1 ("PPS: constrained_intra_pred_flag" , s, &p_Dec->UsedBits); + pps->redundant_pic_cnt_present_flag = read_u_1 ("PPS: redundant_pic_cnt_present_flag" , s, &p_Dec->UsedBits); + + if(more_rbsp_data(s->streamBuffer, s->frame_bitoffset,s->bitstream_length)) // more_data_in_rbsp() + { + //Fidelity Range Extensions Stuff + pps->transform_8x8_mode_flag = read_u_1 ("PPS: transform_8x8_mode_flag" , s, &p_Dec->UsedBits); + pps->pic_scaling_matrix_present_flag = read_u_1 ("PPS: pic_scaling_matrix_present_flag" , s, &p_Dec->UsedBits); + + if(pps->pic_scaling_matrix_present_flag) + { + chroma_format_idc = p_Vid->SeqParSet[pps->seq_parameter_set_id].chroma_format_idc; + n_ScalingList = 6 + ((chroma_format_idc != YUV444) ? 2 : 6) * pps->transform_8x8_mode_flag; + for(i=0; ipic_scaling_list_present_flag[i]= read_u_1 ("PPS: pic_scaling_list_present_flag" , s, &p_Dec->UsedBits); + + if(pps->pic_scaling_list_present_flag[i]) + { + if(i<6) + Scaling_List(pps->ScalingList4x4[i], 16, &pps->UseDefaultScalingMatrix4x4Flag[i], s); + else + Scaling_List(pps->ScalingList8x8[i-6], 64, &pps->UseDefaultScalingMatrix8x8Flag[i-6], s); + } + } + } + pps->second_chroma_qp_index_offset = read_se_v ("PPS: second_chroma_qp_index_offset" , s, &p_Dec->UsedBits); + } + else + { + pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset; + } + + pps->Valid = TRUE; + return p_Dec->UsedBits; +} + + +void PPSConsistencyCheck (pic_parameter_set_rbsp_t *pps) +{ + printf ("Consistency checking a picture parset, to be implemented\n"); +// if (pps->seq_parameter_set_id invalid then do something) +} + +void SPSConsistencyCheck (seq_parameter_set_rbsp_t *sps) +{ + printf ("Consistency checking a sequence parset, to be implemented\n"); +} + +#if (MVC_EXTENSION_ENABLE) +void SubsetSPSConsistencyCheck (subset_seq_parameter_set_rbsp_t *subset_sps) +{ + printf ("Consistency checking a subset sequence parset, to be implemented\n"); +} +#endif + +void MakePPSavailable (VideoParameters *p_Vid, int id, pic_parameter_set_rbsp_t *pps) +{ + assert (pps->Valid == TRUE); + + if (p_Vid->PicParSet[id].Valid == TRUE && p_Vid->PicParSet[id].slice_group_id != NULL) + free (p_Vid->PicParSet[id].slice_group_id); + + memcpy (&p_Vid->PicParSet[id], pps, sizeof (pic_parameter_set_rbsp_t)); + + // we can simply use the memory provided with the pps. the PPS is destroyed after this function + // call and will not try to free if pps->slice_group_id == NULL + p_Vid->PicParSet[id].slice_group_id = pps->slice_group_id; + pps->slice_group_id = NULL; +} + +void CleanUpPPS(VideoParameters *p_Vid) +{ + int i; + + for (i=0; iPicParSet[i].Valid == TRUE && p_Vid->PicParSet[i].slice_group_id != NULL) + free (p_Vid->PicParSet[i].slice_group_id); + + p_Vid->PicParSet[i].Valid = FALSE; + } +} + + +void MakeSPSavailable (VideoParameters *p_Vid, int id, seq_parameter_set_rbsp_t *sps) +{ + assert (sps->Valid == TRUE); + memcpy (&p_Vid->SeqParSet[id], sps, sizeof (seq_parameter_set_rbsp_t)); +} + + +void ProcessSPS (VideoParameters *p_Vid, NALU_t *nalu) +{ + DataPartition *dp = AllocPartition(1); + seq_parameter_set_rbsp_t *sps = AllocSPS(); + + memcpy (dp->bitstream->streamBuffer, &nalu->buf[1], nalu->len-1); + dp->bitstream->code_len = dp->bitstream->bitstream_length = RBSPtoSODB (dp->bitstream->streamBuffer, nalu->len-1); + dp->bitstream->ei_flag = 0; + dp->bitstream->read_len = dp->bitstream->frame_bitoffset = 0; + + InterpretSPS (p_Vid, dp, sps); +#if (MVC_EXTENSION_ENABLE) + get_max_dec_frame_buf_size(sps); +#endif + + if (sps->Valid) + { + if (p_Vid->active_sps) + { + if (sps->seq_parameter_set_id == p_Vid->active_sps->seq_parameter_set_id) + { + if (!sps_is_equal(sps, p_Vid->active_sps)) + { + if (p_Vid->dec_picture) // && p_Vid->num_dec_mb == p_Vid->PicSizeInMbs) //? + { + // this may only happen on slice loss + exit_picture(p_Vid, &p_Vid->dec_picture); + } + p_Vid->active_sps=NULL; + } + } + } + // SPSConsistencyCheck (pps); + MakeSPSavailable (p_Vid, sps->seq_parameter_set_id, sps); +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->profile_idc < (int) sps->profile_idc) + { + p_Vid->profile_idc = sps->profile_idc; + } +#else + p_Vid->profile_idc = sps->profile_idc; +#endif + p_Vid->separate_colour_plane_flag = sps->separate_colour_plane_flag; + if( p_Vid->separate_colour_plane_flag ) + { + p_Vid->ChromaArrayType = 0; + } + else + { + p_Vid->ChromaArrayType = sps->chroma_format_idc; + } + } + + FreePartition (dp, 1); + FreeSPS (sps); +} + +#if (MVC_EXTENSION_ENABLE) +void ProcessSubsetSPS (VideoParameters *p_Vid, NALU_t *nalu) +{ + DataPartition *dp = AllocPartition(1); + subset_seq_parameter_set_rbsp_t *subset_sps; + int curr_seq_set_id; + + memcpy (dp->bitstream->streamBuffer, &nalu->buf[1], nalu->len-1); + dp->bitstream->code_len = dp->bitstream->bitstream_length = RBSPtoSODB (dp->bitstream->streamBuffer, nalu->len-1); + dp->bitstream->ei_flag = 0; + dp->bitstream->read_len = dp->bitstream->frame_bitoffset = 0; + InterpretSubsetSPS (p_Vid, dp, &curr_seq_set_id); + + subset_sps = p_Vid->SubsetSeqParSet + curr_seq_set_id; + get_max_dec_frame_buf_size(&(subset_sps->sps)); + //check capability; + if(subset_sps->num_views_minus1 > MAX_VIEW_NUM ) + { + printf("Warning: num_views:%d is greater than %d, only decode baselayer!\n", subset_sps->num_views_minus1+1, MAX_VIEW_NUM); + subset_sps->Valid = 0; + subset_sps->sps.Valid = 0; + p_Vid->p_Inp->DecodeAllLayers = 0; + } + else if(subset_sps->num_views_minus1==1 && (subset_sps->view_id[0]!=0 || subset_sps->view_id[1]!=1)) + { + OpenOutputFiles(p_Vid, subset_sps->view_id[0], subset_sps->view_id[1]); + } + else + { + int layer; + for(layer=0; layernum_views_minus1+1; layer++) + { + OpenOutputFiles_per_layer(p_Vid, layer); + OpenRefFiles_per_layer(p_Vid, layer); + } + } + + if (subset_sps->Valid) + { + // SubsetSPSConsistencyCheck (subset_sps); + p_Vid->profile_idc = subset_sps->sps.profile_idc; + p_Vid->separate_colour_plane_flag = subset_sps->sps.separate_colour_plane_flag; + if( p_Vid->separate_colour_plane_flag ) + { + p_Vid->ChromaArrayType = 0; + } + else + { + p_Vid->ChromaArrayType = subset_sps->sps.chroma_format_idc; + } + } + + FreePartition (dp, 1); +} +#endif + +void ProcessPPS (VideoParameters *p_Vid, NALU_t *nalu) +{ + DataPartition *dp = AllocPartition(1); + pic_parameter_set_rbsp_t *pps = AllocPPS(); + + memcpy (dp->bitstream->streamBuffer, &nalu->buf[1], nalu->len-1); + dp->bitstream->code_len = dp->bitstream->bitstream_length = RBSPtoSODB (dp->bitstream->streamBuffer, nalu->len-1); + dp->bitstream->ei_flag = 0; + dp->bitstream->read_len = dp->bitstream->frame_bitoffset = 0; + InterpretPPS (p_Vid, dp, pps); + // PPSConsistencyCheck (pps); + if (p_Vid->active_pps) + { + if (pps->pic_parameter_set_id == p_Vid->active_pps->pic_parameter_set_id) + { + if(!pps_is_equal(pps, p_Vid->active_pps)) + { + //copy to next PPS; + memcpy(p_Vid->pNextPPS, p_Vid->active_pps, sizeof (pic_parameter_set_rbsp_t)); + { + if (p_Vid->dec_picture) // && p_Vid->num_dec_mb == p_Vid->PicSizeInMbs) + { + // this may only happen on slice loss + exit_picture(p_Vid, &p_Vid->dec_picture); + } + p_Vid->active_pps = NULL; + } + } + } + } + MakePPSavailable (p_Vid, pps->pic_parameter_set_id, pps); + FreePartition (dp, 1); + FreePPS (pps); +} + +/*! + ************************************************************************ + * \brief + * Updates images max values + * + ************************************************************************ + */ +static void updateMaxValue(FrameFormat *format) +{ + format->max_value[0] = (1 << format->bit_depth[0]) - 1; + format->max_value_sq[0] = format->max_value[0] * format->max_value[0]; + format->max_value[1] = (1 << format->bit_depth[1]) - 1; + format->max_value_sq[1] = format->max_value[1] * format->max_value[1]; + format->max_value[2] = (1 << format->bit_depth[2]) - 1; + format->max_value_sq[2] = format->max_value[2] * format->max_value[2]; +} + +/*! + ************************************************************************ + * \brief + * Reset format information + * + ************************************************************************ + */ +void reset_format_info(seq_parameter_set_rbsp_t *sps, VideoParameters *p_Vid, FrameFormat *source, FrameFormat *output) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + static const int SubWidthC [4]= { 1, 2, 2, 1}; + static const int SubHeightC [4]= { 1, 2, 1, 1}; + + int crop_left, crop_right; + int crop_top, crop_bottom; + + // cropping for luma + if (sps->frame_cropping_flag) + { + crop_left = SubWidthC [sps->chroma_format_idc] * sps->frame_crop_left_offset; + crop_right = SubWidthC [sps->chroma_format_idc] * sps->frame_crop_right_offset; + crop_top = SubHeightC[sps->chroma_format_idc] * ( 2 - sps->frame_mbs_only_flag ) * sps->frame_crop_top_offset; + crop_bottom = SubHeightC[sps->chroma_format_idc] * ( 2 - sps->frame_mbs_only_flag ) * sps->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + + source->width[0] = p_Vid->width - crop_left - crop_right; + source->height[0] = p_Vid->height - crop_top - crop_bottom; + + // cropping for chroma + if (sps->frame_cropping_flag) + { + crop_left = sps->frame_crop_left_offset; + crop_right = sps->frame_crop_right_offset; + crop_top = ( 2 - sps->frame_mbs_only_flag ) * sps->frame_crop_top_offset; + crop_bottom = ( 2 - sps->frame_mbs_only_flag ) * sps->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + + if ((sps->chroma_format_idc==YUV400) && p_Inp->write_uv) + { + source->width[1] = (source->width[0] >> 1); + source->width[2] = source->width[1]; + source->height[1] = (source->height[0] >> 1); + source->height[2] = source->height[1]; + } + else + { + source->width[1] = p_Vid->width_cr - crop_left - crop_right; + source->width[2] = source->width[1]; + source->height[1] = p_Vid->height_cr - crop_top - crop_bottom; + source->height[2] = source->height[1]; + } + + output->width[0] = p_Vid->width; + source->width[1] = p_Vid->width_cr; + source->width[2] = p_Vid->width_cr; + output->height[0] = p_Vid->height; + output->height[1] = p_Vid->height_cr; + output->height[2] = p_Vid->height_cr; + + source->size_cmp[0] = source->width[0] * source->height[0]; + source->size_cmp[1] = source->width[1] * source->height[1]; + source->size_cmp[2] = source->size_cmp[1]; + source->size = source->size_cmp[0] + source->size_cmp[1] + source->size_cmp[2]; + source->mb_width = source->width[0] / MB_BLOCK_SIZE; + source->mb_height = source->height[0] / MB_BLOCK_SIZE; + + // output size (excluding padding) + output->size_cmp[0] = output->width[0] * output->height[0]; + output->size_cmp[1] = output->width[1] * output->height[1]; + output->size_cmp[2] = output->size_cmp[1]; + output->size = output->size_cmp[0] + output->size_cmp[1] + output->size_cmp[2]; + output->mb_width = output->width[0] / MB_BLOCK_SIZE; + output->mb_height = output->height[0] / MB_BLOCK_SIZE; + + + output->bit_depth[0] = source->bit_depth[0] = p_Vid->bitdepth_luma; + output->bit_depth[1] = source->bit_depth[1] = p_Vid->bitdepth_chroma; + output->bit_depth[2] = source->bit_depth[2] = p_Vid->bitdepth_chroma; + output->pic_unit_size_on_disk = (imax(output->bit_depth[0], output->bit_depth[1]) > 8) ? 16 : 8; + output->pic_unit_size_shift3 = output->pic_unit_size_on_disk >> 3; + + output->frame_rate = source->frame_rate; + output->color_model = source->color_model; + output->yuv_format = source->yuv_format = (ColorFormat) sps->chroma_format_idc; + + output->auto_crop_bottom = crop_bottom; + output->auto_crop_right = crop_right; + output->auto_crop_bottom_cr = (crop_bottom * p_Vid->mb_cr_size_y) / MB_BLOCK_SIZE; + output->auto_crop_right_cr = (crop_right * p_Vid->mb_cr_size_x) / MB_BLOCK_SIZE; + + source->auto_crop_bottom = output->auto_crop_bottom; + source->auto_crop_right = output->auto_crop_right; + source->auto_crop_bottom_cr = output->auto_crop_bottom_cr; + source->auto_crop_right_cr = output->auto_crop_right_cr; + + updateMaxValue(source); + updateMaxValue(output); + + if (p_Vid->first_sps == TRUE) { + p_Vid->first_sps = FALSE; + if(!p_Inp->bDisplayDecParams) { + printf("Image Format : %dx%d (%dx%d)\n", source->width[0], source->height[0], p_Vid->width, p_Vid->height); + if (p_Vid->yuv_format == YUV400) + printf("Color Format : 4:0:0 "); + else if (p_Vid->yuv_format == YUV420) + printf("Color Format : 4:2:0 "); + else if (p_Vid->yuv_format == YUV422) + printf("Color Format : 4:2:2 "); + else + printf("Color Format : 4:4:4 "); + + printf("(%d:%d:%d)\n", source->bit_depth[0], source->bit_depth[1], source->bit_depth[2]); + printf("--------------------------------------------------------------------------\n"); + } + if (!p_Inp->silent) + { + printf("POC must = frame# or field# for SNRs to be correct\n"); + printf("--------------------------------------------------------------------------\n"); + printf(" Frame POC Pic# QP SnrY SnrU SnrV Y:U:V Time(ms)\n"); + printf("--------------------------------------------------------------------------\n"); + } + } +} + +static void setup_layer_info(VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps, LayerParameters *p_Lps) +{ + int layer_id = p_Lps->layer_id; + p_Lps->p_Vid = p_Vid; + p_Lps->p_Cps = p_Vid->p_EncodePar[layer_id]; + p_Lps->p_SPS = sps; + p_Lps->p_Dpb = p_Vid->p_Dpb_layer[layer_id]; +} + +static void set_coding_par(seq_parameter_set_rbsp_t *sps, CodingParameters *cps) +{ + // maximum vertical motion vector range in luma quarter pixel units + cps->profile_idc = sps->profile_idc; + cps->lossless_qpprime_flag = sps->lossless_qpprime_flag; + if (sps->level_idc <= 10) + { + cps->max_vmv_r = 64 * 4; + } + else if (sps->level_idc <= 20) + { + cps->max_vmv_r = 128 * 4; + } + else if (sps->level_idc <= 30) + { + cps->max_vmv_r = 256 * 4; + } + else + { + cps->max_vmv_r = 512 * 4; // 512 pixels in quarter pixels + } + + // Fidelity Range Extensions stuff (part 1) + cps->bitdepth_chroma = 0; + cps->width_cr = 0; + cps->height_cr = 0; + cps->bitdepth_luma = (short) (sps->bit_depth_luma_minus8 + 8); + cps->bitdepth_scale[0] = 1 << sps->bit_depth_luma_minus8; + if (sps->chroma_format_idc != YUV400) + { + cps->bitdepth_chroma = (short) (sps->bit_depth_chroma_minus8 + 8); + cps->bitdepth_scale[1] = 1 << sps->bit_depth_chroma_minus8; + } + + cps->max_frame_num = 1<<(sps->log2_max_frame_num_minus4+4); + cps->PicWidthInMbs = (sps->pic_width_in_mbs_minus1 +1); + cps->PicHeightInMapUnits = (sps->pic_height_in_map_units_minus1 +1); + cps->FrameHeightInMbs = ( 2 - sps->frame_mbs_only_flag ) * cps->PicHeightInMapUnits; + cps->FrameSizeInMbs = cps->PicWidthInMbs * cps->FrameHeightInMbs; + + cps->yuv_format=sps->chroma_format_idc; + cps->separate_colour_plane_flag = sps->separate_colour_plane_flag; + if( cps->separate_colour_plane_flag ) + { + cps->ChromaArrayType = 0; + } + else + { + cps->ChromaArrayType = sps->chroma_format_idc; + } + + cps->width = cps->PicWidthInMbs * MB_BLOCK_SIZE; + cps->height = cps->FrameHeightInMbs * MB_BLOCK_SIZE; + + cps->iLumaPadX = MCBUF_LUMA_PAD_X; + cps->iLumaPadY = MCBUF_LUMA_PAD_Y; + cps->iChromaPadX = MCBUF_CHROMA_PAD_X; + cps->iChromaPadY = MCBUF_CHROMA_PAD_Y; + if (sps->chroma_format_idc == YUV420) + { + cps->width_cr = (cps->width >> 1); + cps->height_cr = (cps->height >> 1); + } + else if (sps->chroma_format_idc == YUV422) + { + cps->width_cr = (cps->width >> 1); + cps->height_cr = cps->height; + cps->iChromaPadY = MCBUF_CHROMA_PAD_Y*2; + } + else if (sps->chroma_format_idc == YUV444) + { + //YUV444 + cps->width_cr = cps->width; + cps->height_cr = cps->height; + cps->iChromaPadX = cps->iLumaPadX; + cps->iChromaPadY = cps->iLumaPadY; + } + //pel bitdepth init + cps->bitdepth_luma_qp_scale = 6 * (cps->bitdepth_luma - 8); + + if(cps->bitdepth_luma > cps->bitdepth_chroma || sps->chroma_format_idc == YUV400) + cps->pic_unit_bitsize_on_disk = (cps->bitdepth_luma > 8)? 16:8; + else + cps->pic_unit_bitsize_on_disk = (cps->bitdepth_chroma > 8)? 16:8; + cps->dc_pred_value_comp[0] = 1<<(cps->bitdepth_luma - 1); + cps->max_pel_value_comp[0] = (1<bitdepth_luma) - 1; + cps->mb_size[0][0] = cps->mb_size[0][1] = MB_BLOCK_SIZE; + + if (sps->chroma_format_idc != YUV400) + { + //for chrominance part + cps->bitdepth_chroma_qp_scale = 6 * (cps->bitdepth_chroma - 8); + cps->dc_pred_value_comp[1] = (1 << (cps->bitdepth_chroma - 1)); + cps->dc_pred_value_comp[2] = cps->dc_pred_value_comp[1]; + cps->max_pel_value_comp[1] = (1 << cps->bitdepth_chroma) - 1; + cps->max_pel_value_comp[2] = (1 << cps->bitdepth_chroma) - 1; + cps->num_blk8x8_uv = (1 << sps->chroma_format_idc) & (~(0x1)); + cps->num_uv_blocks = (cps->num_blk8x8_uv >> 1); + cps->num_cdc_coeff = (cps->num_blk8x8_uv << 1); + cps->mb_size[1][0] = cps->mb_size[2][0] = cps->mb_cr_size_x = (sps->chroma_format_idc==YUV420 || sps->chroma_format_idc==YUV422)? 8 : 16; + cps->mb_size[1][1] = cps->mb_size[2][1] = cps->mb_cr_size_y = (sps->chroma_format_idc==YUV444 || sps->chroma_format_idc==YUV422)? 16 : 8; + + cps->subpel_x = cps->mb_cr_size_x == 8 ? 7 : 3; + cps->subpel_y = cps->mb_cr_size_y == 8 ? 7 : 3; + cps->shiftpel_x = cps->mb_cr_size_x == 8 ? 3 : 2; + cps->shiftpel_y = cps->mb_cr_size_y == 8 ? 3 : 2; + cps->total_scale = cps->shiftpel_x + cps->shiftpel_y; + } + else + { + cps->bitdepth_chroma_qp_scale = 0; + cps->max_pel_value_comp[1] = 0; + cps->max_pel_value_comp[2] = 0; + cps->num_blk8x8_uv = 0; + cps->num_uv_blocks = 0; + cps->num_cdc_coeff = 0; + cps->mb_size[1][0] = cps->mb_size[2][0] = cps->mb_cr_size_x = 0; + cps->mb_size[1][1] = cps->mb_size[2][1] = cps->mb_cr_size_y = 0; + cps->subpel_x = 0; + cps->subpel_y = 0; + cps->shiftpel_x = 0; + cps->shiftpel_y = 0; + cps->total_scale = 0; + } + + cps->mb_cr_size = cps->mb_cr_size_x * cps->mb_cr_size_y; + cps->mb_size_blk[0][0] = cps->mb_size_blk[0][1] = cps->mb_size[0][0] >> 2; + cps->mb_size_blk[1][0] = cps->mb_size_blk[2][0] = cps->mb_size[1][0] >> 2; + cps->mb_size_blk[1][1] = cps->mb_size_blk[2][1] = cps->mb_size[1][1] >> 2; + + cps->mb_size_shift[0][0] = cps->mb_size_shift[0][1] = CeilLog2_sf (cps->mb_size[0][0]); + cps->mb_size_shift[1][0] = cps->mb_size_shift[2][0] = CeilLog2_sf (cps->mb_size[1][0]); + cps->mb_size_shift[1][1] = cps->mb_size_shift[2][1] = CeilLog2_sf (cps->mb_size[1][1]); + + cps->rgb_output = (sps->vui_seq_parameters.matrix_coefficients==0); +} + +/*! + ************************************************************************ + * \brief + * Activate Sequence Parameter Sets + * + ************************************************************************ + */ +void activate_sps (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i; + if (p_Vid->active_sps != sps) + { + if (p_Vid->dec_picture) + { + // this may only happen on slice loss + exit_picture(p_Vid, &p_Vid->dec_picture); + } + p_Vid->active_sps = sps; + + if(p_Vid->dpb_layer_id==0 && is_BL_profile(sps->profile_idc) && !p_Vid->p_Dpb_layer[0]->init_done) + { + set_coding_par(sps, p_Vid->p_EncodePar[0]); + setup_layer_info( p_Vid, sps, p_Vid->p_LayerPar[0]); + } + else if(p_Vid->dpb_layer_id>=1 && is_EL_profile(sps->profile_idc) && !p_Vid->p_Dpb_layer[1]->init_done) + { + for(i=1;iactive_subset_sps->num_views_minus1+1;i++) + { + if( !p_Vid->p_Dpb_layer[i]->init_done ) + { + set_coding_par(sps, p_Vid->p_EncodePar[i]); + setup_layer_info(p_Vid, sps, p_Vid->p_LayerPar[i]); + } + } + //set_coding_par(sps, p_Vid->p_EncodePar[1]); + //setup_layer_info(p_Vid, sps, p_Vid->p_LayerPar[1]); + } + else if(p_Vid->dpb_layer_id==2 && is_EL_profile(sps->profile_idc) && !p_Vid->p_Dpb_layer[2]->init_done) + { + set_coding_par(sps, p_Vid->p_EncodePar[2]); + setup_layer_info(p_Vid, sps, p_Vid->p_LayerPar[2]); + } + +//to be removed in future; + set_global_coding_par(p_Vid, p_Vid->p_EncodePar[p_Vid->dpb_layer_id]); +//end; + +#if (MVC_EXTENSION_ENABLE) + //init_frext(p_Vid); + if (/*p_Vid->last_pic_width_in_mbs_minus1 != p_Vid->active_sps->pic_width_in_mbs_minus1 + || p_Vid->last_pic_height_in_map_units_minus1 != p_Vid->active_sps->pic_height_in_map_units_minus1 + || p_Vid->last_max_dec_frame_buffering != GetMaxDecFrameBuffering(p_Vid) + || */(p_Vid->last_profile_idc != p_Vid->active_sps->profile_idc && is_BL_profile(p_Vid->active_sps->profile_idc) && !p_Vid->p_Dpb_layer[0]->init_done /*&& is_BL_profile(p_Vid->last_profile_idc)*/)) + { + //init_frext(p_Vid); + init_global_buffers(p_Vid, 0); + + if (!p_Vid->no_output_of_prior_pics_flag) + { + flush_dpb(p_Vid->p_Dpb_layer[0]); + flush_dpb(p_Vid->p_Dpb_layer[1]); + } + init_dpb(p_Vid, p_Vid->p_Dpb_layer[0], 1); + } + else if(p_Vid->last_profile_idc != p_Vid->active_sps->profile_idc && ( + is_MVC_profile(p_Vid->last_profile_idc) || is_MVC_profile(p_Vid->active_sps->profile_idc) + )&& (!p_Vid->p_Dpb_layer[1]->init_done)) + { + assert(p_Vid->p_Dpb_layer[0]->init_done); + //init_frext(p_Vid); + if(p_Vid->p_Dpb_layer[0]->init_done) + { + free_dpb(p_Vid->p_Dpb_layer[0]); + init_dpb(p_Vid, p_Vid->p_Dpb_layer[0], 1); + } + + init_global_buffers(p_Vid, p_Vid->dpb_layer_id); + // for now lets re_init both buffers. Later, we should only re_init appropriate one + // Note that we seem to be doing this for every frame which seems not good. + //re_init_dpb(p_Vid, p_Vid->p_Dpb_layer[1], 2); +#if MVC_EXTENSION_ENABLE + for(i=1;iactive_subset_sps->num_views_minus1+1;i++) + { + init_global_buffers(p_Vid, i); + init_dpb(p_Vid, p_Vid->p_Dpb_layer[i], 2); + } + // init_dpb(p_Vid, p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id], 2); +#endif + //p_Vid->last_profile_idc = p_Vid->active_sps->profile_idc; + } + //p_Vid->p_Dpb_layer[0]->num_ref_frames = p_Vid->active_sps->num_ref_frames; + //p_Vid->p_Dpb_layer[1]->num_ref_frames = p_Vid->active_sps->num_ref_frames; + p_Vid->last_pic_width_in_mbs_minus1 = p_Vid->active_sps->pic_width_in_mbs_minus1; + p_Vid->last_pic_height_in_map_units_minus1 = p_Vid->active_sps->pic_height_in_map_units_minus1; + p_Vid->last_max_dec_frame_buffering = GetMaxDecFrameBuffering(p_Vid); + p_Vid->last_profile_idc = p_Vid->active_sps->profile_idc; + +#else + //init_frext(p_Vid); + init_global_buffers(p_Vid, 0); + + if (!p_Vid->no_output_of_prior_pics_flag) + { + flush_dpb(p_Vid->p_Dpb_layer[0]); + } + init_dpb(p_Vid, p_Vid->p_Dpb_layer[0], 0); + // for now lets init both buffers. Later, we should only re_init appropriate one + //init_dpb(p_Vid, p_Vid->p_Dpb_layer[0], 1); + // obviously this is not needed her but just adding it for completeness + //init_dpb(p_Vid, p_Vid->p_Dpb_layer[1], 2); +#endif + +#if (DISABLE_ERC == 0) + ercInit(p_Vid, p_Vid->width, p_Vid->height, 1); + if(p_Vid->dec_picture) + { + ercReset(p_Vid->erc_errorVar, p_Vid->PicSizeInMbs, p_Vid->PicSizeInMbs, p_Vid->dec_picture->size_x); + p_Vid->erc_mvperMB = 0; + } +#endif + } + + reset_format_info(sps, p_Vid, &p_Inp->source, &p_Inp->output); +} + +void activate_pps(VideoParameters *p_Vid, pic_parameter_set_rbsp_t *pps) +{ + if (p_Vid->active_pps != pps) + { + if (p_Vid->dec_picture) // && p_Vid->num_dec_mb == p_Vid->pi) + { + // this may only happen on slice loss + exit_picture(p_Vid, &p_Vid->dec_picture); + } + + p_Vid->active_pps = pps; + } +} + +void UseParameterSet (Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + int PicParsetId = currSlice->pic_parameter_set_id; + pic_parameter_set_rbsp_t *pps = &p_Vid->PicParSet[PicParsetId]; + seq_parameter_set_rbsp_t *sps = &p_Vid->SeqParSet[pps->seq_parameter_set_id]; + int i; + + if (pps->Valid != TRUE) + printf ("Trying to use an invalid (uninitialized) Picture Parameter Set with ID %d, expect the unexpected...\n", PicParsetId); +#if (MVC_EXTENSION_ENABLE) + if((currSlice->svc_extension_flag == -1)) + { + if (sps->Valid != TRUE) + printf ("PicParset %d references an invalid (uninitialized) Sequence Parameter Set with ID %d, expect the unexpected...\n", + PicParsetId, (int) pps->seq_parameter_set_id); + } + else + { + // Set SPS to the subset SPS parameters + p_Vid->active_subset_sps = p_Vid->SubsetSeqParSet + pps->seq_parameter_set_id; + sps = &(p_Vid->active_subset_sps->sps); + if (p_Vid->SubsetSeqParSet[pps->seq_parameter_set_id].Valid != TRUE) + printf ("PicParset %d references an invalid (uninitialized) Subset Sequence Parameter Set with ID %d, expect the unexpected...\n", + PicParsetId, (int) pps->seq_parameter_set_id); + } +#else + if (sps->Valid != TRUE) + printf ("PicParset %d references an invalid (uninitialized) Sequence Parameter Set with ID %d, expect the unexpected...\n", + PicParsetId, (int) pps->seq_parameter_set_id); +#endif + + // In theory, and with a well-designed software, the lines above + // are everything necessary. In practice, we need to patch many values + // in p_Vid-> (but no more in p_Inp-> -- these have been taken care of) + + // Set Sequence Parameter Stuff first + // printf ("Using Picture Parameter set %d and associated Sequence Parameter Set %d\n", PicParsetId, pps->seq_parameter_set_id); + if ((int) sps->pic_order_cnt_type < 0 || sps->pic_order_cnt_type > 2) // != 1 + { + printf ("invalid sps->pic_order_cnt_type = %d\n", (int) sps->pic_order_cnt_type); + error ("pic_order_cnt_type != 1", -1000); + } + + if (sps->pic_order_cnt_type == 1) + { + if(sps->num_ref_frames_in_pic_order_cnt_cycle >= MAXnum_ref_frames_in_pic_order_cnt_cycle) + { + error("num_ref_frames_in_pic_order_cnt_cycle too large",-1011); + } + } + p_Vid->dpb_layer_id = currSlice->layer_id; + activate_sps(p_Vid, sps); + activate_pps(p_Vid, pps); + + // currSlice->dp_mode is set by read_new_slice (NALU first byte available there) + if (pps->entropy_coding_mode_flag == (Boolean) CAVLC) + { + currSlice->nal_startcode_follows = uvlc_startcode_follows; + for (i=0; i<3; i++) + { + currSlice->partArr[i].readSyntaxElement = readSyntaxElement_UVLC; + } + } + else + { + currSlice->nal_startcode_follows = cabac_startcode_follows; + for (i=0; i<3; i++) + { + currSlice->partArr[i].readSyntaxElement = readSyntaxElement_CABAC; + } + } + p_Vid->type = currSlice->slice_type; +} + +#if (MVC_EXTENSION_ENABLE) +void seq_parameter_set_mvc_extension(subset_seq_parameter_set_rbsp_t *subset_sps, Bitstream *s) +{ + int i, j, num_views; + + subset_sps->num_views_minus1 = read_ue_v("num_views_minus1", s, &p_Dec->UsedBits); + num_views = 1+subset_sps->num_views_minus1; + if( num_views >0) + { + if ((subset_sps->view_id = (int*) calloc(num_views, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->view_id"); + if ((subset_sps->num_anchor_refs_l0 = (int*) calloc(num_views, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->num_anchor_refs_l0"); + if ((subset_sps->num_anchor_refs_l1 = (int*) calloc(num_views, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->num_anchor_refs_l1"); + if ((subset_sps->anchor_ref_l0 = (int**) calloc(num_views, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->anchor_ref_l0"); + if ((subset_sps->anchor_ref_l1 = (int**) calloc(num_views, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->anchor_ref_l1"); + if ((subset_sps->num_non_anchor_refs_l0 = (int*) calloc(num_views, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->num_non_anchor_refs_l0"); + if ((subset_sps->num_non_anchor_refs_l1 = (int*) calloc(num_views, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->num_non_anchor_refs_l1"); + if ((subset_sps->non_anchor_ref_l0 = (int**) calloc(num_views, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->non_anchor_ref_l0"); + if ((subset_sps->non_anchor_ref_l1 = (int**) calloc(num_views, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->non_anchor_ref_l1"); + } + for(i=0; iview_id[i] = read_ue_v("view_id", s, &p_Dec->UsedBits); + } + for(i=1; inum_anchor_refs_l0[i] = read_ue_v("num_anchor_refs_l0", s, &p_Dec->UsedBits); + if(subset_sps->num_anchor_refs_l0[i]>0) + { + if ((subset_sps->anchor_ref_l0[i] = (int*) calloc(subset_sps->num_anchor_refs_l0[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->anchor_ref_l0[i]"); + for(j=0; jnum_anchor_refs_l0[i]; j++) + subset_sps->anchor_ref_l0[i][j] = read_ue_v("anchor_ref_l0", s, &p_Dec->UsedBits); + } + + subset_sps->num_anchor_refs_l1[i] = read_ue_v("num_anchor_refs_l1", s, &p_Dec->UsedBits); + if(subset_sps->num_anchor_refs_l1[i]>0) + { + if ((subset_sps->anchor_ref_l1[i] = (int*) calloc(subset_sps->num_anchor_refs_l1[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->anchor_ref_l1[i]"); + for(j=0; jnum_anchor_refs_l1[i]; j++) + subset_sps->anchor_ref_l1[i][j] = read_ue_v("anchor_ref_l1", s, &p_Dec->UsedBits); + } + } + for(i=1; inum_non_anchor_refs_l0[i] = read_ue_v("num_non_anchor_refs_l0", s, &p_Dec->UsedBits); + if(subset_sps->num_non_anchor_refs_l0[i]>0) + { + if ((subset_sps->non_anchor_ref_l0[i] = (int*) calloc(subset_sps->num_non_anchor_refs_l0[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->non_anchor_ref_l0[i]"); + for(j=0; jnum_non_anchor_refs_l0[i]; j++) + subset_sps->non_anchor_ref_l0[i][j] = read_ue_v("non_anchor_ref_l0", s, &p_Dec->UsedBits); + } + subset_sps->num_non_anchor_refs_l1[i] = read_ue_v("num_non_anchor_refs_l1", s, &p_Dec->UsedBits); + if(subset_sps->num_non_anchor_refs_l1[i]>0) + { + if ((subset_sps->non_anchor_ref_l1[i] = (int*) calloc(subset_sps->num_non_anchor_refs_l1[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->non_anchor_ref_l1[i]"); + for(j=0; jnum_non_anchor_refs_l1[i]; j++) + subset_sps->non_anchor_ref_l1[i][j] = read_ue_v("non_anchor_ref_l1", s, &p_Dec->UsedBits); + } + } + subset_sps->num_level_values_signalled_minus1 = read_ue_v("num_level_values_signalled_minus1", s, &p_Dec->UsedBits); + if(subset_sps->num_level_values_signalled_minus1 >=0) + { + i = 1+ subset_sps->num_level_values_signalled_minus1; + if ((subset_sps->level_idc = (int*) calloc(i, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->level_idc"); + if ((subset_sps->num_applicable_ops_minus1 = (int*) calloc(i, sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->num_applicable_ops_minus1"); + if ((subset_sps->applicable_op_temporal_id = (int**) calloc(i, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_temporal_id"); + if ((subset_sps->applicable_op_num_target_views_minus1 = (int**) calloc(i, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_num_target_views_minus1"); + if ((subset_sps->applicable_op_target_view_id = (int***) calloc(i, sizeof(int**))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_target_view_id"); + if ((subset_sps->applicable_op_num_views_minus1 = (int**) calloc(i, sizeof(int*))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_num_views_minus1"); + } + for(i=0; i<=subset_sps->num_level_values_signalled_minus1; i++) + { + subset_sps->level_idc[i] = read_u_v(8, "level_idc", s, &p_Dec->UsedBits); + subset_sps->num_applicable_ops_minus1[i] = read_ue_v("num_applicable_ops_minus1", s, &p_Dec->UsedBits); + if(subset_sps->num_applicable_ops_minus1[i]>=0) + { + if ((subset_sps->applicable_op_temporal_id[i] = (int*) calloc(1+subset_sps->num_applicable_ops_minus1[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_temporal_id[i]"); + if ((subset_sps->applicable_op_num_target_views_minus1[i] = (int*) calloc(1+subset_sps->num_applicable_ops_minus1[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_num_target_views_minus1[i]"); + if ((subset_sps->applicable_op_target_view_id[i] = (int**) calloc(1+subset_sps->num_applicable_ops_minus1[i], sizeof(int *))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_target_view_id[i]"); + if ((subset_sps->applicable_op_num_views_minus1[i] = (int*) calloc(1+subset_sps->num_applicable_ops_minus1[i], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_num_views_minus1[i]"); + + for(j=0; j<=subset_sps->num_applicable_ops_minus1[i]; j++) + { + int k; + subset_sps->applicable_op_temporal_id[i][j] = read_u_v(3, "applicable_op_temporal_id", s, &p_Dec->UsedBits); + subset_sps->applicable_op_num_target_views_minus1[i][j] = read_ue_v("applicable_op_num_target_views_minus1", s, &p_Dec->UsedBits); + if(subset_sps->applicable_op_num_target_views_minus1[i][j]>=0) + { + if ((subset_sps->applicable_op_target_view_id[i][j] = (int*) calloc(1+subset_sps->applicable_op_num_target_views_minus1[i][j], sizeof(int))) == NULL) + no_mem_exit("init_subset_seq_parameter_set: subset_sps->applicable_op_target_view_id[i][j]"); + for(k = 0; k <= subset_sps->applicable_op_num_target_views_minus1[i][j]; k++) + subset_sps->applicable_op_target_view_id[i][j][k] = read_ue_v("applicable_op_target_view_id", s, &p_Dec->UsedBits); + } + subset_sps->applicable_op_num_views_minus1[i][j] = read_ue_v("applicable_op_num_views_minus1", s, &p_Dec->UsedBits); + } + } + } +} + +int MemAlloc1D(void** ppBuf, int iEleSize, int iNum) +{ + if(iEleSize*iNum <=0) + return 1; + + *ppBuf = calloc(iNum, iEleSize); + return (*ppBuf == NULL); +} + +void hrd_parameters(MVCVUI_t *pMVCVUI, Bitstream *s) +{ + int i; + + pMVCVUI->cpb_cnt_minus1 = (char) read_ue_v("cpb_cnt_minus1", s, &p_Dec->UsedBits); + assert(pMVCVUI->cpb_cnt_minus1<=31); + pMVCVUI->bit_rate_scale = (char) read_u_v(4, "bit_rate_scale", s, &p_Dec->UsedBits); + pMVCVUI->cpb_size_scale = (char) read_u_v(4, "cpb_size_scale", s, &p_Dec->UsedBits); + for(i=0; i<=pMVCVUI->cpb_cnt_minus1; i++) + { + pMVCVUI->bit_rate_value_minus1[i] = read_ue_v("bit_rate_value_minus1" , s, &p_Dec->UsedBits); + pMVCVUI->cpb_size_value_minus1[i] = read_ue_v("cpb_size_value_minus1" , s, &p_Dec->UsedBits); + pMVCVUI->cbr_flag[i] = (char) read_u_1 ("cbr_flag" , s, &p_Dec->UsedBits); + } + pMVCVUI->initial_cpb_removal_delay_length_minus1 = (char) read_u_v(5, "initial_cpb_removal_delay_length_minus1", s, &p_Dec->UsedBits); + pMVCVUI->cpb_removal_delay_length_minus1 = (char) read_u_v(5, "cpb_removal_delay_length_minus1", s, &p_Dec->UsedBits); + pMVCVUI->dpb_output_delay_length_minus1 = (char) read_u_v(5, "dpb_output_delay_length_minus1", s, &p_Dec->UsedBits); + pMVCVUI->time_offset_length = (char) read_u_v(5, "time_offset_length", s, &p_Dec->UsedBits); + +} + +void mvc_vui_parameters_extension(MVCVUI_t *pMVCVUI, Bitstream *s) +{ + int i, j, iNumOps; + + pMVCVUI->num_ops_minus1 = read_ue_v("vui_mvc_num_ops_minus1", s, &p_Dec->UsedBits); + iNumOps = 1+ pMVCVUI->num_ops_minus1; + if(iNumOps > 0) + { + MemAlloc1D((void **)&(pMVCVUI->temporal_id), sizeof(pMVCVUI->temporal_id[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->num_target_output_views_minus1), sizeof(pMVCVUI->num_target_output_views_minus1[0]), iNumOps); + if ((pMVCVUI->view_id = (int**) calloc(iNumOps, sizeof(int*))) == NULL) + no_mem_exit("mvc_vui_parameters_extension: pMVCVUI->view_id"); + MemAlloc1D((void **)&(pMVCVUI->timing_info_present_flag), sizeof(pMVCVUI->timing_info_present_flag[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->num_units_in_tick), sizeof(pMVCVUI->num_units_in_tick[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->time_scale), sizeof(pMVCVUI->time_scale[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->fixed_frame_rate_flag), sizeof(pMVCVUI->fixed_frame_rate_flag[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->nal_hrd_parameters_present_flag), sizeof(pMVCVUI->nal_hrd_parameters_present_flag[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->vcl_hrd_parameters_present_flag), sizeof(pMVCVUI->vcl_hrd_parameters_present_flag[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->low_delay_hrd_flag), sizeof(pMVCVUI->low_delay_hrd_flag[0]), iNumOps); + MemAlloc1D((void **)&(pMVCVUI->pic_struct_present_flag), sizeof(pMVCVUI->pic_struct_present_flag[0]), iNumOps); + + for(i=0; itemporal_id[i] = (char) read_u_v(3, "vui_mvc_temporal_id", s, &p_Dec->UsedBits); + pMVCVUI->num_target_output_views_minus1[i] = read_ue_v("vui_mvc_num_target_output_views_minus1", s, &p_Dec->UsedBits); + if(pMVCVUI->num_target_output_views_minus1[i] >= 0) + MemAlloc1D((void **)&(pMVCVUI->view_id[i]), sizeof(pMVCVUI->view_id[0][0]), pMVCVUI->num_target_output_views_minus1[i]+1); + for(j=0; j<=pMVCVUI->num_target_output_views_minus1[i]; j++) + pMVCVUI->view_id[i][j] = read_ue_v("vui_mvc_view_id", s, &p_Dec->UsedBits); + pMVCVUI->timing_info_present_flag[i] = (char) read_u_1("vui_mvc_timing_info_present_flag", s, &p_Dec->UsedBits); + if(pMVCVUI->timing_info_present_flag[i]) + { + pMVCVUI->num_units_in_tick[i] = read_u_v(32, "vui_mvc_num_units_in_tick", s, &p_Dec->UsedBits); + pMVCVUI->time_scale[i] = read_u_v(32, "vui_mvc_time_scale" , s, &p_Dec->UsedBits); + pMVCVUI->fixed_frame_rate_flag[i] = (char) read_u_1("vui_mvc_fixed_frame_rate_flag", s, &p_Dec->UsedBits); + } + pMVCVUI->nal_hrd_parameters_present_flag[i] = (char) read_u_1("vui_mvc_nal_hrd_parameters_present_flag", s, &p_Dec->UsedBits); + if(pMVCVUI->nal_hrd_parameters_present_flag[i]) + hrd_parameters(pMVCVUI, s); + pMVCVUI->vcl_hrd_parameters_present_flag[i] = (char) read_u_1("vcl_hrd_parameters_present_flag", s, &p_Dec->UsedBits); + if(pMVCVUI->vcl_hrd_parameters_present_flag[i]) + hrd_parameters(pMVCVUI, s); + if(pMVCVUI->nal_hrd_parameters_present_flag[i]||pMVCVUI->vcl_hrd_parameters_present_flag[i]) + pMVCVUI->low_delay_hrd_flag[i] = (char) read_u_1("vui_mvc_low_delay_hrd_flag", s, &p_Dec->UsedBits); + pMVCVUI->pic_struct_present_flag[i] = (char) read_u_1("vui_mvc_pic_struct_present_flag", s, &p_Dec->UsedBits); + } + } +} + +void init_subset_sps_list(subset_seq_parameter_set_rbsp_t *subset_sps_list, int iSize) +{ + int i; + memset(subset_sps_list, 0, iSize*sizeof(subset_sps_list[0])); + for(i=0; inum_views_minus1>=0) + { + subset_sps->sps.seq_parameter_set_id = (unsigned int) -1; + + free_pointer(subset_sps->view_id); + for(i=0; i<=subset_sps->num_views_minus1; i++) + { + free_pointer(subset_sps->anchor_ref_l0[i]); + free_pointer(subset_sps->anchor_ref_l1[i]); + } + free_pointer(subset_sps->anchor_ref_l0); + free_pointer(subset_sps->anchor_ref_l1); + free_pointer(subset_sps->num_anchor_refs_l0); + free_pointer(subset_sps->num_anchor_refs_l1); + + for(i=0; i<=subset_sps->num_views_minus1; i++) + { + free_pointer(subset_sps->non_anchor_ref_l0[i]); + free_pointer(subset_sps->non_anchor_ref_l1[i]); + } + free_pointer(subset_sps->non_anchor_ref_l0); + free_pointer(subset_sps->non_anchor_ref_l1); + free_pointer(subset_sps->num_non_anchor_refs_l0); + free_pointer(subset_sps->num_non_anchor_refs_l1); + + if(subset_sps->num_level_values_signalled_minus1 >= 0) + { + free_pointer(subset_sps->level_idc); + for(i=0; i<=subset_sps->num_level_values_signalled_minus1; i++) + { + for(j=0; j<=subset_sps->num_applicable_ops_minus1[i]; j++) + { + free_pointer(subset_sps->applicable_op_target_view_id[i][j]); + } + free_pointer(subset_sps->applicable_op_target_view_id[i]); + free_pointer(subset_sps->applicable_op_temporal_id[i]); + free_pointer(subset_sps->applicable_op_num_target_views_minus1[i]); + free_pointer(subset_sps->applicable_op_num_views_minus1[i]); + } + free_pointer(subset_sps->applicable_op_target_view_id); + free_pointer(subset_sps->applicable_op_temporal_id); + free_pointer(subset_sps->applicable_op_num_target_views_minus1); + free_pointer(subset_sps->applicable_op_num_views_minus1); + free_pointer(subset_sps->num_applicable_ops_minus1); + + subset_sps->num_level_values_signalled_minus1 = -1; + } + + //end; + subset_sps->num_views_minus1 = -1; + } + + if(subset_sps && subset_sps->mvc_vui_parameters_present_flag) + { + MVCVUI_t *pMVCVUI = &(subset_sps->MVCVUIParams); + if(pMVCVUI->num_ops_minus1 >=0) + { + free_pointer(pMVCVUI->temporal_id); + free_pointer(pMVCVUI->num_target_output_views_minus1); + for(i=0; i<=pMVCVUI->num_ops_minus1; i++) + free_pointer(pMVCVUI->view_id[i]); + free_pointer(pMVCVUI->view_id); + free_pointer(pMVCVUI->timing_info_present_flag); + free_pointer(pMVCVUI->num_units_in_tick); + free_pointer(pMVCVUI->time_scale); + free_pointer(pMVCVUI->fixed_frame_rate_flag); + free_pointer(pMVCVUI->nal_hrd_parameters_present_flag); + free_pointer(pMVCVUI->vcl_hrd_parameters_present_flag); + free_pointer(pMVCVUI->low_delay_hrd_flag); + free_pointer(pMVCVUI->pic_struct_present_flag); + + pMVCVUI->num_ops_minus1 = -1; + } + subset_sps->mvc_vui_parameters_present_flag = 0; + } +} + +int GetBaseViewId(VideoParameters *p_Vid, subset_seq_parameter_set_rbsp_t **subset_sps) +{ + subset_seq_parameter_set_rbsp_t *curr_subset_sps; + int i, iBaseViewId=0; //-1; + + *subset_sps = NULL; + curr_subset_sps = p_Vid->SubsetSeqParSet; + for(i=0; inum_views_minus1>=0 && curr_subset_sps->sps.Valid) // && curr_subset_sps->sps.seq_parameter_set_id < MAXSPS) + { + iBaseViewId = curr_subset_sps->view_id[BASE_VIEW_IDX]; + break; + } + curr_subset_sps++; + } + + if(ipic_width_in_mbs_minus1 + 1) * (sps->pic_height_in_map_units_minus1 + 1) * (sps->frame_mbs_only_flag?1:2) * 384; + + int size = 0; + + switch (sps->level_idc) + { + case 9: + size = 152064; + break; + case 10: + size = 152064; + break; + case 11: + if (!is_FREXT_profile(sps->profile_idc) && (sps->constrained_set3_flag == 1)) + size = 152064; + else + size = 345600; + break; + case 12: + size = 912384; + break; + case 13: + size = 912384; + break; + case 20: + size = 912384; + break; + case 21: + size = 1824768; + break; + case 22: + size = 3110400; + break; + case 30: + size = 3110400; + break; + case 31: + size = 6912000; + break; + case 32: + size = 7864320; + break; + case 40: + size = 12582912; + break; + case 41: + size = 12582912; + break; + case 42: + size = 13369344; + break; + case 50: + size = 42393600; + break; + case 51: + size = 70778880; + break; + default: + error ("undefined level", 500); + break; + } + + size /= pic_size; + size = imin( size, 16); + sps->max_dec_frame_buffering = size; +} +#endif diff --git a/ldecod/src/quant.c b/ldecod/src/quant.c new file mode 100644 index 0000000..5fa80e2 --- /dev/null +++ b/ldecod/src/quant.c @@ -0,0 +1,353 @@ + +/*! + *********************************************************************** + * \file + * quant.c + * + * \brief + * Quantization functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * + *********************************************************************** + */ + +#include "contributors.h" + +#include "global.h" +#include "memalloc.h" +#include "block.h" +#include "image.h" +#include "mb_access.h" +#include "transform.h" +#include "quant.h" + +int quant_intra_default[16] = { + 6,13,20,28, + 13,20,28,32, + 20,28,32,37, + 28,32,37,42 +}; + +int quant_inter_default[16] = { + 10,14,20,24, + 14,20,24,27, + 20,24,27,30, + 24,27,30,34 +}; + +int quant8_intra_default[64] = { + 6,10,13,16,18,23,25,27, +10,11,16,18,23,25,27,29, +13,16,18,23,25,27,29,31, +16,18,23,25,27,29,31,33, +18,23,25,27,29,31,33,36, +23,25,27,29,31,33,36,38, +25,27,29,31,33,36,38,40, +27,29,31,33,36,38,40,42 +}; + +int quant8_inter_default[64] = { + 9,13,15,17,19,21,22,24, +13,13,17,19,21,22,24,25, +15,17,19,21,22,24,25,27, +17,19,21,22,24,25,27,28, +19,21,22,24,25,27,28,30, +21,22,24,25,27,28,30,32, +22,24,25,27,28,30,32,33, +24,25,27,28,30,32,33,35 +}; + +int quant_org[16] = { //to be use if no q matrix is chosen +16,16,16,16, +16,16,16,16, +16,16,16,16, +16,16,16,16 +}; + +int quant8_org[64] = { //to be use if no q matrix is chosen +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16 +}; + +/*! + *********************************************************************** + * \brief + * Initiate quantization process arrays + *********************************************************************** + */ +void init_qp_process(CodingParameters *cps) +{ + int bitdepth_qp_scale = imax(cps->bitdepth_luma_qp_scale, cps->bitdepth_chroma_qp_scale); + int i; + + // We should allocate memory outside of this process since maybe we will have a change of SPS + // and we may need to recreate these. Currently should only support same bitdepth + if (cps->qp_per_matrix == NULL) + if ((cps->qp_per_matrix = (int*)malloc((MAX_QP + 1 + bitdepth_qp_scale)*sizeof(int))) == NULL) + no_mem_exit("init_qp_process: cps->qp_per_matrix"); + + if (cps->qp_rem_matrix == NULL) + if ((cps->qp_rem_matrix = (int*)malloc((MAX_QP + 1 + bitdepth_qp_scale)*sizeof(int))) == NULL) + no_mem_exit("init_qp_process: cps->qp_rem_matrix"); + + for (i = 0; i < MAX_QP + bitdepth_qp_scale + 1; i++) + { + cps->qp_per_matrix[i] = i / 6; + cps->qp_rem_matrix[i] = i % 6; + } +} + +void free_qp_matrices(CodingParameters *cps) +{ + if (cps->qp_per_matrix != NULL) + { + free (cps->qp_per_matrix); + cps->qp_per_matrix = NULL; + } + + if (cps->qp_rem_matrix != NULL) + { + free (cps->qp_rem_matrix); + cps->qp_rem_matrix = NULL; + } +} + +/*! + ************************************************************************ + * \brief + * For mapping the q-matrix to the active id and calculate quantisation values + * + * \param currSlice + * Slice pointer + * \param pps + * Picture parameter set + * \param sps + * Sequence parameter set + * + ************************************************************************ + */ +void assign_quant_params(Slice *currSlice) +{ + seq_parameter_set_rbsp_t* sps = currSlice->active_sps; + pic_parameter_set_rbsp_t* pps = currSlice->active_pps; + int i; + int n_ScalingList; + + if(!pps->pic_scaling_matrix_present_flag && !sps->seq_scaling_matrix_present_flag) + { + for(i=0; i<12; i++) + currSlice->qmatrix[i] = (i < 6) ? quant_org : quant8_org; + } + else + { + n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12; + if(sps->seq_scaling_matrix_present_flag) // check sps first + { + for(i=0; iseq_scaling_list_present_flag[i]) // fall-back rule A + { + if(i==0) + currSlice->qmatrix[i] = quant_intra_default; + else if(i==3) + currSlice->qmatrix[i] = quant_inter_default; + else + currSlice->qmatrix[i] = currSlice->qmatrix[i-1]; + } + else + { + if(sps->UseDefaultScalingMatrix4x4Flag[i]) + currSlice->qmatrix[i] = (i<3) ? quant_intra_default : quant_inter_default; + else + currSlice->qmatrix[i] = sps->ScalingList4x4[i]; + } + } + else + { + if(!sps->seq_scaling_list_present_flag[i]) // fall-back rule A + { + if(i==6) + currSlice->qmatrix[i] = quant8_intra_default; + else if(i==7) + currSlice->qmatrix[i] = quant8_inter_default; + else + currSlice->qmatrix[i] = currSlice->qmatrix[i-2]; + } + else + { + if(sps->UseDefaultScalingMatrix8x8Flag[i-6]) + currSlice->qmatrix[i] = (i==6 || i==8 || i==10) ? quant8_intra_default:quant8_inter_default; + else + currSlice->qmatrix[i] = sps->ScalingList8x8[i-6]; + } + } + } + } + + if(pps->pic_scaling_matrix_present_flag) // then check pps + { + for(i=0; ipic_scaling_list_present_flag[i]) // fall-back rule B + { + if (i==0) + { + if(!sps->seq_scaling_matrix_present_flag) + currSlice->qmatrix[i] = quant_intra_default; + } + else if (i==3) + { + if(!sps->seq_scaling_matrix_present_flag) + currSlice->qmatrix[i] = quant_inter_default; + } + else + currSlice->qmatrix[i] = currSlice->qmatrix[i-1]; + } + else + { + if(pps->UseDefaultScalingMatrix4x4Flag[i]) + currSlice->qmatrix[i] = (i<3) ? quant_intra_default:quant_inter_default; + else + currSlice->qmatrix[i] = pps->ScalingList4x4[i]; + } + } + else + { + if(!pps->pic_scaling_list_present_flag[i]) // fall-back rule B + { + if (i==6) + { + if(!sps->seq_scaling_matrix_present_flag) + currSlice->qmatrix[i] = quant8_intra_default; + } + else if(i==7) + { + if(!sps->seq_scaling_matrix_present_flag) + currSlice->qmatrix[i] = quant8_inter_default; + } + else + currSlice->qmatrix[i] = currSlice->qmatrix[i-2]; + } + else + { + if(pps->UseDefaultScalingMatrix8x8Flag[i-6]) + currSlice->qmatrix[i] = (i==6 || i==8 || i==10) ? quant8_intra_default:quant8_inter_default; + else + currSlice->qmatrix[i] = pps->ScalingList8x8[i-6]; + } + } + } + } + } + + CalculateQuant4x4Param(currSlice); + if(pps->transform_8x8_mode_flag) + CalculateQuant8x8Param(currSlice); +} + +static void set_dequant4x4(int (*InvLevelScale4x4)[4], const int (*dequant)[4], int *qmatrix) +{ + int j; + for(j=0; j<4; j++) + { + *(*InvLevelScale4x4 ) = *(*dequant ) * *qmatrix++; + *(*InvLevelScale4x4 + 1) = *(*dequant + 1) * *qmatrix++; + *(*InvLevelScale4x4 + 2) = *(*dequant + 2) * *qmatrix++; + *(*InvLevelScale4x4++ + 3) = *(*dequant++ + 3) * *qmatrix++; + } +} + +static void set_dequant8x8(int (*InvLevelScale8x8)[8], const int (*dequant)[8], int *qmatrix) +{ + int j; + for(j = 0; j < 8; j++) + { + *(*InvLevelScale8x8 ) = *(*dequant ) * *qmatrix++; + *(*InvLevelScale8x8 + 1) = *(*dequant + 1) * *qmatrix++; + *(*InvLevelScale8x8 + 2) = *(*dequant + 2) * *qmatrix++; + *(*InvLevelScale8x8 + 3) = *(*dequant + 3) * *qmatrix++; + *(*InvLevelScale8x8 + 4) = *(*dequant + 4) * *qmatrix++; + *(*InvLevelScale8x8 + 5) = *(*dequant + 5) * *qmatrix++; + *(*InvLevelScale8x8 + 6) = *(*dequant + 6) * *qmatrix++; + *(*InvLevelScale8x8++ + 7) = *(*dequant++ + 7) * *qmatrix++; + } +} + +/*! + ************************************************************************ + * \brief + * For calculating the quantisation values at frame level + * + ************************************************************************ + */ +void CalculateQuant4x4Param(Slice *currSlice) +{ + int k; + const int (*p_dequant_coef)[4][4] = dequant_coef; + int (*InvLevelScale4x4_Intra_0)[4][4] = currSlice->InvLevelScale4x4_Intra[0]; + int (*InvLevelScale4x4_Intra_1)[4][4] = currSlice->InvLevelScale4x4_Intra[1]; + int (*InvLevelScale4x4_Intra_2)[4][4] = currSlice->InvLevelScale4x4_Intra[2]; + int (*InvLevelScale4x4_Inter_0)[4][4] = currSlice->InvLevelScale4x4_Inter[0]; + int (*InvLevelScale4x4_Inter_1)[4][4] = currSlice->InvLevelScale4x4_Inter[1]; + int (*InvLevelScale4x4_Inter_2)[4][4] = currSlice->InvLevelScale4x4_Inter[2]; + + + for(k=0; k<6; k++) + { + set_dequant4x4(*InvLevelScale4x4_Intra_0++, *p_dequant_coef , currSlice->qmatrix[0]); + set_dequant4x4(*InvLevelScale4x4_Intra_1++, *p_dequant_coef , currSlice->qmatrix[1]); + set_dequant4x4(*InvLevelScale4x4_Intra_2++, *p_dequant_coef , currSlice->qmatrix[2]); + set_dequant4x4(*InvLevelScale4x4_Inter_0++, *p_dequant_coef , currSlice->qmatrix[3]); + set_dequant4x4(*InvLevelScale4x4_Inter_1++, *p_dequant_coef , currSlice->qmatrix[4]); + set_dequant4x4(*InvLevelScale4x4_Inter_2++, *p_dequant_coef++, currSlice->qmatrix[5]); + } +} + +/*! + ************************************************************************ + * \brief + * Calculate the quantisation and inverse quantisation parameters + * + ************************************************************************ + */ +void CalculateQuant8x8Param(Slice *currSlice) +{ + int k; + const int (*p_dequant_coef)[8][8] = dequant_coef8; + int (*InvLevelScale8x8_Intra_0)[8][8] = currSlice->InvLevelScale8x8_Intra[0]; + int (*InvLevelScale8x8_Intra_1)[8][8] = currSlice->InvLevelScale8x8_Intra[1]; + int (*InvLevelScale8x8_Intra_2)[8][8] = currSlice->InvLevelScale8x8_Intra[2]; + int (*InvLevelScale8x8_Inter_0)[8][8] = currSlice->InvLevelScale8x8_Inter[0]; + int (*InvLevelScale8x8_Inter_1)[8][8] = currSlice->InvLevelScale8x8_Inter[1]; + int (*InvLevelScale8x8_Inter_2)[8][8] = currSlice->InvLevelScale8x8_Inter[2]; + + for(k=0; k<6; k++) + { + set_dequant8x8(*InvLevelScale8x8_Intra_0++, *p_dequant_coef , currSlice->qmatrix[6]); + set_dequant8x8(*InvLevelScale8x8_Inter_0++, *p_dequant_coef++, currSlice->qmatrix[7]); + } + + p_dequant_coef = dequant_coef8; + if( currSlice->active_sps->chroma_format_idc == 3 ) // 4:4:4 + { + for(k=0; k<6; k++) + { + set_dequant8x8(*InvLevelScale8x8_Intra_1++, *p_dequant_coef , currSlice->qmatrix[8]); + set_dequant8x8(*InvLevelScale8x8_Inter_1++, *p_dequant_coef , currSlice->qmatrix[9]); + set_dequant8x8(*InvLevelScale8x8_Intra_2++, *p_dequant_coef , currSlice->qmatrix[10]); + set_dequant8x8(*InvLevelScale8x8_Inter_2++, *p_dequant_coef++, currSlice->qmatrix[11]); + } + } +} diff --git a/ldecod/src/read_comp_cabac.c b/ldecod/src/read_comp_cabac.c new file mode 100644 index 0000000..de3bdc6 --- /dev/null +++ b/ldecod/src/read_comp_cabac.c @@ -0,0 +1,1942 @@ +/*! + *********************************************************************** + * \file read_comp_cabac.c + * + * \brief + * Read Coefficient Components + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + *********************************************************************** +*/ + +#include "contributors.h" + +#include "global.h" +#include "elements.h" +#include "macroblock.h" +#include "cabac.h" +#include "vlc.h" +#include "transform.h" + +#if TRACE +#define TRACE_STRING(s) strncpy(currSE.tracestring, s, TRACESTRING_SIZE) +#define TRACE_DECBITS(i) dectracebitcnt(1) +#define TRACE_printf(s) sprintf(type, "%s", s); +#define TRACE_STRING_P(s) strncpy(currSE->tracestring, s, TRACESTRING_SIZE) +#else +#define TRACE_STRING(s) +#define TRACE_DECBITS(i) +#define TRACE_printf(s) +#define TRACE_STRING_P(s) +#endif + +extern void check_dp_neighbors (Macroblock *currMB); +extern void read_delta_quant (SyntaxElement *currSE, DataPartition *dP, Macroblock *currMB, const byte *partMap, int type); + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 4x4 blocks in a SMB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_4x4_smb_CABAC (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl, int block_y, int block_x, int start_scan, int64 *cbp_blk) +{ + int i,j,k; + int i0, j0; + int level = 1; + DataPartition *dP; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + int **cof = currSlice->cof[pl]; + + for (j = block_y; j < block_y + BLOCK_SIZE_8x8; j += 4) + { + currMB->subblock_y = j; // position for coeff_count ctx + + for (i = block_x; i < block_x + BLOCK_SIZE_8x8; i += 4) + { + currMB->subblock_x = i; // position for coeff_count ctx + pos_scan_4x4 = pos_scan4x4[start_scan]; + level = 1; + + if (start_scan == 0) + { + /* + * make distinction between INTRA and INTER coded + * luminance coefficients + */ + currSE->type = (currMB->is_intra_block ? SE_LUM_DC_INTRA : SE_LUM_DC_INTER); + dP = &(currSlice->partArr[partMap[currSE->type]]); + if (dP->bitstream->ei_flag) + currSE->mapping = linfo_levrun_inter; + else + currSE->reading = readRunLevel_CABAC; + +#if TRACE + if (pl == PLANE_Y) + sprintf(currSE->tracestring, "Luma sng "); + else if (pl == PLANE_U) + sprintf(currSE->tracestring, "Cb sng "); + else + sprintf(currSE->tracestring, "Cr sng "); +#endif + + dP->readSyntaxElement(currMB, currSE, dP); + level = currSE->value1; + + if (level != 0) /* leave if level == 0 */ + { + pos_scan_4x4 += 2 * currSE->value2; + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + *cbp_blk |= i64_power2(j + (i >> 2)) ; + //cof[j + j0][i + i0]= rshift_rnd_sf((level * InvLevelScale4x4[j0][i0]) << qp_per, 4); + cof[j + j0][i + i0]= level; + //currSlice->fcf[pl][j + j0][i + i0]= level; + } + } + + if (level != 0) + { + // make distinction between INTRA and INTER coded luminance coefficients + currSE->type = (currMB->is_intra_block ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER); + dP = &(currSlice->partArr[partMap[currSE->type]]); + + if (dP->bitstream->ei_flag) + currSE->mapping = linfo_levrun_inter; + else + currSE->reading = readRunLevel_CABAC; + + for(k = 1; (k < 17) && (level != 0); ++k) + { +#if TRACE + if (pl == PLANE_Y) + sprintf(currSE->tracestring, "Luma sng "); + else if (pl == PLANE_U) + sprintf(currSE->tracestring, "Cb sng "); + else + sprintf(currSE->tracestring, "Cr sng "); +#endif + + dP->readSyntaxElement(currMB, currSE, dP); + level = currSE->value1; + + if (level != 0) /* leave if level == 0 */ + { + pos_scan_4x4 += 2 * currSE->value2; + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + cof[j + j0][i + i0] = level; + //currSlice->fcf[pl][j + j0][i + i0]= level; + } + } + } + } + } +} + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of all 4x4 blocks in a MB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_4x4_CABAC (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl, int (*InvLevelScale4x4)[4], int qp_per, int cbp) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int start_scan = IS_I16MB (currMB)? 1 : 0; + int block_y, block_x; + int i, j; + int64 *cbp_blk = &currMB->s_cbp[pl].blk; + + if( pl == PLANE_Y || (p_Vid->separate_colour_plane_flag != 0) ) + currSE->context = (IS_I16MB(currMB) ? LUMA_16AC: LUMA_4x4); + else if (pl == PLANE_U) + currSE->context = (IS_I16MB(currMB) ? CB_16AC: CB_4x4); + else + currSE->context = (IS_I16MB(currMB) ? CR_16AC: CR_4x4); + + for (block_y = 0; block_y < MB_BLOCK_SIZE; block_y += BLOCK_SIZE_8x8) /* all modes */ + { + int **cof = &currSlice->cof[pl][block_y]; + for (block_x = 0; block_x < MB_BLOCK_SIZE; block_x += BLOCK_SIZE_8x8) + { + if (cbp & (1 << ((block_y >> 2) + (block_x >> 3)))) // are there any coeff in current block at all + { + read_comp_coeff_4x4_smb_CABAC (currMB, currSE, pl, block_y, block_x, start_scan, cbp_blk); + + if (start_scan == 0) + { + for (j = 0; j < BLOCK_SIZE_8x8; ++j) + { + int *coef = &cof[j][block_x]; + int jj = j & 0x03; + for (i = 0; i < BLOCK_SIZE_8x8; i+=4) + { + if (*coef) + *coef = rshift_rnd_sf((*coef * InvLevelScale4x4[jj][0]) << qp_per, 4); + coef++; + if (*coef) + *coef = rshift_rnd_sf((*coef * InvLevelScale4x4[jj][1]) << qp_per, 4); + coef++; + if (*coef) + *coef = rshift_rnd_sf((*coef * InvLevelScale4x4[jj][2]) << qp_per, 4); + coef++; + if (*coef) + *coef = rshift_rnd_sf((*coef * InvLevelScale4x4[jj][3]) << qp_per, 4); + coef++; + } + } + } + else + { + for (j = 0; j < BLOCK_SIZE_8x8; ++j) + { + int *coef = &cof[j][block_x]; + int jj = j & 0x03; + for (i = 0; i < BLOCK_SIZE_8x8; i += 4) + { + if ((jj != 0) && *coef) + *coef= rshift_rnd_sf((*coef * InvLevelScale4x4[jj][0]) << qp_per, 4); + coef++; + if (*coef) + *coef= rshift_rnd_sf((*coef * InvLevelScale4x4[jj][1]) << qp_per, 4); + coef++; + if (*coef) + *coef= rshift_rnd_sf((*coef * InvLevelScale4x4[jj][2]) << qp_per, 4); + coef++; + if (*coef) + *coef= rshift_rnd_sf((*coef * InvLevelScale4x4[jj][3]) << qp_per, 4); + coef++; + } + } + } + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of all 4x4 blocks in a MB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_4x4_CABAC_ls (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl, int (*InvLevelScale4x4)[4], int qp_per, int cbp) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int start_scan = IS_I16MB (currMB)? 1 : 0; + int block_y, block_x; + int64 *cbp_blk = &currMB->s_cbp[pl].blk; + + if( pl == PLANE_Y || (p_Vid->separate_colour_plane_flag != 0) ) + currSE->context = (IS_I16MB(currMB) ? LUMA_16AC: LUMA_4x4); + else if (pl == PLANE_U) + currSE->context = (IS_I16MB(currMB) ? CB_16AC: CB_4x4); + else + currSE->context = (IS_I16MB(currMB) ? CR_16AC: CR_4x4); + + for (block_y = 0; block_y < MB_BLOCK_SIZE; block_y += BLOCK_SIZE_8x8) /* all modes */ + { + for (block_x = 0; block_x < MB_BLOCK_SIZE; block_x += BLOCK_SIZE_8x8) + { + if (cbp & (1 << ((block_y >> 2) + (block_x >> 3)))) // are there any coeff in current block at all + { + read_comp_coeff_4x4_smb_CABAC (currMB, currSE, pl, block_y, block_x, start_scan, cbp_blk); + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of one 8x8 block +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void readCompCoeff8x8_CABAC (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl, int b8) +{ + if (currMB->cbp & (1<p_Vid; + int transform_pl = (p_Vid->separate_colour_plane_flag != 0) ? currMB->p_Slice->colour_plane_id : pl; + + int **tcoeffs; + int i,j,k; + int level = 1; + + DataPartition *dP; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int boff_x, boff_y; + + int64 cbp_mask = (int64) 51 << (4 * b8 - 2 * (b8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + int64 *cur_cbp = &currMB->s_cbp[pl].blk; + + // select scan type + const byte (*pos_scan8x8) = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN8x8[0] : FIELD_SCAN8x8[0]; + + int qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[pl] ]; + int qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[pl] ]; + + int (*InvLevelScale8x8)[8] = (currMB->is_intra_block == TRUE) ? currSlice->InvLevelScale8x8_Intra[transform_pl][qp_rem] : currSlice->InvLevelScale8x8_Inter[transform_pl][qp_rem]; + + // === set offset in current macroblock === + boff_x = (b8&0x01) << 3; + boff_y = (b8 >> 1) << 3; + tcoeffs = &currSlice->mb_rres[pl][boff_y]; + + currMB->subblock_x = boff_x; // position for coeff_count ctx + currMB->subblock_y = boff_y; // position for coeff_count ctx + + if (pl==PLANE_Y || (p_Vid->separate_colour_plane_flag != 0)) + currSE->context = LUMA_8x8; + else if (pl==PLANE_U) + currSE->context = CB_8x8; + else + currSE->context = CR_8x8; + + currSE->reading = readRunLevel_CABAC; + + // Read DC + currSE->type = ((currMB->is_intra_block == 1) ? SE_LUM_DC_INTRA : SE_LUM_DC_INTER ); // Intra or Inter? + dP = &(currSlice->partArr[partMap[currSE->type]]); + +#if TRACE + if (pl==PLANE_Y) + sprintf(currSE->tracestring, "Luma8x8 DC sng "); + else if (pl==PLANE_U) + sprintf(currSE->tracestring, "Cb 8x8 DC sng "); + else + sprintf(currSE->tracestring, "Cr 8x8 DC sng "); +#endif + + dP->readSyntaxElement(currMB, currSE, dP); + level = currSE->value1; + + //============ decode ============= + if (level != 0) /* leave if level == 0 */ + { + *cur_cbp |= cbp_mask; + + pos_scan8x8 += 2 * (currSE->value2); + + i = *pos_scan8x8++; + j = *pos_scan8x8++; + + tcoeffs[j][boff_x + i] = rshift_rnd_sf((level * InvLevelScale8x8[j][i]) << qp_per, 6); // dequantization + //tcoeffs[ j][boff_x + i] = level; + + // AC coefficients + currSE->type = ((currMB->is_intra_block == 1) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER); + dP = &(currSlice->partArr[partMap[currSE->type]]); + + for(k = 1;(k < 65) && (level != 0);++k) + { +#if TRACE + if (pl==PLANE_Y) + sprintf(currSE->tracestring, "Luma8x8 sng "); + else if (pl==PLANE_U) + sprintf(currSE->tracestring, "Cb 8x8 sng "); + else + sprintf(currSE->tracestring, "Cr 8x8 sng "); +#endif + + dP->readSyntaxElement(currMB, currSE, dP); + level = currSE->value1; + + //============ decode ============= + if (level != 0) /* leave if level == 0 */ + { + pos_scan8x8 += 2 * (currSE->value2); + + i = *pos_scan8x8++; + j = *pos_scan8x8++; + + tcoeffs[ j][boff_x + i] = rshift_rnd_sf((level * InvLevelScale8x8[j][i]) << qp_per, 6); // dequantization + //tcoeffs[ j][boff_x + i] = level; + } + } + /* + for (j = 0; j < 8; j++) + { + for (i = 0; i < 8; i++) + { + if (tcoeffs[ j][boff_x + i]) + tcoeffs[ j][boff_x + i] = rshift_rnd_sf((tcoeffs[ j][boff_x + i] * InvLevelScale8x8[j][i]) << qp_per, 6); // dequantization + } + } + */ + } + } +} + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of one 8x8 block +* from the NAL (CABAC Mode - lossless) +************************************************************************ +*/ +static void readCompCoeff8x8_CABAC_lossless (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl, int b8) +{ + if (currMB->cbp & (1<p_Vid; + + int **tcoeffs; + int i,j,k; + int level = 1; + + DataPartition *dP; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int boff_x, boff_y; + + int64 cbp_mask = (int64) 51 << (4 * b8 - 2 * (b8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + int64 *cur_cbp = &currMB->s_cbp[pl].blk; + + // select scan type + const byte (*pos_scan8x8) = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN8x8[0] : FIELD_SCAN8x8[0]; + + // === set offset in current macroblock === + boff_x = (b8&0x01) << 3; + boff_y = (b8 >> 1) << 3; + tcoeffs = &currSlice->mb_rres[pl][boff_y]; + + currMB->subblock_x = boff_x; // position for coeff_count ctx + currMB->subblock_y = boff_y; // position for coeff_count ctx + + if (pl==PLANE_Y || (p_Vid->separate_colour_plane_flag != 0)) + currSE->context = LUMA_8x8; + else if (pl==PLANE_U) + currSE->context = CB_8x8; + else + currSE->context = CR_8x8; + + currSE->reading = readRunLevel_CABAC; + + for(k=0; (k < 65) && (level != 0);++k) + { + //============ read ============= + /* + * make distinction between INTRA and INTER coded + * luminance coefficients + */ + + currSE->type = ((currMB->is_intra_block == 1) + ? (k==0 ? SE_LUM_DC_INTRA : SE_LUM_AC_INTRA) + : (k==0 ? SE_LUM_DC_INTER : SE_LUM_AC_INTER)); + +#if TRACE + if (pl==PLANE_Y) + sprintf(currSE->tracestring, "Luma8x8 sng "); + else if (pl==PLANE_U) + sprintf(currSE->tracestring, "Cb 8x8 sng "); + else + sprintf(currSE->tracestring, "Cr 8x8 sng "); +#endif + + dP = &(currSlice->partArr[partMap[currSE->type]]); + currSE->reading = readRunLevel_CABAC; + + dP->readSyntaxElement(currMB, currSE, dP); + level = currSE->value1; + + //============ decode ============= + if (level != 0) /* leave if level == 0 */ + { + pos_scan8x8 += 2 * (currSE->value2); + + i = *pos_scan8x8++; + j = *pos_scan8x8++; + + *cur_cbp |= cbp_mask; + + tcoeffs[j][boff_x + i] = level; + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 8x8 blocks in a MB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_8x8_MB_CABAC (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl) +{ + //======= 8x8 transform size & CABAC ======== + readCompCoeff8x8_CABAC (currMB, currSE, pl, 0); + readCompCoeff8x8_CABAC (currMB, currSE, pl, 1); + readCompCoeff8x8_CABAC (currMB, currSE, pl, 2); + readCompCoeff8x8_CABAC (currMB, currSE, pl, 3); +} + + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 8x8 blocks in a MB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_8x8_MB_CABAC_ls (Macroblock *currMB, SyntaxElement *currSE, ColorPlane pl) +{ + //======= 8x8 transform size & CABAC ======== + readCompCoeff8x8_CABAC_lossless (currMB, currSE, pl, 0); + readCompCoeff8x8_CABAC_lossless (currMB, currSE, pl, 1); + readCompCoeff8x8_CABAC_lossless (currMB, currSE, pl, 2); + readCompCoeff8x8_CABAC_lossless (currMB, currSE, pl, 3); +} + + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CABAC_420(Macroblock *currMB) +{ + int i,j; + int level; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int i0, j0; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + int smb = ((p_Vid->type==SP_SLICE) && (currMB->is_intra_block == FALSE)) || (p_Vid->type == SI_SLICE && currMB->mb_type == SI4MB); + + int qp_per_uv[2]; + int qp_rem_uv[2]; + + int intra = (currMB->is_intra_block == TRUE); + + StorablePicture *dec_picture = currSlice->dec_picture; + int yuv = dec_picture->chroma_format_idc - 1; + + int (*InvLevelScale4x4)[4] = NULL; + + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + if (!IS_I16MB (currMB)) + { + int need_transform_size_flag; + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + { + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + } + else + { + currSE.reading = read_CBP_CABAC; + } + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.reading = readMB_transform_size_flag_CABAC; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + if (dP->bitstream->ei_flag) + { + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + dP->readSyntaxElement(currMB, &currSE, dP); + } + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + int **cof = currSlice->cof[0]; + int k; + pos_scan_4x4 = pos_scan4x4[0]; + + currSE.type = SE_LUM_DC_INTRA; + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.context = LUMA_16DC; + currSE.type = SE_LUM_DC_INTRA; + + if (dP->bitstream->ei_flag) + { + currSE.mapping = linfo_levrun_inter; + } + else + { + currSE.reading = readRunLevel_CABAC; + } + + level = 1; // just to get inside the loop + + for(k = 0; (k < 17) && (level != 0); ++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "DC luma 16x16 "); +#endif + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) /* leave if level == 0 */ + { + pos_scan_4x4 += (2 * currSE.value2); + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + cof[j0][i0] = level;// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = level;// add new intra DC coeff + } + } + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + + // luma coefficients + //======= Other Modes & CABAC ======== + //------------------------------------ + if (cbp) + { + if(currMB->luma_transform_size_8x8_flag) + { + //======= 8x8 transform size & CABAC ======== + currMB->read_comp_coeff_8x8_CABAC (currMB, &currSE, PLANE_Y); + } + else + { + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + currMB->read_comp_coeff_4x4_CABAC (currMB, &currSE, PLANE_Y, InvLevelScale4x4, qp_per, cbp); + } + } + + //init quant parameters for chroma + for(i=0; i < 2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + //========================== CHROMA DC ============================ + //----------------------------------------------------------------- + // chroma DC coeff + if(cbp>15) + { + CBPStructure *s_cbp = &currMB->s_cbp[0]; + int uv, ll, k, coef_ctr; + + for (ll = 0; ll < 3; ll += 2) + { + uv = ll >> 1; + + InvLevelScale4x4 = intra ? currSlice->InvLevelScale4x4_Intra[uv + 1][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[uv + 1][qp_rem_uv[uv]]; + //===================== CHROMA DC YUV420 ====================== + memset(currSlice->cofu, 0, 4 *sizeof(int)); + coef_ctr=-1; + + level = 1; + currMB->is_v_block = ll; + currSE.context = CHROMA_DC; + currSE.type = (intra ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER); + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_levrun_c2x2; + else + currSE.reading = readRunLevel_CABAC; + + for(k = 0; (k < (p_Vid->num_cdc_coeff + 1))&&(level!=0);++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "2x2 DC Chroma "); +#endif + + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) + { + s_cbp->blk |= 0xf0000 << (ll<<1) ; + coef_ctr += currSE.value2 + 1; + + // Bug: currSlice->cofu has only 4 entries, hence coef_ctr MUST be <4 (which is + // caught by the assert(). If it is bigger than 4, it starts patching the + // p_Vid->predmode pointer, which leads to bugs later on. + // + // This assert() should be left in the code, because it captures a very likely + // bug early when testing in error prone environments (or when testing NAL + // functionality). + + assert (coef_ctr < p_Vid->num_cdc_coeff); + currSlice->cofu[coef_ctr] = level; + } + } + + + if (smb || (currMB->is_lossless == TRUE)) // check to see if MB type is SPred or SIntra4x4 + { + currSlice->cof[uv + 1][0][0] = currSlice->cofu[0]; + currSlice->cof[uv + 1][0][4] = currSlice->cofu[1]; + currSlice->cof[uv + 1][4][0] = currSlice->cofu[2]; + currSlice->cof[uv + 1][4][4] = currSlice->cofu[3]; + //currSlice->fcf[uv + 1][0][0] = currSlice->cofu[0]; + //currSlice->fcf[uv + 1][4][0] = currSlice->cofu[1]; + //currSlice->fcf[uv + 1][0][4] = currSlice->cofu[2]; + //currSlice->fcf[uv + 1][4][4] = currSlice->cofu[3]; + } + else + { + int temp[4]; + int scale_dc = InvLevelScale4x4[0][0]; + int **cof = currSlice->cof[uv + 1]; + + ihadamard2x2(currSlice->cofu, temp); + + //currSlice->fcf[uv + 1][0][0] = temp[0]; + //currSlice->fcf[uv + 1][0][4] = temp[1]; + //currSlice->fcf[uv + 1][4][0] = temp[2]; + //currSlice->fcf[uv + 1][4][4] = temp[3]; + + cof[0][0] = (((temp[0] * scale_dc) << qp_per_uv[uv]) >> 5); + cof[0][4] = (((temp[1] * scale_dc) << qp_per_uv[uv]) >> 5); + cof[4][0] = (((temp[2] * scale_dc) << qp_per_uv[uv]) >> 5); + cof[4][4] = (((temp[3] * scale_dc) << qp_per_uv[uv]) >> 5); + } + } + } + + //========================== CHROMA AC ============================ + //----------------------------------------------------------------- + // chroma AC coeff, all zero fram start_scan + if (cbp >31) + { + currSE.context = CHROMA_AC; + currSE.type = (currMB->is_intra_block ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER); + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_levrun_inter; + else + currSE.reading = readRunLevel_CABAC; + + if(currMB->is_lossless == FALSE) + { + int b4, b8, uv, k; + int **cof; + CBPStructure *s_cbp = &currMB->s_cbp[0]; + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + InvLevelScale4x4 = intra ? currSlice->InvLevelScale4x4_Intra[uv + 1][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[uv + 1][qp_rem_uv[uv]]; + cof = currSlice->cof[uv + 1]; + + for (b4 = 0; b4 < 4; ++b4) + { + i = cofuv_blk_x[yuv][b8][b4]; + j = cofuv_blk_y[yuv][b8][b4]; + + currMB->subblock_y = subblk_offset_y[yuv][b8][b4]; + currMB->subblock_x = subblk_offset_x[yuv][b8][b4]; + + pos_scan_4x4 = pos_scan4x4[1]; + level = 1; + + for(k = 0; (k < 16) && (level != 0);++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "AC Chroma "); +#endif + + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) + { + s_cbp->blk |= i64_power2(cbp_blk_chroma[b8][b4]); + pos_scan_4x4 += (currSE.value2 << 1); + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + cof[(j<<2) + j0][(i<<2) + i0] = rshift_rnd_sf((level * InvLevelScale4x4[j0][i0])<fcf[uv + 1][(j<<2) + j0][(i<<2) + i0] = level; + } + } //for(k=0;(k<16)&&(level!=0);++k) + } + } + } + else + { + CBPStructure *s_cbp = &currMB->s_cbp[0]; + int b4, b8, k; + int uv; + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + + for (b4=0; b4 < 4; ++b4) + { + i = cofuv_blk_x[yuv][b8][b4]; + j = cofuv_blk_y[yuv][b8][b4]; + + pos_scan_4x4 = pos_scan4x4[1]; + level=1; + + currMB->subblock_y = subblk_offset_y[yuv][b8][b4]; + currMB->subblock_x = subblk_offset_x[yuv][b8][b4]; + + for(k=0;(k<16)&&(level!=0);++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "AC Chroma "); +#endif + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) + { + s_cbp->blk |= i64_power2(cbp_blk_chroma[b8][b4]); + pos_scan_4x4 += (currSE.value2 << 1); + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + currSlice->cof[uv + 1][(j<<2) + j0][(i<<2) + i0] = level; + //currSlice->fcf[uv + 1][(j<<2) + j0][(i<<2) + i0] = level; + } + } + } + } + } //for (b4=0; b4 < 4; b4++) + } +} + + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CABAC_400(Macroblock *currMB) +{ + int k; + int level; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int i0, j0; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + + int intra = (currMB->is_intra_block == TRUE); + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + { + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + } + else + { + currSE.reading = read_CBP_CABAC; + } + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.reading = readMB_transform_size_flag_CABAC; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + if (dP->bitstream->ei_flag) + { + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + dP->readSyntaxElement(currMB, &currSE, dP); + } + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + { + currSE.type = SE_LUM_DC_INTRA; + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.context = LUMA_16DC; + currSE.type = SE_LUM_DC_INTRA; + + if (dP->bitstream->ei_flag) + { + currSE.mapping = linfo_levrun_inter; + } + else + { + currSE.reading = readRunLevel_CABAC; + } + + level = 1; // just to get inside the loop + + for(k = 0; (k < 17) && (level != 0); ++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "DC luma 16x16 "); +#endif + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) /* leave if level == 0 */ + { + pos_scan_4x4 += (2 * currSE.value2); + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = level;// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = level;// add new intra DC coeff + } + } + } + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[PLANE_Y] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[PLANE_Y] ]; + + //======= Other Modes & CABAC ======== + //------------------------------------ + if (cbp) + { + if(currMB->luma_transform_size_8x8_flag) + { + //======= 8x8 transform size & CABAC ======== + currMB->read_comp_coeff_8x8_CABAC (currMB, &currSE, PLANE_Y); + } + else + { + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + currMB->read_comp_coeff_4x4_CABAC (currMB, &currSE, PLANE_Y, InvLevelScale4x4, qp_per, cbp); + } + } +} + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CABAC_444(Macroblock *currMB) +{ + int i, k; + int level; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int coef_ctr, i0, j0; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + + int uv; + int qp_per_uv[2]; + int qp_rem_uv[2]; + + int intra = (currMB->is_intra_block == TRUE); + + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + // QPI + //init constants for every chroma qp offset + for (i=0; i<2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + { + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + } + else + { + currSE.reading = read_CBP_CABAC; + } + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.reading = readMB_transform_size_flag_CABAC; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + if (dP->bitstream->ei_flag) + { + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + dP->readSyntaxElement(currMB, &currSE, dP); + } + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + { + currSE.type = SE_LUM_DC_INTRA; + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.context = LUMA_16DC; + currSE.type = SE_LUM_DC_INTRA; + + if (dP->bitstream->ei_flag) + { + currSE.mapping = linfo_levrun_inter; + } + else + { + currSE.reading = readRunLevel_CABAC; + } + + level = 1; // just to get inside the loop + + for(k = 0; (k < 17) && (level != 0); ++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "DC luma 16x16 "); +#endif + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) /* leave if level == 0 */ + { + pos_scan_4x4 += (2 * currSE.value2); + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = level;// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = level;// add new intra DC coeff + } + } + } + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + + //init quant parameters for chroma + for(i=0; i < 2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + + // luma coefficients + { + //======= Other Modes & CABAC ======== + //------------------------------------ + if (cbp) + { + if(currMB->luma_transform_size_8x8_flag) + { + //======= 8x8 transform size & CABAC ======== + currMB->read_comp_coeff_8x8_CABAC (currMB, &currSE, PLANE_Y); + } + else + { + currMB->read_comp_coeff_4x4_CABAC (currMB, &currSE, PLANE_Y, InvLevelScale4x4, qp_per, cbp); + } + } + } + + for (uv = 0; uv < 2; ++uv ) + { + /*----------------------16x16DC Luma_Add----------------------*/ + if (IS_I16MB (currMB)) // read DC coeffs for new intra modes + { + { + currSE.type = SE_LUM_DC_INTRA; + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if( (p_Vid->separate_colour_plane_flag != 0) ) + currSE.context = LUMA_16DC; + else + currSE.context = (uv==0) ? CB_16DC : CR_16DC; + + if (dP->bitstream->ei_flag) + { + currSE.mapping = linfo_levrun_inter; + } + else + { + currSE.reading = readRunLevel_CABAC; + } + + coef_ctr = -1; + level = 1; // just to get inside the loop + + for(k=0;(k<17) && (level!=0);++k) + { +#if TRACE + if (uv == 0) + snprintf(currSE.tracestring, TRACESTRING_SIZE, "DC Cb 16x16 "); + else + snprintf(currSE.tracestring, TRACESTRING_SIZE, "DC Cr 16x16 "); +#endif + + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) // leave if level == 0 + { + coef_ctr += currSE.value2 + 1; + + i0 = pos_scan4x4[coef_ctr][0]; + j0 = pos_scan4x4[coef_ctr][1]; + currSlice->cof[uv + 1][j0<<2][i0<<2] = level; + //currSlice->fcf[uv + 1][j0<<2][i0<<2] = level; + } + } //k loop + } // else CAVLC + + if(currMB->is_lossless == FALSE) + { + itrans_2(currMB, (ColorPlane) (uv + 1)); // transform new intra DC + } + } //IS_I16MB + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ (currSlice->qp + p_Vid->bitdepth_luma_qp_scale) ]; + qp_rem = p_Vid->qp_rem_matrix[ (currSlice->qp + p_Vid->bitdepth_luma_qp_scale) ]; + + //init constants for every chroma qp offset + qp_per_uv[uv] = p_Vid->qp_per_matrix[ (currMB->qpc[uv] + p_Vid->bitdepth_chroma_qp_scale) ]; + qp_rem_uv[uv] = p_Vid->qp_rem_matrix[ (currMB->qpc[uv] + p_Vid->bitdepth_chroma_qp_scale) ]; + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[uv + 1][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[uv + 1][qp_rem_uv[uv]]; + + { + if (cbp) + { + if(currMB->luma_transform_size_8x8_flag) + { + //======= 8x8 transform size & CABAC ======== + currMB->read_comp_coeff_8x8_CABAC (currMB, &currSE, (ColorPlane) (PLANE_U + uv)); + } + else //4x4 + { + currMB->read_comp_coeff_4x4_CABAC (currMB, &currSE, (ColorPlane) (PLANE_U + uv), InvLevelScale4x4, qp_per_uv[uv], cbp); + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CABAC_422(Macroblock *currMB) +{ + int i,j,k; + int level; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int coef_ctr, i0, j0, b8; + int ll; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + + int uv; + int qp_per_uv[2]; + int qp_rem_uv[2]; + + int intra = (currMB->is_intra_block == TRUE); + + int b4; + StorablePicture *dec_picture = currSlice->dec_picture; + int yuv = dec_picture->chroma_format_idc - 1; + int m6[4]; + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + // QPI + //init constants for every chroma qp offset + for (i=0; i<2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + { + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + } + else + { + currSE.reading = read_CBP_CABAC; + } + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + currSE.reading = readMB_transform_size_flag_CABAC; + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + if (dP->bitstream->ei_flag) + { + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + } + else + { + dP->readSyntaxElement(currMB, &currSE, dP); + } + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + { + currSE.type = SE_LUM_DC_INTRA; + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.context = LUMA_16DC; + currSE.type = SE_LUM_DC_INTRA; + + if (dP->bitstream->ei_flag) + { + currSE.mapping = linfo_levrun_inter; + } + else + { + currSE.reading = readRunLevel_CABAC; + } + + level = 1; // just to get inside the loop + + for(k = 0; (k < 17) && (level != 0); ++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "DC luma 16x16 "); +#endif + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) /* leave if level == 0 */ + { + pos_scan_4x4 += (2 * currSE.value2); + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = level;// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = level;// add new intra DC coeff + } + } + } + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + + //init quant parameters for chroma + for(i=0; i < 2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + + // luma coefficients + { + //======= Other Modes & CABAC ======== + //------------------------------------ + if (cbp) + { + if(currMB->luma_transform_size_8x8_flag) + { + //======= 8x8 transform size & CABAC ======== + currMB->read_comp_coeff_8x8_CABAC (currMB, &currSE, PLANE_Y); + } + else + { + currMB->read_comp_coeff_4x4_CABAC (currMB, &currSE, PLANE_Y, InvLevelScale4x4, qp_per, cbp); + } + } + } + + //========================== CHROMA DC ============================ + //----------------------------------------------------------------- + // chroma DC coeff + if(cbp>15) + { + for (ll=0;ll<3;ll+=2) + { + int (*InvLevelScale4x4)[4] = NULL; + uv = ll>>1; + { + int **imgcof = currSlice->cof[uv + 1]; + int m3[2][4] = {{0,0,0,0},{0,0,0,0}}; + int m4[2][4] = {{0,0,0,0},{0,0,0,0}}; + int qp_per_uv_dc = p_Vid->qp_per_matrix[ (currMB->qpc[uv] + 3 + p_Vid->bitdepth_chroma_qp_scale) ]; //for YUV422 only + int qp_rem_uv_dc = p_Vid->qp_rem_matrix[ (currMB->qpc[uv] + 3 + p_Vid->bitdepth_chroma_qp_scale) ]; //for YUV422 only + if (intra) + InvLevelScale4x4 = currSlice->InvLevelScale4x4_Intra[uv + 1][qp_rem_uv_dc]; + else + InvLevelScale4x4 = currSlice->InvLevelScale4x4_Inter[uv + 1][qp_rem_uv_dc]; + + + //===================== CHROMA DC YUV422 ====================== + { + CBPStructure *s_cbp = &currMB->s_cbp[0]; + coef_ctr=-1; + level=1; + for(k=0;(k<9)&&(level!=0);++k) + { + currSE.context = CHROMA_DC_2x4; + currSE.type = ((currMB->is_intra_block == TRUE) ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER); + currMB->is_v_block = ll; + +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "2x4 DC Chroma "); +#endif + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_levrun_c2x2; + else + currSE.reading = readRunLevel_CABAC; + + dP->readSyntaxElement(currMB, &currSE, dP); + + level = currSE.value1; + + if (level != 0) + { + s_cbp->blk |= ((int64)0xff0000) << (ll<<2) ; + coef_ctr += currSE.value2 + 1; + assert (coef_ctr < p_Vid->num_cdc_coeff); + i0=SCAN_YUV422[coef_ctr][0]; + j0=SCAN_YUV422[coef_ctr][1]; + + m3[i0][j0]=level; + } + } + } + // inverse CHROMA DC YUV422 transform + // horizontal + if(currMB->is_lossless == FALSE) + { + m4[0][0] = m3[0][0] + m3[1][0]; + m4[0][1] = m3[0][1] + m3[1][1]; + m4[0][2] = m3[0][2] + m3[1][2]; + m4[0][3] = m3[0][3] + m3[1][3]; + + m4[1][0] = m3[0][0] - m3[1][0]; + m4[1][1] = m3[0][1] - m3[1][1]; + m4[1][2] = m3[0][2] - m3[1][2]; + m4[1][3] = m3[0][3] - m3[1][3]; + + for (i = 0; i < 2; ++i) + { + m6[0] = m4[i][0] + m4[i][2]; + m6[1] = m4[i][0] - m4[i][2]; + m6[2] = m4[i][1] - m4[i][3]; + m6[3] = m4[i][1] + m4[i][3]; + + imgcof[ 0][i<<2] = m6[0] + m6[3]; + imgcof[ 4][i<<2] = m6[1] + m6[2]; + imgcof[ 8][i<<2] = m6[1] - m6[2]; + imgcof[12][i<<2] = m6[0] - m6[3]; + }//for (i=0;i<2;++i) + + for(j = 0;j < p_Vid->mb_cr_size_y; j += BLOCK_SIZE) + { + for(i=0;i < p_Vid->mb_cr_size_x;i+=BLOCK_SIZE) + { + imgcof[j][i] = rshift_rnd_sf((imgcof[j][i] * InvLevelScale4x4[0][0]) << qp_per_uv_dc, 6); + } + } + } + else + { + for(j=0;j<4;++j) + { + for(i=0;i<2;++i) + { + currSlice->cof[uv + 1][j<<2][i<<2] = m3[i][j]; + //currSlice->fcf[uv + 1][j<<2][i<<2] = m3[i][j]; + } + } + } + + } + }//for (ll=0;ll<3;ll+=2) + } + + //========================== CHROMA AC ============================ + //----------------------------------------------------------------- + // chroma AC coeff, all zero fram start_scan + if (cbp<=31) + { + } + else + { + { + currSE.context = CHROMA_AC; + currSE.type = (currMB->is_intra_block ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER); + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + if (dP->bitstream->ei_flag) + currSE.mapping = linfo_levrun_inter; + else + currSE.reading = readRunLevel_CABAC; + + if(currMB->is_lossless == FALSE) + { + CBPStructure *s_cbp = &currMB->s_cbp[0]; + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + InvLevelScale4x4 = intra ? currSlice->InvLevelScale4x4_Intra[uv + 1][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[uv + 1][qp_rem_uv[uv]]; + + for (b4 = 0; b4 < 4; ++b4) + { + i = cofuv_blk_x[yuv][b8][b4]; + j = cofuv_blk_y[yuv][b8][b4]; + + currMB->subblock_y = subblk_offset_y[yuv][b8][b4]; + currMB->subblock_x = subblk_offset_x[yuv][b8][b4]; + + pos_scan_4x4 = pos_scan4x4[1]; + level=1; + + for(k = 0; (k < 16) && (level != 0);++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "AC Chroma "); +#endif + + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) + { + s_cbp->blk |= i64_power2(cbp_blk_chroma[b8][b4]); + pos_scan_4x4 += (currSE.value2 << 1); + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + currSlice->cof[uv + 1][(j<<2) + j0][(i<<2) + i0] = rshift_rnd_sf((level * InvLevelScale4x4[j0][i0])<fcf[uv + 1][(j<<2) + j0][(i<<2) + i0] = level; + } + } //for(k=0;(k<16)&&(level!=0);++k) + } + } + } + else + { + CBPStructure *s_cbp = &currMB->s_cbp[0]; + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + + for (b4=0; b4 < 4; ++b4) + { + i = cofuv_blk_x[yuv][b8][b4]; + j = cofuv_blk_y[yuv][b8][b4]; + + pos_scan_4x4 = pos_scan4x4[1]; + level=1; + + currMB->subblock_y = subblk_offset_y[yuv][b8][b4]; + currMB->subblock_x = subblk_offset_x[yuv][b8][b4]; + + for(k=0;(k<16)&&(level!=0);++k) + { +#if TRACE + snprintf(currSE.tracestring, TRACESTRING_SIZE, "AC Chroma "); +#endif + dP->readSyntaxElement(currMB, &currSE, dP); + level = currSE.value1; + + if (level != 0) + { + s_cbp->blk |= i64_power2(cbp_blk_chroma[b8][b4]); + pos_scan_4x4 += (currSE.value2 << 1); + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + currSlice->cof[uv + 1][(j<<2) + j0][(i<<2) + i0] = level; + //currSlice->fcf[uv + 1][(j<<2) + j0][(i<<2) + i0] = level; + } + } + } + } + } //for (b4=0; b4 < 4; b4++) + } //for (b8=0; b8 < p_Vid->num_blk8x8_uv; b8++) + } //if (dec_picture->chroma_format_idc != YUV400) +} + +void set_read_CBP_and_coeffs_cabac(Slice *currSlice) +{ + switch (currSlice->p_Vid->active_sps->chroma_format_idc) + { + case YUV444: + if (currSlice->p_Vid->separate_colour_plane_flag == 0) + { + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CABAC_444; + } + else + { + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CABAC_400; + } + break; + case YUV422: + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CABAC_422; + break; + case YUV420: + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CABAC_420; + break; + case YUV400: + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CABAC_400; + break; + default: + assert (1); + currSlice->read_CBP_and_coeffs_from_NAL = NULL; + break; + } +} + + +/*! +************************************************************************ +* \brief +* setup coefficient reading functions for CABAC +* +************************************************************************ +*/ +void set_read_comp_coeff_cabac(Macroblock *currMB) +{ + if (currMB->is_lossless == FALSE) + { + currMB->read_comp_coeff_4x4_CABAC = read_comp_coeff_4x4_CABAC; + currMB->read_comp_coeff_8x8_CABAC = read_comp_coeff_8x8_MB_CABAC; + } + else + { + currMB->read_comp_coeff_4x4_CABAC = read_comp_coeff_4x4_CABAC_ls; + currMB->read_comp_coeff_8x8_CABAC = read_comp_coeff_8x8_MB_CABAC_ls; + } +} \ No newline at end of file diff --git a/ldecod/src/read_comp_cavlc.c b/ldecod/src/read_comp_cavlc.c new file mode 100644 index 0000000..8dd923d --- /dev/null +++ b/ldecod/src/read_comp_cavlc.c @@ -0,0 +1,2156 @@ +/*! + *********************************************************************** + * \file read_comp_cavlc.c + * + * \brief + * Read Coefficient Components (CAVLC version) + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + *********************************************************************** +*/ + +#include "contributors.h" + +#include "global.h" +#include "elements.h" +#include "macroblock.h" +#include "vlc.h" +#include "fast_memory.h" +#include "transform.h" +#include "mb_access.h" + +#if TRACE +#define TRACE_STRING(s) strncpy(currSE.tracestring, s, TRACESTRING_SIZE) +#define TRACE_DECBITS(i) dectracebitcnt(1) +#define TRACE_printf(s) sprintf(type, "%s", s); +#define TRACE_STRING_P(s) strncpy(currSE->tracestring, s, TRACESTRING_SIZE) +#else +#define TRACE_STRING(s) +#define TRACE_DECBITS(i) +#define TRACE_printf(s) +#define TRACE_STRING_P(s) +#endif + +extern void check_dp_neighbors (Macroblock *currMB); +extern void read_delta_quant (SyntaxElement *currSE, DataPartition *dP, Macroblock *currMB, const byte *partMap, int type); + +/*! + ************************************************************************ + * \brief + * Get the Prediction from the Neighboring Blocks for Number of + * Nonzero Coefficients + * + * Luma Blocks + ************************************************************************ + */ +static int predict_nnz(Macroblock *currMB, int block_type, int i,int j) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + PixelPos pix; + + int pred_nnz = 0; + int cnt = 0; + + // left block + get4x4Neighbour(currMB, i - 1, j, p_Vid->mb_size[IS_LUMA], &pix); + + if ((currMB->is_intra_block == TRUE) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && (currSlice->dp_mode == PAR_DP_3)) + { + pix.available &= currSlice->intra_block[pix.mb_addr]; + if (!pix.available) + ++cnt; + } + + if (pix.available) + { + switch (block_type) + { + case LUMA: + pred_nnz = p_Vid->nz_coeff [pix.mb_addr ][0][pix.y][pix.x]; + ++cnt; + break; + case CB: + pred_nnz = p_Vid->nz_coeff [pix.mb_addr ][1][pix.y][pix.x]; + ++cnt; + break; + case CR: + pred_nnz = p_Vid->nz_coeff [pix.mb_addr ][2][pix.y][pix.x]; + ++cnt; + break; + default: + error("writeCoeff4x4_CAVLC: Invalid block type", 600); + break; + } + } + + // top block + get4x4Neighbour(currMB, i, j - 1, p_Vid->mb_size[IS_LUMA], &pix); + + if ((currMB->is_intra_block == TRUE) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && (currSlice->dp_mode==PAR_DP_3)) + { + pix.available &= currSlice->intra_block[pix.mb_addr]; + if (!pix.available) + ++cnt; + } + + if (pix.available) + { + switch (block_type) + { + case LUMA: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][0][pix.y][pix.x]; + ++cnt; + break; + case CB: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][1][pix.y][pix.x]; + ++cnt; + break; + case CR: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][2][pix.y][pix.x]; + ++cnt; + break; + default: + error("writeCoeff4x4_CAVLC: Invalid block type", 600); + break; + } + } + + if (cnt==2) + { + ++pred_nnz; + pred_nnz >>= 1; + } + + return pred_nnz; +} + + +/*! + ************************************************************************ + * \brief + * Get the Prediction from the Neighboring Blocks for Number of + * Nonzero Coefficients + * + * Chroma Blocks + ************************************************************************ + */ +static int predict_nnz_chroma(Macroblock *currMB, int i,int j) +{ + StorablePicture *dec_picture = currMB->p_Slice->dec_picture; + + if (dec_picture->chroma_format_idc != YUV444) + { + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + PixelPos pix; + int pred_nnz = 0; + int cnt = 0; + + //YUV420 and YUV422 + // left block + get4x4Neighbour(currMB, ((i&0x01)<<2) - 1, j, p_Vid->mb_size[IS_CHROMA], &pix); + + if ((currMB->is_intra_block == TRUE) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && (currSlice->dp_mode==PAR_DP_3)) + { + pix.available &= currSlice->intra_block[pix.mb_addr]; + if (!pix.available) + ++cnt; + } + + if (pix.available) + { + pred_nnz = p_Vid->nz_coeff [pix.mb_addr ][1][pix.y][2 * (i>>1) + pix.x]; + ++cnt; + } + + // top block + get4x4Neighbour(currMB, ((i&0x01)<<2), j - 1, p_Vid->mb_size[IS_CHROMA], &pix); + + if ((currMB->is_intra_block == TRUE) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && (currSlice->dp_mode==PAR_DP_3)) + { + pix.available &= currSlice->intra_block[pix.mb_addr]; + if (!pix.available) + ++cnt; + } + + if (pix.available) + { + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][1][pix.y][2 * (i>>1) + pix.x]; + ++cnt; + } + + if (cnt==2) + { + ++pred_nnz; + pred_nnz >>= 1; + } + return pred_nnz; + } + else + return 0; +} + +/*! + ************************************************************************ + * \brief + * Reads coeff of an 4x4 block (CAVLC) + * + * \author + * Karl Lillevold + * contributions by James Au + ************************************************************************ + */ +void read_coeff_4x4_CAVLC (Macroblock *currMB, + int block_type, + int i, int j, int levarr[16], int runarr[16], + int *number_coefficients) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int mb_nr = currMB->mbAddrX; + SyntaxElement currSE; + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + Bitstream *currStream; + + int k, code, vlcnum; + int numcoeff = 0, numtrailingones; + int level_two_or_higher; + int numones, totzeros, abslevel, cdc=0, cac=0; + int zerosleft, ntr, dptype = 0; + int max_coeff_num = 0, nnz; + char type[15]; + static const int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6 + + switch (block_type) + { + case LUMA: + max_coeff_num = 16; + TRACE_printf("Luma"); + dptype = (currMB->is_intra_block == TRUE) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case LUMA_INTRA16x16DC: + max_coeff_num = 16; + TRACE_printf("Lum16DC"); + dptype = SE_LUM_DC_INTRA; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case LUMA_INTRA16x16AC: + max_coeff_num = 15; + TRACE_printf("Lum16AC"); + dptype = SE_LUM_AC_INTRA; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case CHROMA_DC: + max_coeff_num = p_Vid->num_cdc_coeff; + cdc = 1; + TRACE_printf("ChrDC"); + dptype = (currMB->is_intra_block == TRUE) ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case CHROMA_AC: + max_coeff_num = 15; + cac = 1; + TRACE_printf("ChrAC"); + dptype = (currMB->is_intra_block == TRUE) ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + default: + error ("read_coeff_4x4_CAVLC: invalid block type", 600); + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + } + + currSE.type = dptype; + dP = &(currSlice->partArr[partMap[dptype]]); + currStream = dP->bitstream; + + if (!cdc) + { + // luma or chroma AC + nnz = (!cac) ? predict_nnz(currMB, LUMA, i<<2, j<<2) : predict_nnz_chroma(currMB, i, ((j-4)<<2)); + + currSE.value1 = (nnz < 2) ? 0 : ((nnz < 4) ? 1 : ((nnz < 8) ? 2 : 3)); + + readSyntaxElement_NumCoeffTrailingOnes(&currSE, currStream, type); + + numcoeff = currSE.value1; + numtrailingones = currSE.value2; + + p_Vid->nz_coeff[mb_nr][0][j][i] = (byte) numcoeff; + } + else + { + // chroma DC + readSyntaxElement_NumCoeffTrailingOnesChromaDC(p_Vid, &currSE, currStream); + + numcoeff = currSE.value1; + numtrailingones = currSE.value2; + } + + memset(levarr, 0, max_coeff_num * sizeof(int)); + memset(runarr, 0, max_coeff_num * sizeof(int)); + + numones = numtrailingones; + *number_coefficients = numcoeff; + + if (numcoeff) + { + if (numtrailingones) + { + currSE.len = numtrailingones; + +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s trailing ones sign (%d,%d)", type, i, j); +#endif + + readSyntaxElement_FLC (&currSE, currStream); + + code = currSE.inf; + ntr = numtrailingones; + for (k = numcoeff - 1; k > numcoeff - 1 - numtrailingones; k--) + { + ntr --; + levarr[k] = (code>>ntr)&1 ? -1 : 1; + } + } + + // decode levels + level_two_or_higher = (numcoeff > 3 && numtrailingones == 3)? 0 : 1; + vlcnum = (numcoeff > 10 && numtrailingones < 3) ? 1 : 0; + + for (k = numcoeff - 1 - numtrailingones; k >= 0; k--) + { + +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s lev (%d,%d) k=%d vlc=%d ", type, i, j, k, vlcnum); +#endif + + if (vlcnum == 0) + readSyntaxElement_Level_VLC0(&currSE, currStream); + else + readSyntaxElement_Level_VLCN(&currSE, vlcnum, currStream); + + if (level_two_or_higher) + { + currSE.inf += (currSE.inf > 0) ? 1 : -1; + level_two_or_higher = 0; + } + + levarr[k] = currSE.inf; + abslevel = iabs(levarr[k]); + if (abslevel == 1) + ++numones; + + // update VLC table + if (abslevel > incVlc[vlcnum]) + ++vlcnum; + + if (k == numcoeff - 1 - numtrailingones && abslevel >3) + vlcnum = 2; + } + + if (numcoeff < max_coeff_num) + { + // decode total run + vlcnum = numcoeff - 1; + currSE.value1 = vlcnum; + +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s totalrun (%d,%d) vlc=%d ", type, i,j, vlcnum); +#endif + if (cdc) + readSyntaxElement_TotalZerosChromaDC(p_Vid, &currSE, currStream); + else + readSyntaxElement_TotalZeros(&currSE, currStream); + + totzeros = currSE.value1; + } + else + { + totzeros = 0; + } + + // decode run before each coefficient + zerosleft = totzeros; + i = numcoeff - 1; + + if (zerosleft > 0 && i > 0) + { + do + { + // select VLC for runbefore + vlcnum = imin(zerosleft - 1, RUNBEFORE_NUM_M1); + + currSE.value1 = vlcnum; +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s run (%d,%d) k=%d vlc=%d ", + type, i, j, i, vlcnum); +#endif + + readSyntaxElement_Run(&currSE, currStream); + runarr[i] = currSE.value1; + + zerosleft -= runarr[i]; + i --; + } while (zerosleft != 0 && i != 0); + } + runarr[i] = zerosleft; + } // if numcoeff +} + +/*! + ************************************************************************ + * \brief + * Reads coeff of an 4x4 block (CAVLC) + * + * \author + * Karl Lillevold + * contributions by James Au + ************************************************************************ + */ +void read_coeff_4x4_CAVLC_444 (Macroblock *currMB, + int block_type, + int i, int j, int levarr[16], int runarr[16], + int *number_coefficients) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int mb_nr = currMB->mbAddrX; + SyntaxElement currSE; + DataPartition *dP; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + Bitstream *currStream; + + int k, code, vlcnum; + int numcoeff = 0, numtrailingones; + int level_two_or_higher; + int numones, totzeros, abslevel, cdc=0, cac=0; + int zerosleft, ntr, dptype = 0; + int max_coeff_num = 0, nnz; + char type[15]; + static const int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6 + + switch (block_type) + { + case LUMA: + max_coeff_num = 16; + TRACE_printf("Luma"); + dptype = (currMB->is_intra_block == TRUE) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case LUMA_INTRA16x16DC: + max_coeff_num = 16; + TRACE_printf("Lum16DC"); + dptype = SE_LUM_DC_INTRA; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case LUMA_INTRA16x16AC: + max_coeff_num = 15; + TRACE_printf("Lum16AC"); + dptype = SE_LUM_AC_INTRA; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case CB: + max_coeff_num = 16; + TRACE_printf("Luma_add1"); + dptype = ((currMB->is_intra_block == TRUE)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + p_Vid->nz_coeff[mb_nr][1][j][i] = 0; + break; + case CB_INTRA16x16DC: + max_coeff_num = 16; + TRACE_printf("Luma_add1_16DC"); + dptype = SE_LUM_DC_INTRA; + p_Vid->nz_coeff[mb_nr][1][j][i] = 0; + break; + case CB_INTRA16x16AC: + max_coeff_num = 15; + TRACE_printf("Luma_add1_16AC"); + dptype = SE_LUM_AC_INTRA; + p_Vid->nz_coeff[mb_nr][1][j][i] = 0; + break; + case CR: + max_coeff_num = 16; + TRACE_printf("Luma_add2"); + dptype = ((currMB->is_intra_block == TRUE)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + p_Vid->nz_coeff[mb_nr][2][j][i] = 0; + break; + case CR_INTRA16x16DC: + max_coeff_num = 16; + TRACE_printf("Luma_add2_16DC"); + dptype = SE_LUM_DC_INTRA; + p_Vid->nz_coeff[mb_nr][2][j][i] = 0; + break; + case CR_INTRA16x16AC: + max_coeff_num = 15; + TRACE_printf("Luma_add1_16AC"); + dptype = SE_LUM_AC_INTRA; + p_Vid->nz_coeff[mb_nr][2][j][i] = 0; + break; + case CHROMA_DC: + max_coeff_num = p_Vid->num_cdc_coeff; + cdc = 1; + TRACE_printf("ChrDC"); + dptype = (currMB->is_intra_block == TRUE) ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + case CHROMA_AC: + max_coeff_num = 15; + cac = 1; + TRACE_printf("ChrAC"); + dptype = (currMB->is_intra_block == TRUE) ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER; + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + default: + error ("read_coeff_4x4_CAVLC: invalid block type", 600); + p_Vid->nz_coeff[mb_nr][0][j][i] = 0; + break; + } + + currSE.type = dptype; + dP = &(currSlice->partArr[partMap[dptype]]); + currStream = dP->bitstream; + + if (!cdc) + { + // luma or chroma AC + if(block_type==LUMA || block_type==LUMA_INTRA16x16DC || block_type==LUMA_INTRA16x16AC ||block_type==CHROMA_AC) + { + nnz = (!cac) ? predict_nnz(currMB, LUMA, i<<2, j<<2) : predict_nnz_chroma(currMB, i, ((j-4)<<2)); + } + else if (block_type==CB || block_type==CB_INTRA16x16DC || block_type==CB_INTRA16x16AC) + { + nnz = predict_nnz(currMB, CB, i<<2, j<<2); + } + else + { + nnz = predict_nnz(currMB, CR, i<<2, j<<2); + } + + currSE.value1 = (nnz < 2) ? 0 : ((nnz < 4) ? 1 : ((nnz < 8) ? 2 : 3)); + + readSyntaxElement_NumCoeffTrailingOnes(&currSE, currStream, type); + + numcoeff = currSE.value1; + numtrailingones = currSE.value2; + + if(block_type==LUMA || block_type==LUMA_INTRA16x16DC || block_type==LUMA_INTRA16x16AC ||block_type==CHROMA_AC) + p_Vid->nz_coeff[mb_nr][0][j][i] = (byte) numcoeff; + else if (block_type==CB || block_type==CB_INTRA16x16DC || block_type==CB_INTRA16x16AC) + p_Vid->nz_coeff[mb_nr][1][j][i] = (byte) numcoeff; + else + p_Vid->nz_coeff[mb_nr][2][j][i] = (byte) numcoeff; + } + else + { + // chroma DC + readSyntaxElement_NumCoeffTrailingOnesChromaDC(p_Vid, &currSE, currStream); + + numcoeff = currSE.value1; + numtrailingones = currSE.value2; + } + + memset(levarr, 0, max_coeff_num * sizeof(int)); + memset(runarr, 0, max_coeff_num * sizeof(int)); + + numones = numtrailingones; + *number_coefficients = numcoeff; + + if (numcoeff) + { + if (numtrailingones) + { + currSE.len = numtrailingones; + +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s trailing ones sign (%d,%d)", type, i, j); +#endif + + readSyntaxElement_FLC (&currSE, currStream); + + code = currSE.inf; + ntr = numtrailingones; + for (k = numcoeff - 1; k > numcoeff - 1 - numtrailingones; k--) + { + ntr --; + levarr[k] = (code>>ntr)&1 ? -1 : 1; + } + } + + // decode levels + level_two_or_higher = (numcoeff > 3 && numtrailingones == 3)? 0 : 1; + vlcnum = (numcoeff > 10 && numtrailingones < 3) ? 1 : 0; + + for (k = numcoeff - 1 - numtrailingones; k >= 0; k--) + { + +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s lev (%d,%d) k=%d vlc=%d ", type, i, j, k, vlcnum); +#endif + + if (vlcnum == 0) + readSyntaxElement_Level_VLC0(&currSE, currStream); + else + readSyntaxElement_Level_VLCN(&currSE, vlcnum, currStream); + + if (level_two_or_higher) + { + currSE.inf += (currSE.inf > 0) ? 1 : -1; + level_two_or_higher = 0; + } + + levarr[k] = currSE.inf; + abslevel = iabs(levarr[k]); + if (abslevel == 1) + ++numones; + + // update VLC table + if (abslevel > incVlc[vlcnum]) + ++vlcnum; + + if (k == numcoeff - 1 - numtrailingones && abslevel >3) + vlcnum = 2; + } + + if (numcoeff < max_coeff_num) + { + // decode total run + vlcnum = numcoeff - 1; + currSE.value1 = vlcnum; + +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s totalrun (%d,%d) vlc=%d ", type, i,j, vlcnum); +#endif + if (cdc) + readSyntaxElement_TotalZerosChromaDC(p_Vid, &currSE, currStream); + else + readSyntaxElement_TotalZeros(&currSE, currStream); + + totzeros = currSE.value1; + } + else + { + totzeros = 0; + } + + // decode run before each coefficient + zerosleft = totzeros; + i = numcoeff - 1; + + if (zerosleft > 0 && i > 0) + { + do + { + // select VLC for runbefore + vlcnum = imin(zerosleft - 1, RUNBEFORE_NUM_M1); + + currSE.value1 = vlcnum; +#if TRACE + snprintf(currSE.tracestring, + TRACESTRING_SIZE, "%s run (%d,%d) k=%d vlc=%d ", + type, i, j, i, vlcnum); +#endif + + readSyntaxElement_Run(&currSE, currStream); + runarr[i] = currSE.value1; + + zerosleft -= runarr[i]; + i --; + } while (zerosleft != 0 && i != 0); + } + runarr[i] = zerosleft; + } // if numcoeff +} + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 4x4 blocks in a MB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_4x4_CAVLC (Macroblock *currMB, ColorPlane pl, int (*InvLevelScale4x4)[4], int qp_per, int cbp, byte **nzcoeff) +{ + int block_y, block_x, b8; + int i, j, k; + int i0, j0; + int levarr[16] = {0}, runarr[16] = {0}, numcoeff; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + int start_scan = IS_I16MB(currMB) ? 1 : 0; + int64 *cur_cbp = &currMB->s_cbp[pl].blk; + int cur_context; + int block_y4, block_x4; + + if (IS_I16MB(currMB)) + { + if (pl == PLANE_Y) + cur_context = LUMA_INTRA16x16AC; + else if (pl == PLANE_U) + cur_context = CB_INTRA16x16AC; + else + cur_context = CR_INTRA16x16AC; + } + else + { + if (pl == PLANE_Y) + cur_context = LUMA; + else if (pl == PLANE_U) + cur_context = CB; + else + cur_context = CR; + } + + + for (block_y = 0; block_y < 4; block_y += 2) /* all modes */ + { + block_y4 = block_y << 2; + for (block_x = 0; block_x < 4; block_x += 2) + { + block_x4 = block_x << 2; + b8 = (block_y + (block_x >> 1)); + + if (cbp & (1 << b8)) // test if the block contains any coefficients + { + for (j = block_y4; j < block_y4 + 8; j += BLOCK_SIZE) + { + for (i = block_x4; i < block_x4 + 8; i += BLOCK_SIZE) + { + currSlice->read_coeff_4x4_CAVLC(currMB, cur_context, i >> 2, j >> 2, levarr, runarr, &numcoeff); + pos_scan_4x4 = pos_scan4x4[start_scan]; + + for (k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) + { + pos_scan_4x4 += (runarr[k] << 1); + + i0 = *pos_scan_4x4++; + j0 = *pos_scan_4x4++; + + // inverse quant for 4x4 transform only + *cur_cbp |= i64_power2(j + (i >> 2)); + + currSlice->cof[pl][j + j0][i + i0]= rshift_rnd_sf((levarr[k] * InvLevelScale4x4[j0][i0])<fcf[pl][j + j0][i + i0]= levarr[k]; + } + } + } + } + } + else + { + nzcoeff[block_y ][block_x ] = 0; + nzcoeff[block_y ][block_x + 1] = 0; + nzcoeff[block_y + 1][block_x ] = 0; + nzcoeff[block_y + 1][block_x + 1] = 0; + } + } + } +} + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 4x4 blocks in a MB +* from the NAL (CAVLC Lossless Mode) +************************************************************************ +*/ +static void read_comp_coeff_4x4_CAVLC_ls (Macroblock *currMB, ColorPlane pl, int (*InvLevelScale4x4)[4], int qp_per, int cbp, byte **nzcoeff) +{ + int block_y, block_x, b8; + int i, j, k; + int i0, j0; + int levarr[16] = {0}, runarr[16] = {0}, numcoeff; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + int start_scan = IS_I16MB(currMB) ? 1 : 0; + int64 *cur_cbp = &currMB->s_cbp[pl].blk; + int coef_ctr, cur_context; + + if (IS_I16MB(currMB)) + { + if (pl == PLANE_Y) + cur_context = LUMA_INTRA16x16AC; + else if (pl == PLANE_U) + cur_context = CB_INTRA16x16AC; + else + cur_context = CR_INTRA16x16AC; + } + else + { + if (pl == PLANE_Y) + cur_context = LUMA; + else if (pl == PLANE_U) + cur_context = CB; + else + cur_context = CR; + } + + for (block_y=0; block_y < 4; block_y += 2) /* all modes */ + { + for (block_x=0; block_x < 4; block_x += 2) + { + b8 = 2*(block_y>>1) + (block_x>>1); + + if (cbp & (1<read_coeff_4x4_CAVLC(currMB, cur_context, i, j, levarr, runarr, &numcoeff); + + coef_ctr = start_scan - 1; + + for (k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) + { + coef_ctr += runarr[k]+1; + + i0=pos_scan4x4[coef_ctr][0]; + j0=pos_scan4x4[coef_ctr][1]; + + *cur_cbp |= i64_power2((j<<2) + i); + currSlice->cof[pl][(j<<2) + j0][(i<<2) + i0]= levarr[k]; + //currSlice->fcf[pl][(j<<2) + j0][(i<<2) + i0]= levarr[k]; + } + } + } + } + } + else + { + nzcoeff[block_y ][block_x ] = 0; + nzcoeff[block_y ][block_x + 1] = 0; + nzcoeff[block_y + 1][block_x ] = 0; + nzcoeff[block_y + 1][block_x + 1] = 0; + } + } + } +} + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 4x4 blocks in a MB +* from the NAL (CABAC Mode) +************************************************************************ +*/ +static void read_comp_coeff_8x8_CAVLC (Macroblock *currMB, ColorPlane pl, int (*InvLevelScale8x8)[8], int qp_per, int cbp, byte **nzcoeff) +{ + int block_y, block_x, b4, b8; + int block_y4, block_x4; + int i, j, k; + int i0, j0; + int levarr[16] = {0}, runarr[16] = {0}, numcoeff; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + const byte (*pos_scan8x8)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN8x8 : FIELD_SCAN8x8; + int start_scan = IS_I16MB(currMB) ? 1 : 0; + int64 *cur_cbp = &currMB->s_cbp[pl].blk; + int coef_ctr, cur_context; + + if (IS_I16MB(currMB)) + { + if (pl == PLANE_Y) + cur_context = LUMA_INTRA16x16AC; + else if (pl == PLANE_U) + cur_context = CB_INTRA16x16AC; + else + cur_context = CR_INTRA16x16AC; + } + else + { + if (pl == PLANE_Y) + cur_context = LUMA; + else if (pl == PLANE_U) + cur_context = CB; + else + cur_context = CR; + } + + for (block_y = 0; block_y < 4; block_y += 2) /* all modes */ + { + block_y4 = block_y << 2; + + for (block_x = 0; block_x < 4; block_x += 2) + { + block_x4 = block_x << 2; + b8 = block_y + (block_x>>1); + + if (cbp & (1<read_coeff_4x4_CAVLC(currMB, cur_context, i, j, levarr, runarr, &numcoeff); + + coef_ctr = start_scan - 1; + + for (k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) + { + coef_ctr += runarr[k] + 1; + + // do same as CABAC for deblocking: any coeff in the 8x8 marks all the 4x4s + //as containing coefficients + *cur_cbp |= 51 << (block_y4 + block_x); + + b4 = (coef_ctr << 2) + 2*(j - block_y) + (i - block_x); + + i0 = pos_scan8x8[b4][0]; + j0 = pos_scan8x8[b4][1]; + + currSlice->mb_rres[pl][block_y4 +j0][block_x4 +i0] = rshift_rnd_sf((levarr[k] * InvLevelScale8x8[j0][i0])<luma_transform_size_8x8_flag) + } + } + } + else + { + nzcoeff[block_y ][block_x ] = 0; + nzcoeff[block_y ][block_x + 1] = 0; + nzcoeff[block_y + 1][block_x ] = 0; + nzcoeff[block_y + 1][block_x + 1] = 0; + } + } + } +} + +/*! +************************************************************************ +* \brief +* Get coefficients (run/level) of 8x8 blocks in a MB +* from the NAL (CAVLC Lossless Mode) +************************************************************************ +*/ +static void read_comp_coeff_8x8_CAVLC_ls (Macroblock *currMB, ColorPlane pl, int (*InvLevelScale8x8)[8], int qp_per, int cbp, byte **nzcoeff) +{ + int block_y, block_x, b4, b8; + int i, j, k; + int levarr[16] = {0}, runarr[16] = {0}, numcoeff; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + const byte (*pos_scan8x8)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN8x8 : FIELD_SCAN8x8; + int start_scan = IS_I16MB(currMB) ? 1 : 0; + int64 *cur_cbp = &currMB->s_cbp[pl].blk; + int coef_ctr, cur_context; + + if (IS_I16MB(currMB)) + { + if (pl == PLANE_Y) + cur_context = LUMA_INTRA16x16AC; + else if (pl == PLANE_U) + cur_context = CB_INTRA16x16AC; + else + cur_context = CR_INTRA16x16AC; + } + else + { + if (pl == PLANE_Y) + cur_context = LUMA; + else if (pl == PLANE_U) + cur_context = CB; + else + cur_context = CR; + } + + for (block_y=0; block_y < 4; block_y += 2) /* all modes */ + { + for (block_x=0; block_x < 4; block_x += 2) + { + b8 = 2*(block_y>>1) + (block_x>>1); + + if (cbp & (1<read_coeff_4x4_CAVLC(currMB, cur_context, i, j, levarr, runarr, &numcoeff); + + coef_ctr = start_scan - 1; + + for (k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) + { + coef_ctr += runarr[k]+1; + + // do same as CABAC for deblocking: any coeff in the 8x8 marks all the 4x4s + //as containing coefficients + *cur_cbp |= 51 << ((block_y<<2) + block_x); + + b4 = 2*(j-block_y)+(i-block_x); + + iz=pos_scan8x8[coef_ctr*4+b4][0]; + jz=pos_scan8x8[coef_ctr*4+b4][1]; + + currSlice->mb_rres[pl][block_y*4 +jz][block_x*4 +iz] = levarr[k]; + } + } + } + } + } + else + { + nzcoeff[block_y ][block_x ] = 0; + nzcoeff[block_y ][block_x + 1] = 0; + nzcoeff[block_y + 1][block_x ] = 0; + nzcoeff[block_y + 1][block_x + 1] = 0; + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CAVLC_400(Macroblock *currMB) +{ + int k; + int mb_nr = currMB->mbAddrX; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int i0, j0; + + int levarr[16], runarr[16], numcoeff; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + + int intra = (currMB->is_intra_block == TRUE); + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + int (*InvLevelScale8x8)[8] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + currSlice->read_coeff_4x4_CAVLC(currMB, LUMA_INTRA16x16DC, 0, 0, levarr, runarr, &numcoeff); + + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) // leave if level == 0 + { + pos_scan_4x4 += 2 * runarr[k]; + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = levarr[k];// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = levarr[k];// add new intra DC coeff + } + } + + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[PLANE_Y] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[PLANE_Y] ]; + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + InvLevelScale8x8 = intra? currSlice->InvLevelScale8x8_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale8x8_Inter[currSlice->colour_plane_id][qp_rem]; + + // luma coefficients + if (cbp) + { + if (!currMB->luma_transform_size_8x8_flag) // 4x4 transform + { + currMB->read_comp_coeff_4x4_CAVLC (currMB, PLANE_Y, InvLevelScale4x4, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + else // 8x8 transform + { + currMB->read_comp_coeff_8x8_CAVLC (currMB, PLANE_Y, InvLevelScale8x8, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + } + else + { + fast_memset(p_Vid->nz_coeff[mb_nr][0][0], 0, BLOCK_PIXELS * sizeof(byte)); + } +} + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CAVLC_422(Macroblock *currMB) +{ + int i,j,k; + int mb_nr = currMB->mbAddrX; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int coef_ctr, i0, j0, b8; + int ll; + int levarr[16], runarr[16], numcoeff; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + + int uv; + int qp_per_uv[2]; + int qp_rem_uv[2]; + + int intra = (currMB->is_intra_block == TRUE); + + int b4; + //StorablePicture *dec_picture = currSlice->dec_picture; + int m6[4]; + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + int (*InvLevelScale8x8)[8] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + currSlice->read_coeff_4x4_CAVLC(currMB, LUMA_INTRA16x16DC, 0, 0, levarr, runarr, &numcoeff); + + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) // leave if level == 0 + { + pos_scan_4x4 += 2 * runarr[k]; + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = levarr[k];// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = levarr[k];// add new intra DC coeff + } + } + + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + + //init quant parameters for chroma + for(i=0; i < 2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + InvLevelScale8x8 = intra? currSlice->InvLevelScale8x8_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale8x8_Inter[currSlice->colour_plane_id][qp_rem]; + + // luma coefficients + if (cbp) + { + if (!currMB->luma_transform_size_8x8_flag) // 4x4 transform + { + currMB->read_comp_coeff_4x4_CAVLC (currMB, PLANE_Y, InvLevelScale4x4, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + else // 8x8 transform + { + currMB->read_comp_coeff_8x8_CAVLC (currMB, PLANE_Y, InvLevelScale8x8, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + } + else + { + fast_memset(p_Vid->nz_coeff[mb_nr][0][0], 0, BLOCK_PIXELS * sizeof(byte)); + } + + //========================== CHROMA DC ============================ + //----------------------------------------------------------------- + // chroma DC coeff + if(cbp>15) + { + for (ll=0;ll<3;ll+=2) + { + int (*InvLevelScale4x4)[4] = NULL; + uv = ll>>1; + { + int **imgcof = currSlice->cof[PLANE_U + uv]; + int m3[2][4] = {{0,0,0,0},{0,0,0,0}}; + int m4[2][4] = {{0,0,0,0},{0,0,0,0}}; + int qp_per_uv_dc = p_Vid->qp_per_matrix[ (currMB->qpc[uv] + 3 + p_Vid->bitdepth_chroma_qp_scale) ]; //for YUV422 only + int qp_rem_uv_dc = p_Vid->qp_rem_matrix[ (currMB->qpc[uv] + 3 + p_Vid->bitdepth_chroma_qp_scale) ]; //for YUV422 only + if (intra) + InvLevelScale4x4 = currSlice->InvLevelScale4x4_Intra[PLANE_U + uv][qp_rem_uv_dc]; + else + InvLevelScale4x4 = currSlice->InvLevelScale4x4_Inter[PLANE_U + uv][qp_rem_uv_dc]; + + + //===================== CHROMA DC YUV422 ====================== + currSlice->read_coeff_4x4_CAVLC(currMB, CHROMA_DC, 0, 0, levarr, runarr, &numcoeff); + coef_ctr=-1; + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) + { + currMB->s_cbp[0].blk |= ((int64)0xff0000) << (ll<<2); + coef_ctr += runarr[k]+1; + i0 = SCAN_YUV422[coef_ctr][0]; + j0 = SCAN_YUV422[coef_ctr][1]; + + m3[i0][j0]=levarr[k]; + } + } + + // inverse CHROMA DC YUV422 transform + // horizontal + if(currMB->is_lossless == FALSE) + { + m4[0][0] = m3[0][0] + m3[1][0]; + m4[0][1] = m3[0][1] + m3[1][1]; + m4[0][2] = m3[0][2] + m3[1][2]; + m4[0][3] = m3[0][3] + m3[1][3]; + + m4[1][0] = m3[0][0] - m3[1][0]; + m4[1][1] = m3[0][1] - m3[1][1]; + m4[1][2] = m3[0][2] - m3[1][2]; + m4[1][3] = m3[0][3] - m3[1][3]; + + for (i = 0; i < 2; ++i) + { + m6[0] = m4[i][0] + m4[i][2]; + m6[1] = m4[i][0] - m4[i][2]; + m6[2] = m4[i][1] - m4[i][3]; + m6[3] = m4[i][1] + m4[i][3]; + + imgcof[ 0][i<<2] = m6[0] + m6[3]; + imgcof[ 4][i<<2] = m6[1] + m6[2]; + imgcof[ 8][i<<2] = m6[1] - m6[2]; + imgcof[12][i<<2] = m6[0] - m6[3]; + }//for (i=0;i<2;++i) + + for(j = 0;j < p_Vid->mb_cr_size_y; j += BLOCK_SIZE) + { + for(i=0;i < p_Vid->mb_cr_size_x;i+=BLOCK_SIZE) + { + imgcof[j][i] = rshift_rnd_sf((imgcof[j][i] * InvLevelScale4x4[0][0]) << qp_per_uv_dc, 6); + } + } + } + else + { + for(j=0;j<4;++j) + { + currSlice->cof[PLANE_U + uv][j<<2][0] = m3[0][j]; + currSlice->cof[PLANE_U + uv][j<<2][4] = m3[1][j]; + } + } + + } + }//for (ll=0;ll<3;ll+=2) + } + + //========================== CHROMA AC ============================ + //----------------------------------------------------------------- + // chroma AC coeff, all zero fram start_scan + if (cbp<=31) + { + fast_memset(p_Vid->nz_coeff [mb_nr ][1][0], 0, 2 * BLOCK_PIXELS * sizeof(byte)); + } + else + { + if(currMB->is_lossless == FALSE) + { + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + InvLevelScale4x4 = intra ? currSlice->InvLevelScale4x4_Intra[PLANE_U + uv][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[PLANE_U + uv][qp_rem_uv[uv]]; + + for (b4=0; b4 < 4; ++b4) + { + i = cofuv_blk_x[1][b8][b4]; + j = cofuv_blk_y[1][b8][b4]; + + currSlice->read_coeff_4x4_CAVLC(currMB, CHROMA_AC, i + 2*uv, j + 4, levarr, runarr, &numcoeff); + coef_ctr = 0; + + for(k = 0; k < numcoeff;++k) + { + if (levarr[k] != 0) + { + currMB->s_cbp[0].blk |= i64_power2(cbp_blk_chroma[b8][b4]); + coef_ctr += runarr[k] + 1; + + i0=pos_scan4x4[coef_ctr][0]; + j0=pos_scan4x4[coef_ctr][1]; + + currSlice->cof[PLANE_U + uv][(j<<2) + j0][(i<<2) + i0] = rshift_rnd_sf((levarr[k] * InvLevelScale4x4[j0][i0])<fcf[PLANE_U + uv][(j<<2) + j0][(i<<2) + i0] = levarr[k]; + } + } + } + } + } + else + { + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + + for (b4=0; b4 < 4; ++b4) + { + i = cofuv_blk_x[1][b8][b4]; + j = cofuv_blk_y[1][b8][b4]; + + currSlice->read_coeff_4x4_CAVLC(currMB, CHROMA_AC, i + 2*uv, j + 4, levarr, runarr, &numcoeff); + coef_ctr = 0; + + for(k = 0; k < numcoeff;++k) + { + if (levarr[k] != 0) + { + currMB->s_cbp[0].blk |= i64_power2(cbp_blk_chroma[b8][b4]); + coef_ctr += runarr[k] + 1; + + i0=pos_scan4x4[coef_ctr][0]; + j0=pos_scan4x4[coef_ctr][1]; + + currSlice->cof[PLANE_U + uv][(j<<2) + j0][(i<<2) + i0] = levarr[k]; + } + } + } + } + } + } //if (dec_picture->chroma_format_idc != YUV400) +} + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CAVLC_444(Macroblock *currMB) +{ + int i,k; + int mb_nr = currMB->mbAddrX; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int coef_ctr, i0, j0; + int levarr[16], runarr[16], numcoeff; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + + int uv; + int qp_per_uv[3]; + int qp_rem_uv[3]; + + int intra = (currMB->is_intra_block == TRUE); + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + int (*InvLevelScale8x8)[8] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else // read DC coeffs for new intra modes + { + cbp = currMB->cbp; + + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + currSlice->read_coeff_4x4_CAVLC(currMB, LUMA_INTRA16x16DC, 0, 0, levarr, runarr, &numcoeff); + + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) // leave if level == 0 + { + pos_scan_4x4 += 2 * runarr[k]; + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = levarr[k];// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = levarr[k];// add new intra DC coeff + } + } + + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + + //init quant parameters for chroma + for(i=PLANE_U; i <= PLANE_V; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i] ]; + } + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + InvLevelScale8x8 = intra? currSlice->InvLevelScale8x8_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale8x8_Inter[currSlice->colour_plane_id][qp_rem]; + + // luma coefficients + if (cbp) + { + if (!currMB->luma_transform_size_8x8_flag) // 4x4 transform + { + currMB->read_comp_coeff_4x4_CAVLC (currMB, PLANE_Y, InvLevelScale4x4, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + else // 8x8 transform + { + currMB->read_comp_coeff_8x8_CAVLC (currMB, PLANE_Y, InvLevelScale8x8, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + } + else + { + fast_memset(p_Vid->nz_coeff[mb_nr][0][0], 0, BLOCK_PIXELS * sizeof(byte)); + } + + for (uv = PLANE_U; uv <= PLANE_V; ++uv ) + { + /*----------------------16x16DC Luma_Add----------------------*/ + if (IS_I16MB (currMB)) // read DC coeffs for new intra modes + { + if (uv == PLANE_U) + currSlice->read_coeff_4x4_CAVLC(currMB, CB_INTRA16x16DC, 0, 0, levarr, runarr, &numcoeff); + else + currSlice->read_coeff_4x4_CAVLC(currMB, CR_INTRA16x16DC, 0, 0, levarr, runarr, &numcoeff); + + coef_ctr=-1; + + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) // leave if level == 0 + { + coef_ctr += runarr[k] + 1; + + i0 = pos_scan4x4[coef_ctr][0]; + j0 = pos_scan4x4[coef_ctr][1]; + currSlice->cof[uv][j0<<2][i0<<2] = levarr[k];// add new intra DC coeff + //currSlice->fcf[uv][j0<<2][i0<<2] = levarr[k];// add new intra DC coeff + } //if leavarr[k] + } //k loop + + if(currMB->is_lossless == FALSE) + { + itrans_2(currMB, (ColorPlane) (uv)); // transform new intra DC + } + } //IS_I16MB + + update_qp(currMB, currSlice->qp); + + //init constants for every chroma qp offset + qp_per_uv[uv] = p_Vid->qp_per_matrix[ currMB->qp_scaled[uv] ]; + qp_rem_uv[uv] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[uv] ]; + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[uv][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[uv][qp_rem_uv[uv]]; + InvLevelScale8x8 = intra? currSlice->InvLevelScale8x8_Intra[uv][qp_rem_uv[uv]] : currSlice->InvLevelScale8x8_Inter[uv][qp_rem_uv[uv]]; + + if (!currMB->luma_transform_size_8x8_flag) // 4x4 transform + { + currMB->read_comp_coeff_4x4_CAVLC (currMB, (ColorPlane) (uv), InvLevelScale4x4, qp_per_uv[uv], cbp, p_Vid->nz_coeff[mb_nr][uv]); + } + else // 8x8 transform + { + currMB->read_comp_coeff_8x8_CAVLC (currMB, (ColorPlane) (uv), InvLevelScale8x8, qp_per_uv[uv], cbp, p_Vid->nz_coeff[mb_nr][uv]); + } + } +} + +/*! + ************************************************************************ + * \brief + * Get coded block pattern and coefficients (run/level) + * from the NAL + ************************************************************************ + */ +static void read_CBP_and_coeffs_from_NAL_CAVLC_420(Macroblock *currMB) +{ + int i,j,k; + int mb_nr = currMB->mbAddrX; + int cbp; + SyntaxElement currSE; + DataPartition *dP = NULL; + Slice *currSlice = currMB->p_Slice; + const byte *partMap = assignSE2partition[currSlice->dp_mode]; + int coef_ctr, i0, j0, b8; + int ll; + int levarr[16], runarr[16], numcoeff; + + int qp_per, qp_rem; + VideoParameters *p_Vid = currMB->p_Vid; + int smb = ((p_Vid->type==SP_SLICE) && (currMB->is_intra_block == FALSE)) || (p_Vid->type == SI_SLICE && currMB->mb_type == SI4MB); + + int uv; + int qp_per_uv[2]; + int qp_rem_uv[2]; + + int intra = (currMB->is_intra_block == TRUE); + int temp[4]; + + int b4; + //StorablePicture *dec_picture = currSlice->dec_picture; + + int need_transform_size_flag; + + int (*InvLevelScale4x4)[4] = NULL; + int (*InvLevelScale8x8)[8] = NULL; + // select scan type + const byte (*pos_scan4x4)[2] = ((p_Vid->structure == FRAME) && (!currMB->mb_field)) ? SNGL_SCAN : FIELD_SCAN; + const byte *pos_scan_4x4 = pos_scan4x4[0]; + + // read CBP if not new intra mode + if (!IS_I16MB (currMB)) + { + //===== C B P ===== + //--------------------- + currSE.type = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? SE_CBP_INTRA + : SE_CBP_INTER; + + dP = &(currSlice->partArr[partMap[currSE.type]]); + + currSE.mapping = (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + ? currSlice->linfo_cbp_intra + : currSlice->linfo_cbp_inter; + + TRACE_STRING("coded_block_pattern"); + dP->readSyntaxElement(currMB, &currSE, dP); + currMB->cbp = cbp = currSE.value1; + + //============= Transform size flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (IS_DIRECT(currMB) && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15) + && currSlice->Transform8x8Mode); + + if (need_transform_size_flag) + { + currSE.type = SE_HEADER; + dP = &(currSlice->partArr[partMap[SE_HEADER]]); + TRACE_STRING("transform_size_8x8_flag"); + + // read CAVLC transform_size_8x8_flag + currSE.len = 1; + readSyntaxElement_FLC(&currSE, dP->bitstream); + + currMB->luma_transform_size_8x8_flag = (Boolean) currSE.value1; + } + + //===== DQUANT ===== + //---------------------- + // Delta quant only if nonzero coeffs + if (cbp !=0) + { + read_delta_quant(&currSE, dP, currMB, partMap, ((currMB->is_intra_block == FALSE)) ? SE_DELTA_QUANT_INTER : SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if ((currMB->is_intra_block == FALSE) && currSlice->dpC_NotPresent ) + currMB->dpl_flag = 1; + + if( intra && currSlice->dpB_NotPresent ) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + + // check for prediction from neighbours + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + cbp = 0; + currMB->cbp = cbp; + } + } + } + } + else + { + cbp = currMB->cbp; + read_delta_quant(&currSE, dP, currMB, partMap, SE_DELTA_QUANT_INTRA); + + if (currSlice->dp_mode) + { + if (currSlice->dpB_NotPresent) + { + currMB->ei_flag = 1; + currMB->dpl_flag = 1; + } + check_dp_neighbors (currMB); + if (currMB->dpl_flag) + { + currMB->cbp = cbp = 0; + } + } + + if (!currMB->dpl_flag) + { + pos_scan_4x4 = pos_scan4x4[0]; + + currSlice->read_coeff_4x4_CAVLC(currMB, LUMA_INTRA16x16DC, 0, 0, levarr, runarr, &numcoeff); + + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) // leave if level == 0 + { + pos_scan_4x4 += 2 * runarr[k]; + + i0 = ((*pos_scan_4x4++) << 2); + j0 = ((*pos_scan_4x4++) << 2); + + currSlice->cof[0][j0][i0] = levarr[k];// add new intra DC coeff + //currSlice->fcf[0][j0][i0] = levarr[k];// add new intra DC coeff + } + } + + + if(currMB->is_lossless == FALSE) + itrans_2(currMB, (ColorPlane) currSlice->colour_plane_id);// transform new intra DC + } + } + + update_qp(currMB, currSlice->qp); + + qp_per = p_Vid->qp_per_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + qp_rem = p_Vid->qp_rem_matrix[ currMB->qp_scaled[currSlice->colour_plane_id] ]; + + //init quant parameters for chroma + for(i=0; i < 2; ++i) + { + qp_per_uv[i] = p_Vid->qp_per_matrix[ currMB->qp_scaled[i + 1] ]; + qp_rem_uv[i] = p_Vid->qp_rem_matrix[ currMB->qp_scaled[i + 1] ]; + } + + InvLevelScale4x4 = intra? currSlice->InvLevelScale4x4_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale4x4_Inter[currSlice->colour_plane_id][qp_rem]; + InvLevelScale8x8 = intra? currSlice->InvLevelScale8x8_Intra[currSlice->colour_plane_id][qp_rem] : currSlice->InvLevelScale8x8_Inter[currSlice->colour_plane_id][qp_rem]; + + // luma coefficients + if (cbp) + { + if (!currMB->luma_transform_size_8x8_flag) // 4x4 transform + { + currMB->read_comp_coeff_4x4_CAVLC (currMB, PLANE_Y, InvLevelScale4x4, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + else // 8x8 transform + { + currMB->read_comp_coeff_8x8_CAVLC (currMB, PLANE_Y, InvLevelScale8x8, qp_per, cbp, p_Vid->nz_coeff[mb_nr][PLANE_Y]); + } + } + else + { + fast_memset(p_Vid->nz_coeff[mb_nr][0][0], 0, BLOCK_PIXELS * sizeof(byte)); + } + + //========================== CHROMA DC ============================ + //----------------------------------------------------------------- + // chroma DC coeff + if(cbp>15) + { + for (ll=0;ll<3;ll+=2) + { + uv = ll>>1; + + InvLevelScale4x4 = intra ? currSlice->InvLevelScale4x4_Intra[PLANE_U + uv][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[PLANE_U + uv][qp_rem_uv[uv]]; + //===================== CHROMA DC YUV420 ====================== + memset(currSlice->cofu, 0, 4 *sizeof(int)); + coef_ctr=-1; + + currSlice->read_coeff_4x4_CAVLC(currMB, CHROMA_DC, 0, 0, levarr, runarr, &numcoeff); + + for(k = 0; k < numcoeff; ++k) + { + if (levarr[k] != 0) + { + currMB->s_cbp[0].blk |= 0xf0000 << (ll<<1) ; + coef_ctr += runarr[k] + 1; + currSlice->cofu[coef_ctr]=levarr[k]; + } + } + + + if (smb || (currMB->is_lossless == TRUE)) // check to see if MB type is SPred or SIntra4x4 + { + currSlice->cof[PLANE_U + uv][0][0] = currSlice->cofu[0]; + currSlice->cof[PLANE_U + uv][4][0] = currSlice->cofu[1]; + currSlice->cof[PLANE_U + uv][0][4] = currSlice->cofu[2]; + currSlice->cof[PLANE_U + uv][4][4] = currSlice->cofu[3]; + //currSlice->fcf[PLANE_U + uv][0][0] = currSlice->cofu[0]; + //currSlice->fcf[PLANE_U + uv][4][0] = currSlice->cofu[1]; + //currSlice->fcf[PLANE_U + uv][0][4] = currSlice->cofu[2]; + //currSlice->fcf[PLANE_U + uv][4][4] = currSlice->cofu[3]; + } + else + { + ihadamard2x2(currSlice->cofu, temp); + //currSlice->fcf[PLANE_U + uv][0][0] = temp[0]; + //currSlice->fcf[PLANE_U + uv][0][4] = temp[1]; + //currSlice->fcf[PLANE_U + uv][4][0] = temp[2]; + //currSlice->fcf[PLANE_U + uv][4][4] = temp[3]; + + currSlice->cof[PLANE_U + uv][0][0] = (((temp[0] * InvLevelScale4x4[0][0])<>5); + currSlice->cof[PLANE_U + uv][0][4] = (((temp[1] * InvLevelScale4x4[0][0])<>5); + currSlice->cof[PLANE_U + uv][4][0] = (((temp[2] * InvLevelScale4x4[0][0])<>5); + currSlice->cof[PLANE_U + uv][4][4] = (((temp[3] * InvLevelScale4x4[0][0])<>5); + } + } + } + + //========================== CHROMA AC ============================ + //----------------------------------------------------------------- + // chroma AC coeff, all zero fram start_scan + if (cbp<=31) + { + fast_memset(p_Vid->nz_coeff [mb_nr ][1][0], 0, 2 * BLOCK_PIXELS * sizeof(byte)); + } + else + { + if(currMB->is_lossless == FALSE) + { + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + InvLevelScale4x4 = intra ? currSlice->InvLevelScale4x4_Intra[PLANE_U + uv][qp_rem_uv[uv]] : currSlice->InvLevelScale4x4_Inter[PLANE_U + uv][qp_rem_uv[uv]]; + + for (b4=0; b4 < 4; ++b4) + { + i = cofuv_blk_x[0][b8][b4]; + j = cofuv_blk_y[0][b8][b4]; + + currSlice->read_coeff_4x4_CAVLC(currMB, CHROMA_AC, i + 2*uv, j + 4, levarr, runarr, &numcoeff); + coef_ctr = 0; + + for(k = 0; k < numcoeff;++k) + { + if (levarr[k] != 0) + { + currMB->s_cbp[0].blk |= i64_power2(cbp_blk_chroma[b8][b4]); + coef_ctr += runarr[k] + 1; + + i0=pos_scan4x4[coef_ctr][0]; + j0=pos_scan4x4[coef_ctr][1]; + + currSlice->cof[PLANE_U + uv][(j<<2) + j0][(i<<2) + i0] = rshift_rnd_sf((levarr[k] * InvLevelScale4x4[j0][i0])<fcf[PLANE_U + uv][(j<<2) + j0][(i<<2) + i0] = levarr[k]; + } + } + } + } + } + else + { + for (b8=0; b8 < p_Vid->num_blk8x8_uv; ++b8) + { + currMB->is_v_block = uv = (b8 > ((p_Vid->num_uv_blocks) - 1 )); + + for (b4=0; b4 < 4; ++b4) + { + i = cofuv_blk_x[0][b8][b4]; + j = cofuv_blk_y[0][b8][b4]; + + currSlice->read_coeff_4x4_CAVLC(currMB, CHROMA_AC, i + 2*uv, j + 4, levarr, runarr, &numcoeff); + coef_ctr = 0; + + for(k = 0; k < numcoeff;++k) + { + if (levarr[k] != 0) + { + currMB->s_cbp[0].blk |= i64_power2(cbp_blk_chroma[b8][b4]); + coef_ctr += runarr[k] + 1; + + i0=pos_scan4x4[coef_ctr][0]; + j0=pos_scan4x4[coef_ctr][1]; + + currSlice->cof[PLANE_U + uv][(j<<2) + j0][(i<<2) + i0] = levarr[k]; + } + } + } + } + } + } +} + + +/*! +************************************************************************ +* \brief +* setup coefficient reading functions for CAVLC +* +************************************************************************ +*/ +void set_read_comp_coeff_cavlc(Macroblock *currMB) +{ + if (currMB->is_lossless == FALSE) + { + currMB->read_comp_coeff_4x4_CAVLC = read_comp_coeff_4x4_CAVLC; + currMB->read_comp_coeff_8x8_CAVLC = read_comp_coeff_8x8_CAVLC; + } + else + { + currMB->read_comp_coeff_4x4_CAVLC = read_comp_coeff_4x4_CAVLC_ls; + currMB->read_comp_coeff_8x8_CAVLC = read_comp_coeff_8x8_CAVLC_ls; + } +} + + +void set_read_CBP_and_coeffs_cavlc(Slice *currSlice) +{ + switch (currSlice->p_Vid->active_sps->chroma_format_idc) + { + case YUV444: + if (currSlice->p_Vid->separate_colour_plane_flag == 0) + { + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CAVLC_444; + } + else + { + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CAVLC_400; + } + break; + case YUV422: + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CAVLC_422; + break; + case YUV420: + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CAVLC_420; + break; + case YUV400: + currSlice->read_CBP_and_coeffs_from_NAL = read_CBP_and_coeffs_from_NAL_CAVLC_400; + break; + default: + assert (1); + currSlice->read_CBP_and_coeffs_from_NAL = NULL; + break; + } +} diff --git a/ldecod/src/report_dec.c b/ldecod/src/report_dec.c new file mode 100644 index 0000000..5781b30 --- /dev/null +++ b/ldecod/src/report_dec.c @@ -0,0 +1,566 @@ + +/*! + ************************************************************************ + * \file report_dec.c + * + * \brief + * functions for frame format related information + * + * \author + * Joao Carreira + ************************************************************************ + */ + +#include +#include "global.h" +#include "report_dec.h" + +#include "image.h" + +#define LOGFILE "log.dec" +#define DATADECFILE "dataDec.txt" +#define TRACEFILE "trace_dec.txt" + +void init_report (InputParameters *p_Inp) +{ + if(!p_Inp->bDisplayDecParams) + { + fprintf(stdout,"-------------------------------- Decoder Params -------------------------------\n"); + fprintf(stdout," Input H.264 bitstream : %s \n",p_Inp->infile); + fprintf(stdout," Output Decoded YUV : %s[VIEW] \n",p_Inp->outfile); + if(p_Inp->reffile[0]) + fprintf(stdout," Input reference file : %s \n",p_Inp->reffile); + if(p_Inp->reffile[0] || p_Inp->conceal_mode) + fprintf(stdout," IDRPeriod : %d \n",p_Inp->IDR_Period); + if (p_Inp->conceal_mode) + { + fprintf(stdout," ConcealMode : %d \n",p_Inp->conceal_mode); + fprintf(stdout," SearchModeRef : %d \n",p_Inp->search_mode_ref); + fprintf(stdout," SearchModeNonRef : %d \n",p_Inp->search_mode_nonref); + } + +#ifdef _LEAKYBUCKET_ + fprintf(stdout," Rate_decoder : %8ld \n",p_Inp->R_decoder); + fprintf(stdout," B_decoder : %8ld \n",p_Inp->B_decoder); + fprintf(stdout," F_decoder : %8ld \n",p_Inp->F_decoder); + // Leaky Bucket Param file + fprintf(stdout," LeakyBucketParamFile: %s \n",p_Inp->LeakyBucketParamFile); + calc_buffer(p_Inp); + fprintf(stdout,"-------------------------------------------------------------------------------\n"); +#endif + + } + + if (!p_Inp->silent) + { + //fprintf(stdout,"POC must = frame# or field# for SNRs to be correct\n"); + fprintf(stdout,"-------------------------------------------------------------------------------\n"); + fprintf(stdout," Frame POC View Pic# QP SnrY SnrU SnrV Y:U:V Time(ms)\n"); + fprintf(stdout,"-------------------------------------------------------------------------------\n"); + } +} + + +void FinalReport (VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i; + int nFramesDec = 0, nFramesConceal = 0, nFramesOut = 0; + int n_views; + + // normalize time + p_Vid->tot_time = timenorm(p_Vid->tot_time); + + if( p_Vid->p_Inp->statsfile[0] ) + report_stats(p_Vid); + + for (i=0;inFramesDecoded[i]; + nFramesConceal += p_Vid->nFramesConceal[i]; + nFramesOut += p_Vid->nFramesOut[i]; + } + + if( p_Vid->active_subset_sps ) + n_views = p_Vid->active_subset_sps->num_views_minus1+1; + else + n_views = 1; + + if(p_Inp->reffile[0]) + { + fprintf(stdout,"------------------------- Average SNR all frames -------------------------- \n"); + for(i=0;isnr[GetViewIdx(p_Vid, i)]; + fprintf(stdout," SNR View %2d Y|U|V(dB) : %5.2f | %5.2f | %5.2f\n", GetViewIdx(p_Vid, i), snr->snra[0], snr->snra[1], snr->snra[2]); + } + + } + fprintf(stdout,"------------------------------ Final Report ------------------------------- \n"); + + fprintf(stdout," Frames Decoded = %4d ( %3d", nFramesDec, p_Vid->nFramesDecoded[0] ); + for(i=1;inFramesDecoded[GetViewIdx(p_Vid, i)]); + } + fprintf(stdout," )\n"); + + fprintf(stdout," Frames Concealed = %4d ( %3d", nFramesConceal, p_Vid->nFramesConceal[0] ); + for(i=1;inFramesConceal[i]); + } + fprintf(stdout," )\n"); + + fprintf(stdout," Frames Outputed = %4d ( %3d", nFramesOut, p_Vid->nFramesOut[0] ); + for(i=1;inFramesOut[i]); + } + fprintf(stdout," )\n"); + + fprintf(stdout," Total decoding time : %.3f sec (%.3f fps)[%d frm/%" FORMAT_OFF_T " ms]\n",p_Vid->tot_time*0.001,(nFramesDec + nFramesConceal) * 1000.0 / p_Vid->tot_time, (nFramesDec + nFramesConceal), p_Vid->tot_time); + +} + +#if( MVC_EXTENSION_ENABLE == 0) +/*! + ************************************************************************ + * \brief + * Reports the gathered information to appropriate outputs + * + * \par Input: + * InputParameters *p_Inp, + * VideoParameters *p_Vid, + * struct snr_par *stat + * + * \par Output: + * None + ************************************************************************ + */ +void report_to_logfile(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + SNRParameters *snr = p_Vid->snr; + pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps; +#define OUTSTRING_SIZE 255 + char string[OUTSTRING_SIZE]; + FILE *p_log; +#ifndef WIN32 + time_t now; + struct tm *l_time; +#else + char timebuf[128]; +#endif + static const char yuv_formats[4][4]= { {"400"}, {"420"}, {"422"}, {"444"} }; + + // write to log file + fprintf(stdout," Output status file : %s \n",LOGFILE); + snprintf(string, OUTSTRING_SIZE, "%s", LOGFILE); + + if ((p_log=fopen(string,"r"))==0) // check if file exist + { + if ((p_log=fopen(string,"a"))==0) + { + snprintf(errortext, ET_SIZE, "Error open file %s for appending",string); + error(errortext, 500); + } + else // Create header to new file + { + fprintf(p_log," -------------------------------------------------------------------------------------------------------------------\n"); + fprintf(p_log,"| Decoder statistics. This file is made first time, later runs are appended |\n"); + fprintf(p_log," ------------------------------------------------------------------------------------------------------------------- \n"); + fprintf(p_log,"| ver | Date | Time | Sequence |#Img| Format | YUV |Coding|SNRY 1|SNRU 1|SNRV 1|SNRY N|SNRU N|SNRV N|\n"); + fprintf(p_log," -------------------------------------------------------------------------------------------------------------------\n"); + } + } + else + { + fclose(p_log); + p_log=fopen(string,"a"); // File exist,just open for appending + } + + fprintf(p_log,"|%s/%-4s", VERSION, EXT_VERSION); + +#ifdef WIN32 + _strdate( timebuf ); + fprintf(p_log,"| %1.5s |",timebuf ); + + _strtime( timebuf); + fprintf(p_log," % 1.5s |",timebuf); +#else + now = time ((time_t *) NULL); // Get the system time and put it into 'now' as 'calender time' + time (&now); + l_time = localtime (&now); + strftime (string, sizeof string, "%d-%b-%Y", l_time); + fprintf(p_log,"| %1.5s |",string ); + + strftime (string, sizeof string, "%H:%M:%S", l_time); + fprintf(p_log,"| %1.5s |",string ); +#endif + + fprintf(p_log,"%20.20s|",p_Inp->infile); + + fprintf(p_log,"%3d |",p_Vid->number); + fprintf(p_log,"%4dx%-4d|", p_Vid->width, p_Vid->height); + fprintf(p_log," %s |", &(yuv_formats[p_Vid->yuv_format][0])); + + if (active_pps) + { + if (active_pps->entropy_coding_mode_flag == CAVLC) + fprintf(p_log," CAVLC|"); + else + fprintf(p_log," CABAC|"); + } + + fprintf(p_log,"%6.3f|",snr->snr1[0]); + fprintf(p_log,"%6.3f|",snr->snr1[1]); + fprintf(p_log,"%6.3f|",snr->snr1[2]); + fprintf(p_log,"%6.3f|",snr->snra[0][0]); + fprintf(p_log,"%6.3f|",snr->snra[0][1]); + fprintf(p_log,"%6.3f|",snr->snra[0][2]); + fprintf(p_log,"\n"); + fclose(p_log); + + //snprintf(string, OUTSTRING_SIZE,"%s", DATADECFILE); + //p_log=fopen(string,"a"); + + //if(p_Vid->Bframe_ctr != 0) // B picture used + //{ + // fprintf(p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5d " + // "%2.2f %2.2f %2.2f %5d " + // "%2.2f %2.2f %2.2f %5d %.3f\n", + // p_Vid->number, 0, p_Vid->ppSliceList[0]->qp, + // snr->snr1[0], + // snr->snr1[1], + // snr->snr1[2], + // 0, + // 0.0, + // 0.0, + // 0.0, + // 0, + // snr->snra[0], + // snr->snra[1], + // snr->snra[2], + // 0, + // (double)0.001*p_Vid->tot_time/(p_Vid->number + p_Vid->Bframe_ctr - 1)); + //} + //else + //{ + // fprintf(p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5d " + // "%2.2f %2.2f %2.2f %5d " + // "%2.2f %2.2f %2.2f %5d %.3f\n", + // p_Vid->number, 0, p_Vid->ppSliceList[0]? p_Vid->ppSliceList[0]->qp: 0, + // snr->snr1[0], + // snr->snr1[1], + // snr->snr1[2], + // 0, + // 0.0, + // 0.0, + // 0.0, + // 0, + // snr->snra[0], + // snr->snra[1], + // snr->snra[2], + // 0, + // p_Vid->number ? ((double)0.001*p_Vid->tot_time/p_Vid->number) : 0.0); + //} + //fclose(p_log); +} + + +#endif +/*! +************************************************************************ +* \brief +* calculate the average value of a vector +* +************************************************************************ +*/ +static inline double average (int* elem, unsigned int n_elem) +{ + unsigned int y; + double x; + + for(x = 0, y = 0; n_elem > y; y++) //y is the # that cycles through the array + { + x += elem[y]; //adds everything to x + } + + return(x/n_elem);//divides it by how many numbers they entered +} +/*! +************************************************************************ +* \brief +* calculate the variance of a vector +* +************************************************************************ +*/ +static inline double variance (int* elem, unsigned int n_elem, double average) +{ + unsigned int i; + double n; + double average2; + double variance; + + for (n=0, i=0;i *(int *)arg2) + return -1; + else + return 0; +} + +void calculate_stats (VideoParameters *p_Vid) +{ + int view, i, j; + int *burst_elem, n_burst_elem; + + burst_elem = (int*) malloc (p_Vid->nFramesOut[0] * sizeof(int)); + n_burst_elem = p_Vid->nFramesOut[0]; + + // Loop all views + for (view=0;viewp_PFrames[view]; + + if (!p_Vid->p_PFrames[view]) + continue; + + if (p_Vid->nFramesOut[view] > n_burst_elem ) + { + free(burst_elem); + burst_elem = (int*) malloc (p_Vid->nFramesOut[view] * sizeof(int)); + n_burst_elem = p_Vid->nFramesOut[view]; + } + + /************** Calculate Lost Frames ****************/ + memset(burst_elem,0,n_burst_elem * sizeof(int)); + for (i=0, j=0;inFramesOut[view]-1;i++) + { + if (!Vector[i]) + { + p_Vid->LostFrames[view].total_frames++; + ///burst_elem[j]++; + + if(!Vector[i] && !Vector[i+1]) + { + burst_elem[j]++; + } + else + { + burst_elem[j]++; + j++; + } + } + } + if (!Vector[i]) + { + p_Vid->LostFrames[view].total_frames++; + } + qsort(burst_elem,j,sizeof(int),sort_by_value); + for (j=0; ;j++) + if (!burst_elem[j]) + break; + if (j != 0) + { + p_Vid->LostFrames[view].burst_average = (float) (average (burst_elem, j)); + p_Vid->LostFrames[view].burst_variance = (float)( variance(burst_elem, j, p_Vid->LostFrames[view].burst_average)); + } + else + { + p_Vid->LostFrames[view].burst_average = 0; + p_Vid->LostFrames[view].burst_variance = 0; + } + /************** Calculate Afected Frames *************/ + memset(burst_elem,0,n_burst_elem * sizeof(int)); + for (i=0, j=0;inFramesOut[view]-1;i++) + { + if (Vector[i] <= 0) + { + p_Vid->AfectedFrames[view].total_frames++; + if( (Vector[i] <=0) && (Vector[i+1] <=0) ) + { + burst_elem[j]++; + } + else + { + burst_elem[j]++; + j++; + } + } + } + if (Vector[i] <= 0) + { + p_Vid->AfectedFrames[view].total_frames++; + } + qsort(burst_elem,j,sizeof(int),sort_by_value); + for (j=0; ;j++) + if (!burst_elem[j]) + break; + if (j != 0) + { + p_Vid->AfectedFrames[view].burst_average = (float)( average (burst_elem, j) ); + p_Vid->AfectedFrames[view].burst_variance = (float)( variance(burst_elem, j, p_Vid->AfectedFrames[view].burst_average)); + } + else + { + p_Vid->AfectedFrames[view].burst_average = 0; + p_Vid->AfectedFrames[view].burst_variance = 0; + } + } + free(burst_elem); + +} + +void report_stats (VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + FILE *f_stats=NULL; + char out_Stats[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + int view; + + calculate_stats(p_Vid); + + if (p_Inp->statsfile[0]) + { + for (view=0;viewp_PFrames[view] != NULL) + { + strcpy(chBuf, p_Inp->statsfile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + sprintf(out_Stats, "%s_ViewId0%1d.%s", chBuf, view, pch+1); + if ((f_stats=fopen(out_Stats,"r+"))==NULL) + { + /*First Time*/ + if ((f_stats=fopen(out_Stats,"w"))==NULL) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_Stats); + error(errortext, 500); + } + n_Loops = 1; + /* Write Header */ + fprintf(f_stats, "NLoops; %4d;\n", n_Loops); + fprintf(f_stats, "Mean Received Frames; Mean Lost Frames; Mean Lost Burst Average; Mean Lost Burst Variance; Mean Affected Frames; Mean Affected Burst Average; Mean Affected Burst Variance; Mean PSNR Y;\n"); + fprintf(f_stats, "%4.3f;" , (float) p_Vid->nFramesDecoded[view]); + fprintf(f_stats, "%4.3f;" , (float) p_Vid->LostFrames[view].total_frames); + fprintf(f_stats, "%4.3f;" , p_Vid->LostFrames[view].burst_average); + fprintf(f_stats, "%4.3f;" , p_Vid->LostFrames[view].burst_variance); + fprintf(f_stats, "%4.3f;" , (float) p_Vid->AfectedFrames[view].total_frames); + fprintf(f_stats, "%4.3f;" , p_Vid->AfectedFrames[view].burst_average); + fprintf(f_stats, "%4.3f;" , p_Vid->AfectedFrames[view].burst_variance); + fprintf(f_stats, "%4.3f;\n", (float)p_Vid->snr[view]->snra[0]); + fprintf(f_stats, "Received Frames; Lost Frames; Lost Burst Average; Lost Burst Variance; Affected Frames; Affected Burst Average; Affected Burst Variance; PSNR Y\n"); + } + else + { + fseek(f_stats,0L,SEEK_SET); + fscanf(f_stats, "NLoops; %d;\n", &n_Loops); + fscanf(f_stats, "Mean Received Frames; Mean Lost Frames; Mean Lost Burst Average; Mean Lost Burst Variance; Mean Affected Frames; Mean Affected Burst Average; Mean Affected Burst Variance; Mean PSNR Y;\n"); + fscanf(f_stats, "%f;" , &prev_mean_dec_frames); + fscanf(f_stats, "%f;" , &prev_mean_total_frames_LostFrames); + fscanf(f_stats, "%f;" , &prev_mean_burst_average_LostFrames); + fscanf(f_stats, "%f;" , &prev_mean_burst_variance_LostFrames); + fscanf(f_stats, "%f;" , &prev_mean_total_frames_AfectedFrames); + fscanf(f_stats, "%f;" , &prev_mean_burst_average_AfectedFrames); + fscanf(f_stats, "%f;" , &prev_mean_burst_variance_AfectedFrames); + fscanf(f_stats, "%f;" , &prev_mean_psnr_y); + + /* Calculate new mean values */ + prev_mean_dec_frames = ((prev_mean_dec_frames*((float)n_Loops))+p_Vid->nFramesDecoded[view])/((float)(n_Loops+1)); + prev_mean_total_frames_LostFrames = ((prev_mean_total_frames_LostFrames*((float)n_Loops))+p_Vid->LostFrames[view].total_frames)/((float)(n_Loops+1)); + prev_mean_burst_average_LostFrames = ((prev_mean_burst_average_LostFrames*((float)n_Loops))+p_Vid->LostFrames[view].burst_average)/((float)(n_Loops+1)); + prev_mean_burst_variance_LostFrames = ((prev_mean_burst_variance_LostFrames*((float)n_Loops))+p_Vid->LostFrames[view].burst_variance)/((float)(n_Loops+1)); + prev_mean_total_frames_AfectedFrames = ((prev_mean_total_frames_AfectedFrames*((float)n_Loops))+p_Vid->AfectedFrames[view].total_frames)/((float)(n_Loops+1)); + prev_mean_burst_average_AfectedFrames = ((prev_mean_burst_average_AfectedFrames*((float)n_Loops))+p_Vid->AfectedFrames[view].burst_average)/((float)(n_Loops+1)); + prev_mean_burst_variance_AfectedFrames = ((prev_mean_burst_variance_AfectedFrames*((float)n_Loops))+p_Vid->AfectedFrames[view].burst_variance)/((float)(n_Loops+1)); + prev_mean_psnr_y = ((prev_mean_psnr_y*((float)n_Loops))+((float)p_Vid->snr[view]->snra[0]))/((float)(n_Loops+1)); + + n_Loops++; + + /* Write new mean values */ + fseek(f_stats,0L,SEEK_SET); + fprintf(f_stats, "NLoops; %4d;\n", n_Loops); + fprintf(f_stats, "Mean Received Frames; Mean Lost Frames; Mean Lost Burst Average; Mean Lost Burst Variance; Mean Affected Frames; Mean Affected Burst Average; Mean Affected Burst Variance; Mean PSNR Y;\n"); + fprintf(f_stats, "%4.3f;" , prev_mean_dec_frames); + fprintf(f_stats, "%4.3f;" , prev_mean_total_frames_LostFrames); + fprintf(f_stats, "%4.3f;" , prev_mean_burst_average_LostFrames); + fprintf(f_stats, "%4.3f;" , prev_mean_burst_variance_LostFrames); + fprintf(f_stats, "%4.3f;" , prev_mean_total_frames_AfectedFrames); + fprintf(f_stats, "%4.3f;" , prev_mean_burst_average_AfectedFrames); + fprintf(f_stats, "%4.3f;" , prev_mean_burst_variance_AfectedFrames); + fprintf(f_stats, "%4.3f;\n", prev_mean_psnr_y); + } + + fseek(f_stats,0L,SEEK_END); + fprintf(f_stats, "%4d; ", p_Vid->nFramesDecoded[view]); + fprintf(f_stats, "%4d;%4.3f;%4.3f;", p_Vid->LostFrames[view].total_frames, + p_Vid->LostFrames[view].burst_average, + p_Vid->LostFrames[view].burst_variance); + fprintf(f_stats, "%4d;%4.3f;%4.3f;", p_Vid->AfectedFrames[view].total_frames, + p_Vid->AfectedFrames[view].burst_average, + p_Vid->AfectedFrames[view].burst_variance); + fprintf(f_stats, "%4.3f;", p_Vid->snr[view]->snra[0]); + fprintf(f_stats, "\n"); + fclose(f_stats); + } + } + } + + for (view=0;viewp_PFrames[view] != NULL) + { + int i; + strcpy(chBuf, p_Inp->outfile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + sprintf(out_Stats, "%s_ViewId0%1d_FRAMEERRORPATTERN.dat", chBuf, view); + if ((f_stats=fopen(out_Stats,"w"))==NULL) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_Stats); + error(errortext, 500); + } + for (i=0;inFramesOut[view];i++) + { + fprintf(f_stats,"%d,",p_Vid->p_PFrames[view][i]); + } + fclose(f_stats); + } + } + +} diff --git a/ldecod/src/rtp.c b/ldecod/src/rtp.c new file mode 100644 index 0000000..7317e50 --- /dev/null +++ b/ldecod/src/rtp.c @@ -0,0 +1,388 @@ + +/*! + ************************************************************************ + * \file rtp.c + * + * \brief + * Network Adaptation layer for RTP packets + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + ************************************************************************ + */ + + +/*! + + A quick guide to the basics of the RTP decoder implementation + + This module contains the RTP packetization, de-packetization, and the + handling of Parameter Sets, see VCEG-N52 and accompanying documents. + Note: Compound packets are not yet implemented! + + The interface between every NAL (including the RTP NAL) and the VCL is + based on Slices. The slice data structure on which the VCL is working + is defined in the type Slice (in defines.h). This type contains the + various fields of the slice header and a partition array, which itself + contains the data partitions the slice consists of. When data + partitioning is not used, then the whole slice bit string is stored + in partition #0. When individual partitions are missing, this is + indicated by the size of the bit strings in the partition array. + A complete missing slice (e.g. if a Full Slice packet was lost) is + indicated in a similar way. + + part of the slice structure is the error indication (ei-flag). The + Ei-flag is set in such cases in which at least one partition of a slice + is damaged or missing.When data partitioning is used, it can happen that + one partition does not contain any symbols but the ei_flag is cleared, + which indicates the intentional missing of symbols of that partition. + A typical example for this behaviour is the Intra Slice, which does not + have symnbols in its type C partition. + + The VCL requests new data to work on through the call of readSliceRTP(). + This function calls the main state machine of this module in ReadRTPpaacket(). + + ReadRTPpacket assumes, when called, that in an error free environment + a complete slice, consisting of one Full Slice RTP packet, or three Partition + packets of types A, B, C with consecutive sequence numbers, can be read. + It first interprets any trailing SUPP and Parameter Update (Header) packets. + Then it reads one video data packet. Two cases have to be distinguished: + + 1. Type A, or Full Slice packet + In this case, the PictureID and the macroblock mumbers are used to + identify the potential loss of a slice. A slice is lost, when the + StartMB of the newly read slice header is not equal to the current + state of the decoder + 1.1 Loss detected + In this case the last packet is unread (fseek back), and a dummy slice + containing the missing macroblocks is conveyed to the VCL. At the next + call of the NAL, the same packet is read again, but this time no packet + loss is detected by the above algorithm, + 1.2. No loss + In this case it is checked whether a Full Slice packet or a type A data + partition was read + 1.2.1 Full Slice + The Full Slice packet is conveyed to the NAL + 1.2.2 Type A Partition + The function RTPReadDataPartitionedSlice() is called, which collects + the remaining type B, C partitions and handles them appropriately. + + Paraneter Update Packets (aka Header packets) are in an SDP-like syntax + and are interpreted by a simple parser in the function + RTPInterpretParameterSetPacket() + + Each Slice header contaions the information on which parameter set to be used. + The function RTPSetImgInp() copies the information of the relevant parameter + set in the VCL's global variables p_Vid-> and p_Inp-> IMPORTANT: any changes + in the semantics of the p_Vid-> and p_Inp-> structure members must be represented + in this function as well! + + A note to the stream-buffer data structure: The stream buffer always contains + only the contents of the partition in question, and not the slice/partition + header. Decoding has to start at bitoffset 0 (CAVLC) or bytreoffset 0 (CABAC). + + The remaining functions should be self-explanatory. + +*/ + +#if defined(WIN32) || defined(WIN64) +#include +#else +#include +#endif + +#include "contributors.h" +#include "global.h" +#include "errorconcealment.h" +#include "rtp.h" +#include "fmo.h" +#include "sei.h" +#include "memalloc.h" + +int RTPReadPacket (RTPpacket_t *p, int bitstream); + +/*! + ************************************************************************ + * \brief + * Opens the bit stream file named fn + * \return + * none + ************************************************************************ + */ +void OpenRTPFile (char *fn, int *p_BitStreamFile) +{ + if (((*p_BitStreamFile) = open(fn, OPENFLAGS_READ)) == -1) + { + snprintf(errortext, ET_SIZE, "Cannot open RTP file '%s'", fn); + error(errortext,500); + } +} + + +/*! + ************************************************************************ + * \brief + * Closes the bit stream file + ************************************************************************ + */ +void CloseRTPFile(int *p_BitStreamFile) +{ + if ((*p_BitStreamFile) != -1) + { + close(*p_BitStreamFile); + (*p_BitStreamFile) = - 1; + } +} + + +/*! + ************************************************************************ + * \brief + * Fills nalu->buf and nalu->len with the payload of an RTP packet. + * Other fields in nalu-> remain uninitialized (will be taken care of + * by NALUtoRBSP. + * + * \return + * 4 in case of ok (for compatibility with get_annex_b_NALU) + * 0 if there is nothing any more to read (EOF) + * -1 in case of any error + * + ************************************************************************ + */ + +int GetRTPNALU (VideoParameters *p_Vid, NALU_t *nalu, int BitStreamFile) +{ + static uint16 first_call = 1; //!< triggers sequence number initialization on first call + static uint16 old_seq = 0; //!< store the last RTP sequence number for loss detection + + RTPpacket_t *p; + int ret; + + if ((p=malloc (sizeof (RTPpacket_t)))== NULL) + no_mem_exit ("GetRTPNALU-1"); + if ((p->packet=malloc (MAXRTPPACKETSIZE))== NULL) + no_mem_exit ("GetRTPNALU-2"); + if ((p->payload=malloc (MAXRTPPACKETSIZE))== NULL) + no_mem_exit ("GetRTPNALU-3"); + + ret = RTPReadPacket (p, BitStreamFile); + nalu->forbidden_bit = 1; + nalu->len = 0; + + if (ret > 0) // we got a packet ( -1=error, 0=end of file ) + { + if (first_call) + { + first_call = 0; + old_seq = (uint16) (p->seq - 1); + } + + nalu->lost_packets = (uint16) ( p->seq - (old_seq + 1) ); + old_seq = p->seq; + + assert (p->paylen < nalu->max_size); + + nalu->len = p->paylen; + memcpy (nalu->buf, p->payload, p->paylen); + nalu->forbidden_bit = (nalu->buf[0]>>7) & 1; + nalu->nal_reference_idc = (NalRefIdc) ((nalu->buf[0]>>5) & 3); + nalu->nal_unit_type = (NaluType) ((nalu->buf[0]) & 0x1f); + if (nalu->lost_packets) + { + printf ("Warning: RTP sequence number discontinuity detected\n"); + } + } + + // free memory + free (p->payload); + free (p->packet); + free (p); + +// printf ("Got an RTP NALU, len %d, first byte %x\n", nalu->len, nalu->buf[0]); + + if (ret>0) + // length of packet + return nalu->len; + else + // error code + return ret; +} + + + +/*! + ***************************************************************************** + * + * \brief + * DecomposeRTPpacket interprets the RTP packet and writes the various + * structure members of the RTPpacket_t structure + * + * \return + * 0 in case of success + * negative error code in case of failure + * + * \param p + * Caller is responsible to allocate enough memory for the generated payload + * in parameter->payload. Typically a malloc of paclen-12 bytes is sufficient + * + * \par Side effects + * none + * + * \date + * 30 Spetember 2001 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + +int DecomposeRTPpacket (RTPpacket_t *p) + +{ + // consistency check + assert (p->packlen < 65536 - 28); // IP, UDP headers + assert (p->packlen >= 12); // at least a complete RTP header + assert (p->payload != NULL); + assert (p->packet != NULL); + + // Extract header information + + p->v = (p->packet[0] >> 6) & 0x03; + p->p = (p->packet[0] >> 5) & 0x01; + p->x = (p->packet[0] >> 4) & 0x01; + p->cc = (p->packet[0] >> 0) & 0x0F; + + p->m = (p->packet[1] >> 7) & 0x01; + p->pt = (p->packet[1] >> 0) & 0x7F; + + memcpy (&p->seq, &p->packet[2], 2); + p->seq = ntohs((uint16)p->seq); + + memcpy (&p->timestamp, &p->packet[4], 4);// change to shifts for unified byte sex + p->timestamp = ntohl(p->timestamp); + memcpy (&p->ssrc, &p->packet[8], 4);// change to shifts for unified byte sex + p->ssrc = ntohl(p->ssrc); + + // header consistency checks + if ( (p->v != 2) + || (p->p != 0) + || (p->x != 0) + || (p->cc != 0) ) + { + printf ("DecomposeRTPpacket, RTP header consistency problem, header follows\n"); + DumpRTPHeader (p); + return -1; + } + p->paylen = p->packlen-12; + memcpy (p->payload, &p->packet[12], p->paylen); + return 0; +} + +/*! + ***************************************************************************** + * + * \brief + * DumpRTPHeader is a debug tool that dumps a human-readable interpretation + * of the RTP header + * + * \return + * n.a. + * \param p + * the RTP packet to be dumped, after DecompositeRTPpacket() + * + * \par Side effects + * Debug output to stdout + * + * \date + * 30 Spetember 2001 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + +void DumpRTPHeader (RTPpacket_t *p) + +{ + int i; + for (i=0; i< 30; i++) + printf ("%02x ", p->packet[i]); + printf ("Version (V): %d\n", (int) p->v); + printf ("Padding (P): %d\n", (int) p->p); + printf ("Extension (X): %d\n", (int) p->x); + printf ("CSRC count (CC): %d\n", (int) p->cc); + printf ("Marker bit (M): %d\n", (int) p->m); + printf ("Payload Type (PT): %d\n", (int) p->pt); + printf ("Sequence Number: %d\n", (int) p->seq); + printf ("Timestamp: %d\n", (int) p->timestamp); + printf ("SSRC: %d\n", (int) p->ssrc); +} + + +/*! + ***************************************************************************** + * + * \brief + * RTPReadPacket reads one packet from file + * + * \return + * 0: EOF + * negative: error + * positive: size of RTP packet in bytes + * + * \param p + * packet data structure, with memory for p->packet allocated + * + * \param bitstream + * target file + * + * \par Side effects: + * - File pointer in bits moved + * - p->xxx filled by reading and Decomposepacket() + * + * \date + * 04 November, 2001 + * + * \author + * Stephan Wenger, stewe@cs.tu-berlin.de + *****************************************************************************/ +int RTPReadPacket (RTPpacket_t *p, int bitstream) +{ + int64 Filepos; + int intime; + + assert (p != NULL); + assert (p->packet != NULL); + assert (p->payload != NULL); + + Filepos = tell (bitstream); + if (4 != read (bitstream, &p->packlen, 4)) + { + return 0; + } + if (4 != read (bitstream, &intime, 4)) + { + lseek (bitstream, Filepos, SEEK_SET); + printf ("RTPReadPacket: File corruption, could not read Timestamp, exit\n"); + exit (-1); + } + + assert (p->packlen < MAXRTPPACKETSIZE); + + if (p->packlen != (unsigned int) read (bitstream, p->packet, p->packlen)) + { + printf ("RTPReadPacket: File corruption, could not read %d bytes\n", (int) p->packlen); + exit (-1); // EOF inidication + } + + if (DecomposeRTPpacket (p) < 0) + { + // this should never happen, hence exit() is ok. We probably do not want to attempt + // to decode a packet that obviously wasn't generated by RTP + printf ("Errors reported by DecomposePacket(), exit\n"); + exit (-700); + } + assert (p->pt == H264PAYLOADTYPE); + assert (p->ssrc == H264SSRC); + return p->packlen; +} + diff --git a/ldecod/src/sei.c b/ldecod/src/sei.c new file mode 100644 index 0000000..61c6648 --- /dev/null +++ b/ldecod/src/sei.c @@ -0,0 +1,2236 @@ +/*! + ************************************************************************ + * \file sei.c + * + * \brief + * Functions to implement SEI messages + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Dong Tian + * - Karsten Suehring + ************************************************************************ + */ + +#include "contributors.h" + +#include +#include "global.h" +#include "memalloc.h" +#include "sei.h" +#include "vlc.h" +#include "header.h" +#include "mbuffer.h" +#include "parset.h" + + +// #define PRINT_BUFFERING_PERIOD_INFO // uncomment to print buffering period SEI info +// #define PRINT_PICTURE_TIMING_INFO // uncomment to print picture timing SEI info +// #define WRITE_MAP_IMAGE // uncomment to write spare picture map +// #define PRINT_SUBSEQUENCE_INFO // uncomment to print sub-sequence SEI info +// #define PRINT_SUBSEQUENCE_LAYER_CHAR // uncomment to print sub-sequence layer characteristics SEI info +// #define PRINT_SUBSEQUENCE_CHAR // uncomment to print sub-sequence characteristics SEI info +// #define PRINT_SCENE_INFORMATION // uncomment to print scene information SEI info +// #define PRINT_PAN_SCAN_RECT // uncomment to print pan-scan rectangle SEI info +// #define PRINT_RECOVERY_POINT // uncomment to print random access point SEI info +// #define PRINT_FILLER_PAYLOAD_INFO // uncomment to print filler payload SEI info +// #define PRINT_DEC_REF_PIC_MARKING // uncomment to print decoded picture buffer management repetition SEI info +// #define PRINT_RESERVED_INFO // uncomment to print reserved SEI info +// #define PRINT_USER_DATA_UNREGISTERED_INFO // uncomment to print unregistered user data SEI info +// #define PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO // uncomment to print ITU-T T.35 user data SEI info +// #define PRINT_FULL_FRAME_FREEZE_INFO // uncomment to print full-frame freeze SEI info +// #define PRINT_FULL_FRAME_FREEZE_RELEASE_INFO // uncomment to print full-frame freeze release SEI info +// #define PRINT_FULL_FRAME_SNAPSHOT_INFO // uncomment to print full-frame snapshot SEI info +// #define PRINT_PROGRESSIVE_REFINEMENT_END_INFO // uncomment to print Progressive refinement segment start SEI info +// #define PRINT_PROGRESSIVE_REFINEMENT_END_INFO // uncomment to print Progressive refinement segment end SEI info +// #define PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO // uncomment to print Motion-constrained slice group set SEI info +// #define PRINT_FILM_GRAIN_CHARACTERISTICS_INFO // uncomment to print Film grain characteristics SEI info +// #define PRINT_DEBLOCKING_FILTER_DISPLAY_PREFERENCE_INFO // uncomment to print deblocking filter display preference SEI info +// #define PRINT_STEREO_VIDEO_INFO_INFO // uncomment to print stereo video SEI info +// #define PRINT_TONE_MAPPING // uncomment to print tone-mapping SEI info +// #define PRINT_POST_FILTER_HINT_INFO // uncomment to print post-filter hint SEI info +// #define PRINT_FRAME_PACKING_ARRANGEMENT_INFO // uncomment to print frame packing arrangement SEI info +/*! + ************************************************************************ + * \brief + * Interpret the SEI rbsp + * \param msg + * a pointer that point to the sei message. + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void InterpretSEIMessage(byte* msg, int size, VideoParameters *p_Vid, Slice *pSlice) +{ + int payload_type = 0; + int payload_size = 0; + int offset = 1; + byte tmp_byte; + + do + { + // sei_message(); + payload_type = 0; + tmp_byte = msg[offset++]; + while (tmp_byte == 0xFF) + { + payload_type += 255; + tmp_byte = msg[offset++]; + } + payload_type += tmp_byte; // this is the last byte + + payload_size = 0; + tmp_byte = msg[offset++]; + while (tmp_byte == 0xFF) + { + payload_size += 255; + tmp_byte = msg[offset++]; + } + payload_size += tmp_byte; // this is the last byte + + switch ( payload_type ) // sei_payload( type, size ); + { + case SEI_BUFFERING_PERIOD: + interpret_buffering_period_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_PIC_TIMING: + interpret_picture_timing_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_PAN_SCAN_RECT: + interpret_pan_scan_rect_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_FILLER_PAYLOAD: + interpret_filler_payload_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_USER_DATA_REGISTERED_ITU_T_T35: + interpret_user_data_registered_itu_t_t35_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_USER_DATA_UNREGISTERED: + interpret_user_data_unregistered_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_RECOVERY_POINT: + interpret_recovery_point_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_DEC_REF_PIC_MARKING_REPETITION: + interpret_dec_ref_pic_marking_repetition_info( msg+offset, payload_size, p_Vid, pSlice ); + break; + case SEI_SPARE_PIC: + interpret_spare_pic( msg+offset, payload_size, p_Vid ); + break; + case SEI_SCENE_INFO: + interpret_scene_information( msg+offset, payload_size, p_Vid ); + break; + case SEI_SUB_SEQ_INFO: + interpret_subsequence_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_SUB_SEQ_LAYER_CHARACTERISTICS: + interpret_subsequence_layer_characteristics_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_SUB_SEQ_CHARACTERISTICS: + interpret_subsequence_characteristics_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_FULL_FRAME_FREEZE: + interpret_full_frame_freeze_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_FULL_FRAME_FREEZE_RELEASE: + interpret_full_frame_freeze_release_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_FULL_FRAME_SNAPSHOT: + interpret_full_frame_snapshot_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_PROGRESSIVE_REFINEMENT_SEGMENT_START: + interpret_progressive_refinement_start_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_PROGRESSIVE_REFINEMENT_SEGMENT_END: + interpret_progressive_refinement_end_info( msg+offset, payload_size, p_Vid ); + break; + case SEI_MOTION_CONSTRAINED_SLICE_GROUP_SET: + interpret_motion_constrained_slice_group_set_info( msg+offset, payload_size, p_Vid ); + case SEI_FILM_GRAIN_CHARACTERISTICS: + interpret_film_grain_characteristics_info ( msg+offset, payload_size, p_Vid ); + break; + case SEI_DEBLOCKING_FILTER_DISPLAY_PREFERENCE: + interpret_deblocking_filter_display_preference_info ( msg+offset, payload_size, p_Vid ); + break; + case SEI_STEREO_VIDEO_INFO: + interpret_stereo_video_info_info ( msg+offset, payload_size, p_Vid ); + break; + case SEI_TONE_MAPPING: + interpret_tone_mapping( msg+offset, payload_size, p_Vid ); + break; + case SEI_POST_FILTER_HINTS: + interpret_post_filter_hints_info ( msg+offset, payload_size, p_Vid ); + break; + case SEI_FRAME_PACKING_ARRANGEMENT: + interpret_frame_packing_arrangement_info( msg+offset, payload_size, p_Vid ); + break; + default: + interpret_reserved_info( msg+offset, payload_size, p_Vid ); + break; + } + offset += payload_size; + + } while( msg[offset] != 0x80 ); // more_rbsp_data() msg[offset] != 0x80 + // ignore the trailing bits rbsp_trailing_bits(); + assert(msg[offset] == 0x80); // this is the trailing bits + assert( offset+1 == size ); +} + + +/*! +************************************************************************ +* \brief +* Interpret the spare picture SEI message +* \param payload +* a pointer that point to the sei payload +* \param size +* the size of the sei message +* \param p_Vid +* the image pointer +* +************************************************************************ +*/ +void interpret_spare_pic( byte* payload, int size, VideoParameters *p_Vid ) +{ + int i,x,y; + Bitstream* buf; + int bit0, bit1, bitc, no_bit0; + int target_frame_num = 0; + int num_spare_pics; + int delta_spare_frame_num, CandidateSpareFrameNum, SpareFrameNum = 0; + int ref_area_indicator; + + int m, n, left, right, top, bottom,directx, directy; + byte ***map; + +#ifdef WRITE_MAP_IMAGE + int symbol_size_in_bytes = p_Vid->pic_unit_bitsize_on_disk/8; + int j, k, i0, j0, tmp, kk; + char filename[20] = "map_dec.yuv"; + FILE *fp; + imgpel** Y; + static int old_pn=-1; + static int first = 1; + + printf("Spare picture SEI message\n"); +#endif + + p_Dec->UsedBits = 0; + + assert( payload!=NULL); + assert( p_Vid!=NULL); + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + target_frame_num = read_ue_v("SEI: target_frame_num", buf, &p_Dec->UsedBits); + +#ifdef WRITE_MAP_IMAGE + printf( "target_frame_num is %d\n", target_frame_num ); +#endif + + num_spare_pics = 1 + read_ue_v("SEI: num_spare_pics_minus1", buf, &p_Dec->UsedBits); + +#ifdef WRITE_MAP_IMAGE + printf( "num_spare_pics is %d\n", num_spare_pics ); +#endif + + get_mem3D(&map, num_spare_pics, p_Vid->height >> 4, p_Vid->width >> 4); + + for (i=0; iUsedBits); + + SpareFrameNum = CandidateSpareFrameNum - delta_spare_frame_num; + if( SpareFrameNum < 0 ) + SpareFrameNum = MAX_FN + SpareFrameNum; + + ref_area_indicator = read_ue_v("SEI: ref_area_indicator", buf, &p_Dec->UsedBits); + + switch ( ref_area_indicator ) + { + case 0: // The whole frame can serve as spare picture + for (y=0; yheight >> 4; y++) + for (x=0; xwidth >> 4; x++) + map[i][y][x] = 0; + break; + case 1: // The map is not compressed + for (y=0; yheight >> 4; y++) + for (x=0; xwidth >> 4; x++) + { + map[i][y][x] = (byte) read_u_1("SEI: ref_mb_indicator", buf, &p_Dec->UsedBits); + } + break; + case 2: // The map is compressed + //!KS: could not check this function, description is unclear (as stated in Ed. Note) + bit0 = 0; + bit1 = 1; + bitc = bit0; + no_bit0 = -1; + + x = ( (p_Vid->width >> 4) - 1 ) / 2; + y = ( (p_Vid->height >> 4) - 1 ) / 2; + left = right = x; + top = bottom = y; + directx = 0; + directy = 1; + + for (m=0; mheight >> 4; m++) + for (n=0; nwidth >> 4; n++) + { + + if (no_bit0<0) + { + no_bit0 = read_ue_v("SEI: zero_run_length", buf, &p_Dec->UsedBits); + } + if (no_bit0>0) + map[i][y][x] = (byte) bit0; + else + map[i][y][x] = (byte) bit1; + no_bit0--; + + // go to the next mb: + if ( directx == -1 && directy == 0 ) + { + if (x > left) x--; + else if (x == 0) + { + y = bottom + 1; + bottom++; + directx = 1; + directy = 0; + } + else if (x == left) + { + x--; + left--; + directx = 0; + directy = 1; + } + } + else if ( directx == 1 && directy == 0 ) + { + if (x < right) x++; + else if (x == (p_Vid->width >> 4) - 1) + { + y = top - 1; + top--; + directx = -1; + directy = 0; + } + else if (x == right) + { + x++; + right++; + directx = 0; + directy = -1; + } + } + else if ( directx == 0 && directy == -1 ) + { + if ( y > top) y--; + else if (y == 0) + { + x = left - 1; + left--; + directx = 0; + directy = 1; + } + else if (y == top) + { + y--; + top--; + directx = -1; + directy = 0; + } + } + else if ( directx == 0 && directy == 1 ) + { + if (y < bottom) y++; + else if (y == (p_Vid->height >> 4) - 1) + { + x = right+1; + right++; + directx = 0; + directy = -1; + } + else if (y == bottom) + { + y++; + bottom++; + directx = 1; + directy = 0; + } + } + + + } + break; + default: + printf( "Wrong ref_area_indicator %d!\n", ref_area_indicator ); + exit(0); + break; + } + + } // end of num_spare_pics + +#ifdef WRITE_MAP_IMAGE + // begin to write map seq + if ( old_pn != p_Vid->number ) + { + old_pn = p_Vid->number; + get_mem2Dpel(&Y, p_Vid->height, p_Vid->width); + if (first) + { + fp = fopen( filename, "wb" ); + first = 0; + } + else + fp = fopen( filename, "ab" ); + assert( fp != NULL ); + for (kk=0; kkheight >> 4; i++) + for (j=0; j < p_Vid->width >> 4; j++) + { + tmp=map[kk][i][j]==0? p_Vid->max_pel_value_comp[0] : 0; + for (i0=0; i0<16; i0++) + for (j0=0; j0<16; j0++) + Y[i*16+i0][j*16+j0]=tmp; + } + + // write the map image + for (i=0; i < p_Vid->height; i++) + for (j=0; j < p_Vid->width; j++) + fwrite(&(Y[i][j]), symbol_size_in_bytes, 1, p_out); + + for (k=0; k < 2; k++) + for (i=0; i < p_Vid->height>>1; i++) + for (j=0; j < p_Vid->width>>1; j++) + fwrite(&(p_Vid->dc_pred_value_comp[1]), symbol_size_in_bytes, 1, p_out); + } + fclose( fp ); + free_mem2Dpel( Y ); + } + // end of writing map image +#undef WRITE_MAP_IMAGE +#endif + + free_mem3D( map ); + + free(buf); +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Sub-sequence information SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_subsequence_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + Bitstream* buf; + int sub_seq_layer_num, sub_seq_id, first_ref_pic_flag, leading_non_ref_pic_flag, last_pic_flag, + sub_seq_frame_num_flag, sub_seq_frame_num; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + sub_seq_layer_num = read_ue_v("SEI: sub_seq_layer_num" , buf, &p_Dec->UsedBits); + sub_seq_id = read_ue_v("SEI: sub_seq_id" , buf, &p_Dec->UsedBits); + first_ref_pic_flag = read_u_1 ("SEI: first_ref_pic_flag" , buf, &p_Dec->UsedBits); + leading_non_ref_pic_flag = read_u_1 ("SEI: leading_non_ref_pic_flag", buf, &p_Dec->UsedBits); + last_pic_flag = read_u_1 ("SEI: last_pic_flag" , buf, &p_Dec->UsedBits); + sub_seq_frame_num_flag = read_u_1 ("SEI: sub_seq_frame_num_flag" , buf, &p_Dec->UsedBits); + if (sub_seq_frame_num_flag) + { + sub_seq_frame_num = read_ue_v("SEI: sub_seq_frame_num" , buf, &p_Dec->UsedBits); + } + +#ifdef PRINT_SUBSEQUENCE_INFO + printf("Sub-sequence information SEI message\n"); + printf("sub_seq_layer_num = %d\n", sub_seq_layer_num ); + printf("sub_seq_id = %d\n", sub_seq_id); + printf("first_ref_pic_flag = %d\n", first_ref_pic_flag); + printf("leading_non_ref_pic_flag = %d\n", leading_non_ref_pic_flag); + printf("last_pic_flag = %d\n", last_pic_flag); + printf("sub_seq_frame_num_flag = %d\n", sub_seq_frame_num_flag); + if (sub_seq_frame_num_flag) + { + printf("sub_seq_frame_num = %d\n", sub_seq_frame_num); + } +#endif + + free(buf); +#ifdef PRINT_SUBSEQUENCE_INFO +#undef PRINT_SUBSEQUENCE_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the Sub-sequence layer characteristics SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_subsequence_layer_characteristics_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + Bitstream* buf; + long num_sub_layers, accurate_statistics_flag, average_bit_rate, average_frame_rate; + int i; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + num_sub_layers = 1 + read_ue_v("SEI: num_sub_layers_minus1", buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_LAYER_CHAR + printf("Sub-sequence layer characteristics SEI message\n"); + printf("num_sub_layers_minus1 = %d\n", num_sub_layers - 1); +#endif + + for (i=0; iUsedBits); + average_bit_rate = read_u_v(16,"SEI: average_bit_rate" , buf, &p_Dec->UsedBits); + average_frame_rate = read_u_v(16,"SEI: average_frame_rate" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_LAYER_CHAR + printf("layer %d: accurate_statistics_flag = %ld \n", i, accurate_statistics_flag); + printf("layer %d: average_bit_rate = %ld \n", i, average_bit_rate); + printf("layer %d: average_frame_rate = %ld \n", i, average_frame_rate); +#endif + } + free (buf); +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Sub-sequence characteristics SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_subsequence_characteristics_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + Bitstream* buf; + int i; + int sub_seq_layer_num, sub_seq_id, duration_flag, average_rate_flag, accurate_statistics_flag; + unsigned long sub_seq_duration, average_bit_rate, average_frame_rate; + int num_referenced_subseqs, ref_sub_seq_layer_num, ref_sub_seq_id, ref_sub_seq_direction; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + sub_seq_layer_num = read_ue_v("SEI: sub_seq_layer_num", buf, &p_Dec->UsedBits); + sub_seq_id = read_ue_v("SEI: sub_seq_id", buf, &p_Dec->UsedBits); + duration_flag = read_u_1 ("SEI: duration_flag", buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_CHAR + printf("Sub-sequence characteristics SEI message\n"); + printf("sub_seq_layer_num = %d\n", sub_seq_layer_num ); + printf("sub_seq_id = %d\n", sub_seq_id); + printf("duration_flag = %d\n", duration_flag); +#endif + + if ( duration_flag ) + { + sub_seq_duration = read_u_v (32, "SEI: duration_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_SUBSEQUENCE_CHAR + printf("sub_seq_duration = %ld\n", sub_seq_duration); +#endif + } + + average_rate_flag = read_u_1 ("SEI: average_rate_flag", buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_CHAR + printf("average_rate_flag = %d\n", average_rate_flag); +#endif + + if ( average_rate_flag ) + { + accurate_statistics_flag = read_u_1 ( "SEI: accurate_statistics_flag", buf, &p_Dec->UsedBits); + average_bit_rate = read_u_v (16, "SEI: average_bit_rate", buf, &p_Dec->UsedBits); + average_frame_rate = read_u_v (16, "SEI: average_frame_rate", buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_CHAR + printf("accurate_statistics_flag = %d\n", accurate_statistics_flag); + printf("average_bit_rate = %ld\n", average_bit_rate); + printf("average_frame_rate = %ld\n", average_frame_rate); +#endif + } + + num_referenced_subseqs = read_ue_v("SEI: num_referenced_subseqs", buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_CHAR + printf("num_referenced_subseqs = %d\n", num_referenced_subseqs); +#endif + + for (i=0; iUsedBits); + ref_sub_seq_id = read_ue_v("SEI: ref_sub_seq_id", buf, &p_Dec->UsedBits); + ref_sub_seq_direction = read_u_1 ("SEI: ref_sub_seq_direction", buf, &p_Dec->UsedBits); + +#ifdef PRINT_SUBSEQUENCE_CHAR + printf("ref_sub_seq_layer_num = %d\n", ref_sub_seq_layer_num); + printf("ref_sub_seq_id = %d\n", ref_sub_seq_id); + printf("ref_sub_seq_direction = %d\n", ref_sub_seq_direction); +#endif + } + + free( buf ); +#ifdef PRINT_SUBSEQUENCE_CHAR +#undef PRINT_SUBSEQUENCE_CHAR +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Scene information SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_scene_information( byte* payload, int size, VideoParameters *p_Vid ) +{ + Bitstream* buf; + int scene_id, scene_transition_type, second_scene_id; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + scene_id = read_ue_v("SEI: scene_id" , buf, &p_Dec->UsedBits); + scene_transition_type = read_ue_v("SEI: scene_transition_type", buf, &p_Dec->UsedBits); + if ( scene_transition_type > 3 ) + { + second_scene_id = read_ue_v("SEI: scene_transition_type", buf, &p_Dec->UsedBits); + } + +#ifdef PRINT_SCENE_INFORMATION + printf("Scene information SEI message\n"); + printf("scene_transition_type = %d\n", scene_transition_type); + printf("scene_id = %d\n", scene_id); + if ( scene_transition_type > 3 ) + { + printf("second_scene_id = %d\n", second_scene_id); + } +#endif + free( buf ); +#ifdef PRINT_SCENE_INFORMATION +#undef PRINT_SCENE_INFORMATION +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Filler payload SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_filler_payload_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int payload_cnt = 0; + + while (payload_cnt=16); + + for (offset = 0; offset < 16; offset++) + { +#ifdef PRINT_USER_DATA_UNREGISTERED_INFO + printf("%02x",payload[offset]); +#endif + } + +#ifdef PRINT_USER_DATA_UNREGISTERED_INFO + printf("\n"); +#endif + + while (offset < size) + { + payload_byte = payload[offset]; + offset ++; +#ifdef PRINT_USER_DATA_UNREGISTERED_INFO + printf("Unreg data payload_byte = %d\n", payload_byte); +#endif + } +#ifdef PRINT_USER_DATA_UNREGISTERED_INFO +#undef PRINT_USER_DATA_UNREGISTERED_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the User data registered by ITU-T T.35 SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_user_data_registered_itu_t_t35_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int offset = 0; + byte itu_t_t35_country_code, itu_t_t35_country_code_extension_byte, payload_byte; + + itu_t_t35_country_code = payload[offset]; + offset++; +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO + printf("User data registered by ITU-T T.35 SEI message\n"); + printf(" itu_t_t35_country_code = %d \n", itu_t_t35_country_code); +#endif + if(itu_t_t35_country_code == 0xFF) + { + itu_t_t35_country_code_extension_byte = payload[offset]; + offset++; +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO + printf(" ITU_T_T35_COUNTRY_CODE_EXTENSION_BYTE %d \n", itu_t_t35_country_code_extension_byte); +#endif + } + while (offset < size) + { + payload_byte = payload[offset]; + offset ++; +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO + printf("itu_t_t35 payload_byte = %d\n", payload_byte); +#endif + } +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO +#undef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Pan scan rectangle SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_pan_scan_rect_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int pan_scan_rect_cancel_flag; + int pan_scan_cnt_minus1, i; + int pan_scan_rect_repetition_period; + int pan_scan_rect_id, pan_scan_rect_left_offset, pan_scan_rect_right_offset; + int pan_scan_rect_top_offset, pan_scan_rect_bottom_offset; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + pan_scan_rect_id = read_ue_v("SEI: pan_scan_rect_id", buf, &p_Dec->UsedBits); + + pan_scan_rect_cancel_flag = read_u_1("SEI: pan_scan_rect_cancel_flag", buf, &p_Dec->UsedBits); + if (!pan_scan_rect_cancel_flag) + { + pan_scan_cnt_minus1 = read_ue_v("SEI: pan_scan_cnt_minus1", buf, &p_Dec->UsedBits); + for (i = 0; i <= pan_scan_cnt_minus1; i++) + { + pan_scan_rect_left_offset = read_se_v("SEI: pan_scan_rect_left_offset" , buf, &p_Dec->UsedBits); + pan_scan_rect_right_offset = read_se_v("SEI: pan_scan_rect_right_offset" , buf, &p_Dec->UsedBits); + pan_scan_rect_top_offset = read_se_v("SEI: pan_scan_rect_top_offset" , buf, &p_Dec->UsedBits); + pan_scan_rect_bottom_offset = read_se_v("SEI: pan_scan_rect_bottom_offset", buf, &p_Dec->UsedBits); +#ifdef PRINT_PAN_SCAN_RECT + printf("Pan scan rectangle SEI message %d/%d\n", i, pan_scan_cnt_minus1); + printf("pan_scan_rect_id = %d\n", pan_scan_rect_id); + printf("pan_scan_rect_left_offset = %d\n", pan_scan_rect_left_offset); + printf("pan_scan_rect_right_offset = %d\n", pan_scan_rect_right_offset); + printf("pan_scan_rect_top_offset = %d\n", pan_scan_rect_top_offset); + printf("pan_scan_rect_bottom_offset = %d\n", pan_scan_rect_bottom_offset); +#endif + } + pan_scan_rect_repetition_period = read_ue_v("SEI: pan_scan_rect_repetition_period", buf, &p_Dec->UsedBits); + } + + free (buf); +#ifdef PRINT_PAN_SCAN_RECT +#undef PRINT_PAN_SCAN_RECT +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Random access point SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_recovery_point_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int recovery_frame_cnt, exact_match_flag, broken_link_flag, changing_slice_group_idc; + + + Bitstream* buf; + + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + recovery_frame_cnt = read_ue_v( "SEI: recovery_frame_cnt" , buf, &p_Dec->UsedBits); + exact_match_flag = read_u_1 ( "SEI: exact_match_flag" , buf, &p_Dec->UsedBits); + broken_link_flag = read_u_1 ( "SEI: broken_link_flag" , buf, &p_Dec->UsedBits); + changing_slice_group_idc = read_u_v ( 2, "SEI: changing_slice_group_idc", buf, &p_Dec->UsedBits); + + p_Vid->recovery_point = 1; + p_Vid->recovery_frame_cnt = recovery_frame_cnt; + +#ifdef PRINT_RECOVERY_POINT + printf("Recovery point SEI message\n"); + printf("recovery_frame_cnt = %d\n", recovery_frame_cnt); + printf("exact_match_flag = %d\n", exact_match_flag); + printf("broken_link_flag = %d\n", broken_link_flag); + printf("changing_slice_group_idc = %d\n", changing_slice_group_idc); +#endif + free (buf); +#ifdef PRINT_RECOVERY_POINT +#undef PRINT_RECOVERY_POINT +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Decoded Picture Buffer Management Repetition SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_dec_ref_pic_marking_repetition_info( byte* payload, int size, VideoParameters *p_Vid, Slice *pSlice ) +{ + int original_idr_flag, original_frame_num; + int original_field_pic_flag, original_bottom_field_flag; + + DecRefPicMarking_t *tmp_drpm; + DecRefPicMarking_t *old_drpm; + int old_idr_flag, old_no_output_of_prior_pics_flag, old_long_term_reference_flag , old_adaptive_ref_pic_buffering_flag; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + original_idr_flag = read_u_1 ( "SEI: original_idr_flag" , buf, &p_Dec->UsedBits); + original_frame_num = read_ue_v( "SEI: original_frame_num" , buf, &p_Dec->UsedBits); + + if ( !p_Vid->active_sps->frame_mbs_only_flag ) + { + original_field_pic_flag = read_u_1 ( "SEI: original_field_pic_flag", buf, &p_Dec->UsedBits); + if ( original_field_pic_flag ) + { + original_bottom_field_flag = read_u_1 ( "SEI: original_bottom_field_flag", buf, &p_Dec->UsedBits); + } + } + +#ifdef PRINT_DEC_REF_PIC_MARKING + printf("Decoded Picture Buffer Management Repetition SEI message\n"); + printf("original_idr_flag = %d\n", original_idr_flag); + printf("original_frame_num = %d\n", original_frame_num); + if ( active_sps->frame_mbs_only_flag ) + { + printf("original_field_pic_flag = %d\n", original_field_pic_flag); + if ( original_field_pic_flag ) + { + printf("original_bottom_field_flag = %d\n", original_bottom_field_flag); + } + } +#endif + + // we need to save everything that is probably overwritten in dec_ref_pic_marking() + old_drpm = pSlice->dec_ref_pic_marking_buffer; + old_idr_flag = pSlice->idr_flag; //p_Vid->idr_flag; + + old_no_output_of_prior_pics_flag = pSlice->no_output_of_prior_pics_flag; //p_Vid->no_output_of_prior_pics_flag; + old_long_term_reference_flag = pSlice->long_term_reference_flag; + old_adaptive_ref_pic_buffering_flag = pSlice->adaptive_ref_pic_buffering_flag; + + // set new initial values + //p_Vid->idr_flag = original_idr_flag; + pSlice->idr_flag = original_idr_flag; + pSlice->dec_ref_pic_marking_buffer = NULL; + + dec_ref_pic_marking(p_Vid, buf, pSlice); + + // print out decoded values +#ifdef PRINT_DEC_REF_PIC_MARKING + if (p_Vid->idr_flag) + { + printf("no_output_of_prior_pics_flag = %d\n", p_Vid->no_output_of_prior_pics_flag); + printf("long_term_reference_flag = %d\n", p_Vid->long_term_reference_flag); + } + else + { + printf("adaptive_ref_pic_buffering_flag = %d\n", p_Vid->adaptive_ref_pic_buffering_flag); + if (p_Vid->adaptive_ref_pic_buffering_flag) + { + tmp_drpm=p_Vid->dec_ref_pic_marking_buffer; + while (tmp_drpm != NULL) + { + printf("memory_management_control_operation = %d\n", tmp_drpm->memory_management_control_operation); + + if ((tmp_drpm->memory_management_control_operation==1)||(tmp_drpm->memory_management_control_operation==3)) + { + printf("difference_of_pic_nums_minus1 = %d\n", tmp_drpm->difference_of_pic_nums_minus1); + } + if (tmp_drpm->memory_management_control_operation==2) + { + printf("long_term_pic_num = %d\n", tmp_drpm->long_term_pic_num); + } + if ((tmp_drpm->memory_management_control_operation==3)||(tmp_drpm->memory_management_control_operation==6)) + { + printf("long_term_frame_idx = %d\n", tmp_drpm->long_term_frame_idx); + } + if (tmp_drpm->memory_management_control_operation==4) + { + printf("max_long_term_pic_idx_plus1 = %d\n", tmp_drpm->max_long_term_frame_idx_plus1); + } + tmp_drpm = tmp_drpm->Next; + } + } + } +#endif + + while (pSlice->dec_ref_pic_marking_buffer) + { + tmp_drpm=pSlice->dec_ref_pic_marking_buffer; + + pSlice->dec_ref_pic_marking_buffer=tmp_drpm->Next; + free (tmp_drpm); + } + + // restore old values in p_Vid + pSlice->dec_ref_pic_marking_buffer = old_drpm; + pSlice->idr_flag = old_idr_flag; + pSlice->no_output_of_prior_pics_flag = old_no_output_of_prior_pics_flag; + p_Vid->no_output_of_prior_pics_flag = pSlice->no_output_of_prior_pics_flag; + pSlice->long_term_reference_flag = old_long_term_reference_flag; + pSlice->adaptive_ref_pic_buffering_flag = old_adaptive_ref_pic_buffering_flag; + + free (buf); +#ifdef PRINT_DEC_REF_PIC_MARKING +#undef PRINT_DEC_REF_PIC_MARKING +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the Full-frame freeze SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_full_frame_freeze_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int full_frame_freeze_repetition_period; + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + full_frame_freeze_repetition_period = read_ue_v( "SEI: full_frame_freeze_repetition_period" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_FULL_FRAME_FREEZE_INFO + printf("full_frame_freeze_repetition_period = %d\n", full_frame_freeze_repetition_period); +#endif + + free (buf); +#ifdef PRINT_FULL_FRAME_FREEZE_INFO +#undef PRINT_FULL_FRAME_FREEZE_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Full-frame freeze release SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_full_frame_freeze_release_info( byte* payload, int size, VideoParameters *p_Vid ) +{ +#ifdef PRINT_FULL_FRAME_FREEZE_RELEASE_INFO + printf("Full-frame freeze release SEI message\n"); + if (size) + { + printf("payload size of this message should be zero, but is %d bytes.\n", size); + } +#endif + +#ifdef PRINT_FULL_FRAME_FREEZE_RELEASE_INFO +#undef PRINT_FULL_FRAME_FREEZE_RELEASE_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the Full-frame snapshot SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_full_frame_snapshot_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int snapshot_id; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + snapshot_id = read_ue_v("SEI: snapshot_id", buf, &p_Dec->UsedBits); + +#ifdef PRINT_FULL_FRAME_SNAPSHOT_INFO + printf("Full-frame snapshot SEI message\n"); + printf("snapshot_id = %d\n", snapshot_id); +#endif + free (buf); +#ifdef PRINT_FULL_FRAME_SNAPSHOT_INFO +#undef PRINT_FULL_FRAME_SNAPSHOT_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the Progressive refinement segment start SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_progressive_refinement_start_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int progressive_refinement_id, num_refinement_steps_minus1; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + progressive_refinement_id = read_ue_v("SEI: progressive_refinement_id" , buf, &p_Dec->UsedBits); + num_refinement_steps_minus1 = read_ue_v("SEI: num_refinement_steps_minus1", buf, &p_Dec->UsedBits); + +#ifdef PRINT_PROGRESSIVE_REFINEMENT_START_INFO + printf("Progressive refinement segment start SEI message\n"); + printf("progressive_refinement_id = %d\n", progressive_refinement_id); + printf("num_refinement_steps_minus1 = %d\n", num_refinement_steps_minus1); +#endif + free (buf); +#ifdef PRINT_PROGRESSIVE_REFINEMENT_START_INFO +#undef PRINT_PROGRESSIVE_REFINEMENT_START_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Progressive refinement segment end SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_progressive_refinement_end_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int progressive_refinement_id; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + progressive_refinement_id = read_ue_v("SEI: progressive_refinement_id" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_PROGRESSIVE_REFINEMENT_END_INFO + printf("Progressive refinement segment end SEI message\n"); + printf("progressive_refinement_id = %d\n", progressive_refinement_id); +#endif + free (buf); +#ifdef PRINT_PROGRESSIVE_REFINEMENT_END_INFO +#undef PRINT_PROGRESSIVE_REFINEMENT_END_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Motion-constrained slice group set SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_motion_constrained_slice_group_set_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int num_slice_groups_minus1, slice_group_id, exact_match_flag, pan_scan_rect_flag, pan_scan_rect_id; + int i; + int sliceGroupSize; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + num_slice_groups_minus1 = read_ue_v("SEI: num_slice_groups_minus1" , buf, &p_Dec->UsedBits); + sliceGroupSize = CeilLog2( num_slice_groups_minus1 + 1 ); +#ifdef PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO + printf("Motion-constrained slice group set SEI message\n"); + printf("num_slice_groups_minus1 = %d\n", num_slice_groups_minus1); +#endif + + for (i=0; i<=num_slice_groups_minus1;i++) + { + + slice_group_id = read_u_v (sliceGroupSize, "SEI: slice_group_id" , buf, &p_Dec->UsedBits); +#ifdef PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO + printf("slice_group_id = %d\n", slice_group_id); +#endif + } + + exact_match_flag = read_u_1("SEI: exact_match_flag" , buf, &p_Dec->UsedBits); + pan_scan_rect_flag = read_u_1("SEI: pan_scan_rect_flag" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO + printf("exact_match_flag = %d\n", exact_match_flag); + printf("pan_scan_rect_flag = %d\n", pan_scan_rect_flag); +#endif + + if (pan_scan_rect_flag) + { + pan_scan_rect_id = read_ue_v("SEI: pan_scan_rect_id" , buf, &p_Dec->UsedBits); +#ifdef PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO + printf("pan_scan_rect_id = %d\n", pan_scan_rect_id); +#endif + } + + free (buf); +#ifdef PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO +#undef PRINT_MOTION_CONST_SLICE_GROUP_SET_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the film grain characteristics SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_film_grain_characteristics_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int film_grain_characteristics_cancel_flag; + int model_id, separate_colour_description_present_flag; + int film_grain_bit_depth_luma_minus8, film_grain_bit_depth_chroma_minus8, film_grain_full_range_flag, film_grain_colour_primaries, film_grain_transfer_characteristics, film_grain_matrix_coefficients; + int blending_mode_id, log2_scale_factor, comp_model_present_flag[3]; + int num_intensity_intervals_minus1, num_model_values_minus1; + int intensity_interval_lower_bound, intensity_interval_upper_bound; + int comp_model_value; + int film_grain_characteristics_repetition_period; + + int c, i, j; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + film_grain_characteristics_cancel_flag = read_u_1("SEI: film_grain_characteristics_cancel_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("film_grain_characteristics_cancel_flag = %d\n", film_grain_characteristics_cancel_flag); +#endif + if(!film_grain_characteristics_cancel_flag) + { + + model_id = read_u_v(2, "SEI: model_id", buf, &p_Dec->UsedBits); + separate_colour_description_present_flag = read_u_1("SEI: separate_colour_description_present_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("model_id = %d\n", model_id); + printf("separate_colour_description_present_flag = %d\n", separate_colour_description_present_flag); +#endif + if (separate_colour_description_present_flag) + { + film_grain_bit_depth_luma_minus8 = read_u_v(3, "SEI: film_grain_bit_depth_luma_minus8", buf, &p_Dec->UsedBits); + film_grain_bit_depth_chroma_minus8 = read_u_v(3, "SEI: film_grain_bit_depth_chroma_minus8", buf, &p_Dec->UsedBits); + film_grain_full_range_flag = read_u_v(1, "SEI: film_grain_full_range_flag", buf, &p_Dec->UsedBits); + film_grain_colour_primaries = read_u_v(8, "SEI: film_grain_colour_primaries", buf, &p_Dec->UsedBits); + film_grain_transfer_characteristics = read_u_v(8, "SEI: film_grain_transfer_characteristics", buf, &p_Dec->UsedBits); + film_grain_matrix_coefficients = read_u_v(8, "SEI: film_grain_matrix_coefficients", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("film_grain_bit_depth_luma_minus8 = %d\n", film_grain_bit_depth_luma_minus8); + printf("film_grain_bit_depth_chroma_minus8 = %d\n", film_grain_bit_depth_chroma_minus8); + printf("film_grain_full_range_flag = %d\n", film_grain_full_range_flag); + printf("film_grain_colour_primaries = %d\n", film_grain_colour_primaries); + printf("film_grain_transfer_characteristics = %d\n", film_grain_transfer_characteristics); + printf("film_grain_matrix_coefficients = %d\n", film_grain_matrix_coefficients); +#endif + } + blending_mode_id = read_u_v(2, "SEI: blending_mode_id", buf, &p_Dec->UsedBits); + log2_scale_factor = read_u_v(4, "SEI: log2_scale_factor", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("blending_mode_id = %d\n", blending_mode_id); + printf("log2_scale_factor = %d\n", log2_scale_factor); +#endif + for (c = 0; c < 3; c ++) + { + comp_model_present_flag[c] = read_u_1("SEI: comp_model_present_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("comp_model_present_flag = %d\n", comp_model_present_flag[c]); +#endif + } + for (c = 0; c < 3; c ++) + if (comp_model_present_flag[c]) + { + num_intensity_intervals_minus1 = read_u_v(8, "SEI: num_intensity_intervals_minus1", buf, &p_Dec->UsedBits); + num_model_values_minus1 = read_u_v(3, "SEI: num_model_values_minus1", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("num_intensity_intervals_minus1 = %d\n", num_intensity_intervals_minus1); + printf("num_model_values_minus1 = %d\n", num_model_values_minus1); +#endif + for (i = 0; i <= num_intensity_intervals_minus1; i ++) + { + intensity_interval_lower_bound = read_u_v(8, "SEI: intensity_interval_lower_bound", buf, &p_Dec->UsedBits); + intensity_interval_upper_bound = read_u_v(8, "SEI: intensity_interval_upper_bound", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("intensity_interval_lower_bound = %d\n", intensity_interval_lower_bound); + printf("intensity_interval_upper_bound = %d\n", intensity_interval_upper_bound); +#endif + for (j = 0; j <= num_model_values_minus1; j++) + { + comp_model_value = read_se_v("SEI: comp_model_value", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("comp_model_value = %d\n", comp_model_value); +#endif + } + } + } + film_grain_characteristics_repetition_period = read_ue_v("SEI: film_grain_characteristics_repetition_period", buf, &p_Dec->UsedBits); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO + printf("film_grain_characteristics_repetition_period = %d\n", film_grain_characteristics_repetition_period); +#endif + } + + free (buf); +#ifdef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO +#undef PRINT_FILM_GRAIN_CHARACTERISTICS_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the deblocking filter display preference SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_deblocking_filter_display_preference_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int deblocking_display_preference_cancel_flag; + int display_prior_to_deblocking_preferred_flag, dec_frame_buffering_constraint_flag, deblocking_display_preference_repetition_period; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + deblocking_display_preference_cancel_flag = read_u_1("SEI: deblocking_display_preference_cancel_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_DEBLOCKING_FILTER_DISPLAY_PREFERENCE_INFO + printf("deblocking_display_preference_cancel_flag = %d\n", deblocking_display_preference_cancel_flag); +#endif + if(!deblocking_display_preference_cancel_flag) + { + display_prior_to_deblocking_preferred_flag = read_u_1("SEI: display_prior_to_deblocking_preferred_flag", buf, &p_Dec->UsedBits); + dec_frame_buffering_constraint_flag = read_u_1("SEI: dec_frame_buffering_constraint_flag", buf, &p_Dec->UsedBits); + deblocking_display_preference_repetition_period = read_ue_v("SEI: deblocking_display_preference_repetition_period", buf, &p_Dec->UsedBits); +#ifdef PRINT_DEBLOCKING_FILTER_DISPLAY_PREFERENCE_INFO + printf("display_prior_to_deblocking_preferred_flag = %d\n", display_prior_to_deblocking_preferred_flag); + printf("dec_frame_buffering_constraint_flag = %d\n", dec_frame_buffering_constraint_flag); + printf("deblocking_display_preference_repetition_period = %d\n", deblocking_display_preference_repetition_period); +#endif + } + + free (buf); +#ifdef PRINT_DEBLOCKING_FILTER_DISPLAY_PREFERENCE_INFO +#undef PRINT_DEBLOCKING_FILTER_DISPLAY_PREFERENCE_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the stereo video info SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_stereo_video_info_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int field_views_flags; + int top_field_is_left_view_flag, current_frame_is_left_view_flag, next_frame_is_second_view_flag; + int left_view_self_contained_flag; + int right_view_self_contained_flag; + + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + field_views_flags = read_u_1("SEI: field_views_flags", buf, &p_Dec->UsedBits); +#ifdef PRINT_STEREO_VIDEO_INFO_INFO + printf("field_views_flags = %d\n", field_views_flags); +#endif + if (field_views_flags) + { + top_field_is_left_view_flag = read_u_1("SEI: top_field_is_left_view_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_STEREO_VIDEO_INFO_INFO + printf("top_field_is_left_view_flag = %d\n", top_field_is_left_view_flag); +#endif + } + else + { + current_frame_is_left_view_flag = read_u_1("SEI: current_frame_is_left_view_flag", buf, &p_Dec->UsedBits); + next_frame_is_second_view_flag = read_u_1("SEI: next_frame_is_second_view_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_STEREO_VIDEO_INFO_INFO + printf("current_frame_is_left_view_flag = %d\n", current_frame_is_left_view_flag); + printf("next_frame_is_second_view_flag = %d\n", next_frame_is_second_view_flag); +#endif + } + + left_view_self_contained_flag = read_u_1("SEI: left_view_self_contained_flag", buf, &p_Dec->UsedBits); + right_view_self_contained_flag = read_u_1("SEI: right_view_self_contained_flag", buf, &p_Dec->UsedBits); +#ifdef PRINT_STEREO_VIDEO_INFO_INFO + printf("left_view_self_contained_flag = %d\n", left_view_self_contained_flag); + printf("right_view_self_contained_flag = %d\n", right_view_self_contained_flag); +#endif + + free (buf); +#ifdef PRINT_STEREO_VIDEO_INFO_INFO +#undef PRINT_STEREO_VIDEO_INFO_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the Reserved SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_reserved_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int offset = 0; + byte payload_byte; + +#ifdef PRINT_RESERVED_INFO + printf("Reserved SEI message\n"); +#endif + + while (offset < size) + { + payload_byte = payload[offset]; + offset ++; +#ifdef PRINT_RESERVED_INFO + printf("reserved_sei_message_payload_byte = %d\n", payload_byte); +#endif + } +#ifdef PRINT_RESERVED_INFO +#undef PRINT_RESERVED_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Buffering period SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_buffering_period_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + int seq_parameter_set_id, initial_cpb_removal_delay, initial_cpb_removal_delay_offset; + unsigned int k; + + Bitstream* buf; + seq_parameter_set_rbsp_t *sps; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + seq_parameter_set_id = read_ue_v("SEI: seq_parameter_set_id" , buf, &p_Dec->UsedBits); + + sps = &p_Vid->SeqParSet[seq_parameter_set_id]; + + activate_sps(p_Vid, sps); + +#ifdef PRINT_BUFFERING_PERIOD_INFO + printf("Buffering period SEI message\n"); + printf("seq_parameter_set_id = %d\n", seq_parameter_set_id); +#endif + + // Note: NalHrdBpPresentFlag and CpbDpbDelaysPresentFlag can also be set "by some means not specified in this Recommendation | International Standard" + if (sps->vui_parameters_present_flag) + { + + if (sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + { + for (k=0; kvui_seq_parameters.nal_hrd_parameters.cpb_cnt_minus1+1; k++) + { + initial_cpb_removal_delay = read_u_v(sps->vui_seq_parameters.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1+1, "SEI: initial_cpb_removal_delay" , buf, &p_Dec->UsedBits); + initial_cpb_removal_delay_offset = read_u_v(sps->vui_seq_parameters.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1+1, "SEI: initial_cpb_removal_delay_offset" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_BUFFERING_PERIOD_INFO + printf("nal initial_cpb_removal_delay[%d] = %d\n", k, initial_cpb_removal_delay); + printf("nal initial_cpb_removal_delay_offset[%d] = %d\n", k, initial_cpb_removal_delay_offset); +#endif + } + } + + if (sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + { + for (k=0; kvui_seq_parameters.vcl_hrd_parameters.cpb_cnt_minus1+1; k++) + { + initial_cpb_removal_delay = read_u_v(sps->vui_seq_parameters.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1+1, "SEI: initial_cpb_removal_delay" , buf, &p_Dec->UsedBits); + initial_cpb_removal_delay_offset = read_u_v(sps->vui_seq_parameters.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1+1, "SEI: initial_cpb_removal_delay_offset" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_BUFFERING_PERIOD_INFO + printf("vcl initial_cpb_removal_delay[%d] = %d\n", k, initial_cpb_removal_delay); + printf("vcl initial_cpb_removal_delay_offset[%d] = %d\n", k, initial_cpb_removal_delay_offset); +#endif + } + } + } + + free (buf); +#ifdef PRINT_BUFFERING_PERIOD_INFO +#undef PRINT_BUFFERING_PERIOD_INFO +#endif +} + + +/*! + ************************************************************************ + * \brief + * Interpret the Picture timing SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_picture_timing_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int cpb_removal_delay, dpb_output_delay, pic_struct_present_flag, pic_struct; + int clock_timestamp_flag; + int ct_type, nuit_field_based_flag, counting_type, full_timestamp_flag, discontinuity_flag, cnt_dropped_flag, nframes; + int seconds_value, minutes_value, hours_value, seconds_flag, minutes_flag, hours_flag, time_offset; + int NumClockTs = 0; + int i; + + int cpb_removal_len = 24; + int dpb_output_len = 24; + + Boolean CpbDpbDelaysPresentFlag; + + Bitstream* buf; + + if (NULL==active_sps) + { + fprintf (stdout, "Warning: no active SPS, timing SEI cannot be parsed\n"); + return; + } + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + +#ifdef PRINT_PICTURE_TIMING_INFO + printf("Picture timing SEI message\n"); +#endif + + // CpbDpbDelaysPresentFlag can also be set "by some means not specified in this Recommendation | International Standard" + CpbDpbDelaysPresentFlag = (Boolean) (active_sps->vui_parameters_present_flag + && ( (active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag != 0) + ||(active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag != 0))); + + if (CpbDpbDelaysPresentFlag ) + { + if (active_sps->vui_parameters_present_flag) + { + if (active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + { + cpb_removal_len = active_sps->vui_seq_parameters.nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1; + dpb_output_len = active_sps->vui_seq_parameters.nal_hrd_parameters.dpb_output_delay_length_minus1 + 1; + } + else if (active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + { + cpb_removal_len = active_sps->vui_seq_parameters.vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1; + dpb_output_len = active_sps->vui_seq_parameters.vcl_hrd_parameters.dpb_output_delay_length_minus1 + 1; + } + } + + if ((active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag)|| + (active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag)) + { + cpb_removal_delay = read_u_v(cpb_removal_len, "SEI: cpb_removal_delay" , buf, &p_Dec->UsedBits); + dpb_output_delay = read_u_v(dpb_output_len, "SEI: dpb_output_delay" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("cpb_removal_delay = %d\n",cpb_removal_delay); + printf("dpb_output_delay = %d\n",dpb_output_delay); +#endif + } + } + + if (!active_sps->vui_parameters_present_flag) + { + pic_struct_present_flag = 0; + } + else + { + pic_struct_present_flag = active_sps->vui_seq_parameters.pic_struct_present_flag; + } + + if (pic_struct_present_flag) + { + pic_struct = read_u_v(4, "SEI: pic_struct" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("pic_struct = %d\n",pic_struct); +#endif + switch (pic_struct) + { + case 0: + case 1: + case 2: + NumClockTs = 1; + break; + case 3: + case 4: + case 7: + NumClockTs = 2; + break; + case 5: + case 6: + case 8: + NumClockTs = 3; + break; + default: + error("reserved pic_struct used (can't determine NumClockTs)", 500); + } + for (i=0; iUsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("clock_timestamp_flag = %d\n",clock_timestamp_flag); +#endif + if (clock_timestamp_flag) + { + ct_type = read_u_v(2, "SEI: ct_type" , buf, &p_Dec->UsedBits); + nuit_field_based_flag = read_u_1( "SEI: nuit_field_based_flag" , buf, &p_Dec->UsedBits); + counting_type = read_u_v(5, "SEI: counting_type" , buf, &p_Dec->UsedBits); + full_timestamp_flag = read_u_1( "SEI: full_timestamp_flag" , buf, &p_Dec->UsedBits); + discontinuity_flag = read_u_1( "SEI: discontinuity_flag" , buf, &p_Dec->UsedBits); + cnt_dropped_flag = read_u_1( "SEI: cnt_dropped_flag" , buf, &p_Dec->UsedBits); + nframes = read_u_v(8, "SEI: nframes" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_PICTURE_TIMING_INFO + printf("ct_type = %d\n",ct_type); + printf("nuit_field_based_flag = %d\n",nuit_field_based_flag); + printf("full_timestamp_flag = %d\n",full_timestamp_flag); + printf("discontinuity_flag = %d\n",discontinuity_flag); + printf("cnt_dropped_flag = %d\n",cnt_dropped_flag); + printf("nframes = %d\n",nframes); +#endif + if (full_timestamp_flag) + { + seconds_value = read_u_v(6, "SEI: seconds_value" , buf, &p_Dec->UsedBits); + minutes_value = read_u_v(6, "SEI: minutes_value" , buf, &p_Dec->UsedBits); + hours_value = read_u_v(5, "SEI: hours_value" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("seconds_value = %d\n",seconds_value); + printf("minutes_value = %d\n",minutes_value); + printf("hours_value = %d\n",hours_value); +#endif + } + else + { + seconds_flag = read_u_1( "SEI: seconds_flag" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("seconds_flag = %d\n",seconds_flag); +#endif + if (seconds_flag) + { + seconds_value = read_u_v(6, "SEI: seconds_value" , buf, &p_Dec->UsedBits); + minutes_flag = read_u_1( "SEI: minutes_flag" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("seconds_value = %d\n",seconds_value); + printf("minutes_flag = %d\n",minutes_flag); +#endif + if(minutes_flag) + { + minutes_value = read_u_v(6, "SEI: minutes_value" , buf, &p_Dec->UsedBits); + hours_flag = read_u_1( "SEI: hours_flag" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("minutes_value = %d\n",minutes_value); + printf("hours_flag = %d\n",hours_flag); +#endif + if(hours_flag) + { + hours_value = read_u_v(5, "SEI: hours_value" , buf, &p_Dec->UsedBits); +#ifdef PRINT_PICTURE_TIMING_INFO + printf("hours_value = %d\n",hours_value); +#endif + } + } + } + } + { + int time_offset_length; + if (active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + time_offset_length = active_sps->vui_seq_parameters.vcl_hrd_parameters.time_offset_length; + else if (active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + time_offset_length = active_sps->vui_seq_parameters.nal_hrd_parameters.time_offset_length; + else + time_offset_length = 24; + if (time_offset_length) + time_offset = read_i_v(time_offset_length, "SEI: time_offset" , buf, &p_Dec->UsedBits); + else + time_offset = 0; +#ifdef PRINT_PICTURE_TIMING_INFO + printf("time_offset = %d\n",time_offset); +#endif + } + } + } + } + + free (buf); +#ifdef PRINT_PICTURE_TIMING_INFO +#undef PRINT_PICTURE_TIMING_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the Frame Packing Arrangement SEI message + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + ************************************************************************ + */ +void interpret_frame_packing_arrangement_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + frame_packing_arrangement_information_struct seiFramePackingArrangement; + Bitstream* buf; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO + printf("Frame packing arrangement SEI message\n"); +#endif + + seiFramePackingArrangement.frame_packing_arrangement_id = (unsigned int)read_ue_v( "SEI: frame_packing_arrangement_id", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame_packing_arrangement_cancel_flag = read_u_1( "SEI: frame_packing_arrangement_cancel_flag", buf, &p_Dec->UsedBits ); +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO + printf("frame_packing_arrangement_id = %d\n", seiFramePackingArrangement.frame_packing_arrangement_id); + printf("frame_packing_arrangement_cancel_flag = %d\n", seiFramePackingArrangement.frame_packing_arrangement_cancel_flag); +#endif + if ( seiFramePackingArrangement.frame_packing_arrangement_cancel_flag == FALSE ) + { + seiFramePackingArrangement.frame_packing_arrangement_type = (unsigned char)read_u_v( 7, "SEI: frame_packing_arrangement_type", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.quincunx_sampling_flag = read_u_1( "SEI: quincunx_sampling_flag", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.content_interpretation_type = (unsigned char)read_u_v( 6, "SEI: content_interpretation_type", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.spatial_flipping_flag = read_u_1( "SEI: spatial_flipping_flag", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame0_flipped_flag = read_u_1( "SEI: frame0_flipped_flag", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.field_views_flag = read_u_1( "SEI: field_views_flag", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.current_frame_is_frame0_flag = read_u_1( "SEI: current_frame_is_frame0_flag", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame0_self_contained_flag = read_u_1( "SEI: frame0_self_contained_flag", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame1_self_contained_flag = read_u_1( "SEI: frame1_self_contained_flag", buf, &p_Dec->UsedBits ); +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO + printf("frame_packing_arrangement_type = %d\n", seiFramePackingArrangement.frame_packing_arrangement_type); + printf("quincunx_sampling_flag = %d\n", seiFramePackingArrangement.quincunx_sampling_flag); + printf("content_interpretation_type = %d\n", seiFramePackingArrangement.content_interpretation_type); + printf("spatial_flipping_flag = %d\n", seiFramePackingArrangement.spatial_flipping_flag); + printf("frame0_flipped_flag = %d\n", seiFramePackingArrangement.frame0_flipped_flag); + printf("field_views_flag = %d\n", seiFramePackingArrangement.field_views_flag); + printf("current_frame_is_frame0_flag = %d\n", seiFramePackingArrangement.current_frame_is_frame0_flag); + printf("frame0_self_contained_flag = %d\n", seiFramePackingArrangement.frame0_self_contained_flag); + printf("frame1_self_contained_flag = %d\n", seiFramePackingArrangement.frame1_self_contained_flag); +#endif + if ( seiFramePackingArrangement.quincunx_sampling_flag == FALSE && seiFramePackingArrangement.frame_packing_arrangement_type != 5 ) + { + seiFramePackingArrangement.frame0_grid_position_x = (unsigned char)read_u_v( 4, "SEI: frame0_grid_position_x", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame0_grid_position_y = (unsigned char)read_u_v( 4, "SEI: frame0_grid_position_y", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame1_grid_position_x = (unsigned char)read_u_v( 4, "SEI: frame1_grid_position_x", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame1_grid_position_y = (unsigned char)read_u_v( 4, "SEI: frame1_grid_position_y", buf, &p_Dec->UsedBits ); +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO + printf("frame0_grid_position_x = %d\n", seiFramePackingArrangement.frame0_grid_position_x); + printf("frame0_grid_position_y = %d\n", seiFramePackingArrangement.frame0_grid_position_y); + printf("frame1_grid_position_x = %d\n", seiFramePackingArrangement.frame1_grid_position_x); + printf("frame1_grid_position_y = %d\n", seiFramePackingArrangement.frame1_grid_position_y); +#endif + } + seiFramePackingArrangement.frame_packing_arrangement_reserved_byte = (unsigned char)read_u_v( 8, "SEI: frame_packing_arrangement_reserved_byte", buf, &p_Dec->UsedBits ); + seiFramePackingArrangement.frame_packing_arrangement_repetition_period = (unsigned int)read_ue_v( "SEI: frame_packing_arrangement_repetition_period", buf, &p_Dec->UsedBits ); +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO + printf("frame_packing_arrangement_reserved_byte = %d\n", seiFramePackingArrangement.frame_packing_arrangement_reserved_byte); + printf("frame_packing_arrangement_repetition_period = %d\n", seiFramePackingArrangement.frame_packing_arrangement_repetition_period); +#endif + } + seiFramePackingArrangement.frame_packing_arrangement_extension_flag = read_u_1( "SEI: frame_packing_arrangement_extension_flag", buf, &p_Dec->UsedBits ); +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO + printf("frame_packing_arrangement_extension_flag = %d\n", seiFramePackingArrangement.frame_packing_arrangement_extension_flag); +#endif + + free (buf); +#ifdef PRINT_FRAME_PACKING_ARRANGEMENT_INFO +#undef PRINT_FRAME_PACKING_ARRANGEMENT_INFO +#endif +} + +/*! + ************************************************************************ + * \brief + * Interpret the HDR tone-mapping SEI message (JVT-T060) + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +typedef struct +{ + unsigned int tone_map_id; + unsigned char tone_map_cancel_flag; + unsigned int tone_map_repetition_period; + unsigned char coded_data_bit_depth; + unsigned char sei_bit_depth; + unsigned int model_id; + // variables for model 0 + int min_value; + int max_value; + // variables for model 1 + int sigmoid_midpoint; + int sigmoid_width; + // variables for model 2 + int start_of_coded_interval[1<bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + seiToneMappingTmp.tone_map_id = read_ue_v("SEI: tone_map_id", buf, &p_Dec->UsedBits); + seiToneMappingTmp.tone_map_cancel_flag = (unsigned char) read_u_1("SEI: tone_map_cancel_flag", buf, &p_Dec->UsedBits); + +#ifdef PRINT_TONE_MAPPING + printf("Tone-mapping SEI message\n"); + printf("tone_map_id = %d\n", seiToneMappingTmp.tone_map_id); + + if (seiToneMappingTmp.tone_map_id != 0) + printf("WARNING! Tone_map_id != 0, print the SEI message info only. The tone mapping is actually applied only when Tone_map_id==0\n\n"); + printf("tone_map_cancel_flag = %d\n", seiToneMappingTmp.tone_map_cancel_flag); +#endif + + if (!seiToneMappingTmp.tone_map_cancel_flag) + { + seiToneMappingTmp.tone_map_repetition_period = read_ue_v( "SEI: tone_map_repetition_period", buf, &p_Dec->UsedBits); + seiToneMappingTmp.coded_data_bit_depth = (unsigned char)read_u_v (8,"SEI: coded_data_bit_depth" , buf, &p_Dec->UsedBits); + seiToneMappingTmp.sei_bit_depth = (unsigned char)read_u_v (8,"SEI: sei_bit_depth" , buf, &p_Dec->UsedBits); + seiToneMappingTmp.model_id = read_ue_v( "SEI: model_id" , buf, &p_Dec->UsedBits); + +#ifdef PRINT_TONE_MAPPING + printf("tone_map_repetition_period = %d\n", seiToneMappingTmp.tone_map_repetition_period); + printf("coded_data_bit_depth = %d\n", seiToneMappingTmp.coded_data_bit_depth); + printf("sei_bit_depth = %d\n", seiToneMappingTmp.sei_bit_depth); + printf("model_id = %d\n", seiToneMappingTmp.model_id); +#endif + + max_coded_num = 1<UsedBits); + seiToneMappingTmp.max_value = read_u_v (32,"SEI: min_value", buf, &p_Dec->UsedBits); +#ifdef PRINT_TONE_MAPPING + printf("min_value = %d, max_value = %d\n", seiToneMappingTmp.min_value, seiToneMappingTmp.max_value); +#endif + } + else if (seiToneMappingTmp.model_id == 1) + { // sigmoidal mapping + seiToneMappingTmp.sigmoid_midpoint = read_u_v (32,"SEI: sigmoid_midpoint", buf, &p_Dec->UsedBits); + seiToneMappingTmp.sigmoid_width = read_u_v (32,"SEI: sigmoid_width", buf, &p_Dec->UsedBits); +#ifdef PRINT_TONE_MAPPING + printf("sigmoid_midpoint = %d, sigmoid_width = %d\n", seiToneMappingTmp.sigmoid_midpoint, seiToneMappingTmp.sigmoid_width); +#endif + } + else if (seiToneMappingTmp.model_id == 2) + { // user defined table mapping + for (i=0; i>3)<<3), "SEI: start_of_coded_interval" , buf, &p_Dec->UsedBits); +#ifdef PRINT_TONE_MAPPING // too long to print + //printf("start_of_coded_interval[%d] = %d\n", i, seiToneMappingTmp.start_of_coded_interval[i]); +#endif + } + } + else if (seiToneMappingTmp.model_id == 3) + { // piece-wise linear mapping + seiToneMappingTmp.num_pivots = read_u_v (16,"SEI: num_pivots", buf, &p_Dec->UsedBits); +#ifdef PRINT_TONE_MAPPING + printf("num_pivots = %d\n", seiToneMappingTmp.num_pivots); +#endif + seiToneMappingTmp.coded_pivot_value[0] = 0; + seiToneMappingTmp.sei_pivot_value[0] = 0; + seiToneMappingTmp.coded_pivot_value[seiToneMappingTmp.num_pivots+1] = max_coded_num-1; + seiToneMappingTmp.sei_pivot_value[seiToneMappingTmp.num_pivots+1] = max_output_num-1; + + for (i=1; i < seiToneMappingTmp.num_pivots+1; i++) + { + seiToneMappingTmp.coded_pivot_value[i] = read_u_v( (((seiToneMappingTmp.coded_data_bit_depth+7)>>3)<<3), "SEI: coded_pivot_value", buf, &p_Dec->UsedBits); + seiToneMappingTmp.sei_pivot_value[i] = read_u_v( (((seiToneMappingTmp.sei_bit_depth+7)>>3)<<3), "SEI: sei_pivot_value", buf, &p_Dec->UsedBits); +#ifdef PRINT_TONE_MAPPING + printf("coded_pivot_value[%d] = %d, sei_pivot_value[%d] = %d\n", i, seiToneMappingTmp.coded_pivot_value[i], i, seiToneMappingTmp.sei_pivot_value[i]); +#endif + } + } + +#if (ENABLE_OUTPUT_TONEMAPPING) + // Currently, only when the map_id == 0, the tone-mapping is actually applied. + if (seiToneMappingTmp.tone_map_id== 0) + { + int j; + p_Vid->seiToneMapping->seiHasTone_mapping = TRUE; + p_Vid->seiToneMapping->tone_map_repetition_period = seiToneMappingTmp.tone_map_repetition_period; + p_Vid->seiToneMapping->coded_data_bit_depth = seiToneMappingTmp.coded_data_bit_depth; + p_Vid->seiToneMapping->sei_bit_depth = seiToneMappingTmp.sei_bit_depth; + p_Vid->seiToneMapping->model_id = seiToneMappingTmp.model_id; + p_Vid->seiToneMapping->count = 0; + + // generate the look up table of tone mapping + switch(seiToneMappingTmp.model_id) + { + case 0: // linear mapping with clipping + for (i=0; i<=seiToneMappingTmp.min_value; i++) + p_Vid->seiToneMapping->lut[i] = 0; + + for (i=seiToneMappingTmp.min_value+1; i < seiToneMappingTmp.max_value; i++) + p_Vid->seiToneMapping->lut[i] = (imgpel) ((i-seiToneMappingTmp.min_value) * (max_output_num-1)/(seiToneMappingTmp.max_value- seiToneMappingTmp.min_value)); + + for (i=seiToneMappingTmp.max_value; iseiToneMapping->lut[i] = (imgpel) (max_output_num - 1); + break; + case 1: // sigmoid mapping + + for (i=0; i < max_coded_num; i++) + { + double tmp = 1.0 + exp( -6*(double)(i-seiToneMappingTmp.sigmoid_midpoint)/seiToneMappingTmp.sigmoid_width); + p_Vid->seiToneMapping->lut[i] = (imgpel)( (double)(max_output_num-1)/ tmp + 0.5); + } + break; + case 2: // user defined table + if (0 < max_output_num-1) + { + for (j=0; jseiToneMapping->lut[i] = (imgpel) j; + } + } + p_Vid->seiToneMapping->lut[i] = (imgpel) (max_output_num - 1); + } + break; + case 3: // piecewise linear mapping + for (j=0; jseiToneMapping->lut[i] = (imgpel) (seiToneMappingTmp.sei_pivot_value[j] + (int)(( (i - seiToneMappingTmp.coded_pivot_value[j]) * slope))); + } + } + break; + + default: + break; + } // end switch + } +#endif + } // end !tone_map_cancel_flag + free (buf); +} + +#if (ENABLE_OUTPUT_TONEMAPPING) +// tone map using the look-up-table generated according to SEI tone mapping message +void tone_map (imgpel** imgX, imgpel* lut, int size_x, int size_y) +{ + int i, j; + + for(i=0;iseiHasTone_mapping = FALSE; + seiToneMapping->count = 0; +} + +void update_tone_mapping_sei(ToneMappingSEI *seiToneMapping) +{ + + if(seiToneMapping->tone_map_repetition_period == 0) + { + seiToneMapping->seiHasTone_mapping = FALSE; + seiToneMapping->count = 0; + } + else if (seiToneMapping->tone_map_repetition_period>1) + { + seiToneMapping->count++; + if (seiToneMapping->count>=seiToneMapping->tone_map_repetition_period) + { + seiToneMapping->seiHasTone_mapping = FALSE; + seiToneMapping->count = 0; + } + } +} +#endif + +/*! + ************************************************************************ + * \brief + * Interpret the post filter hints SEI message (JVT-U035) + * \param payload + * a pointer that point to the sei payload + * \param size + * the size of the sei message + * \param p_Vid + * the image pointer + * + ************************************************************************ + */ +void interpret_post_filter_hints_info( byte* payload, int size, VideoParameters *p_Vid ) +{ + Bitstream* buf; + unsigned int filter_hint_size_y, filter_hint_size_x, filter_hint_type, color_component, cx, cy, additional_extension_flag; + int ***filter_hint; + + buf = malloc(sizeof(Bitstream)); + buf->bitstream_length = size; + buf->streamBuffer = payload; + buf->frame_bitoffset = 0; + + p_Dec->UsedBits = 0; + + filter_hint_size_y = read_ue_v("SEI: filter_hint_size_y", buf, &p_Dec->UsedBits); // interpret post-filter hint SEI here + filter_hint_size_x = read_ue_v("SEI: filter_hint_size_x", buf, &p_Dec->UsedBits); // interpret post-filter hint SEI here + filter_hint_type = read_u_v(2, "SEI: filter_hint_type", buf, &p_Dec->UsedBits); // interpret post-filter hint SEI here + + get_mem3Dint (&filter_hint, 3, filter_hint_size_y, filter_hint_size_x); + + for (color_component = 0; color_component < 3; color_component ++) + for (cy = 0; cy < filter_hint_size_y; cy ++) + for (cx = 0; cx < filter_hint_size_x; cx ++) + filter_hint[color_component][cy][cx] = read_se_v("SEI: filter_hint", buf, &p_Dec->UsedBits); // interpret post-filter hint SEI here + + additional_extension_flag = read_u_1("SEI: additional_extension_flag", buf, &p_Dec->UsedBits); // interpret post-filter hint SEI here + +#ifdef PRINT_POST_FILTER_HINT_INFO + printf(" Post-filter hint SEI message\n"); + printf(" post_filter_hint_size_y %d \n", filter_hint_size_y); + printf(" post_filter_hint_size_x %d \n", filter_hint_size_x); + printf(" post_filter_hint_type %d \n", filter_hint_type); + for (color_component = 0; color_component < 3; color_component ++) + for (cy = 0; cy < filter_hint_size_y; cy ++) + for (cx = 0; cx < filter_hint_size_x; cx ++) + printf(" post_filter_hint[%d][%d][%d] %d \n", color_component, cy, cx, filter_hint[color_component][cy][cx]); + + printf(" additional_extension_flag %d \n", additional_extension_flag); + +#undef PRINT_POST_FILTER_HINT_INFO +#endif + + free_mem3Dint (filter_hint); + free( buf ); +} diff --git a/ldecod/src/stream_parser.c b/ldecod/src/stream_parser.c new file mode 100644 index 0000000..8675f14 --- /dev/null +++ b/ldecod/src/stream_parser.c @@ -0,0 +1,546 @@ +/*! + ************************************************************************************* + * \file stream_parser.c + * + * \brief + * Functions for dump NALU information and simluation NAL loss + * Functions to parser the decoded h264 stream + * \date + * 29.11.2011 + * + * \version + * 1.0 + * + * \author + * Jo�o Carreira + * + ************************************************************************************* + */ + +#include "global.h" +#include "nalucommon.h" +#include "memalloc.h" +#include "mbuffer.h" + +#include "ifunctions.h" + +//! NAL unit structure + +typedef struct nalu_parser_t +{ + int need_parse; + int *lost_nalu; + int n_NALU; +#if (MVC_EXTENSION_ENABLE) + int view_id; + int frame_no[MAX_VIEW_NUM]; +#endif + FILE *p_FileDumpNAL; + +} NALU_PARSER_t; + +/*! + ************************************************************************ + * \brief + * Alloc NALU Parser + * @return: 0 if no errors + ************************************************************************ + */ +void init_parse_nalu( VideoParameters *p_Vid) +{ + NALU_PARSER_t *p_NAlParser; + + if( (p_NAlParser = (NALU_PARSER_t*) calloc( 1, sizeof(NALU_PARSER_t))) == NULL ) + no_mem_exit( "alloc_video_params: p_Vid->p_ParserNAL"); + + memset( p_NAlParser, 0, sizeof(NALU_PARSER_t)); + + p_NAlParser->n_NALU = 0; + p_NAlParser->need_parse = 1; + + p_NAlParser->p_FileDumpNAL = NULL; + if( p_Vid->p_Inp->dump_nalu ) + { + char FileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + strcpy( chBuf, p_Vid->p_Inp->infile); + pch = strrchr( chBuf, '.'); + if( pch ) + *pch = '\0'; + if( strcmp( "nul", chBuf) ) + { + sprintf( FileName, "%s_NALUDebug.txt", chBuf); + p_NAlParser->p_FileDumpNAL = fopen( FileName, "w"); + } + } + if( p_NAlParser->p_FileDumpNAL ) + { + fprintf( p_NAlParser->p_FileDumpNAL, " Number | Type | Length |\n"); + fflush( p_NAlParser->p_FileDumpNAL); + } + + if( p_NAlParser->lost_nalu == 0 ) // frst time + { + int i = 0, str_len = strlen( p_Vid->p_Inp->drop_nalu); + int n_num = 0; + char *p_cur_init, *p_cur_end; + + if( str_len ) + { + p_NAlParser->lost_nalu = (int *) malloc( str_len * sizeof(int)); + /* Parser the vector with Losted NALU */ + p_cur_end = p_cur_init = p_Vid->p_Inp->drop_nalu; + while( i < str_len ) + { + if( *p_cur_end == '_' ) + { + *p_cur_end = '\0'; + p_NAlParser->lost_nalu[n_num] = atoi( p_cur_init); + p_cur_init = p_cur_end = p_cur_end + 1; + + n_num++; + } + p_cur_end++; + i++; + } + + *p_cur_end = '\0'; + p_NAlParser->lost_nalu[n_num] = atoi( p_cur_init); + p_cur_init = p_cur_end = p_cur_end + 1; + n_num++; + p_NAlParser->lost_nalu[n_num] = -1; + n_num++; + p_NAlParser->lost_nalu = (int *) realloc( p_NAlParser->lost_nalu, n_num * sizeof(int)); + } + } + + p_Vid->p_ParserNAL = p_NAlParser; + return; +} + +/*! + ************************************************************************ + * \brief + * Free NALU Parser + * @return: void + ************************************************************************ + */ +void free_parse_nalu( VideoParameters *p_Vid) +{ + NALU_PARSER_t *p_NAlParser = (NALU_PARSER_t *) p_Vid->p_ParserNAL; + + if( p_NAlParser->p_FileDumpNAL ) + { + fclose( p_NAlParser->p_FileDumpNAL); + } + + free( p_NAlParser->lost_nalu); + free( p_NAlParser); +} + +static int check_nal( int *lost_nalu, int n_nalu) +{ + + do + { + if( *lost_nalu == n_nalu ) + if( *(lost_nalu + 1) == -1 ) + return -1; + else + return 0; + lost_nalu++; + } while( *lost_nalu != -1 ); + return 1; +} + +/*! + ************************************************************************ + * \brief + * Return the status of current NALU + * Dump to a file the found NALU + * @return: 1 for error free and 0 for an erroneous NALU + ************************************************************************ + */ +int parse_nalu( VideoParameters *p_Vid, NALU_t *nalu) +{ + NALU_PARSER_t *p_NAlParser = (NALU_PARSER_t *) p_Vid->p_ParserNAL; + int iRet = 1; + int view_id = 0; + if( p_NAlParser->p_FileDumpNAL ) + { + +#if( MVC_EXTENSION_ENABLE ) + if( nalu->nal_unit_type == 5 || nalu->nal_unit_type == 1 ) + { + p_NAlParser->frame_no[0]++; + view_id = 0; + } + else if( nalu->nal_unit_type == 20 ) + { + //p_NAlParser->frame_no[nalu->view_id]++; + //view_id = 1; + } + fprintf( p_NAlParser->p_FileDumpNAL, " %3d | %2d | %5d | %5d |\n", p_NAlParser->n_NALU, nalu->nal_unit_type, nalu->len, + p_NAlParser->frame_no[view_id]); + +#else + fprintf(p_NAlParser->p_FileDumpNAL, " %3d | %2d | %5d | %5d |\n", p_NAlParser->n_NALU, nalu->nal_unit_type, nalu->len, 0 ); +#endif + fflush( p_NAlParser->p_FileDumpNAL); + } + + if( p_NAlParser->need_parse && p_NAlParser->lost_nalu ) + { + if( (iRet = check_nal( p_NAlParser->lost_nalu, p_NAlParser->n_NALU)) <= 0 ) + { + if( iRet == -1 ) + p_NAlParser->need_parse = 0; + + printf( "[NALU Parser] Lost NAL Unit: %d\n", p_NAlParser->n_NALU); + iRet = 0; + } + else + { + iRet = 1; + } + } + + p_NAlParser->n_NALU++; + + return iRet; +} + +/*! + ************************************************************************ + * \brief + * Prediction Parser + ************************************************************************ + */ + +typedef struct prediction_parser_t +{ + FILE *p_File[MAX_VIEW_NUM]; + +} PREDICTION_PARSER; + +void init_prediction_parser( VideoParameters *p_Vid) +{ + PREDICTION_PARSER *PredParser; + char FileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + + p_Vid->p_PredictionParser = NULL; + + if( p_Vid->p_Inp->PredictionParser ) + { + + p_Vid->p_PredictionParser = malloc( sizeof(PREDICTION_PARSER)); + memset( p_Vid->p_PredictionParser, 0, sizeof(PREDICTION_PARSER)); + PredParser = (PREDICTION_PARSER *) p_Vid->p_PredictionParser; + + strcpy( chBuf, p_Vid->p_Inp->infile); + pch = strrchr( chBuf, '.'); + if( pch ) + *pch = '\0'; + if( strcmp( "nul", chBuf) ) + { + sprintf( FileName, "%s_ViewID00_PredictionParser.txt", chBuf); + PredParser->p_File[0] = fopen( FileName, "w"); + sprintf( FileName, "%s_ViewID01_PredictionParser.txt", chBuf); + PredParser->p_File[1] = fopen( FileName, "w"); + } + } +} +void free_prediction_parser( VideoParameters *p_Vid) +{ + int i; + PREDICTION_PARSER *PredParser = (PREDICTION_PARSER *) p_Vid->p_PredictionParser; + + if( PredParser != NULL ) + { + + for( i = 0; i < MAX_VIEW_NUM; i++ ) + { + if( PredParser->p_File[i] ) + fclose( PredParser->p_File[i]); + } + free( PredParser); + } +} +void parse_prediction( VideoParameters *p_Vid, Slice *CurrSlice, StorablePicture *CurrPic) +{ + PREDICTION_PARSER *PredParser = (PREDICTION_PARSER *) p_Vid->p_PredictionParser; + FILE *pFile = PredParser->p_File[CurrPic->view_id]; + int FrameNo = CurrPic->frame_no; + int yBlock4x4, xBlock4x4; + int mb_width = CurrPic->PicWidthInMbs; + int mb_height = (CurrPic->PicSizeInMbs) / (CurrPic->PicWidthInMbs); + short mv_x, mv_y; + //Count variables + int countInterView[2] = + { 0, 0 }, countIntraView[2] = + { 0, 0 }, countIntraFrame = + { 0 }, countSkipBlocks = 0, countBiPred = 0; + unsigned int sum_mv_temporal_one = 0, sum_mv_temporal = 0; + + for( yBlock4x4 = 0; yBlock4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; yBlock4x4++ ) + { + for( xBlock4x4 = 0; xBlock4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; xBlock4x4++ ) + { + // get position + int yPel = yBlock4x4 * BLOCK_SIZE; + int xPel = xBlock4x4 * BLOCK_SIZE; + // get block 8x8 cordinates within a MB + int idx_8x8 = (xPel % MB_BLOCK_SIZE) / SMB_BLOCK_SIZE + 2 * ((yPel % MB_BLOCK_SIZE) / SMB_BLOCK_SIZE); + //get references idx + char ref_idx_l0 = CurrPic->mv_info[yBlock4x4][xBlock4x4].ref_idx[LIST_0]; + char ref_idx_l1 = CurrPic->mv_info[yBlock4x4][xBlock4x4].ref_idx[LIST_1]; + + int idx_mb = (yPel / MB_BLOCK_SIZE) * mb_width + (xPel / MB_BLOCK_SIZE); + Macroblock *currMB = &(p_Vid->mb_data[idx_mb]); + + // Check References + if( ref_idx_l0 < 0 && ref_idx_l1 < 0 ) + { + countIntraFrame++; + } + else + { + + if( ref_idx_l0 >= 0 ) + { // LIST_0 + if( CurrSlice->view_id != CurrSlice->listX[LIST_0][ref_idx_l0]->view_id ) + { + countInterView[LIST_0]++; + } + else + { + countIntraView[LIST_0]++; + mv_x = CurrPic->mv_info[yBlock4x4][xBlock4x4].mv[LIST_0].mv_x; + mv_y = CurrPic->mv_info[yBlock4x4][xBlock4x4].mv[LIST_0].mv_y; + if( mv_x / 4 > 0 || mv_y / 4 > 0 ) + sum_mv_temporal_one++; + sum_mv_temporal++; + } + } + if( ref_idx_l1 >= 0 ) + { // LIST_1 + if( CurrSlice->view_id != CurrSlice->listX[LIST_0][ref_idx_l1]->view_id ) + { + countInterView[LIST_1]++; + } + else + { + countIntraView[LIST_1]++; + mv_x = CurrPic->mv_info[yBlock4x4][xBlock4x4].mv[LIST_0].mv_x; + mv_y = CurrPic->mv_info[yBlock4x4][xBlock4x4].mv[LIST_0].mv_y; + if( abs_ivec( mv_x / 4, mv_y / 4) > 0 ) + sum_mv_temporal_one++; + sum_mv_temporal++; + } + } + if( ref_idx_l0 >= 0 && ref_idx_l1 >= 0 ) + countBiPred++; + } + + } + } + + // Dump to file + fprintf( pFile, "%4d;%8d;%8d;%8d;%8d;%8d;%8d\n", FrameNo, countIntraFrame, countIntraView[LIST_0], countIntraView[LIST_1], countInterView[LIST_0], + countInterView[LIST_1], sum_mv_temporal_one); +} + +void parse_mv_prediction( VideoParameters *p_Vid, Slice *pCurrSlice, StorablePicture *pDecPic) +{ + + //Count variables + int countInterView[2] = + { 0, 0 }, countIntraView[2] = + { 0, 0 }, countIntraFrame = + { 0 }, countSkipBlocks = 0, countBiPred = 0; + + // if( pCurrSlice->view_id == 0) + //return; + + if( pDecPic->slice_type == I_SLICE ) + return; + + { + int yBlock4x4, xBlock4x4; + int mb_width = pDecPic->PicWidthInMbs; + int mb_height = (pDecPic->PicSizeInMbs) / (pDecPic->PicWidthInMbs); + + for( yBlock4x4 = 0; yBlock4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; yBlock4x4++ ) + { + for( xBlock4x4 = 0; xBlock4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; xBlock4x4++ ) + { + // get position + int yPel = yBlock4x4 * BLOCK_SIZE; + int xPel = xBlock4x4 * BLOCK_SIZE; + // get block 8x8 cordinates within a MB + int idx_8x8 = (xPel % MB_BLOCK_SIZE) / SMB_BLOCK_SIZE + 2 * ((yPel % MB_BLOCK_SIZE) / SMB_BLOCK_SIZE); + //get references idx + char ref_idx_l0 = pDecPic->mv_info[yBlock4x4][xBlock4x4].ref_idx[LIST_0]; + char ref_idx_l1 = pDecPic->mv_info[yBlock4x4][xBlock4x4].ref_idx[LIST_1]; + + int idx_mb = (yPel / MB_BLOCK_SIZE) * mb_width + (xPel / MB_BLOCK_SIZE); + Macroblock *currMB = &(p_Vid->mb_data[idx_mb]); + + // Check References + if( ref_idx_l0 < 0 && ref_idx_l1 < 0 ) + { + countIntraFrame++; + } + else + { + if( ref_idx_l0 >= 0 ) + { // LIST_0 + if( pCurrSlice->view_id != pCurrSlice->listX[LIST_0][ref_idx_l0]->view_id ) + countInterView[LIST_0]++; + else + countIntraView[LIST_0]++; + } + if( ref_idx_l1 >= 0 ) + { // LIST_1 + if( pCurrSlice->view_id != pCurrSlice->listX[LIST_1][ref_idx_l1]->view_id ) + countInterView[LIST_1]++; + else + countIntraView[LIST_1]++; + } + if( ref_idx_l0 >= 0 && ref_idx_l1 >= 0 ) + countBiPred++; + + } + + /* switch( currMB->b8mode[idx_8x8] ) + { + case PSKIP: + countSkipBlocks++; + break; + }*/ + } + } + } + // Verbose + //printf("== Debugging Tool == frame of view %d\n", pDecPic->view_id); + printf( "[Stream Parser] Pred: IntraFrame %d | Intraview %d + %d | Interview %d + %d\n", countIntraFrame, countIntraView[LIST_0], countIntraView[LIST_1], + countInterView[LIST_0], countInterView[LIST_1]); + printf( "[Stream Parser] Number of Bi Pred Blocks: %d \n", countBiPred); + printf( "[Stream Parser] Number of SKIP Blocks: %d \n", p_Vid->n_SKIP); + +} + +void parse_mv_values( VideoParameters *p_Vid, Slice *pCurrSlice, StorablePicture *p_Pic, int ReportToFile) +{ + int yBlock4x4, xBlock4x4, iList; + int mb_width = p_Pic->PicWidthInMbs; + int mb_height = (p_Pic->PicSizeInMbs) / (p_Pic->PicWidthInMbs); + + double sum_mv_temporal_one = 0, sum_mv_temporal_one_total = 0; + double sum_mv_temporal = 0, mv_average_temporal = 0, mv_abs; + double sum_mv_spatial = 0, mv_average_spatial = 0; + unsigned int n_elem_temp = 0, n_elem_spatial = 0; + double sum_intra_blocks = 0; + int mv_x, mv_y, mv_ref; + int scale_factor; + FILE *pReportFile = NULL, *pReportFile_Disp = NULL, *pReportFile_Temp = NULL; + char out_ViewFileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + int FinalList = LIST_0; + + p_Vid->NoZeroMVsCount = 0; + + if( p_Pic->slice_type == I_SLICE ) + return; + + //if( ReportToFile ) + //{ + // strcpy( chBuf , p_Vid->p_Inp->outfile ); + // pch = strrchr( chBuf , '.' ); + // if(pch) + // *pch = '\0'; + // if( !strcmp("nul", chBuf) ) + // return; + // sprintf(out_ViewFileName, "%s-Motion4x4Report_ViewId%02d.txt", chBuf, p_Pic->view_id); + // pReportFile = fopen( out_ViewFileName , "wt" ); + // if( !pReportFile ) + // return; + //} + if( ReportToFile ) + { + strcpy( chBuf, p_Vid->p_Inp->outfile); + pch = strrchr( chBuf, '.'); + if( pch ) + *pch = '\0'; + if( !strcmp( "nul", chBuf) ) + return; + sprintf( out_ViewFileName, "%s_DVs_F%d_V%02d.txt", chBuf, p_Pic->poc, p_Pic->view_id); + pReportFile_Disp = fopen( out_ViewFileName, "wt"); + sprintf( out_ViewFileName, "%s_MVs_F%d_V%02d.txt", chBuf, p_Pic->poc, p_Pic->view_id); + pReportFile_Temp = fopen( out_ViewFileName, "wt"); + } + + FinalList = pCurrSlice->slice_type == B_SLICE ? LIST_1 : LIST_0; + + for( iList = LIST_0; iList <= FinalList; iList++ ) + { + for( yBlock4x4 = 0; yBlock4x4 < mb_height * MB_BLOCK_SIZE / BLOCK_SIZE; yBlock4x4++ ) + { + for( xBlock4x4 = 0; xBlock4x4 < mb_width * MB_BLOCK_SIZE / BLOCK_SIZE; xBlock4x4++ ) + { + mv_x = p_Pic->mv_info[yBlock4x4][xBlock4x4].mv[iList].mv_x; + mv_y = p_Pic->mv_info[yBlock4x4][xBlock4x4].mv[iList].mv_y; + mv_ref = p_Pic->mv_info[yBlock4x4][xBlock4x4].ref_idx[iList]; + + if( mv_ref >= 0 ) + { // Valid motion vector + scale_factor = iabs( p_Pic->poc - pCurrSlice->listX[iList][mv_ref]->poc); + if( scale_factor ) + { + mv_abs = (abs_ivec( mv_x, mv_y) / scale_factor); + if( mv_x / 4 > 0 || mv_y / 4 > 0 ) + sum_mv_temporal_one++; + sum_mv_temporal_one_total++; + sum_mv_temporal += mv_abs; + n_elem_temp++; + if( pReportFile_Temp ) + fprintf( pReportFile_Temp, "%d;%d;%d;%d;\n", xBlock4x4, yBlock4x4, mv_x, mv_y); + } + else + { + mv_abs = abs_ivec( mv_x, mv_y); + sum_mv_spatial += mv_abs; + n_elem_spatial++; + if( pReportFile_Disp ) + fprintf( pReportFile_Disp, "%d;%d;%d;%d;\n", xBlock4x4, yBlock4x4, mv_x, mv_y); + } + } + else + { + sum_intra_blocks++; + } + } + } + } + + if( pReportFile ) + fclose( pReportFile); + if( pReportFile_Temp ) + fclose( pReportFile_Temp); + if( pReportFile_Disp ) + fclose( pReportFile_Disp); + + sum_intra_blocks = sum_intra_blocks / ((double) (mb_width * mb_height * MB_BLOCK_SIZE / BLOCK_SIZE * MB_BLOCK_SIZE / BLOCK_SIZE)); + + mv_average_temporal = n_elem_temp ? (sum_mv_temporal / n_elem_temp / 4) : 0; + mv_average_spatial = n_elem_spatial ? (sum_mv_spatial / n_elem_spatial / 4) : 0; + + // Verbose + //printf("== Debugging Tool == Frame of view %d\n", p_Pic->view_id); + + printf( "[Stream Parser] Motion Vectors values - Temporal: %2.4f \\ Spatial: %2.4f\n", mv_average_temporal, mv_average_spatial); + printf( "[Stream Parser] INTRA blocks: %2.4f\n", sum_intra_blocks); + printf( "[Stream Parser] Motion Vectors greater that one: %f\n", sum_mv_temporal_one / sum_mv_temporal_one_total); + + p_Vid->NoZeroMVsCount = sum_mv_temporal_one * 100 / sum_mv_temporal_one_total; + p_Vid->IntraBlocks = sum_intra_blocks * 100; + return; +} diff --git a/ldecod/src/transcode_dec.c b/ldecod/src/transcode_dec.c new file mode 100644 index 0000000..47f9aad --- /dev/null +++ b/ldecod/src/transcode_dec.c @@ -0,0 +1,104 @@ +/*! +************************************************************************ +* \file transcode_dec.c +* +* \brief +* Functions to save transcoding information in the decoder +* +* \author +* - João Carreira +* +************************************************************************ +*/ + +#include "transcode_dec.h" +#include "transcode_common.h" +#include "memalloc.h" + +typedef struct trans_t +{ + int p_fileout[MAX_VIEW_NUM]; + +} TRANS_DEC_T; + +void initTranscodeModule( VideoParameters *p_Vid ) +{ + TRANS_DEC_T *TranscodeModule = NULL; + InputParameters *p_Inp = p_Vid->p_Inp; + char out_ViewFileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + int view_id, number_of_views; + + if ( ( TranscodeModule = (TRANS_DEC_T*)calloc(1, sizeof(TRANS_DEC_T)) ) == NULL ) + no_mem_exit("alloc_video_params: p_Vid->p_Transcode"); + + memset(TranscodeModule,0,sizeof(TRANS_DEC_T)); + + memset(TranscodeModule->p_fileout,-1,MAX_VIEW_NUM*sizeof(int)); + + if( p_Vid->p_Inp->DecodeAllLayers && p_Vid->active_subset_sps) + number_of_views = p_Vid->active_subset_sps->num_views_minus1+1; + else + number_of_views = 1; + + for(view_id=0; view_idp_Inp->TranscodeFile, "\"\"")!=0) && (strlen(p_Vid->p_Inp->TranscodeFile)>0)) + { + strcpy(chBuf, p_Vid->p_Inp->TranscodeFile); + pch = strrchr(chBuf, '.'); + if(pch) + *pch = '\0'; + if (strcmp("nul", chBuf)) + { + sprintf(out_ViewFileName, "%s_ViewId%02d.dat", chBuf, view_id); + + if ((TranscodeModule->p_fileout[view_id]=open(out_ViewFileName, OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", out_ViewFileName); + error(errortext,500); + } + } + } + } + + p_Vid->p_Transcode = TranscodeModule; +} + +void closeTranscodeModule( VideoParameters *p_Vid ) +{ + TRANS_DEC_T *TranscodeModule = (TRANS_DEC_T *) p_Vid->p_Transcode; + int i; + for(i=0; ip_fileout[i] != -1 ) + { + close( TranscodeModule->p_fileout[i] ); + } + } + + free(TranscodeModule); + p_Vid->p_Transcode = NULL; + +} + + +void saveTranscodingInfo( VideoParameters *p_Vid, StorablePicture *p_Decoded ) +{ + TRANS_DEC_T *TranscodeModule = (TRANS_DEC_T *) p_Vid->p_Transcode; + TRANS_FRAME_NODE_T node; + int pfile = TranscodeModule->p_fileout[p_Decoded->view_id]; + + if( p_Decoded->idr_flag ) + return; + + if( pfile >= 0 ) + { + node.frame_height = p_Decoded->size_y; + node.frame_width = p_Decoded->size_x; + node.poc = p_Decoded->poc; + node.view_id = p_Decoded->view_id; + node.pp_mv_info = p_Decoded->mv_info; + + write_trans_node( pfile, node); + } +} \ No newline at end of file diff --git a/ldecod/src/transform8x8.c b/ldecod/src/transform8x8.c new file mode 100644 index 0000000..3d7964b --- /dev/null +++ b/ldecod/src/transform8x8.c @@ -0,0 +1,115 @@ + +/*! + *************************************************************************** + * \file transform8x8.c + * + * \brief + * 8x8 transform functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * + * \date + * 12. October 2003 + ************************************************************************** + */ + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "elements.h" +#include "transform8x8.h" +#include "transform.h" +#include "quant.h" + +static void recon8x8(int **m7, imgpel **mb_rec, imgpel **mpr, int max_imgpel_value, int ioff) +{ + int j; + int *m_tr = NULL; + imgpel *m_rec = NULL; + imgpel *m_prd = NULL; + + for( j = 0; j < 8; j++) + { + m_tr = (*m7++) + ioff; + m_rec = (*mb_rec++) + ioff; + m_prd = (*mpr++) + ioff; + + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec++ = (imgpel) iClip1(max_imgpel_value, (*m_prd++) + rshift_rnd_sf(*m_tr++, DQ_BITS_8)); + *m_rec = (imgpel) iClip1(max_imgpel_value, (*m_prd ) + rshift_rnd_sf(*m_tr , DQ_BITS_8)); + } +} + +static void copy8x8(imgpel **mb_rec, imgpel **mpr, int ioff) +{ + int j; + + for( j = 0; j < 8; j++) + { + memcpy((*mb_rec++) + ioff, (*mpr++) + ioff, 8 * sizeof(imgpel)); + } +} + +static void recon8x8_lossless(int **m7, imgpel **mb_rec, imgpel **mpr, int max_imgpel_value, int ioff) +{ + int i, j; + for( j = 0; j < 8; j++) + { + for( i = ioff; i < ioff + 8; i++) + (*mb_rec)[i] = (imgpel) iClip1(max_imgpel_value, ((*m7)[i] + (long)(*mpr)[i])); + mb_rec++; + m7++; + mpr++; + } +} + +/*! + *********************************************************************** + * \brief + * Inverse 8x8 transformation + *********************************************************************** + */ +void itrans8x8(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< used color plane + int ioff, //!< index to 4x4 block + int joff) //!< index to 4x4 block +{ + Slice *currSlice = currMB->p_Slice; + + int **m7 = currSlice->mb_rres[pl]; + + if (currMB->is_lossless == TRUE) + { + recon8x8_lossless(&m7[joff], &currSlice->mb_rec[pl][joff], &currSlice->mb_pred[pl][joff], currMB->p_Vid->max_pel_value_comp[pl], ioff); + } + else + { + inverse8x8(&m7[joff], &m7[joff], ioff); + recon8x8 (&m7[joff], &currSlice->mb_rec[pl][joff], &currSlice->mb_pred[pl][joff], currMB->p_Vid->max_pel_value_comp[pl], ioff); + } +} + +/*! + *********************************************************************** + * \brief + * Inverse 8x8 transformation + *********************************************************************** + */ +void icopy8x8(Macroblock *currMB, //!< current macroblock + ColorPlane pl, //!< used color plane + int ioff, //!< index to 4x4 block + int joff) //!< index to 4x4 block +{ + Slice *currSlice = currMB->p_Slice; + + copy8x8 (&currSlice->mb_rec[pl][joff], &currSlice->mb_pred[pl][joff], ioff); +} diff --git a/ldecod/src/vlc.c b/ldecod/src/vlc.c new file mode 100644 index 0000000..789de49 --- /dev/null +++ b/ldecod/src/vlc.c @@ -0,0 +1,1289 @@ +/*! + ************************************************************************ + * \file vlc.c + * + * \brief + * VLC support functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langøy + * - Detlev Marpe + * - Gabi Blaettermann + ************************************************************************ + */ +#include "contributors.h" + +#include "global.h" +#include "vlc.h" +#include "elements.h" + + +// A little trick to avoid those horrible #if TRACE all over the source code +#if TRACE +#define SYMTRACESTRING(s) strncpy(symbol.tracestring,s,TRACESTRING_SIZE) +#else +#define SYMTRACESTRING(s) // do nothing +#endif + +// Note that all NA values are filled with 0 + +/*! + ************************************************************************************* + * \brief + * read_ue_v, reads an ue(v) syntax element, the length in bits is stored in + * the global p_Dec->UsedBits variable + * + * \param tracestring + * the string for the trace file + * + * \param bitstream + * the stream to be read from + * + * \return + * the value of the coded syntax element + * + ************************************************************************************* + */ +int read_ue_v (char *tracestring, Bitstream *bitstream, int *used_bits) +{ + SyntaxElement symbol; + + //assert (bitstream->streamBuffer != NULL); + symbol.type = SE_HEADER; + symbol.mapping = linfo_ue; // Mapping rule + SYMTRACESTRING(tracestring); + readSyntaxElement_VLC (&symbol, bitstream); + *used_bits+=symbol.len; + return symbol.value1; +} + + +/*! + ************************************************************************************* + * \brief + * read_ue_v, reads an se(v) syntax element, the length in bits is stored in + * the global p_Dec->UsedBits variable + * + * \param tracestring + * the string for the trace file + * + * \param bitstream + * the stream to be read from + * + * \return + * the value of the coded syntax element + * + ************************************************************************************* + */ +int read_se_v (char *tracestring, Bitstream *bitstream, int *used_bits) +{ + SyntaxElement symbol; + + //assert (bitstream->streamBuffer != NULL); + symbol.type = SE_HEADER; + symbol.mapping = linfo_se; // Mapping rule: signed integer + SYMTRACESTRING(tracestring); + readSyntaxElement_VLC (&symbol, bitstream); + *used_bits+=symbol.len; + return symbol.value1; +} + + +/*! + ************************************************************************************* + * \brief + * read_ue_v, reads an u(v) syntax element, the length in bits is stored in + * the global p_Dec->UsedBits variable + * + * \param LenInBits + * length of the syntax element + * + * \param tracestring + * the string for the trace file + * + * \param bitstream + * the stream to be read from + * + * \return + * the value of the coded syntax element + * + ************************************************************************************* + */ +int read_u_v (int LenInBits, char*tracestring, Bitstream *bitstream, int *used_bits) +{ + SyntaxElement symbol; + symbol.inf = 0; + + //assert (bitstream->streamBuffer != NULL); + symbol.type = SE_HEADER; + symbol.mapping = linfo_ue; // Mapping rule + symbol.len = LenInBits; + SYMTRACESTRING(tracestring); + readSyntaxElement_FLC (&symbol, bitstream); + *used_bits+=symbol.len; + + return symbol.inf; +} + +/*! + ************************************************************************************* + * \brief + * read_i_v, reads an i(v) syntax element, the length in bits is stored in + * the global p_Dec->UsedBits variable + * + * \param LenInBits + * length of the syntax element + * + * \param tracestring + * the string for the trace file + * + * \param bitstream + * the stream to be read from + * + * \return + * the value of the coded syntax element + * + ************************************************************************************* + */ +int read_i_v (int LenInBits, char*tracestring, Bitstream *bitstream, int *used_bits) +{ + SyntaxElement symbol; + symbol.inf = 0; + + //assert (bitstream->streamBuffer != NULL); + symbol.type = SE_HEADER; + symbol.mapping = linfo_ue; // Mapping rule + symbol.len = LenInBits; + SYMTRACESTRING(tracestring); + readSyntaxElement_FLC (&symbol, bitstream); + *used_bits+=symbol.len; + + // can be negative + symbol.inf = -( symbol.inf & (1 << (LenInBits - 1)) ) | symbol.inf; + + return symbol.inf; +} + + +/*! + ************************************************************************************* + * \brief + * read_ue_v, reads an u(1) syntax element, the length in bits is stored in + * the global p_Dec->UsedBits variable + * + * \param tracestring + * the string for the trace file + * + * \param bitstream + * the stream to be read from + * + * \return + * the value of the coded syntax element + * + ************************************************************************************* + */ +Boolean read_u_1 (char *tracestring, Bitstream *bitstream, int *used_bits) +{ + return (Boolean) read_u_v (1, tracestring, bitstream, used_bits); +} + + + +/*! + ************************************************************************ + * \brief + * mapping rule for ue(v) syntax elements + * \par Input: + * lenght and info + * \par Output: + * number in the code table + ************************************************************************ + */ +void linfo_ue(int len, int info, int *value1, int *dummy) +{ + //assert ((len >> 1) < 32); + *value1 = (int) (((unsigned int) 1 << (len >> 1)) + (unsigned int) (info) - 1); +} + +/*! + ************************************************************************ + * \brief + * mapping rule for se(v) syntax elements + * \par Input: + * lenght and info + * \par Output: + * signed mvd + ************************************************************************ + */ +void linfo_se(int len, int info, int *value1, int *dummy) +{ + //assert ((len >> 1) < 32); + unsigned int n = ((unsigned int) 1 << (len >> 1)) + (unsigned int) info - 1; + *value1 = (n + 1) >> 1; + if((n & 0x01) == 0) // lsb is signed bit + *value1 = -*value1; +} + + +/*! + ************************************************************************ + * \par Input: + * length and info + * \par Output: + * cbp (intra) + ************************************************************************ + */ +void linfo_cbp_intra_normal(int len,int info,int *cbp, int *dummy) +{ + int cbp_idx; + + linfo_ue(len, info, &cbp_idx, dummy); + *cbp=NCBP[1][cbp_idx][0]; +} + + +/*! + ************************************************************************ + * \par Input: + * length and info + * \par Output: + * cbp (intra) + ************************************************************************ + */ +void linfo_cbp_intra_other(int len,int info,int *cbp, int *dummy) +{ + int cbp_idx; + + linfo_ue(len, info, &cbp_idx, dummy); + *cbp=NCBP[0][cbp_idx][0]; +} + +/*! + ************************************************************************ + * \par Input: + * length and info + * \par Output: + * cbp (inter) + ************************************************************************ + */ +void linfo_cbp_inter_normal(int len,int info,int *cbp, int *dummy) +{ + int cbp_idx; + + linfo_ue(len, info, &cbp_idx, dummy); + *cbp=NCBP[1][cbp_idx][1]; +} + +/*! + ************************************************************************ + * \par Input: + * length and info + * \par Output: + * cbp (inter) + ************************************************************************ + */ +void linfo_cbp_inter_other(int len,int info,int *cbp, int *dummy) +{ + int cbp_idx; + + linfo_ue(len, info, &cbp_idx, dummy); + *cbp=NCBP[0][cbp_idx][1]; +} + +/*! + ************************************************************************ + * \par Input: + * length and info + * \par Output: + * level, run + ************************************************************************ + */ +void linfo_levrun_inter(int len, int info, int *level, int *irun) +{ + //assert (((len >> 1) - 5) < 32); + + if (len <= 9) + { + int l2 = imax(0,(len >> 1)-1); + int inf = info >> 1; + + *level = NTAB1[l2][inf][0]; + *irun = NTAB1[l2][inf][1]; + if ((info & 0x01) == 1) + *level = -*level; // make sign + } + else // if len > 9, skip using the array + { + *irun = (info & 0x1e) >> 1; + *level = LEVRUN1[*irun] + (info >> 5) + ( 1 << ((len >> 1) - 5)); + if ((info & 0x01) == 1) + *level = -*level; + } + + if (len == 1) // EOB + *level = 0; +} + + +/*! + ************************************************************************ + * \par Input: + * length and info + * \par Output: + * level, run + ************************************************************************ + */ +void linfo_levrun_c2x2(int len, int info, int *level, int *irun) +{ + if (len<=5) + { + int l2 = imax(0, (len >> 1) - 1); + int inf = info >> 1; + *level = NTAB3[l2][inf][0]; + *irun = NTAB3[l2][inf][1]; + if ((info & 0x01) == 1) + *level = -*level; // make sign + } + else // if len > 5, skip using the array + { + *irun = (info & 0x06) >> 1; + *level = LEVRUN3[*irun] + (info >> 3) + (1 << ((len >> 1) - 3)); + if ((info & 0x01) == 1) + *level = -*level; + } + + if (len == 1) // EOB + *level = 0; +} + +/*! + ************************************************************************ + * \brief + * read next UVLC codeword from UVLC-partition and + * map it to the corresponding syntax element + ************************************************************************ + */ +int readSyntaxElement_VLC(SyntaxElement *sym, Bitstream *currStream) +{ + + sym->len = GetVLCSymbol (currStream->streamBuffer, currStream->frame_bitoffset, &(sym->inf), currStream->bitstream_length); + if (sym->len == -1) + return -1; + + currStream->frame_bitoffset += sym->len; + sym->mapping(sym->len, sym->inf, &(sym->value1), &(sym->value2)); + +#if TRACE + tracebits(sym->tracestring, sym->len, sym->inf, sym->value1); +#endif + + return 1; +} + + +/*! + ************************************************************************ + * \brief + * read next UVLC codeword from UVLC-partition and + * map it to the corresponding syntax element + ************************************************************************ + */ +int readSyntaxElement_UVLC(Macroblock *currMB, SyntaxElement *sym, struct datapartition_dec *dP) +{ + return (readSyntaxElement_VLC(sym, dP->bitstream)); +} + +/*! + ************************************************************************ + * \brief + * read next VLC codeword for 4x4 Intra Prediction Mode and + * map it to the corresponding Intra Prediction Direction + ************************************************************************ + */ +int readSyntaxElement_Intra4x4PredictionMode(SyntaxElement *sym, Bitstream *currStream) +{ + sym->len = GetVLCSymbol_IntraMode (currStream->streamBuffer, currStream->frame_bitoffset, &(sym->inf), currStream->bitstream_length); + + if (sym->len == -1) + return -1; + + currStream->frame_bitoffset += sym->len; + sym->value1 = (sym->len == 1) ? -1 : sym->inf; + +#if TRACE + tracebits2(sym->tracestring, sym->len, sym->value1); +#endif + + return 1; +} + +int GetVLCSymbol_IntraMode (byte buffer[],int totbitoffset,int *info, int bytecount) +{ + int byteoffset = (totbitoffset >> 3); // byte from start of buffer + int bitoffset = (7 - (totbitoffset & 0x07)); // bit from start of byte + byte *cur_byte = &(buffer[byteoffset]); + int ctr_bit = (*cur_byte & (0x01 << bitoffset)); // control bit for current bit posision + + //First bit + if (ctr_bit) + { + *info = 0; + return 1; + } + + if (byteoffset >= bytecount) + { + return -1; + } + else + { + int inf = (*(cur_byte) << 8) + *(cur_byte + 1); + inf <<= (sizeof(byte) * 8) - bitoffset; + inf = inf & 0xFFFF; + inf >>= (sizeof(byte) * 8) * 2 - 3; + + *info = inf; + return 4; // return absolute offset in bit from start of frame + } +} + + +/*! + ************************************************************************ + * \brief + * test if bit buffer contains only stop bit + * + * \param buffer + * buffer containing VLC-coded data bits + * \param totbitoffset + * bit offset from start of partition + * \param bytecount + * buffer length + * \return + * true if more bits available + ************************************************************************ + */ +int more_rbsp_data (byte buffer[],int totbitoffset,int bytecount) +{ + long byteoffset = (totbitoffset >> 3); // byte from start of buffer + // there is more until we're in the last byte + if (byteoffset < (bytecount - 1)) + return TRUE; + else + { + int bitoffset = (7 - (totbitoffset & 0x07)); // bit from start of byte + byte *cur_byte = &(buffer[byteoffset]); + // read one bit + int ctr_bit = ctr_bit = ((*cur_byte)>> (bitoffset--)) & 0x01; // control bit for current bit posision + + //assert (byteoffset=0 && !cnt) + { + cnt |= ((*cur_byte)>> (bitoffset--)) & 0x01; // set up control bit + } + + return (cnt); + } + } +} + + +/*! + ************************************************************************ + * \brief + * Check if there are symbols for the next MB + ************************************************************************ + */ +int uvlc_startcode_follows(Slice *currSlice, int dummy) +{ + byte dp_Nr = assignSE2partition[currSlice->dp_mode][SE_MBTYPE]; + DataPartition *dP = &(currSlice->partArr[dp_Nr]); + Bitstream *currStream = dP->bitstream; + byte *buf = currStream->streamBuffer; + + return (!(more_rbsp_data(buf, currStream->frame_bitoffset,currStream->bitstream_length))); +} + + + +/*! + ************************************************************************ + * \brief + * read one exp-golomb VLC symbol + * + * \param buffer + * containing VLC-coded data bits + * \param totbitoffset + * bit offset from start of partition + * \param info + * returns the value of the symbol + * \param bytecount + * buffer length + * \return + * bits read + ************************************************************************ + */ +int GetVLCSymbol (byte buffer[],int totbitoffset,int *info, int bytecount) +{ + long byteoffset = (totbitoffset >> 3); // byte from start of buffer + int bitoffset = (7 - (totbitoffset & 0x07)); // bit from start of byte + int bitcounter = 1; + int len = 0; + byte *cur_byte = &(buffer[byteoffset]); + int ctr_bit = ((*cur_byte) >> (bitoffset)) & 0x01; // control bit for current bit posision + + while (ctr_bit == 0) + { // find leading 1 bit + len++; + bitcounter++; + bitoffset--; + bitoffset &= 0x07; + cur_byte += (bitoffset == 7); + byteoffset+= (bitoffset == 7); + ctr_bit = ((*cur_byte) >> (bitoffset)) & 0x01; + } + + if (byteoffset + ((len + 7) >> 3) > bytecount) + return -1; + else + { + // make infoword + int inf = 0; // shortest possible code is 1, then info is always 0 + + while (len--) + { + bitoffset --; + bitoffset &= 0x07; + cur_byte += (bitoffset == 7); + bitcounter++; + inf <<= 1; + inf |= ((*cur_byte) >> (bitoffset)) & 0x01; + } + + *info = inf; + return bitcounter; // return absolute offset in bit from start of frame + } +} + + +/*! + ************************************************************************ + * \brief + * Reads bits from the bitstream buffer (Threshold based) + * + * \param inf + * bytes to extract numbits from with bitoffset already applied + * \param numbits + * number of bits to read + * + ************************************************************************ + */ + +//static inline int ShowBitsThres (int inf, int bitcount, int numbits) +static inline int ShowBitsThres (int inf, int numbits) +{ + return ((inf) >> ((sizeof(byte) * 24) - (numbits))); + /* + if ((numbits + 7) > bitcount) + { + return -1; + } + else + { + //Worst case scenario is that we will need to traverse 3 bytes + inf >>= (sizeof(byte)*8)*3 - numbits; + } + + return inf; //Will be a small unsigned integer so will not need any conversion when returning as int + */ +} + + +/*! + ************************************************************************ + * \brief + * code from bitstream (2d tables) + ************************************************************************ + */ + +static int code_from_bitstream_2d(SyntaxElement *sym, + Bitstream *currStream, + const byte *lentab, + const byte *codtab, + int tabwidth, + int tabheight, + int *code) +{ + int i, j; + const byte *len = &lentab[0], *cod = &codtab[0]; + + int *frame_bitoffset = &currStream->frame_bitoffset; + byte *buf = &currStream->streamBuffer[*frame_bitoffset >> 3]; + + //Apply bitoffset to three bytes (maximum that may be traversed by ShowBitsThres) + unsigned int inf = ((*buf) << 16) + (*(buf + 1) << 8) + *(buf + 2); //Even at the end of a stream we will still be pulling out of allocated memory as alloc is done by MAX_CODED_FRAME_SIZE + inf <<= (*frame_bitoffset & 0x07); //Offset is constant so apply before extracting different numbers of bits + inf &= 0xFFFFFF; //Arithmetic shift so wipe any sign which may be extended inside ShowBitsThres + + // this VLC decoding method is not optimized for speed + for (j = 0; j < tabheight; j++) + { + for (i = 0; i < tabwidth; i++) + { + if ((*len == 0) || (ShowBitsThres(inf, (int) *len) != *cod)) + { + ++len; + ++cod; + } + else + { + sym->len = *len; + *frame_bitoffset += *len; // move bitstream pointer + *code = *cod; + sym->value1 = i; + sym->value2 = j; + return 0; // found code and return + } + } + } + return -1; // failed to find code +} + + +/*! + ************************************************************************ + * \brief + * read FLC codeword from UVLC-partition + ************************************************************************ + */ +int readSyntaxElement_FLC(SyntaxElement *sym, Bitstream *currStream) +{ + int BitstreamLengthInBits = (currStream->bitstream_length << 3) + 7; + + if ((GetBits(currStream->streamBuffer, currStream->frame_bitoffset, &(sym->inf), BitstreamLengthInBits, sym->len)) < 0) + return -1; + + sym->value1 = sym->inf; + currStream->frame_bitoffset += sym->len; // move bitstream pointer + +#if TRACE + tracebits2(sym->tracestring, sym->len, sym->inf); +#endif + + return 1; +} + + + +/*! + ************************************************************************ + * \brief + * read NumCoeff/TrailingOnes codeword from UVLC-partition + ************************************************************************ + */ + +int readSyntaxElement_NumCoeffTrailingOnes(SyntaxElement *sym, + Bitstream *currStream, + char *type) +{ + int frame_bitoffset = currStream->frame_bitoffset; + int BitstreamLengthInBytes = currStream->bitstream_length; + int BitstreamLengthInBits = (BitstreamLengthInBytes << 3) + 7; + byte *buf = currStream->streamBuffer; + + static const byte lentab[3][4][17] = + { + { // 0702 + { 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16}, + { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16}, + { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16}, + { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}, + }, + { + { 2, 6, 6, 7, 8, 8, 9,11,11,12,12,12,13,13,13,14,14}, + { 0, 2, 5, 6, 6, 7, 8, 9,11,11,12,12,13,13,14,14,14}, + { 0, 0, 3, 6, 6, 7, 8, 9,11,11,12,12,13,13,13,14,14}, + { 0, 0, 0, 4, 4, 5, 6, 6, 7, 9,11,11,12,13,13,13,14}, + }, + { + { 4, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,10}, + { 0, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,10}, + { 0, 0, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10}, + { 0, 0, 0, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9,10,10,10}, + }, + }; + + static const byte codtab[3][4][17] = + { + { + { 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7,4}, + { 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10,6}, + { 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9,5}, + { 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12,8}, + }, + { + { 3,11, 7, 7, 7, 4, 7,15,11,15,11, 8,15,11, 7, 9,7}, + { 0, 2, 7,10, 6, 6, 6, 6,14,10,14,10,14,10,11, 8,6}, + { 0, 0, 3, 9, 5, 5, 5, 5,13, 9,13, 9,13, 9, 6,10,5}, + { 0, 0, 0, 5, 4, 6, 8, 4, 4, 4,12, 8,12,12, 8, 1,4}, + }, + { + {15,15,11, 8,15,11, 9, 8,15,11,15,11, 8,13, 9, 5,1}, + { 0,14,15,12,10, 8,14,10,14,14,10,14,10, 7,12, 8,4}, + { 0, 0,13,14,11, 9,13, 9,13,10,13, 9,13, 9,11, 7,3}, + { 0, 0, 0,12,11,10, 9, 8,13,12,12,12, 8,12,10, 6,2}, + }, + }; + + int retval = 0, code; + int vlcnum = sym->value1; + // vlcnum is the index of Table used to code coeff_token + // vlcnum==3 means (8<=nC) which uses 6bit FLC + + if (vlcnum == 3) + { + // read 6 bit FLC + //code = ShowBits(buf, frame_bitoffset, BitstreamLengthInBytes, 6); + code = ShowBits(buf, frame_bitoffset, BitstreamLengthInBits, 6); + currStream->frame_bitoffset += 6; + sym->value2 = (code & 3); + sym->value1 = (code >> 2); + + if (!sym->value1 && sym->value2 == 3) + { + // #c = 0, #t1 = 3 => #c = 0 + sym->value2 = 0; + } + else + sym->value1++; + + sym->len = 6; + } + else + { + //retval = code_from_bitstream_2d(sym, currStream, &lentab[vlcnum][0][0], &codtab[vlcnum][0][0], 17, 4, &code); + retval = code_from_bitstream_2d(sym, currStream, lentab[vlcnum][0], codtab[vlcnum][0], 17, 4, &code); + if (retval) + { + printf("ERROR: failed to find NumCoeff/TrailingOnes\n"); + exit(-1); + } + } + +#if TRACE + snprintf(sym->tracestring, TRACESTRING_SIZE, "%s # c & tr.1s vlc=%d #c=%d #t1=%d", + type, vlcnum, sym->value1, sym->value2); + tracebits2(sym->tracestring, sym->len, code); +#endif + + return retval; +} + + +/*! + ************************************************************************ + * \brief + * read NumCoeff/TrailingOnes codeword from UVLC-partition ChromaDC + ************************************************************************ + */ +int readSyntaxElement_NumCoeffTrailingOnesChromaDC(VideoParameters *p_Vid, SyntaxElement *sym, Bitstream *currStream) +{ + static const byte lentab[3][4][17] = + { + //YUV420 + {{ 2, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 3, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV422 + {{ 1, 7, 7, 9, 9,10,11,12,13, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 2, 7, 7, 9,10,11,12,12, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 3, 7, 7, 9,10,11,12, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 5, 6, 7, 7,10,11, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV444 + {{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16}, + { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16}, + { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16}, + { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}} + }; + + static const byte codtab[3][4][17] = + { + //YUV420 + {{ 1, 7, 4, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 6, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV422 + {{ 1,15,14, 7, 6, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1,13,12, 5, 6, 6, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 1,11,10, 4, 5, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 1, 1, 9, 8, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV444 + {{ 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7, 4}, + { 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10, 6}, + { 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9, 5}, + { 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12, 8}} + + }; + + int code; + int yuv = p_Vid->active_sps->chroma_format_idc - 1; + int retval = code_from_bitstream_2d(sym, currStream, &lentab[yuv][0][0], &codtab[yuv][0][0], 17, 4, &code); + + if (retval) + { + printf("ERROR: failed to find NumCoeff/TrailingOnes ChromaDC\n"); + exit(-1); + } + +#if TRACE + snprintf(sym->tracestring, TRACESTRING_SIZE, "ChrDC # c & tr.1s #c=%d #t1=%d", + sym->value1, sym->value2); + tracebits2(sym->tracestring, sym->len, code); + +#endif + + return retval; +} + +/*! + ************************************************************************ + * \brief + * read Level VLC0 codeword from UVLC-partition + ************************************************************************ + */ +int readSyntaxElement_Level_VLC0(SyntaxElement *sym, Bitstream *currStream) +{ + int frame_bitoffset = currStream->frame_bitoffset; + int BitstreamLengthInBytes = currStream->bitstream_length; + int BitstreamLengthInBits = (BitstreamLengthInBytes << 3) + 7; + byte *buf = currStream->streamBuffer; + int len = 1, sign = 0, level = 0, code = 1; + + while (!ShowBits(buf, frame_bitoffset++, BitstreamLengthInBits, 1)) + len++; + + if (len < 15) + { + sign = (len - 1) & 1; + level = ((len - 1) >> 1) + 1; + } + else if (len == 15) + { + // escape code + code <<= 4; + code |= ShowBits(buf, frame_bitoffset, BitstreamLengthInBits, 4); + len += 4; + frame_bitoffset += 4; + sign = (code & 0x01); + level = ((code >> 1) & 0x07) + 8; + } + else if (len >= 16) + { + // escape code + int addbit = (len - 16); + int offset = (2048 << addbit) - 2032; + len -= 4; + code = ShowBits(buf, frame_bitoffset, BitstreamLengthInBits, len); + sign = (code & 0x01); + frame_bitoffset += len; + level = (code >> 1) + offset; + + code |= (1 << (len)); // for display purpose only + len += addbit + 16; + } + + sym->inf = (sign) ? -level : level ; + sym->len = len; + +#if TRACE + tracebits2(sym->tracestring, sym->len, code); +#endif + + currStream->frame_bitoffset = frame_bitoffset; + return 0; +} + +/*! + ************************************************************************ + * \brief + * read Level VLC codeword from UVLC-partition + ************************************************************************ + */ +int readSyntaxElement_Level_VLCN(SyntaxElement *sym, int vlc, Bitstream *currStream) +{ + int frame_bitoffset = currStream->frame_bitoffset; + int BitstreamLengthInBytes = currStream->bitstream_length; + int BitstreamLengthInBits = (BitstreamLengthInBytes << 3) + 7; + byte *buf = currStream->streamBuffer; + + int levabs, sign; + int len = 1; + int code = 1, sb; + + int shift = vlc - 1; + + // read pre zeros + while (!ShowBits(buf, frame_bitoffset ++, BitstreamLengthInBits, 1)) + len++; + + frame_bitoffset -= len; + + if (len < 16) + { + levabs = ((len - 1) << shift) + 1; + + // read (vlc-1) bits -> suffix + if (shift) + { + sb = ShowBits(buf, frame_bitoffset + len, BitstreamLengthInBits, shift); + code = (code << (shift) )| sb; + levabs += sb; + len += (shift); + } + + // read 1 bit -> sign + sign = ShowBits(buf, frame_bitoffset + len, BitstreamLengthInBits, 1); + code = (code << 1)| sign; + len ++; + } + else // escape + { + int addbit = len - 5; + int offset = (1 << addbit) + (15 << shift) - 2047; + + sb = ShowBits(buf, frame_bitoffset + len, BitstreamLengthInBits, addbit); + code = (code << addbit ) | sb; + len += addbit; + + levabs = sb + offset; + + // read 1 bit -> sign + sign = ShowBits(buf, frame_bitoffset + len, BitstreamLengthInBits, 1); + + code = (code << 1)| sign; + + len++; + } + + sym->inf = (sign)? -levabs : levabs; + sym->len = len; + + currStream->frame_bitoffset = frame_bitoffset + len; + +#if TRACE + tracebits2(sym->tracestring, sym->len, code); +#endif + + return 0; +} + +/*! + ************************************************************************ + * \brief + * read Total Zeros codeword from UVLC-partition + ************************************************************************ + */ +int readSyntaxElement_TotalZeros(SyntaxElement *sym, Bitstream *currStream) +{ + static const byte lentab[TOTRUN_NUM][16] = + { + + { 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9}, + { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6}, + { 4,3,3,3,4,4,3,3,4,5,5,6,5,6}, + { 5,3,4,4,3,3,3,4,3,4,5,5,5}, + { 4,4,4,3,3,3,3,3,4,5,4,5}, + { 6,5,3,3,3,3,3,3,4,3,6}, + { 6,5,3,3,3,2,3,4,3,6}, + { 6,4,5,3,2,2,3,3,6}, + { 6,6,4,2,2,3,2,5}, + { 5,5,3,2,2,2,4}, + { 4,4,3,3,1,3}, + { 4,4,2,1,3}, + { 3,3,1,2}, + { 2,2,1}, + { 1,1}, + }; + + static const byte codtab[TOTRUN_NUM][16] = + { + {1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1}, + {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0}, + {5,7,6,5,4,3,4,3,2,3,2,1,1,0}, + {3,7,5,4,6,5,4,3,3,2,2,1,0}, + {5,4,3,7,6,5,4,3,2,1,1,0}, + {1,1,7,6,5,4,3,2,1,1,0}, + {1,1,5,4,3,3,2,1,1,0}, + {1,1,1,3,3,2,2,1,0}, + {1,0,1,3,2,1,1,1,}, + {1,0,1,3,2,1,1,}, + {0,1,1,2,1,3}, + {0,1,1,1,1}, + {0,1,1,1}, + {0,1,1}, + {0,1}, + }; + + int code; + int vlcnum = sym->value1; + int retval = code_from_bitstream_2d(sym, currStream, &lentab[vlcnum][0], &codtab[vlcnum][0], 16, 1, &code); + + if (retval) + { + printf("ERROR: failed to find Total Zeros !cdc\n"); + exit(-1); + } + +#if TRACE + tracebits2(sym->tracestring, sym->len, code); +#endif + + return retval; +} + +/*! + ************************************************************************ + * \brief + * read Total Zeros Chroma DC codeword from UVLC-partition + ************************************************************************ + */ +int readSyntaxElement_TotalZerosChromaDC(VideoParameters *p_Vid, SyntaxElement *sym, Bitstream *currStream) +{ + static const byte lentab[3][TOTRUN_NUM][16] = + { + //YUV420 + {{ 1,2,3,3}, + { 1,2,2}, + { 1,1}}, + //YUV422 + {{ 1,3,3,4,4,4,5,5}, + { 3,2,3,3,3,3,3}, + { 3,3,2,2,3,3}, + { 3,2,2,2,3}, + { 2,2,2,2}, + { 2,2,1}, + { 1,1}}, + //YUV444 + {{ 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9}, + { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6}, + { 4,3,3,3,4,4,3,3,4,5,5,6,5,6}, + { 5,3,4,4,3,3,3,4,3,4,5,5,5}, + { 4,4,4,3,3,3,3,3,4,5,4,5}, + { 6,5,3,3,3,3,3,3,4,3,6}, + { 6,5,3,3,3,2,3,4,3,6}, + { 6,4,5,3,2,2,3,3,6}, + { 6,6,4,2,2,3,2,5}, + { 5,5,3,2,2,2,4}, + { 4,4,3,3,1,3}, + { 4,4,2,1,3}, + { 3,3,1,2}, + { 2,2,1}, + { 1,1}} + }; + + static const byte codtab[3][TOTRUN_NUM][16] = + { + //YUV420 + {{ 1,1,1,0}, + { 1,1,0}, + { 1,0}}, + //YUV422 + {{ 1,2,3,2,3,1,1,0}, + { 0,1,1,4,5,6,7}, + { 0,1,1,2,6,7}, + { 6,0,1,2,7}, + { 0,1,2,3}, + { 0,1,1}, + { 0,1}}, + //YUV444 + {{1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1}, + {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0}, + {5,7,6,5,4,3,4,3,2,3,2,1,1,0}, + {3,7,5,4,6,5,4,3,3,2,2,1,0}, + {5,4,3,7,6,5,4,3,2,1,1,0}, + {1,1,7,6,5,4,3,2,1,1,0}, + {1,1,5,4,3,3,2,1,1,0}, + {1,1,1,3,3,2,2,1,0}, + {1,0,1,3,2,1,1,1,}, + {1,0,1,3,2,1,1,}, + {0,1,1,2,1,3}, + {0,1,1,1,1}, + {0,1,1,1}, + {0,1,1}, + {0,1}} + }; + + int code; + int yuv = p_Vid->active_sps->chroma_format_idc - 1; + int vlcnum = sym->value1; + int retval = code_from_bitstream_2d(sym, currStream, &lentab[yuv][vlcnum][0], &codtab[yuv][vlcnum][0], 16, 1, &code); + + if (retval) + { + printf("ERROR: failed to find Total Zeros\n"); + exit(-1); + } + +#if TRACE + tracebits2(sym->tracestring, sym->len, code); +#endif + + return retval; +} + + +/*! + ************************************************************************ + * \brief + * read Run codeword from UVLC-partition + ************************************************************************ + */ +int readSyntaxElement_Run(SyntaxElement *sym, Bitstream *currStream) +{ + static const byte lentab[TOTRUN_NUM][16] = + { + {1,1}, + {1,2,2}, + {2,2,2,2}, + {2,2,2,3,3}, + {2,2,3,3,3,3}, + {2,3,3,3,3,3,3}, + {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11}, + }; + + static const byte codtab[TOTRUN_NUM][16] = + { + {1,0}, + {1,1,0}, + {3,2,1,0}, + {3,2,1,1,0}, + {3,2,3,2,1,0}, + {3,0,1,3,2,5,4}, + {7,6,5,4,3,2,1,1,1,1,1,1,1,1,1}, + }; + int code; + int vlcnum = sym->value1; + int retval = code_from_bitstream_2d(sym, currStream, &lentab[vlcnum][0], &codtab[vlcnum][0], 16, 1, &code); + + if (retval) + { + printf("ERROR: failed to find Run\n"); + exit(-1); + } + +#if TRACE + tracebits2(sym->tracestring, sym->len, code); +#endif + + return retval; +} + + +/*! + ************************************************************************ + * \brief + * Reads bits from the bitstream buffer + * + * \param buffer + * containing VLC-coded data bits + * \param totbitoffset + * bit offset from start of partition + * \param info + * returns value of the read bits + * \param bitcount + * total bytes in bitstream + * \param numbits + * number of bits to read + * + ************************************************************************ + */ +int GetBits (byte buffer[],int totbitoffset,int *info, int bitcount, + int numbits) +{ + if ((totbitoffset + numbits ) > bitcount) + { + return -1; + } + else + { + int bitoffset = 7 - (totbitoffset & 0x07); // bit from start of byte + int byteoffset = (totbitoffset >> 3); // byte from start of buffer + int bitcounter = numbits; + byte *curbyte = &(buffer[byteoffset]); + int inf = 0; + + while (numbits--) + { + inf <<=1; + inf |= ((*curbyte)>> (bitoffset--)) & 0x01; + if (bitoffset == -1 ) + { //Move onto next byte to get all of numbits + curbyte++; + bitoffset = 7; + } + // Above conditional could also be avoided using the following: + // curbyte -= (bitoffset >> 3); + // bitoffset &= 0x07; + } + *info = inf; + + return bitcounter; // return absolute offset in bit from start of frame + } +} + +/*! + ************************************************************************ + * \brief + * Reads bits from the bitstream buffer + * + * \param buffer + * buffer containing VLC-coded data bits + * \param totbitoffset + * bit offset from start of partition + * \param bitcount + * total bytes in bitstream + * \param numbits + * number of bits to read + * + ************************************************************************ + */ + +int ShowBits (byte buffer[],int totbitoffset,int bitcount, int numbits) +{ + if ((totbitoffset + numbits ) > bitcount) + { + return -1; + } + else + { + int bitoffset = 7 - (totbitoffset & 0x07); // bit from start of byte + int byteoffset = (totbitoffset >> 3); // byte from start of buffer + byte *curbyte = &(buffer[byteoffset]); + int inf = 0; + + while (numbits--) + { + inf <<=1; + inf |= ((*curbyte)>> (bitoffset--)) & 0x01; + + if (bitoffset == -1 ) + { //Move onto next byte to get all of numbits + curbyte++; + bitoffset = 7; + } + } + return inf; // return absolute offset in bit from start of frame + } +} + diff --git a/ldecod/use_opencv_release.props b/ldecod/use_opencv_release.props new file mode 100644 index 0000000..1ae09b8 --- /dev/null +++ b/ldecod/use_opencv_release.props @@ -0,0 +1,17 @@ + + + + + + + + $(OPENCV_DIR)\lib\; + opencv_calib3d246.lib;opencv_contrib246.lib;opencv_core246.lib;opencv_features2d246.lib;opencv_flann246.lib;opencv_gpu246.lib;opencv_highgui246.lib;opencv_imgproc246.lib;opencv_legacy246.lib;opencv_ml246.lib;opencv_nonfree246.lib;opencv_objdetect246.lib;opencv_photo246.lib;opencv_stitching246.lib;opencv_superres246.lib;opencv_ts246.lib;opencv_video246.lib;opencv_videostab246.lib;%(AdditionalDependencies) + + + $(OPENCV_DIR)\include\;%(AdditionalIncludeDirectories) + HAVE_OPENCV;%(PreprocessorDefinitions) + + + + \ No newline at end of file diff --git a/ldecod/use_opencv_x86_release.props b/ldecod/use_opencv_x86_release.props new file mode 100644 index 0000000..1fe1406 --- /dev/null +++ b/ldecod/use_opencv_x86_release.props @@ -0,0 +1,17 @@ + + + + + + + + $(OPENCV_X86_DIR)\lib\; + opencv_calib3d233.lib;opencv_contrib233.lib;opencv_core233.lib;opencv_features2d233.lib;opencv_flann233.lib;opencv_gpu233.lib;opencv_highgui233.lib;opencv_imgproc233.lib;opencv_legacy233.lib;opencv_ml233.lib;opencv_objdetect233.lib;opencv_stitching233.lib;opencv_ts233.lib;opencv_video233.lib;%(AdditionalDependencies) + + + $(OPENCV_X86_DIR)\include\;%(AdditionalIncludeDirectories) + HAVE_OPENCV;%(PreprocessorDefinitions) + + + + \ No newline at end of file diff --git a/ldecod_vc10.vcxproj b/ldecod_vc10.vcxproj new file mode 100644 index 0000000..45ec315 --- /dev/null +++ b/ldecod_vc10.vcxproj @@ -0,0 +1,565 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + release_parser + Win32 + + + release_parser + x64 + + + Release + Win32 + + + Release + x64 + + + + ldecod + {5499B067-CF32-4141-A757-E0A29866994A} + ldecod + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\bin\ + .\bin\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + true + true + .\bin\ + .\bin\ + .\bin\ + .\bin\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + false + false + false + false + + + + .\ldecod/$(Configuration)_$(Platform)_vc10/ldecod.tlb + + + + + /MP %(AdditionalOptions) + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + false + + + .\ldecod/$(Configuration)_$(Platform)_vc10/ldecod.pch + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + true + Level3 + true + EditAndContinue + Default + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\ldecod/$(Configuration)_$(Platform)_vc10/ldecod.pdb + false + Console + false + + + MachineX86 + + + + + .\ldecod/$(Configuration)_$(Platform)_vc10/ldecod.tlb + + + + + /MP %(AdditionalOptions) + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + true + + + .\ldecod/$(Configuration)_$(Platform)_vc10/ldecod.pch + .\ldecod/$(Configuration)_$(Platform)_vc10/ + .\ldecod/$(Configuration)_$(Platform)_vc10/ + .\ldecod/$(Configuration)_$(Platform)_vc10/ + true + Level3 + true + ProgramDatabase + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\ldecod/$(Configuration)_$(Platform)_vc10/ldecod.pdb + false + Console + false + + + + + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.tlb + + + + + %(AdditionalOptions) + MaxSpeed + AnySuitable + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + false + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pch + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ + Level3 + true + ProgramDatabase + Cdecl + Default + + + Neither + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /FIXED:NO %(AdditionalOptions) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pdb + false + Console + false + + + MachineX86 + + + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.tlb + + + + + %(AdditionalOptions) + MaxSpeed + AnySuitable + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + false + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pch + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + .\ldecod\$(Configuration)_$(Platform)_vc10\ + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ + Level3 + true + ProgramDatabase + Cdecl + Default + + + Neither + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /FIXED:NO %(AdditionalOptions) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pdb + false + Console + false + + + MachineX86 + + + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.tlb + + + + + %(AdditionalOptions) + MaxSpeed + AnySuitable + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + false + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pch + .\ldecod\$(Configuration)_$(Platform)_vc10/ + .\ldecod\$(Configuration)_$(Platform)_vc10/ + .\ldecod\$(Configuration)_$(Platform)_vc10/ + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ + Level3 + true + ProgramDatabase + Cdecl + Default + Neither + false + StreamingSIMDExtensions2 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /FIXED:NO %(AdditionalOptions) + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pdb + false + Console + false + + + Default + + + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.tlb + + + + + %(AdditionalOptions) + MaxSpeed + AnySuitable + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + true + false + + + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pch + .\ldecod\$(Configuration)_$(Platform)_vc10/ + .\ldecod\$(Configuration)_$(Platform)_vc10/ + .\ldecod\$(Configuration)_$(Platform)_vc10/ + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ + Level3 + true + ProgramDatabase + Cdecl + Default + Neither + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /FIXED:NO %(AdditionalOptions) + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)_parser$(TargetExt) + true + true + .\ldecod\$(Configuration)_$(Platform)_vc10/ldecod.pdb + false + Console + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ldecod_vc10.vcxproj.filters b/ldecod_vc10.vcxproj.filters new file mode 100644 index 0000000..ba55b40 --- /dev/null +++ b/ldecod_vc10.vcxproj.filters @@ -0,0 +1,496 @@ + + + + + + + + + {45079de0-5d68-41ce-9d18-5d46f22c6853} + + + {9c7796bb-c64f-4d78-a028-bd13e8177aab} + + + {3952ab50-719a-4c3a-b5ec-1209d4d9e084} + + + {d91cfc9d-ed81-4e7f-a92b-cbabd1227627} + + + {04deefe3-6346-4041-9dc6-b021cafb3b82} + + + {0325f21c-1221-46e4-9a20-2a1e3ece8319} + + + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files\ferc + + + Project Header Files\ferc + + + Project Header Files\ferc + + + Project Header Files\ferc + + + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files\ferc + + + Project Source Files\ferc + + + Project Source Files\ferc + + + Project Source Files\ferc + + + Project Source Files\ferc + + + Project Source Files\ferc + + + Project Source Files\ferc + + + Project Source Files\ferc + + + \ No newline at end of file diff --git a/ldecod_vc10.vcxproj.user b/ldecod_vc10.vcxproj.user new file mode 100644 index 0000000..f225daa --- /dev/null +++ b/ldecod_vc10.vcxproj.user @@ -0,0 +1,15 @@ + + + + -d zdecoder_config.cfg + + + ..\jm_debug + WindowsLocalDebugger + + + ..\jm_debug + WindowsLocalDebugger + -d zdecoder_config.cfg + + \ No newline at end of file diff --git a/ldecod_vc7.vcproj b/ldecod_vc7.vcproj new file mode 100644 index 0000000..b7b93f0 --- /dev/null +++ b/ldecod_vc7.vcproj @@ -0,0 +1,853 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ldecod_vc8.vcproj b/ldecod_vc8.vcproj new file mode 100644 index 0000000..8e2d9e7 --- /dev/null +++ b/ldecod_vc8.vcproj @@ -0,0 +1,1347 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ldecod_vc9.vcproj b/ldecod_vc9.vcproj new file mode 100644 index 0000000..19d8610 --- /dev/null +++ b/ldecod_vc9.vcproj @@ -0,0 +1,956 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lencod/Makefile b/lencod/Makefile new file mode 100644 index 0000000..0660748 --- /dev/null +++ b/lencod/Makefile @@ -0,0 +1,132 @@ +### +### Makefile for H.264/AVC encoder +### +### generated for UNIX/LINUX environments +### by H. Schwarz, Limin Wang +### + + + +NAME= lencod + +### include debug information: 1=yes, 0=no +DBG?= 0 +### Generate 32 bit executable : 1=yes, 0=no +M32?= 0 +### include O level optimization : 0-3 +OPT?= 3 +### Static Compilation +STC?= 0 +### OPENMP support : 1=yes, 0=no +OPENMP?= 1 + +DEPEND= dependencies + +BINDIR= ../bin +INCDIR= inc +SRCDIR= src +OBJDIR= obj + +ADDSRCDIR= ../lcommon/src +ADDINCDIR= ../lcommon/inc + +ifeq ($(STC),1) +ifeq ($(DBG),1) ### Do not use static compilation for Debug mode +STC=0 +STATIC= +else +STATIC= -static +endif +else +STATIC= +endif + +LIBS= -lm $(STATIC) +CFLAGS= -std=gnu99 -pedantic -ffloat-store -fno-strict-aliasing -fsigned-char $(STATIC) +FLAGS= $(CFLAGS) -Wall -I$(INCDIR) -I$(ADDINCDIR) -D __USE_LARGEFILE64 -D _FILE_OFFSET_BITS=64 + +ifeq ($(M32),1) +FLAGS+=-m32 +endif + +ifeq ($(OPENMP),1) +FLAGS+=-fopenmp +endif + + +OPT_FLAG = -O$(OPT) +ifeq ($(DBG),1) +SUFFIX= .dbg +FLAGS+= -g +else +SUFFIX= +FLAGS+= $(OPT_FLAG) +endif + +OBJSUF= .o$(SUFFIX) + +SRC= $(wildcard $(SRCDIR)/*.c) +ADDSRC= $(wildcard $(ADDSRCDIR)/*.c) +OBJ= $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o$(SUFFIX)) $(ADDSRC:$(ADDSRCDIR)/%.c=$(OBJDIR)/%.o$(SUFFIX)) +BIN= $(BINDIR)/$(NAME)$(SUFFIX).exe + +.PHONY: default distclean clean tags depend + +default: messages objdir_mk depend bin + +messages: +ifeq ($(M32),1) + @echo 'Compiling with M32 support...' +endif +ifeq ($(DBG),1) + @echo 'Compiling with Debug support...' + @echo 'Note static compilation not supported in this mode.' +endif +ifeq ($(STC),1) + @echo 'Compiling with -static support...' +endif +ifeq ($(OPENMP),1) + @echo 'Compiling with -fopenmp support...' +endif + +clean: + @echo remove all objects + @rm -rf $(OBJDIR) + +distclean: clean + @rm -f $(DEPEND) tags + @rm -f $(BIN) + +tags: + @echo update tag table + @ctags inc/*.h src/*.c + +bin: $(OBJ) + @echo + @echo 'creating binary "$(BIN)"' + @$(CC) $(FLAGS) -o $(BIN) $(OBJ) $(LIBS) + @echo '... done' + @echo + +depend: + @echo + @echo 'checking dependencies' + @$(SHELL) -ec '$(CC) $(FLAGS) -MM $(CFLAGS) -I$(INCDIR) -I$(ADDINCDIR) $(SRC) $(ADDSRC) \ + | sed '\''s@\(.*\)\.o[ :]@$(OBJDIR)/\1.o$(SUFFIX):@g'\'' \ + >$(DEPEND)' + @echo + +$(OBJDIR)/%.o$(SUFFIX): $(SRCDIR)/%.c + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +$(OBJDIR)/%.o$(SUFFIX): $(ADDSRCDIR)/%.c + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +objdir_mk: + @echo 'Creating $(OBJDIR) ...' + @mkdir -p $(OBJDIR) + +-include $(DEPEND) + diff --git a/lencod/inc/annexb.h b/lencod/inc/annexb.h new file mode 100644 index 0000000..f033bf1 --- /dev/null +++ b/lencod/inc/annexb.h @@ -0,0 +1,25 @@ +/*! + ************************************************************************************** + * \file + * annexb.h + * \brief + * Byte stream operations support + * + * \date 7 December 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + *************************************************************************************** + */ + +#ifndef _ANNEXB_H_ +#define _ANNEXB_H_ + +#include "nalucommon.h" + +extern int WriteAnnexbNALU (VideoParameters *p_Vid, NALU_t *n, FILE **f_annexb); +extern void OpenAnnexbFile (char *fn, FILE **f_annexb); +extern void CloseAnnexbFile(FILE *f_annexb); + + +#endif //_ANNEXB_H_ diff --git a/lencod/inc/annexb_split.h b/lencod/inc/annexb_split.h new file mode 100644 index 0000000..e435f4f --- /dev/null +++ b/lencod/inc/annexb_split.h @@ -0,0 +1,34 @@ +/*! +************************************************************************************* +* \file annexb_split.h +* +* \brief +* +* \date +* 03-02-2012 +* +* \version +* 1.0 +* +* \author +* João Carreira +* +************************************************************************************* +*/ + +#ifndef _ANNEXB_SPLIT_H_ +#define _ANNEXB_SPLIT_H_ + +#include "global.h" +#include "nalucommon.h" + +extern void split_annexb_files( VideoParameters *p_Vid, NaluType nalu_type, void *data_pointer, size_t length ); + +extern void OpenAnnexbFileBaseView (VideoParameters *p_Vid, char *Filename); +extern void OpenAnnexbFileAuxView (VideoParameters *p_Vid, char *Filename); + +extern void CloseAnnexbFileBaseView(VideoParameters *p_Vid); +extern void CloseAnnexbFileAuxView(VideoParameters *p_Vid); + +extern void fflush_split_files( VideoParameters *p_Vid ); +#endif \ No newline at end of file diff --git a/lencod/inc/biariencode.h b/lencod/inc/biariencode.h new file mode 100644 index 0000000..0db5459 --- /dev/null +++ b/lencod/inc/biariencode.h @@ -0,0 +1,69 @@ + +/*! + *************************************************************************** + * \file + * biariencode.h + * + * \brief + * Headerfile for binary arithmetic encoding routines + * + * \author + * - Detlev Marpe + * - Gabi Blaettermann + * - Gunnar Marten + * + * Copyright (C) 2000 HEINRICH HERTZ INSTITUTE All Rights Reserved. + * + * \date + * 21. Oct 2000 + ************************************************************************** + */ + + +#ifndef _BIARIENCOD_H_ +#define _BIARIENCOD_H_ + + +/************************************************************************ + * D e f i n i t i o n s + *********************************************************************** + */ + +// some definitions to increase the readability of the source code + +#define B_BITS 10 // Number of bits to represent the whole coding interval +#define BITS_TO_LOAD 16 +#define MAX_BITS 26 //(B_BITS + BITS_TO_LOAD) +#define MASK_BITS 18 //(MAX_BITS - 8) +#define ONE 0x04000000 //(1 << MAX_BITS) +#define ONE_M1 0x03FFFFFF //(ONE - 1) +#define HALF 0x01FE //(1 << (B_BITS-1)) - 2 +#define QUARTER 0x0100 //(1 << (B_BITS-2)) +#define MIN_BITS_TO_GO 0 +#define B_LOAD_MASK 0xFFFF // ((1<Ecodestrm_len) + eep->Epbuf + 1) << 3) + (eep->Echunks_outstanding * BITS_TO_LOAD) + BITS_TO_LOAD - eep->Ebits_to_go; +} + +#endif // BIARIENCOD_H + diff --git a/lencod/inc/block.h b/lencod/inc/block.h new file mode 100644 index 0000000..25bcbb6 --- /dev/null +++ b/lencod/inc/block.h @@ -0,0 +1,103 @@ + +/*! + ************************************************************************ + * \file block.h + * + * \brief + * constant arrays for single block processing + * + * \author + * Inge Lille-Langoy \n + * Telenor Satellite Services \n + * P.O.Box 6914 St.Olavs plass \n + * N-0130 Oslo, Norway + * + ************************************************************************ + */ + +#ifndef _BLOCK_H_ +#define _BLOCK_H_ + + +#include "global.h" + +extern int residual_transform_quant_luma_4x4(Macroblock *currMB, ColorPlane pl, int block_x,int block_y, int *coeff_cost, int intra); + +static const byte QP_SCALE_CR[52]= +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, + 28,29,29,30,31,32,32,33,34,34,35,35,36,36,37,37, 37,38,38,38,39,39,39,39 +}; + +//! look up tables for FRExt_chroma support +static const unsigned char subblk_offset_x[3][8][4] = +{ + { + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12} + } +}; + + +static const unsigned char subblk_offset_y[3][8][4] = +{ + { + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {8, 8,12,12}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {8, 8,12,12}, + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {8, 8,12,12} + } +}; + +#endif + diff --git a/lencod/inc/cabac.h b/lencod/inc/cabac.h new file mode 100644 index 0000000..52e5f3b --- /dev/null +++ b/lencod/inc/cabac.h @@ -0,0 +1,73 @@ + +/*! + *************************************************************************** + * \file + * cabac.h + * + * \brief + * Headerfile for entropy coding routines + * + * \author + * Detlev Marpe \n + * Copyright (C) 2000 HEINRICH HERTZ INSTITUTE All Rights Reserved. + * + * \date + * 21. Oct 2000 (Changes by Tobias Oelbaum 28.08.2001) + *************************************************************************** + */ + + +#ifndef _CABAC_H_ +#define _CABAC_H_ + +static const byte maxpos [] = {15, 14, 63, 31, 31, 15, 3, 14, 7, 15, 15, 14, 63, 31, 31, 15, 15, 14, 63, 31, 31, 15}; +static const byte c1isdc [] = { 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1}; + +static const byte type2ctx_bcbp[] = { 0, 1, 2, 3, 3, 4, 5, 6, 5, 5, 10, 11, 12, 13, 13, 14, 16, 17, 18, 19, 19, 20}; +static const byte type2ctx_map [] = { 0, 1, 2, 3, 4, 5, 6, 7, 6, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}; // 8 +static const byte type2ctx_last[] = { 0, 1, 2, 3, 4, 5, 6, 7, 6, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}; // 8 +static const byte type2ctx_one [] = { 0, 1, 2, 3, 3, 4, 5, 6, 5, 5, 10, 11, 12, 13, 13, 14, 16, 17, 18, 19, 19, 20}; // 7 +static const byte type2ctx_abs [] = { 0, 1, 2, 3, 3, 4, 5, 6, 5, 5, 10, 11, 12, 13, 13, 14, 16, 17, 18, 19, 19, 20}; // 7 +static const byte max_c2 [] = { 4, 4, 4, 4, 4, 4, 3, 4, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; // 9 + + +extern const byte* pos2ctx_map []; +extern const byte* pos2ctx_map_int []; +extern const byte* pos2ctx_last []; + +// CABAC +extern MotionInfoContexts* create_contexts_MotionInfo (void); +extern TextureInfoContexts* create_contexts_TextureInfo(void); + +extern void delete_contexts_MotionInfo (MotionInfoContexts *enco_ctx); +extern void delete_contexts_TextureInfo (TextureInfoContexts *enco_ctx); +extern void writeMB_I_typeInfo_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeMB_B_typeInfo_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeMB_P_typeInfo_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeIntraPredMode_CABAC (SyntaxElement *se, DataPartition *dp); +extern void writeB8_typeInfo_CABAC (SyntaxElement *se, DataPartition *dp); +extern void writeB8_B_typeInfo_CABAC (SyntaxElement *se, DataPartition *dp); + +extern void writeRefPic_B_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeRefPic_P_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); + +extern void writeMVD_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeCBP_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeDquant_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeRunLevel_CABAC (Macroblock* currMB, SyntaxElement *se, DataPartition *dp); +extern void writeCIPredMode_CABAC (Macroblock* currMB, SyntaxElement *se, DataPartition *dp); +extern void print_ctx_TextureInfo (TextureInfoContexts *enco_ctx); +extern void writeMB_Pskip_flagInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeMB_Bskip_flagInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeFieldModeInfo_CABAC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); //GB +extern void writeCBP_BIT_CABAC (Macroblock *currMB, int b8, int bit, int cbp, EncodingEnvironmentPtr eep_dp, TextureInfoContexts *ctx); + +extern void CheckAvailabilityOfNeighborsCABAC (Macroblock* currMB); +extern void writeMB_transform_size_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp); + +extern void write_and_store_CBP_block_bit_444 (Macroblock* currMB, EncodingEnvironmentPtr eep_dp, int type, int cbp_bit, TextureInfoContexts* tex_ctx); +extern void write_and_store_CBP_block_bit (Macroblock* currMB, EncodingEnvironmentPtr eep_dp, int type, int cbp_bit, TextureInfoContexts* tex_ctx); + + +#endif // CABAC_H + diff --git a/lencod/inc/cconv_yuv2rgb.h b/lencod/inc/cconv_yuv2rgb.h new file mode 100644 index 0000000..5b801d9 --- /dev/null +++ b/lencod/inc/cconv_yuv2rgb.h @@ -0,0 +1,28 @@ +/*! + *************************************************************************** + * \file + * cconv_yuv2rgb.h + * + * \author + * Woo-Shik Kim + * + * \date + * 29 May 2008 + * + * \brief + * Headerfile for YUV to RGB color conversion + ************************************************************************** + */ + +#ifndef _CCONV_YUV2RGB_H_ +#define _CCONV_YUV2RGB_H_ + +#include "img_distortion.h" + +extern void init_YUVtoRGB (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void YUVtoRGB (VideoParameters *p_Vid, ImageStructure *YUV, ImageStructure *RGB); +extern int create_RGB_memory(VideoParameters *p_Vid); +extern void delete_RGB_memory(VideoParameters *p_Vid); + +#endif + diff --git a/lencod/inc/configfile.h b/lencod/inc/configfile.h new file mode 100644 index 0000000..396474e --- /dev/null +++ b/lencod/inc/configfile.h @@ -0,0 +1,642 @@ + +/*! + *********************************************************************** + * \file + * configfile.h + * \brief + * Prototypes for configfile.c and definitions of used structures. + *********************************************************************** + */ + +#include "fmo.h" + +#ifndef _CONFIGFILE_H_ +#define _CONFIGFILE_H_ + +#include "config_common.h" + +#define DEFAULTCONFIGFILENAME "encoder.cfg" + +#define PROFILE_IDC 88 +#define LEVEL_IDC 21 + +InputParameters cfgparams; + + +#ifdef INCLUDED_BY_CONFIGFILE_C +// Mapping_Map Syntax: +// {NAMEinConfigFile, &cfgparams.VariableName, Type, InitialValue, LimitType, MinLimit, MaxLimit, CharSize} +// Types : {0:int, 1:text, 2: double} +// LimitType: {0:none, 1:both, 2:minimum, 3: QP based} +// We could separate this based on types to make it more flexible and allow also defaults for text types. +Mapping Map[] = { + //! Edited by Joao Carreira + {"TranscodeFileBase", &cfgparams.TranscodeFile[0], 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE }, + {"List1NotUsed", &cfgparams.List1NotUsed, 0, 0.0, 1, 0.0, 2.0, }, + + {"ProfileIDC", &cfgparams.ProfileIDC, 0, (double) PROFILE_IDC, 0, 0.0, 0.0, }, + {"IntraProfile", &cfgparams.IntraProfile, 0, 0.0, 1, 0.0, 1.0, }, + {"LevelIDC", &cfgparams.LevelIDC, 0, (double) LEVEL_IDC, 0, 0.0, 0.0, }, + {"FrameRate", &cfgparams.source.frame_rate, 2, (double) INIT_FRAME_RATE, 1, 0.0, 480.0, }, + {"Enable32Pulldown", &cfgparams.enable_32_pulldown, 0, 0.0, 1, 0.0, 2.0, }, + {"ResendSPS", &cfgparams.ResendSPS, 0, 0.0, 1, 0.0, 3.0, }, + {"StartFrame", &cfgparams.start_frame, 0, 0.0, 2, 0.0, 0.0, }, + {"IntraPeriod", &cfgparams.intra_period, 0, 0.0, 2, 0.0, 0.0, }, + {"IDRPeriod", &cfgparams.idr_period, 0, 0.0, 2, 0.0, 0.0, }, + {"IntraDelay", &cfgparams.intra_delay, 0, 0.0, 2, 0.0, 0.0, }, + {"AdaptiveIntraPeriod", &cfgparams.adaptive_intra_period, 0, 0.0, 1, 0.0, 1.0, }, + {"AdaptiveIDRPeriod", &cfgparams.adaptive_idr_period, 0, 0.0, 1, 0.0, 2.0, }, + {"EnableOpenGOP", &cfgparams.EnableOpenGOP, 0, 0.0, 1, 0.0, 1.0, }, + {"EnableIDRGOP", &cfgparams.EnableIDRGOP, 0, 0.0, 1, 0.0, 1.0, }, + {"FramesToBeEncoded", &cfgparams.no_frames, 0, 1.0, 2, -1.0, 0.0, }, + {"QPISlice", &cfgparams.qp[I_SLICE], 0, 24.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"QPPSlice", &cfgparams.qp[P_SLICE], 0, 24.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"QPBSlice", &cfgparams.qp[B_SLICE], 0, 24.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"QPSPSlice", &cfgparams.qp[SP_SLICE], 0, 24.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"QPSISlice", &cfgparams.qp[SI_SLICE], 0, 24.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"ChangeQPFrame", &cfgparams.qp2frame, 0, 0.0, 2, 0.0, 0.0, }, + {"ChangeQPI", &cfgparams.qp2off[I_SLICE], 0, 0.0, 0, (double) -MAX_QP, (double) MAX_QP, }, + {"ChangeQPP", &cfgparams.qp2off[P_SLICE], 0, 0.0, 0, (double) -MAX_QP, (double) MAX_QP, }, + {"ChangeQPB", &cfgparams.qp2off[B_SLICE], 0, 0.0, 0, (double) -MAX_QP, (double) MAX_QP, }, + {"ChangeQPSP", &cfgparams.qp2off[SP_SLICE], 0, 0.0, 0, (double) -MAX_QP, (double) MAX_QP, }, + {"ChangeQPSI", &cfgparams.qp2off[SI_SLICE], 0, 0.0, 0, (double) -MAX_QP, (double) MAX_QP, }, + {"QPSP2Slice", &cfgparams.qpsp, 0, 0.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"FrameSkip", &cfgparams.frame_skip, 0, 0.0, 2, 0.0, 0.0, }, + {"DisableSubpelME", &cfgparams.DisableSubpelME[0], 0, 0.0, 1, 0.0, 1.0, }, + {"SearchRange", &cfgparams.search_range[0], 0, 16.0, 2, 0.0, 0.0, }, + {"NumberReferenceFrames", &cfgparams.num_ref_frames, 0, 1.0, 1, 0.0, 16.0, }, + {"PList0References", &cfgparams.P_List0_refs[0], 0, 0.0, 1, 0.0, 16.0, }, + {"BList0References", &cfgparams.B_List0_refs[0], 0, 0.0, 1, 0.0, 16.0, }, + {"BList1References", &cfgparams.B_List1_refs[0], 0, 1.0, 1, 0.0, 16.0, }, + {"NumberOfViews", &cfgparams.num_of_views, 0, 1.0, 1, 1.0, 2.0, }, +#if (MVC_EXTENSION_ENABLE) + {"View1ConfigFile", &cfgparams.View1ConfigName, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + //! Edit by João Carreira + {"OutputBaseView", &cfgparams.outfile_base, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE }, + {"OutputAuxView", &cfgparams.outfile_aux, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE }, +#endif + {"Log2MaxFNumMinus4", &cfgparams.Log2MaxFNumMinus4, 0, 0.0, 1, -1.0, 12.0, }, + {"Log2MaxPOCLsbMinus4", &cfgparams.Log2MaxPOCLsbMinus4, 0, 2.0, 1, -1.0, 12.0, }, + {"GenerateMultiplePPS", &cfgparams.GenerateMultiplePPS, 0, 0.0, 1, 0.0, 1.0, }, + {"ResendPPS", &cfgparams.ResendPPS, 0, 0.0, 1, 0.0, 1.0, }, + {"SendAUD", &cfgparams.SendAUD, 0, 0.0, 1, 0.0, 3.0, }, + {"SourceWidth", &cfgparams.source.width[0], 0, 176.0, 2, 0.0, 0.0, }, + {"SourceHeight", &cfgparams.source.height[0], 0, 144.0, 2, 0.0, 0.0, }, + {"SourceResize", &cfgparams.src_resize, 0, 0.0, 1, 0.0, 1.0, }, + {"OutputWidth", &cfgparams.output.width[0], 0, 176.0, 2, 16.0, 0.0, }, + {"OutputHeight", &cfgparams.output.height[0], 0, 144.0, 2, 16.0, 0.0, }, + {"Grayscale", &cfgparams.grayscale, 0, 0.0, 0, 0.0, 1.0, }, + {"MbLineIntraUpdate", &cfgparams.intra_upd, 0, 0.0, 1, 0.0, 1.0, }, + {"SliceMode", &cfgparams.slice_mode, 0, 0.0, 1, 0.0, 3.0, }, + {"SliceArgument", &cfgparams.slice_argument, 0, 1.0, 2, 1.0, 1.0, }, + {"UseConstrainedIntraPred", &cfgparams.UseConstrainedIntraPred, 0, 0.0, 1, 0.0, 1.0, }, + {"InputFile", &cfgparams.input_file1.fname, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"InputHeaderLength", &cfgparams.infile_header, 0, 0.0, 2, 0.0, 1.0, }, + {"OutputFile", &cfgparams.outfile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"ReconFile", &cfgparams.ReconFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"TraceFile", &cfgparams.TraceFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"StatsFile", &cfgparams.StatsFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"DisposableP", &cfgparams.DisposableP, 0, 0.0, 1, 0.0, 1.0, }, + {"SetFirstAsLongTerm", &cfgparams.SetFirstAsLongTerm, 0, 0.0, 1, 0.0, 1.0, }, + {"MultiSourceData", &cfgparams.MultiSourceData, 0, 0.0, 0, 0.0, 2.0, }, + {"InputFile3", &cfgparams.input_file3.fname, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"SEIVUI32Pulldown", &cfgparams.SEIVUI32Pulldown, 0, 0.0, 1, 0.0, 5.0, }, + + {"ProcessInput", &cfgparams.ProcessInput, 0, 0.0, 1, 0.0, 4.0, }, + {"DispPQPOffset", &cfgparams.DispPQPOffset, 0, 0.0, 0,-51.0, 51.0, }, + {"NumberBFrames", &cfgparams.NumberBFrames, 0, 0.0, 2, 0.0, 0.0, }, + {"PReplaceBSlice", &cfgparams.PReplaceBSlice, 0, 0.0, 1, 0.0, 1.0, }, + {"BRefPicQPOffset", &cfgparams.qpBRSOffset, 0, 0.0, 0,-51.0, 51.0, }, + {"DirectModeType", &cfgparams.direct_spatial_mv_pred_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"DirectInferenceFlag", &cfgparams.directInferenceFlag, 0, 1.0, 1, 0.0, 1.0, }, + {"SPPicturePeriodicity", &cfgparams.sp_periodicity, 0, 0.0, 2, 0.0, 0.0, }, + {"SI_FRAMES", &cfgparams.si_frame_indicator, 0, 0.0, 1, 0.0, 1.0, }, + {"SP_output", &cfgparams.sp_output_indicator, 0, 0.0, 1, 0.0, 1.0, }, + {"SP_output_name", &cfgparams.sp_output_filename, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"SPSwitchPeriod", &cfgparams.sp_switch_period, 0, 0.0, 2, 0.0, 0.0, }, + {"SP2_FRAMES", &cfgparams.sp2_frame_indicator, 0, 0.0, 1, 0.0, 1.0, }, + {"SP2_input_name1", &cfgparams.sp2_input_filename1, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"SP2_input_name2", &cfgparams.sp2_input_filename2, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"SymbolMode", &cfgparams.symbol_mode, 0, 0.0, 1, (double) CAVLC, (double) CABAC, }, + {"OutFileMode", &cfgparams.of_mode, 0, 0.0, 1, 0.0, 1.0, }, + {"PartitionMode", &cfgparams.partition_mode, 0, 0.0, 1, 0.0, 1.0, }, + {"PSliceSkip", &cfgparams.InterSearch[0][0][0], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch16x16", &cfgparams.InterSearch[0][0][1], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch16x8", &cfgparams.InterSearch[0][0][2], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch8x16", &cfgparams.InterSearch[0][0][3], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch8x8", &cfgparams.InterSearch[0][0][4], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch8x4", &cfgparams.InterSearch[0][0][5], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch4x8", &cfgparams.InterSearch[0][0][6], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch4x4", &cfgparams.InterSearch[0][0][7], 0, 1.0, 1, 0.0, 1.0, }, + // B slice partition modes. + {"BSliceDirect", &cfgparams.InterSearch[0][1][0], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch16x16", &cfgparams.InterSearch[0][1][1], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch16x8", &cfgparams.InterSearch[0][1][2], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch8x16", &cfgparams.InterSearch[0][1][3], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch8x8", &cfgparams.InterSearch[0][1][4], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch8x4", &cfgparams.InterSearch[0][1][5], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch4x8", &cfgparams.InterSearch[0][1][6], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch4x4", &cfgparams.InterSearch[0][1][7], 0, 1.0, 1, 0.0, 1.0, }, + //Bipredicting Motion Estimation parameters + {"BiPredMotionEstimation", &cfgparams.BiPredMotionEstimation, 0, 0.0, 1, 0.0, 1.0, }, + {"BiPredSearch16x16", &cfgparams.BiPredSearch[0], 0, 1.0, 1, 0.0, 1.0, }, + {"BiPredSearch16x8", &cfgparams.BiPredSearch[1], 0, 0.0, 1, 0.0, 1.0, }, + {"BiPredSearch8x16", &cfgparams.BiPredSearch[2], 0, 0.0, 1, 0.0, 1.0, }, + {"BiPredSearch8x8", &cfgparams.BiPredSearch[3], 0, 0.0, 1, 0.0, 1.0, }, + {"BiPredMERefinements", &cfgparams.BiPredMERefinements, 0, 0.0, 1, 0.0, 5.0, }, + {"BiPredMESearchRange", &cfgparams.BiPredMESearchRange[0], 0, 8.0, 2, 0.0, 0.0, }, + {"BiPredMESubPel", &cfgparams.BiPredMESubPel, 0, 1.0, 1, 0.0, 2.0, }, + {"DisableIntraInInter", &cfgparams.DisableIntraInInter[0], 0, 0.0, 1, 0.0, 1.0, }, + {"IntraDisableInterOnly", &cfgparams.IntraDisableInterOnly, 0, 0.0, 1, 0.0, 1.0, }, + {"DisableIntra4x4", &cfgparams.DisableIntra4x4, 0, 0.0, 1, 0.0, 1.0, }, + {"DisableIntra16x16", &cfgparams.DisableIntra16x16, 0, 0.0, 1, 0.0, 1.0, }, + {"Intra4x4ParDisable", &cfgparams.Intra4x4ParDisable, 0, 0.0, 1, 0.0, 1.0, }, + {"Intra4x4DiagDisable", &cfgparams.Intra4x4DiagDisable, 0, 0.0, 1, 0.0, 1.0, }, + {"Intra4x4DirDisable", &cfgparams.Intra4x4DirDisable, 0, 0.0, 1, 0.0, 1.0, }, + {"Intra16x16ParDisable", &cfgparams.Intra16x16ParDisable, 0, 0.0, 1, 0.0, 1.0, }, + {"Intra16x16PlaneDisable", &cfgparams.Intra16x16PlaneDisable, 0, 0.0, 1, 0.0, 1.0, }, + {"EnableIPCM", &cfgparams.EnableIPCM, 0, 0.0, 1, 0.0, 2.0, }, + {"ChromaIntraDisable", &cfgparams.ChromaIntraDisable, 0, 0.0, 1, 0.0, 1.0, }, + {"RDOptimization", &cfgparams.rdopt, 0, 0.0, 1, 0.0, 3.0, }, + + {"DistortionEstimation", &cfgparams.de, 0, 1.0, 2, 0.0, 8.0, }, + {"SubMBCodingState", &cfgparams.subMBCodingState, 0, 2.0, 1, 0.0, 2.0, }, + {"I16RDOpt", &cfgparams.I16rdo, 0, 0.0, 1, 0.0, 1.0, }, + {"MDReference", &cfgparams.MDReference[0], 0, 0.0, 1, 0.0, 1.0, }, + {"EnhLayerMDReference", &cfgparams.MDReference[1], 0, 0.0, 1, 0.0, 1.0, }, + {"DistortionSSIM", &cfgparams.Distortion[SSIM], 0, 0.0, 1, 0.0, 1.0, }, + {"DistortionMS_SSIM", &cfgparams.Distortion[MS_SSIM], 0, 0.0, 1, 0.0, 1.0, }, + {"SSIMOverlapSize", &cfgparams.SSIMOverlapSize, 0, 1.0, 2, 1.0, 1.0, }, + {"DistortionYUVtoRGB", &cfgparams.DistortionYUVtoRGB, 0, 0.0, 1, 0.0, 1.0, }, + {"CtxAdptLagrangeMult", &cfgparams.CtxAdptLagrangeMult, 0, 0.0, 1, 0.0, 1.0, }, + {"FastCrIntraDecision", &cfgparams.FastCrIntraDecision, 0, 0.0, 1, 0.0, 1.0, }, + {"DisableThresholding", &cfgparams.disthres, 0, 0.0, 1, 0.0, 1.0, }, + {"DisableBSkipRDO", &cfgparams.nobskip, 0, 0.0, 1, 0.0, 1.0, }, + {"BiasSkipRDO", &cfgparams.BiasSkipRDO, 0, 0.0, 1, 0.0, 1.0, }, + {"ForceTrueRateRDO", &cfgparams.ForceTrueRateRDO, 0, 0.0, 1, 0.0, 2.0, }, + {"LossRateA", &cfgparams.LossRateA, 2, 0.0, 2, 0.0, 0.0, }, + {"LossRateB", &cfgparams.LossRateB, 2, 0.0, 2, 0.0, 0.0, }, + {"LossRateC", &cfgparams.LossRateC, 2, 0.0, 2, 0.0, 0.0, }, + {"FirstFrameCorrect", &cfgparams.FirstFrameCorrect, 0, 0.0, 2, 0.0, 0.0, }, + {"NumberOfDecoders", &cfgparams.NoOfDecoders, 0, 0.0, 2, 0.0, 0.0, }, + {"ErrorConcealment", &cfgparams.ErrorConcealment, 0, 0.0, 2, 0.0, 0.0, }, + {"RestrictRefFrames", &cfgparams.RestrictRef , 0, 0.0, 1, 0.0, 1.0, }, +#ifdef _LEAKYBUCKET_ + {"NumberofLeakyBuckets", &cfgparams.NumberLeakyBuckets, 0, 2.0, 1, 2.0, 255.0, }, + {"LeakyBucketRateFile", &cfgparams.LeakyBucketRateFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"LeakyBucketParamFile", &cfgparams.LeakyBucketParamFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, +#endif + {"PicInterlace", &cfgparams.PicInterlace, 0, 0.0, 1, 0.0, 3.0, }, + {"MbInterlace", &cfgparams.MbInterlace, 0, 0.0, 1, 0.0, 3.0, }, + + {"IntraBottom", &cfgparams.IntraBottom, 0, 0.0, 1, 0.0, 1.0, }, + + {"NumFramesInELayerSubSeq", &cfgparams.NumFramesInELSubSeq, 0, 0.0, 2, 0.0, 0.0, }, + {"RandomIntraMBRefresh", &cfgparams.RandomIntraMBRefresh, 0, 0.0, 2, 0.0, 0.0, }, + {"WeightedPrediction", &cfgparams.WeightedPrediction, 0, 0.0, 1, 0.0, 1.0, }, + {"WeightedBiprediction", &cfgparams.WeightedBiprediction, 0, 0.0, 1, 0.0, 2.0, }, + {"WPMethod", &cfgparams.WPMethod, 0, 0.0, 1, 0.0, 1.0, }, + {"WPIterMC", &cfgparams.WPIterMC, 0, 0.0, 1, 0.0, 1.0, }, + {"ChromaWeightSupport", &cfgparams.ChromaWeightSupport, 0, 0.0, 1, 0.0, 1.0, }, + {"EnhancedBWeightSupport", &cfgparams.EnhancedBWeightSupport, 0, 0.0, 1, 0.0, 2.0, }, + {"UseWeightedReferenceME", &cfgparams.UseWeightedReferenceME, 0, 0.0, 1, 0.0, 1.0, }, + {"RDPictureDecision", &cfgparams.RDPictureDecision, 0, 0.0, 1, 0.0, 1.0, }, + {"RDPSliceBTest", &cfgparams.RDPSliceBTest, 0, 0.0, 1, 0.0, 1.0, }, + {"RDPSliceITest", &cfgparams.RDPSliceITest, 0, 1.0, 1, 0.0, 1.0, }, + {"RDPictureMaxPassISlice", &cfgparams.RDPictureMaxPassISlice, 0, 1.0, 1, 1.0, 3.0, }, + {"RDPictureMaxPassPSlice", &cfgparams.RDPictureMaxPassPSlice, 0, 2.0, 1, 1.0, 6.0, }, + {"RDPictureMaxPassBSlice", &cfgparams.RDPictureMaxPassBSlice, 0, 3.0, 1, 1.0, 6.0, }, + {"RDPictureDeblocking", &cfgparams.RDPictureDeblocking, 0, 0.0, 1, 0.0, 1.0, }, + {"RDPictureDirectMode", &cfgparams.RDPictureDirectMode, 0, 0.0, 1, 0.0, 1.0, }, + {"RDPictureFrameQPPSlice", &cfgparams.RDPictureFrameQPPSlice, 0, 0.0, 1, 0.0, 1.0, }, + {"RDPictureFrameQPBSlice", &cfgparams.RDPictureFrameQPBSlice, 0, 0.0, 1, 0.0, 1.0, }, + {"SkipIntraInInterSlices", &cfgparams.SkipIntraInInterSlices, 0, 0.0, 1, 0.0, 1.0, }, + {"BReferencePictures", &cfgparams.BRefPictures, 0, 0.0, 1, 0.0, 2.0, }, + {"HierarchicalCoding", &cfgparams.HierarchicalCoding, 0, 0.0, 1, 0.0, 3.0, }, + {"HierarchyLevelQPEnable", &cfgparams.HierarchyLevelQPEnable, 0, 0.0, 1, 0.0, 1.0, }, + {"ExplicitHierarchyFormat", &cfgparams.ExplicitHierarchyFormat, 1, 0.0, 0, 0.0, 0.0, INPUT_TEXT_SIZE,}, + {"ExplicitSeqCoding", &cfgparams.ExplicitSeqCoding, 0, 0.0, 1, 0.0, 3.0, }, + {"ExplicitSeqFile", &cfgparams.ExplicitSeqFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"LowDelay", &cfgparams.LowDelay, 0, 0.0, 1, 0.0, 1.0, }, + {"ReferenceReorder", &cfgparams.ReferenceReorder, 0, 0.0, 1, 0.0, 2.0, }, + {"PocMemoryManagement", &cfgparams.PocMemoryManagement, 0, 0.0, 1, 0.0, 2.0, }, + + + {"DFParametersFlag", &cfgparams.DFSendParameters, 0, 0.0, 1, 0.0, 1.0, }, + {"DFDisableRefISlice", &cfgparams.DFDisableIdc[1][I_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefISlice", &cfgparams.DFDisableIdc[0][I_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefPSlice", &cfgparams.DFDisableIdc[1][P_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefPSlice", &cfgparams.DFDisableIdc[0][P_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefBSlice", &cfgparams.DFDisableIdc[1][B_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefBSlice", &cfgparams.DFDisableIdc[0][B_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefSPSlice", &cfgparams.DFDisableIdc[1][SP_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefSPSlice", &cfgparams.DFDisableIdc[0][SP_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefSISlice", &cfgparams.DFDisableIdc[1][SI_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefSISlice", &cfgparams.DFDisableIdc[0][SI_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFAlphaRefISlice", &cfgparams.DFAlpha[1][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefISlice", &cfgparams.DFAlpha[0][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefPSlice", &cfgparams.DFAlpha[1][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefPSlice", &cfgparams.DFAlpha[0][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefBSlice", &cfgparams.DFAlpha[1][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefBSlice", &cfgparams.DFAlpha[0][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefSPSlice", &cfgparams.DFAlpha[1][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefSPSlice", &cfgparams.DFAlpha[0][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefSISlice", &cfgparams.DFAlpha[1][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefSISlice", &cfgparams.DFAlpha[0][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefISlice", &cfgparams.DFBeta[1][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefISlice", &cfgparams.DFBeta[0][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefPSlice", &cfgparams.DFBeta[1][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefPSlice", &cfgparams.DFBeta[0][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefBSlice", &cfgparams.DFBeta[1][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefBSlice", &cfgparams.DFBeta[0][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefSPSlice", &cfgparams.DFBeta[1][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefSPSlice", &cfgparams.DFBeta[0][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefSISlice", &cfgparams.DFBeta[1][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefSISlice", &cfgparams.DFBeta[0][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"SparePictureOption", &cfgparams.SparePictureOption, 0, 0.0, 1, 0.0, 1.0, }, + {"SparePictureDetectionThr", &cfgparams.SPDetectionThreshold, 0, 0.0, 2, 0.0, 0.0, }, + {"SparePicturePercentageThr",&cfgparams.SPPercentageThreshold, 0, 0.0, 2, 0.0, 100.0, }, + + {"num_slice_groups_minus1", &cfgparams.num_slice_groups_minus1, 0, 0.0, 1, 0.0, (double)MAXSLICEGROUPIDS - 1 }, + {"slice_group_map_type", &cfgparams.slice_group_map_type, 0, 0.0, 1, 0.0, 6.0, }, + {"slice_group_change_direction_flag", &cfgparams.slice_group_change_direction_flag, 0, 0.0, 1, 0.0, 2.0, }, + {"slice_group_change_rate_minus1", &cfgparams.slice_group_change_rate_minus1, 0, 0.0, 2, 0.0, 1.0, }, + {"SliceGroupConfigFileName", &cfgparams.SliceGroupConfigFileName, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + + {"UseRedundantPicture", &cfgparams.redundant_pic_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"NumRedundantHierarchy", &cfgparams.NumRedundantHierarchy, 0, 0.0, 1, 0.0, 4.0, }, + {"PrimaryGOPLength", &cfgparams.PrimaryGOPLength, 0, 1.0, 1, 1.0, 16.0, }, + {"NumRefPrimary", &cfgparams.NumRefPrimary, 0, 1.0, 1, 1.0, 16.0, }, + + {"PicOrderCntType", &cfgparams.pic_order_cnt_type, 0, 0.0, 1, 0.0, 2.0, }, + + {"ContextInitMethod", &cfgparams.context_init_method, 0, 0.0, 1, 0.0, 1.0, }, + {"FixedModelNumber", &cfgparams.model_number, 0, 0.0, 1, 0.0, 2.0, }, + + {"ReportFrameStats", &cfgparams.ReportFrameStats, 0, 0.0, 1, 0.0, 1.0, }, + {"DisplayEncParams", &cfgparams.DisplayEncParams, 0, 0.0, 1, 0.0, 1.0, }, + {"Verbose", &cfgparams.Verbose, 0, 1.0, 1, 0.0, 4.0, }, + {"SkipGlobalStats", &cfgparams.skip_gl_stats, 0, 0.0, 1, 0.0, 1.0, }, + {"OnTheFlyFractMCP", &cfgparams.OnTheFlyFractMCP, 0, 0.0, 1, 0.0, 3.0, }, + {"ChromaMCBuffer", &cfgparams.ChromaMCBuffer, 0, 0.0, 1, 0.0, 1.0, }, + {"ChromaMEEnable", &cfgparams.ChromaMEEnable, 0, 0.0, 1, 0.0, 2.0, }, + {"ChromaMEWeight", &cfgparams.ChromaMEWeight, 0, 1.0, 2, 1.0, 0.0, }, + {"MESoftenSSEMetric", &cfgparams.MESoftenSSEMetric, 0, 0.0, 1, 0.0, 1.0, }, + {"MEDistortionFPel", &cfgparams.MEErrorMetric[F_PEL], 0, 0.0, 1, 0.0, 3.0, }, + {"MEDistortionHPel", &cfgparams.MEErrorMetric[H_PEL], 0, 0.0, 1, 0.0, 3.0, }, + {"MEDistortionQPel", &cfgparams.MEErrorMetric[Q_PEL], 0, 2.0, 1, 0.0, 3.0, }, + {"MDDistortion", &cfgparams.ModeDecisionMetric, 0, 2.0, 1, 0.0, 2.0, }, + {"SkipDeBlockNonRef", &cfgparams.SkipDeBlockNonRef, 0, 0.0, 1, 0.0, 1.0, }, + + // Rate Control + {"RateControlEnable", &cfgparams.RCEnable, 0, 0.0, 1, 0.0, 1.0, }, + {"Bitrate", &cfgparams.bit_rate, 0, 0.0, 2, 0.0, 0.0, }, + {"InitialQP", &cfgparams.SeinitialQP, 0, 0.0, 3, (double) MIN_QP, (double) MAX_QP, }, + {"BasicUnit", &cfgparams.basicunit, 0, 0.0, 2, 0.0, 0.0, }, + {"ChannelType", &cfgparams.channel_type, 0, 0.0, 1, 0.0, 1.0, }, + {"RCUpdateMode", &cfgparams.RCUpdateMode, 0, 0.0, 1, 0.0, 4.0, }, + {"RCISliceBitRatio", &cfgparams.RCISliceBitRatio, 2, 1.0, 1, 0.0, 20.0, }, + {"RCBSliceBitRatio0", &cfgparams.RCBSliceBitRatio[0], 2, 0.5, 1, 0.0, 20.0, }, + {"RCBSliceBitRatio1", &cfgparams.RCBSliceBitRatio[1], 2, 0.25, 1, 0.0, 20.0, }, + {"RCBSliceBitRatio2", &cfgparams.RCBSliceBitRatio[2], 2, 0.25, 1, 0.0, 20.0, }, + {"RCBSliceBitRatio3", &cfgparams.RCBSliceBitRatio[3], 2, 0.25, 1, 0.0, 20.0, }, + {"RCBSliceBitRatio4", &cfgparams.RCBSliceBitRatio[4], 2, 0.25, 1, 0.0, 20.0, }, + {"RCBoverPRatio", &cfgparams.RCBoverPRatio, 2, 0.45, 1, 0.0, 1000.0, }, + {"RCIoverPRatio", &cfgparams.RCIoverPRatio, 2, 3.80, 1, 0.0, 1000.0, }, + {"RCMinQPPSlice", &cfgparams.RCMinQP[P_SLICE], 0, (double) MIN_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMaxQPPSlice", &cfgparams.RCMaxQP[P_SLICE], 0, (double) MAX_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMinQPBSlice", &cfgparams.RCMinQP[B_SLICE], 0, (double) MIN_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMaxQPBSlice", &cfgparams.RCMaxQP[B_SLICE], 0, (double) MAX_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMinQPISlice", &cfgparams.RCMinQP[I_SLICE], 0, (double) MIN_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMaxQPISlice", &cfgparams.RCMaxQP[I_SLICE], 0, (double) MAX_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMinQPSPSlice", &cfgparams.RCMinQP[SP_SLICE], 0, (double) MIN_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMaxQPSPSlice", &cfgparams.RCMaxQP[SP_SLICE], 0, (double) MAX_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMinQPSISlice", &cfgparams.RCMinQP[SI_SLICE], 0, (double) MIN_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMaxQPSISlice", &cfgparams.RCMaxQP[SI_SLICE], 0, (double) MAX_QP, 3, (double) MIN_QP, (double) MAX_QP, }, + {"RCMaxQPChange", &cfgparams.RCMaxQPChange, 0, 4.0, 1, 0.0, 51.0, }, + + // Q_Matrix + {"QmatrixFile", &cfgparams.QmatrixFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"ScalingMatrixPresentFlag", &cfgparams.ScalingMatrixPresentFlag, 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag0", &cfgparams.ScalingListPresentFlag[0], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag1", &cfgparams.ScalingListPresentFlag[1], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag2", &cfgparams.ScalingListPresentFlag[2], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag3", &cfgparams.ScalingListPresentFlag[3], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag4", &cfgparams.ScalingListPresentFlag[4], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag5", &cfgparams.ScalingListPresentFlag[5], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag6", &cfgparams.ScalingListPresentFlag[6], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag7", &cfgparams.ScalingListPresentFlag[7], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag8", &cfgparams.ScalingListPresentFlag[8], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag9", &cfgparams.ScalingListPresentFlag[9], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag10", &cfgparams.ScalingListPresentFlag[10], 0, 0.0, 1, 0.0, 3.0, }, + {"ScalingListPresentFlag11", &cfgparams.ScalingListPresentFlag[11], 0, 0.0, 1, 0.0, 3.0, }, + + // Chroma QP Offset + {"ChromaQPOffset", &cfgparams.chroma_qp_index_offset, 0, 0.0, 1,-51.0, 51.0, }, + + // Fidelity Range Extensions +// New Input bit-depth entries + {"SourceBitDepthLuma", &cfgparams.source.bit_depth[0], 0, 8.0, 1, 8.0, 14.0, }, + {"SourceBitDepthChroma", &cfgparams.source.bit_depth[1], 0, 8.0, 1, 8.0, 14.0, }, + {"SourceBitDepthRescale", &cfgparams.src_BitDepthRescale, 0, 0.0, 1, 0.0, 1.0, }, +// Old variables replaced from BitDepthLuma and BitDepthChroma. Considered only if SourceBitDepthRescale is 1. + {"OutputBitDepthLuma", &cfgparams.output.bit_depth[0], 0, 8.0, 1, 8.0, 14.0, }, + {"OutputBitDepthChroma", &cfgparams.output.bit_depth[1], 0, 8.0, 1, 8.0, 14.0, }, + + {"YUVFormat", &cfgparams.yuv_format, 0, 1.0, 1, 0.0, 3.0, }, + {"RGBInput", &cfgparams.source.color_model, 0, 0.0, 1, 0.0, 1.0, }, + {"PixelFormat", &cfgparams.source.pixel_format, 0, 0.0, 1, 0.0, 4.0, }, + {"Interleaved", &cfgparams.input_file1.is_interleaved , 0, 0.0, 1, 0.0, 1.0, }, + {"StandardRange", &cfgparams.stdRange, 0, 0.0, 1, 0.0, 1.0, }, + {"VideoCode", &cfgparams.videoCode, 0, 1.0, 1, 0.0, 8.0, }, + {"CbQPOffset", &cfgparams.cb_qp_index_offset, 0, 0.0, 1,-51.0, 51.0, }, + {"CrQPOffset", &cfgparams.cr_qp_index_offset, 0, 0.0, 1,-51.0, 51.0, }, + {"Transform8x8Mode", &cfgparams.Transform8x8Mode, 0, 0.0, 1, 0.0, 2.0, }, + // Lossless Coding + {"LosslessCoding", &cfgparams.LosslessCoding, 0, 0.0, 1, 0.0, 1.0, }, + + // Explicit Lambda Parameters for RDO + {"UseExplicitLambdaParams", &cfgparams.UseExplicitLambdaParams, 0, 0.0, 1, 0.0, 3.0, }, + {"UpdateLambdaChromaME", &cfgparams.UpdateLambdaChromaME, 0, 0.0, 1, 0.0, 3.0, }, + {"FixedLambdaPSlice", &cfgparams.FixedLambda[P_SLICE], 2, 0.1, 2, 0.0, 0.0, }, + {"FixedLambdaBSlice", &cfgparams.FixedLambda[B_SLICE], 2, 0.1, 2, 0.0, 0.0, }, + {"FixedLambdaISlice", &cfgparams.FixedLambda[I_SLICE], 2, 0.1, 2, 0.0, 0.0, }, + {"FixedLambdaSPSlice", &cfgparams.FixedLambda[SP_SLICE], 2, 0.1, 2, 0.0, 0.0, }, + {"FixedLambdaSISlice", &cfgparams.FixedLambda[SI_SLICE], 2, 0.1, 2, 0.0, 0.0, }, + {"FixedLambdaRefBSlice", &cfgparams.FixedLambda[5], 2, 0.1, 2, 0.0, 0.0, }, + {"LambdaWeightPSlice", &cfgparams.LambdaWeight[P_SLICE], 2, 0.68, 2, 0.0, 0.0, }, + {"LambdaWeightBSlice", &cfgparams.LambdaWeight[B_SLICE], 2, 2.00, 2, 0.0, 0.0, }, + {"LambdaWeightISlice", &cfgparams.LambdaWeight[I_SLICE], 2, 0.65, 2, 0.0, 0.0, }, + {"LambdaWeightSPSlice", &cfgparams.LambdaWeight[SP_SLICE], 2, 1.50, 2, 0.0, 0.0, }, + {"LambdaWeightSISlice", &cfgparams.LambdaWeight[SI_SLICE], 2, 0.65, 2, 0.0, 0.0, }, + {"LambdaWeightRefBSlice", &cfgparams.LambdaWeight[5], 2, 1.50, 2, 0.0, 0.0, }, + // Usage of explicit "initial" offsets for quantization + {"QOffsetMatrixFile", &cfgparams.QOffsetMatrixFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"OffsetMatrixPresentFlag", &cfgparams.OffsetMatrixPresentFlag, 0, 0.0, 1, 0.0, 1.0, }, + + // Adaptive rounding technique based on JVT-N011 + {"AdaptiveRounding", &cfgparams.AdaptiveRounding, 0, 0.0, 1, 0.0, 1.0, }, + {"AdaptRoundingFixed", &cfgparams.AdaptRoundingFixed, 0, 1.0, 1, 0.0, 1.0, }, + {"AdaptRndPeriod", &cfgparams.AdaptRndPeriod, 0, 16.0, 2, 1.0, 0.0, }, + {"AdaptRndChroma", &cfgparams.AdaptRndChroma, 0, 0.0, 1, 0.0, 1.0, }, + {"AdaptRndWFactorIRef", &cfgparams.AdaptRndWFactor[1][I_SLICE], 0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndWFactorPRef", &cfgparams.AdaptRndWFactor[1][P_SLICE], 0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndWFactorBRef", &cfgparams.AdaptRndWFactor[1][B_SLICE], 0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndWFactorINRef", &cfgparams.AdaptRndWFactor[0][I_SLICE], 0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndWFactorPNRef", &cfgparams.AdaptRndWFactor[0][P_SLICE], 0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndWFactorBNRef", &cfgparams.AdaptRndWFactor[0][B_SLICE], 0, 4.0, 1, 0.0, 4096.0, }, + + {"AdaptRndCrWFactorIRef", &cfgparams.AdaptRndCrWFactor[1][I_SLICE],0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndCrWFactorPRef", &cfgparams.AdaptRndCrWFactor[1][P_SLICE],0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndCrWFactorBRef", &cfgparams.AdaptRndCrWFactor[1][B_SLICE],0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndCrWFactorINRef", &cfgparams.AdaptRndCrWFactor[0][I_SLICE],0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndCrWFactorPNRef", &cfgparams.AdaptRndCrWFactor[0][P_SLICE],0, 4.0, 1, 0.0, 4096.0, }, + {"AdaptRndCrWFactorBNRef", &cfgparams.AdaptRndCrWFactor[0][B_SLICE],0, 4.0, 1, 0.0, 4096.0, }, + + // Prediction Structure + {"PreferDispOrder", &cfgparams.PreferDispOrder, 0, 1.0, 1, 0.0, 1.0, }, + {"PreferPowerOfTwo", &cfgparams.PreferPowerOfTwo, 0, 0.0, 1, 0.0, 1.0, }, + {"FrmStructBufferLength", &cfgparams.FrmStructBufferLength, 0, 16.0, 1, 1.0, 128.0, }, + + // Fast Mode Decision + {"EarlySkipEnable", &cfgparams.EarlySkipEnable, 0, 0.0, 1, 0.0, 1.0, }, + {"SelectiveIntraEnable", &cfgparams.SelectiveIntraEnable, 0, 0.0, 1, 0.0, 1.0, }, + + //================================ + // Motion Estimation (ME) Parameters + //================================ + {"RestrictSearchRange", &cfgparams.full_search, 0, 2.0, 1, 0.0, 2.0, }, + // ME Limits + {"UseMVLimits", &cfgparams.UseMVLimits, 0, 0.0, 1, 0.0, 1.0, }, + {"SetMVXLimit", &cfgparams.SetMVXLimit, 0, 0.0, 1, 0.0, 2048.0, }, + {"SetMVYLimit", &cfgparams.SetMVYLimit, 0, 0.0, 1, 0.0, 512.0, }, + // Fast ME enable + {"SearchMode", &cfgparams.SearchMode[0], 0, 0.0, 1, -1.0, 3.0, }, + // Parameters for UMHEX control + {"UMHexDSR", &cfgparams.UMHexDSR, 0, 1.0, 1, 0.0, 1.0, }, + {"UMHexScale", &cfgparams.UMHexScale, 0, 1.0, 0, 0.0, 0.0, }, + // Parameters for EPZS control + {"EPZSPattern", &cfgparams.EPZSPattern, 0, 2.0, 1, 0.0, 5.0, }, + {"EPZSDualRefinement", &cfgparams.EPZSDual, 0, 3.0, 1, 0.0, 6.0, }, + {"EPZSFixedPredictors", &cfgparams.EPZSFixed, 0, 3.0, 1, 0.0, 3.0, }, +#if (MVC_EXTENSION_ENABLE) + {"EPZSTemporal", &cfgparams.EPZSTemporal[0], 0, 1.0, 1, 0.0, 1.0, }, +#else + {"EPZSTemporal", &cfgparams.EPZSTemporal, 0, 1.0, 1, 0.0, 1.0, }, +#endif + {"EPZSSpatialMem", &cfgparams.EPZSSpatialMem, 0, 1.0, 1, 0.0, 1.0, }, + {"EPZSBlockType", &cfgparams.EPZSBlockType, 0, 1.0, 1, 0.0, 1.0, }, +#if (MVC_EXTENSION_ENABLE) + {"EPZSMinThresScale", &cfgparams.EPZSMinThresScale[0], 0, 0.0, 0, 0.0, 0.0, }, + {"EPZSMaxThresScale", &cfgparams.EPZSMaxThresScale[0], 0, 2.0, 0, 0.0, 0.0, }, + {"EPZSMedThresScale", &cfgparams.EPZSMedThresScale[0], 0, 1.0, 0, 0.0, 0.0, }, + {"EPZSSubPelThresScale", &cfgparams.EPZSSubPelThresScale[0], 0, 1.0, 0, 0.0, 0.0, }, +#else + {"EPZSMinThresScale", &cfgparams.EPZSMinThresScale, 0, 0.0, 0, 0.0, 0.0, }, + {"EPZSMaxThresScale", &cfgparams.EPZSMaxThresScale, 0, 2.0, 0, 0.0, 0.0, }, + {"EPZSMedThresScale", &cfgparams.EPZSMedThresScale, 0, 1.0, 0, 0.0, 0.0, }, + {"EPZSSubPelThresScale", &cfgparams.EPZSSubPelThresScale, 0, 2.0, 0, 0.0, 0.0, }, +#endif + {"EPZSSubPelME", &cfgparams.EPZSSubPelME, 0, 1.0, 1, 0.0, 2.0, }, + {"EPZSSubPelMEBiPred", &cfgparams.EPZSSubPelMEBiPred, 0, 1.0, 1, 0.0, 2.0, }, + {"EPZSSubPelGrid", &cfgparams.EPZSSubPelGrid, 0, 0.0, 1, 0.0, 1.0, }, + {"EPZSSubPelThresScale", &cfgparams.EPZSSubPelThresScale, 0, 1.0, 0, 0.0, 0.0, }, + {"DisableMEPrediction", &cfgparams.DisableMEPrediction, 0, 0.0, 1, 0.0, 1.0, }, + // Tone mapping SEI cfg file + {"ToneMappingSEIPresentFlag",&cfgparams.ToneMappingSEIPresentFlag, 0, 0.0, 1, 0.0, 1.0, }, + {"ToneMappingFile", &cfgparams.ToneMappingFile, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + + {"SeparateColourPlane", &cfgparams.separate_colour_plane_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"WeightY", &cfgparams.WeightY, 2, 1.00, 1, 0.0, 4.0, }, + {"WeightCb", &cfgparams.WeightCb, 2, 1.00, 1, 0.0, 4.0, }, + {"WeightCr", &cfgparams.WeightCr, 2, 1.00, 1, 0.0, 4.0, }, + {"WPMCPrecision", &cfgparams.WPMCPrecision, 0, 0.0, 1, 0.0, 2.0, }, + {"WPMCPrecFullRef", &cfgparams.WPMCPrecFullRef, 0, 0.0, 1, 0.0, 1.0, }, + {"WPMCPrecBSlice", &cfgparams.WPMCPrecBSlice, 0, 1.0, 1, 0.0, 2.0, }, + {"RCCpbSize", &cfgparams.rc_cpb_size, 0,1024.0, 2, 0.0, 0.0, }, + {"MinIDRDistance", &cfgparams.MinIDRDistance, 0, 10.0, 1, 0.0, 128.0, }, + // Trellis based quantization + {"UseRDOQuant", &cfgparams.UseRDOQuant, 0, 0.0, 1, 0.0, 1.0, }, + {"RDOQ_DC", &cfgparams.RDOQ_DC, 0, 1.0, 1, 0.0, 1.0, }, + {"RDOQ_CR", &cfgparams.RDOQ_CR, 0, 1.0, 1, 0.0, 1.0, }, + {"RDOQ_DC_CR", &cfgparams.RDOQ_DC_CR, 0, 1.0, 1, 0.0, 1.0, }, + {"RDOQ_QP_Num", &cfgparams.RDOQ_QP_Num, 0, 1.0, 1, 1.0, 9.0, }, + {"RDOQ_CP_Mode", &cfgparams.RDOQ_CP_Mode, 0, 0.0, 1, 0.0, 1.0, }, + {"RDOQ_CP_MV", &cfgparams.RDOQ_CP_MV, 0, 0.0, 1, 0.0, 1.0, }, + {"RDOQ_Fast", &cfgparams.RDOQ_Fast, 0, 0.0, 1, 0.0, 1.0, }, + // VUI parameters + {"GenerateSEIMessage", &cfgparams.GenerateSEIMessage, 0, 0.0, 1, 0.0, 1.0, }, + {"EnableVUISupport", &cfgparams.EnableVUISupport, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_aspect_ratio_info_present_flag", &cfgparams.VUI.aspect_ratio_info_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_aspect_ratio_idc", &cfgparams.VUI.aspect_ratio_idc, 0, 0.0, 1, 0.0, 255.0, }, + {"VUI_sar_width", &cfgparams.VUI.sar_width, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_sar_height", &cfgparams.VUI.sar_height, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_overscan_info_present_flag", &cfgparams.VUI.overscan_info_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_overscan_appropriate_flag", &cfgparams.VUI.overscan_appropriate_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_video_signal_type_present_flag", &cfgparams.VUI.video_signal_type_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_video_format", &cfgparams.VUI.video_format, 0, 5.0, 1, 0.0, 7.0, }, + {"VUI_video_full_range_flag", &cfgparams.VUI.video_full_range_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_colour_description_present_flag", &cfgparams.VUI.colour_description_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_colour_primaries", &cfgparams.VUI.colour_primaries, 0, 2.0, 1, 0.0, 255.0, }, + {"VUI_transfer_characteristics", &cfgparams.VUI.transfer_characteristics, 0, 2.0, 1, 0.0, 255.0, }, + {"VUI_matrix_coefficients", &cfgparams.VUI.matrix_coefficients, 0, 2.0, 1, 0.0, 255.0, }, + {"VUI_chroma_location_info_present_flag", &cfgparams.VUI.chroma_location_info_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_chroma_sample_loc_type_top_field", &cfgparams.VUI.chroma_sample_loc_type_top_field, 0, 0.0, 1, 0.0, 5.0, }, + {"VUI_chroma_sample_loc_type_bottom_field",&cfgparams.VUI.chroma_sample_loc_type_bottom_field,0, 0.0, 1, 0.0, 5.0, }, + {"VUI_timing_info_present_flag", &cfgparams.VUI.timing_info_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_num_units_in_tick", &cfgparams.VUI.num_units_in_tick, 0,1000.0, 2, 0.0, 0.0, }, + {"VUI_time_scale", &cfgparams.VUI.time_scale, 0,60000.0, 2, 0.0, 0.0, }, + {"VUI_fixed_frame_rate_flag", &cfgparams.VUI.fixed_frame_rate_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_nal_hrd_parameters_present_flag", &cfgparams.VUI.nal_hrd_parameters_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_nal_cpb_cnt_minus1", &cfgparams.VUI.nal_cpb_cnt_minus1, 0, 0.0, 1, 0.0, 31.0, }, + {"VUI_nal_bit_rate_scale", &cfgparams.VUI.nal_bit_rate_scale, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_nal_cpb_size_scale", &cfgparams.VUI.nal_cpb_size_scale, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_nal_bit_rate_value_minus1", &cfgparams.VUI.nal_bit_rate_value_minus1, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_nal_cpb_size_value_minus1", &cfgparams.VUI.nal_cpb_size_value_minus1, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_nal_vbr_cbr_flag", &cfgparams.VUI.nal_vbr_cbr_flag, 0, 1.0, 1, 0.0, 1.0, }, + {"VUI_nal_initial_cpb_removal_delay_length_minus1", &cfgparams.VUI.nal_initial_cpb_removal_delay_length_minus1, 0, 23.0, 2, 0.0, 0.0, }, + {"VUI_nal_cpb_removal_delay_length_minus1",&cfgparams.VUI.nal_cpb_removal_delay_length_minus1,0, 23.0, 2, 0.0, 0.0, }, + {"VUI_nal_dpb_output_delay_length_minus1", &cfgparams.VUI.nal_dpb_output_delay_length_minus1, 0, 23.0, 2, 0.0, 0.0, }, + {"VUI_nal_time_offset_length", &cfgparams.VUI.nal_time_offset_length, 0, 24.0, 2, 0.0, 0.0, }, + {"VUI_vcl_hrd_parameters_present_flag", &cfgparams.VUI.vcl_hrd_parameters_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_vcl_cpb_cnt_minus1", &cfgparams.VUI.vcl_cpb_cnt_minus1, 0, 0.0, 1, 0.0, 31.0, }, + {"VUI_vcl_bit_rate_scale", &cfgparams.VUI.vcl_bit_rate_scale, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_vcl_cpb_size_scale", &cfgparams.VUI.vcl_cpb_size_scale, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_vcl_bit_rate_value_minus1", &cfgparams.VUI.vcl_bit_rate_value_minus1, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_vcl_cpb_size_value_minus1", &cfgparams.VUI.vcl_cpb_size_value_minus1, 0, 0.0, 2, 0.0, 0.0, }, + {"VUI_vcl_vbr_cbr_flag", &cfgparams.VUI.vcl_vbr_cbr_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_vcl_initial_cpb_removal_delay_length_minus1", &cfgparams.VUI.vcl_initial_cpb_removal_delay_length_minus1, 0, 23.0, 2, 0.0, 0.0, }, + {"VUI_vcl_cpb_removal_delay_length_minus1",&cfgparams.VUI.vcl_cpb_removal_delay_length_minus1,0, 23.0, 2, 0.0, 0.0, }, + {"VUI_vcl_dpb_output_delay_length_minus1", &cfgparams.VUI.vcl_dpb_output_delay_length_minus1, 0, 23.0, 2, 0.0, 0.0, }, + {"VUI_vcl_time_offset_length", &cfgparams.VUI.vcl_time_offset_length, 0, 24.0, 2, 0.0, 0.0, }, + {"VUI_low_delay_hrd_flag", &cfgparams.VUI.low_delay_hrd_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_pic_struct_present_flag", &cfgparams.VUI.pic_struct_present_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_bitstream_restriction_flag", &cfgparams.VUI.bitstream_restriction_flag, 0, 0.0, 1, 0.0, 1.0, }, + {"VUI_motion_vectors_over_pic_boundaries_flag", &cfgparams.VUI.motion_vectors_over_pic_boundaries_flag, 0, 1.0, 1, 0.0, 1.0, }, + {"VUI_max_bytes_per_pic_denom", &cfgparams.VUI.max_bytes_per_pic_denom, 0, 2.0, 1, 0.0, 16.0, }, + {"VUI_max_bits_per_mb_denom", &cfgparams.VUI.max_bits_per_mb_denom, 0, 1.0, 1, 0.0, 16.0, }, + {"VUI_log2_max_mv_length_vertical", &cfgparams.VUI.log2_max_mv_length_vertical, 0, 16.0, 1, 0.0, 16.0, }, + {"VUI_log2_max_mv_length_horizontal", &cfgparams.VUI.log2_max_mv_length_horizontal, 0, 16.0, 1, 0.0, 16.0, }, + {"VUI_num_reorder_frames", &cfgparams.VUI.num_reorder_frames, 0, 16.0, 1, 0.0, 16.0, }, + {"VUI_max_dec_frame_buffering", &cfgparams.VUI.max_dec_frame_buffering, 0, 16.0, 1, 0.0, 16.0, }, + {"SEIMessageText", &cfgparams.SEIMessageText, 1, 0.0, 0, 0.0, 0.0, INPUT_TEXT_SIZE,}, + // {NAMEinConfigFile, &cfgparams.VariableName, Type,InitialValue, LimitType, MinLimit, MaxLimit, CharSize} +#if B0_MORE_REF + {"BLevel0MoreRef", &cfgparams.BLevel0MoreRef, 0, 1.0, 1, 0.0, 1.0, }, +#endif +#if KEEP_B_SAME_LIST + {"BIdenticalList", &cfgparams.BIdenticalList, 0, 1.0, 1, 0.0, 2.0, }, +#endif +#if CRA + {"CRA", &cfgparams.useCRA, 0, 1.0, 1, 0.0, 1.0, }, +#endif +#if HM50_LIKE_MMCO + {"HM50RefStructure", &cfgparams.HM50LikeMMCO, 0, 1.0, 1, 0.0, 1.0, }, +#endif +#if LD_REF_SETTING + {"LDRefSetting", &cfgparams.useF701RefForLD, 0, 1.0, 1, 0.0, 1.0, }, +#endif + {NULL, NULL, -1, 0.0, 0, 0.0, 0.0, }, +}; + + +#if (MVC_EXTENSION_ENABLE) +Mapping MapView1[] = { + //! Edited by Joao Carreira + {"TranscodeFileAux", &cfgparams.TranscodeFile[1], 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE }, + + {"InputFile", &cfgparams.input_file2.fname, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"ReconFile", &cfgparams.ReconFile2, 1, 0.0, 0, 0.0, 0.0, FILE_NAME_SIZE, }, + {"SearchRange", &cfgparams.search_range[1], 0, 16.0, 2, 0.0, 0.0, }, + {"DisableSubpelME", &cfgparams.DisableSubpelME[1], 0, 0.0, 1, 0.0, 1.0, }, + {"DisableIntraInInter", &cfgparams.DisableIntraInInter[1], 0, 0.0, 1, 0.0, 1.0, }, + {"MVCInterViewReorder", &cfgparams.MVCInterViewReorder, 0, 0.0, 1, 0.0, 2.0, }, + //! Edited by Joao Carreira + {"PFramesOnlyView1", &cfgparams.PFramesOnlyView1, 0, 0.0, 1, 0.0, 2.0, }, + {"Force_InterViewPred", &cfgparams.Force_InterView, 0, 0.0, 1, 0.0, 2.0, }, + {"Force_BiPredMultiview", &cfgparams.Force_BiPredMultiview, 0, 0.0, 1, 0.0, 2.0, }, + + {"MVCFlipViews", &cfgparams.MVCFlipViews, 0, 0.0, 1, 0.0, 1.0, }, + {"QPOffset", &cfgparams.View1QPOffset, 0, 0.0, 0, (double) -MAX_QP, (double) MAX_QP, }, + {"MVCInterViewForceB", &cfgparams.MVCInterViewForceB, 0, 0.0, 1, 0.0, 1.0, }, + {"MVCEnableInterViewFlag", &cfgparams.enable_inter_view_flag, 0, 1.0, 1, 0.0, 1.0, }, + {"SepViewInterSearch", &cfgparams.SepViewInterSearch, 0, 0.0, 1, 0.0, 1.0, }, + {"NoResidueRDO", &cfgparams.View1NoResidueRDO, 0, 1.0, 1, 0.0, 1.0, }, + {"PList0References", &cfgparams.P_List0_refs[1], 0, 0.0, 1, 0.0, 16.0, }, + {"BList0References", &cfgparams.B_List0_refs[1], 0, 0.0, 1, 0.0, 16.0, }, + {"BList1References", &cfgparams.B_List1_refs[1], 0, 1.0, 1, 0.0, 16.0, }, + {"LambdaMultiplier", &cfgparams.enh_layer_lambda_multiplier, 2, 1.0, 2, 0.0, 0.0, }, + {"MELambdaMultiplier", &cfgparams.enh_layer_me_lambda_multiplier, 2, 1.0, 2, 0.0, 0.0, }, + {"PSliceSkip", &cfgparams.InterSearch[1][0][0], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch16x16", &cfgparams.InterSearch[1][0][1], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch16x8", &cfgparams.InterSearch[1][0][2], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch8x16", &cfgparams.InterSearch[1][0][3], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch8x8", &cfgparams.InterSearch[1][0][4], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch8x4", &cfgparams.InterSearch[1][0][5], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch4x8", &cfgparams.InterSearch[1][0][6], 0, 1.0, 1, 0.0, 1.0, }, + {"PSliceSearch4x4", &cfgparams.InterSearch[1][0][7], 0, 1.0, 1, 0.0, 1.0, }, + // B slice partition modes. + {"BSliceDirect", &cfgparams.InterSearch[1][1][0], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch16x16", &cfgparams.InterSearch[1][1][1], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch16x8", &cfgparams.InterSearch[1][1][2], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch8x16", &cfgparams.InterSearch[1][1][3], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch8x8", &cfgparams.InterSearch[1][1][4], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch8x4", &cfgparams.InterSearch[1][1][5], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch4x8", &cfgparams.InterSearch[1][1][6], 0, 1.0, 1, 0.0, 1.0, }, + {"BSliceSearch4x4", &cfgparams.InterSearch[1][1][7], 0, 1.0, 1, 0.0, 1.0, }, + {"BiPredMESearchRange", &cfgparams.BiPredMESearchRange[1], 0, 8.0, 2, 0.0, 0.0, }, + {"MDReference", &cfgparams.MDReference[1], 0, 0.0, 1, 0.0, 1.0, }, + {"DFDisableRefISlice", &cfgparams.EnhLayerDFDisableIdc[1][I_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefISlice", &cfgparams.EnhLayerDFDisableIdc[0][I_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefPSlice", &cfgparams.EnhLayerDFDisableIdc[1][P_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefPSlice", &cfgparams.EnhLayerDFDisableIdc[0][P_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefBSlice", &cfgparams.EnhLayerDFDisableIdc[1][B_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefBSlice", &cfgparams.EnhLayerDFDisableIdc[0][B_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefSPSlice", &cfgparams.EnhLayerDFDisableIdc[1][SP_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefSPSlice", &cfgparams.EnhLayerDFDisableIdc[0][SP_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableRefSISlice", &cfgparams.EnhLayerDFDisableIdc[1][SI_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFDisableNRefSISlice", &cfgparams.EnhLayerDFDisableIdc[0][SI_SLICE], 0, 0.0, 1, 0.0, 2.0, }, + {"DFAlphaRefISlice", &cfgparams.EnhLayerDFAlpha[1][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefISlice", &cfgparams.EnhLayerDFAlpha[0][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefPSlice", &cfgparams.EnhLayerDFAlpha[1][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefPSlice", &cfgparams.EnhLayerDFAlpha[0][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefBSlice", &cfgparams.EnhLayerDFAlpha[1][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefBSlice", &cfgparams.EnhLayerDFAlpha[0][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefSPSlice", &cfgparams.EnhLayerDFAlpha[1][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefSPSlice", &cfgparams.EnhLayerDFAlpha[0][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaRefSISlice", &cfgparams.EnhLayerDFAlpha[1][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFAlphaNRefSISlice", &cfgparams.EnhLayerDFAlpha[0][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefISlice", &cfgparams.EnhLayerDFBeta[1][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefISlice", &cfgparams.EnhLayerDFBeta[0][I_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefPSlice", &cfgparams.EnhLayerDFBeta[1][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefPSlice", &cfgparams.EnhLayerDFBeta[0][P_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefBSlice", &cfgparams.EnhLayerDFBeta[1][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefBSlice", &cfgparams.EnhLayerDFBeta[0][B_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefSPSlice", &cfgparams.EnhLayerDFBeta[1][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefSPSlice", &cfgparams.EnhLayerDFBeta[0][SP_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaRefSISlice", &cfgparams.EnhLayerDFBeta[1][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"DFBetaNRefSISlice", &cfgparams.EnhLayerDFBeta[0][SI_SLICE], 0, 0.0, 1, -6.0, 6.0, }, + {"SearchMode", &cfgparams.SearchMode[1], 0, 0.0, 1, -1.0, 3.0, }, + {"EPZSTemporal", &cfgparams.EPZSTemporal[1], 0, 0.0, 1, 0.0, 1.0, }, + {"EnableEPZSScalers", &cfgparams.EnableEnhLayerEPZSScalers, 0, 0.0, 1, 0.0, 1.0, }, + {"EPZSMinThresScale", &cfgparams.EPZSMinThresScale[1], 0, 0.0, 0, 0.0, 0.0, }, + {"EPZSMaxThresScale", &cfgparams.EPZSMaxThresScale[1], 0, 2.0, 0, 0.0, 0.0, }, + {"EPZSMedThresScale", &cfgparams.EPZSMedThresScale[1], 0, 1.0, 0, 0.0, 0.0, }, + {"EPZSSubPelThresScale", &cfgparams.EPZSSubPelThresScale[1], 0, 1.0, 0, 0.0, 0.0, }, + {NULL, NULL, -1, 0.0, 0, 0.0, 0.0, }, +}; +#endif + +#endif + +#ifndef INCLUDED_BY_CONFIGFILE_C +extern Mapping Map[]; +extern Mapping MapView1[]; +#endif + +extern void Configure (VideoParameters *p_Vid, InputParameters *p_Inp, int ac, char *av[]); +extern void get_number_of_frames (InputParameters *p_Inp, VideoDataFile *input_file); +extern void read_slice_group_info(VideoParameters *p_Vid, InputParameters *p_Inp); + +#endif + diff --git a/lencod/inc/conformance.h b/lencod/inc/conformance.h new file mode 100644 index 0000000..1e25565 --- /dev/null +++ b/lencod/inc/conformance.h @@ -0,0 +1,32 @@ + +/*! + ************************************************************************ + * \file conformance.h + * + * \brief + * Level & Profile Related definitions + * + * \author + * Alexis Michael Tourapis \n + * + ************************************************************************ + */ + +#ifndef _CONFORMANCE_H_ +#define _CONFORMANCE_H_ + +extern void profile_check (InputParameters *p_Inp); +extern void level_check (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void update_mv_limits (VideoParameters *p_Vid, byte is_field); +extern void clip_mv_range (VideoParameters *p_Vid, int search_range, MotionVector *mv, int res); +extern int out_of_bounds_mvs (VideoParameters *p_Vid, const MotionVector *mv); +extern void test_clip_mvs (VideoParameters *p_Vid, MotionVector *mv, Boolean write_mb); +extern Boolean CheckPredictionParams(Macroblock *currMB, Block8x8Info *b8x8info, int mode); + +extern unsigned int getMaxMBPS(unsigned int levelIdc); +extern unsigned int getMinCR (unsigned int levelIdc); +extern unsigned int getMaxBR (unsigned int levelIdc); +extern unsigned int getMaxCPB (unsigned int levelIdc); + +#endif + diff --git a/lencod/inc/context_ini.h b/lencod/inc/context_ini.h new file mode 100644 index 0000000..e624711 --- /dev/null +++ b/lencod/inc/context_ini.h @@ -0,0 +1,27 @@ + +/*! + ************************************************************************************* + * \file context_ini.h + * + * \brief + * CABAC context initializations + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Heiko Schwarz + ************************************************************************************** + */ + +#ifndef _CONTEXT_INI_ +#define _CONTEXT_INI_ + +extern void create_context_memory (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void free_context_memory (VideoParameters *p_Vid); +extern void update_field_frame_contexts (VideoParameters *p_Vid, int); +extern void SetCtxModelNumber (Slice *currSlice); +extern void init_contexts (Slice *currSlice); +extern void store_contexts (Slice *currSlice); + +#endif + diff --git a/lencod/inc/contributors.h b/lencod/inc/contributors.h new file mode 100644 index 0000000..8f83ce4 --- /dev/null +++ b/lencod/inc/contributors.h @@ -0,0 +1,217 @@ + +/*! \file + * contributors.h + * \brief + * List of contributors and copyright information. + * + * \par Copyright statements + \verbatim + MPEG-4 AVC/H.264 JM coder/decoder + + Copyright (C) 2000/2009 by + Apple Computer, Inc. + Dolby Laboratories, Inc., USA + Ericsson Radio Systems, Sweden + Fraunhofer-Institute for Telecommunications Heinrich-Hertz-Institut (HHI), Germany + LSI Logic, Canada + Microsoft Corp., USA + Motorola Inc., USA + Nokia Corporation, Finland + Nokia Inc., USA + RealNetworks, Inc., USA + Sejong Univ., Digital Media System Lab., Korea + Siemens AG, Germany + Telenor Broadband Services, Norway + TELES AG, Germany + Thomson, Inc., USA + University of Hannover, Institut of Communication Theory and Signal Processing,Germany + Videolocus, Canada + + \endverbatim + \par Full Contact Information + \verbatim + + Lowell Winger + Guy Côté + Michael Gallant + VideoLocus Inc. + 97 Randall Dr. + Waterloo, ON, Canada N2V1C5 + + Inge Lille-Langøy + Telenor Broadband Services + P.O.Box 6914 St.Olavs plass + N-0130 Oslo, Norway + + Rickard Sjoberg + Ericsson Radio Systems + KI/ERA/T/VV + 164 80 Stockholm, Sweden + + Stephan Wenger + TU Berlin / TELES AG + Sekr. FR 6-3 + Franklinstr. 28-29 + D-10587 Berlin, Germany + + Jani Lainema + Ragip Kurceren + Nokia Inc. / Nokia Research Center + 6000 Connection Drive + Irving, TX 75039, USA + + Miska M. Hannuksela + Nokia Corporation / Nokia Mobile Phones + P.O. Box 88 + 33721 Tampere, Finland + + Sebastian Purreiter + Siemens AG + ICM MD MP RD MCH 83 + P.O.Box 80 17 07 + D-81617 Munich, Germany + + Thomas Wedi + University of Hannover + Institut of Communication Theory and Signal Processing + Appelstr. 9a + 30167 Hannover + + Thomas Stockhammer + Tobias Oelbaum (TO) + Institute for Communications Engineering + Munich University of Technology + 80290 Munich + Germany + + Yann Le Maguet + Philips Research France + + Dong Tian + Ye-Kui Wang + Tampere University of Technology + Tampere International Center for Signal Processing + 33720 Tampere, Finland + + Karsten Suehring + Heiko Schwarz + Detlev Marpe + Guido Heising + Fraunhofer-Institute for Telecommunications + Heinrich-Hertz-Institut (HHI) + Einsteinufer 37 + 10587 Berlin + Germany + + Limin Wang + Krit Panusopone + Rajeev Gandhi + Yue Yu + Motorola Inc. + 6450 Sequence Drive + San Diego, CA 92121 USA + + Feng Wu + Xiaoyan Sun + Microsoft Research Asia + 3/F, Beijing Sigma Center + No.49, Zhichun Road, Hai Dian District, + Beijing China 100080 + + Mathias Wien + Achim Dahlhoff + Institut und Lehrstuhl für Nachrichtentechnik + RWTH Aachen University + 52072 Aachen + Germany + + Yoshihiro Kikuchi + Takeshi Chujoh + Toshiba Corporation + Research and Development Center + Kawasaki 212-8582, Japan + + Shinya Kadono + Matsushita Electric Industrial Co., Ltd. + 1006 Kadoma, Kadoma + Osaka 663-8113, Japan + + Dzung Hoang + 10533 Roy Butler Dr. + Austin, TX 78717 + + Eric Viscito + eV Consulting + 52 Tracy Ln + Shelburne, VT 05482 USA + + Dzung Hoang + Xilient Inc. + 10181 Bubb Rd. + Cupertino, CA 95014 + + Barry Haskell + Apple Computer, Inc. + 2 Infinite Loop + Cupertino, California 95014 + + Greg Conklin + RealNetworks, Inc. + 2601 Elliott Ave + Seattle, WA 98101 + + Jill Boyce + Cristina Gomila + Thomson Inc + 2 Independence Way + Princeton, NJ 08540 + + Haoping Yu + Corporate Research + Thomson Inc + 101 West 103rd Street + Indianapolis, IN 46290 + + Siwei Ma + Institute of Computing Technology + Chinese Academy of Sciences + Kexueyuan South Road 6 + Haidian District + Beijing, China + + Zhibo Chen + JianFeng Xu + Wenfang Fu + Dept.of E&E, Tsinghua Univ + Haidian District + Beijing China, 100084 + + Alexis Michael Tourapis + Athanasios Leontaris + Peshala Pahalawatta + Yuwen He + Yan Ye + Dolby Laboratories Inc. + 3601 West Alameda Ave. + Burbank, CA 91505 + + Xiaoquan Yi + Jun Zhang + Dept. of C.E. Santa Clara Univ. + 500 El Camino Real + Santa Clara, CA 95053 + + Shun-ichi Sekiguchi + Information Technology R&D Center, + Mitsubishi Electric Corporation + 5-1-1, Ofuna, Kamakura, Japan + + Yung-Lyul Lee + Ki-Hun Han + Department of Computer Engineering, + Sejong University + 98 Kunja-Dong, Kwangjin-Gu, Seoul 143-747, Korea + + \endverbatim + */ + diff --git a/lencod/inc/defines.h b/lencod/inc/defines.h new file mode 100644 index 0000000..bb8344f --- /dev/null +++ b/lencod/inc/defines.h @@ -0,0 +1,372 @@ +/*! + ************************************************************************** + * \file defines.h + * + * \brief + * Header file containing some useful global definitions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Karsten Suehring + * - Alexis Michael Tourapis + * + * + * \date + * 21. March 2001 + ************************************************************************** + */ + + +#ifndef _DEFINES_H_ +#define _DEFINES_H_ + +#if defined _DEBUG +# define TRACE 0 //!< 0:Trace off 1:Trace on 2:detailed CABAC context information +#else +# define TRACE 0 //!< 0:Trace off 1:Trace on 2:detailed CABAC context information +#endif + +#define JM "18 (FRExt)" +#define VERSION "18.2" +#define EXT_VERSION "(FRExt)" + +//! Edited by Joao Carreira +#define MAX_TRANSCODED_FRAMES 100 + +#define GET_METIME 1 //!< Enables or disables ME computation time +#define DUMP_DPB 0 //!< Dump DPB info for debug purposes +#define PRINTREFLIST 1 //!< Print ref list info for debug purposes +#define IMGTYPE 0 //!< Define imgpel size type. 0 implies byte (cannot handle >8 bit depths) and 1 implies unsigned short +#define ENABLE_FIELD_CTX 1 //!< Enables field context types for CABAC. If disabled, results in speedup for progressive content. +#define ENABLE_HIGH444_CTX 1 //!< Enables High 444 context types for CABAC. If disabled, results in speedup of non High444 profile encodings. +#define DEBUG_BITDEPTH 0 //!< Ensures that > 8 bit content have no values that would result in out of range results +#define ALLOW_GRAYSCALE 1 //!< Allow encoding in grayscale +#define ZEROSNR 1 //!< PSNR computation method +#define USE_RND_COST 0 //!< Perform ME RD decision using a rounding estimate of the motion cost +#define JM_INT_DIVIDE 1 +#define JM_MEM_DISTORTION 0 +#define JCOST_CALC_SCALEUP 1 //!< 1: J = (D<>LAMBDA_ACCURACY_BITS) +#define INTRA_RDCOSTCALC_ET 1 //!< Early termination +#define INTRA_RDCOSTCALC_NNZ 1 //1: to recover block's nzn after rdcost calculation; +#define JCOST_OVERFLOWCHECK 0 //!<1: to check the J cost if it is overflow> +#define JM_PARALLEL_DEBLOCK 0 //!< Enables Parallel Deblocking +#define SIMULCAST_ENABLE 0 + +#define MVC_EXTENSION_ENABLE 1 //!< enable support for the Multiview High Profile +//! Added by Joao Carreira +#define MAX_VIEW_NUM 2 +#define BASE_VIEW_IDX 0 + +#define EOS_OUTPUT 0 + +#define EPZSREF 1 + +#define MAX_RC_MODE 3 +#define RC_MAX_TEMPORAL_LEVELS 5 + +#define SSE_MEMORY_ALIGNMENT 16 +#define MAX_NUM_DPB_LAYERS 2 +//#define BEST_NZ_COEFF 1 // yuwen 2005.11.03 => for high complexity mode decision (CAVLC, #TotalCoeff) + +// defines for creating similar coding structures like HM +#define OUTPUT_REF_LIST 0 //!< for debug purpose, output the reference picture list. do not support field + +#define B0_MORE_REF 0 ///!< used for random access setting, treat POC(HM like poc, =JM poc/2)%(NumberOfBFrames+1)==0 as B0, i.e. use more references at temporal level 0 +#define KEEP_B_SAME_LIST 1 ///!< keep B pictures using two identical reference picture lists +#define CRA 1 ///!< used for random access setting, HM CRA like random access point + ///!< using open GOP is not enough, for example, 32 is an Intra picture, when encoding 40, everything is OK. + ///!< but when encoding 36, there is one reference picture (32) in list0; actually, there should be two (32, 40) as HM. + ///!< setting number of reference frame to 1 at picture 40, using RPLR to let list1 use 32 as reference, + ///!< and marking all pictures unused for reference except 32 to solve this problem +#define HM50_LIKE_MMCO 1 ///!< use the HM-5.0 like MMCO, keep the identical referencing structure as HM-5.0 +#define LD_REF_SETTING 1 ///!< used for low delay setting, 1+X referencing structure, as proposed in JCTVC-F701 + + +//AVC Profile IDC definitions +enum { + FREXT_CAVLC444 = 44, //!< YUV 4:4:4/14 "CAVLC 4:4:4" + BASELINE = 66, //!< YUV 4:2:0/8 "Baseline" + MAIN = 77, //!< YUV 4:2:0/8 "Main" + EXTENDED = 88, //!< YUV 4:2:0/8 "Extended" + FREXT_HP = 100, //!< YUV 4:2:0/8 "High" + FREXT_Hi10P = 110, //!< YUV 4:2:0/10 "High 10" + FREXT_Hi422 = 122, //!< YUV 4:2:2/10 "High 4:2:2" + FREXT_Hi444 = 244, //!< YUV 4:4:4/14 "High 4:4:4" + MULTIVIEW_HIGH = 118, //!< YUV 4:2:0/8 "Multiview High" + STEREO_HIGH = 128 //!< YUV 4:2:0/8 "Stereo High" +} ProfileIDC; + +// Some typedefs used in the software +#include "types.h" + +#define FILE_NAME_SIZE 255 +#define INPUT_TEXT_SIZE 1024 + +#define CAVLC_LEVEL_LIMIT 2063 + +#if (ENABLE_HIGH444_CTX == 1) +# define NUM_BLOCK_TYPES 22 +#else +# define NUM_BLOCK_TYPES 10 +#endif + +#define _LEAKYBUCKET_ + +// --------------------------------------------------------------------------------- +// FLAGS and DEFINES for new chroma intra prediction, Dzung Hoang +// Threshold values to zero out quantized transform coefficients. +// Recommend that _CHROMA_COEFF_COST_ be low to improve chroma quality +#define _LUMA_COEFF_COST_ 4 //!< threshold for luma coeffs +#define _CHROMA_COEFF_COST_ 4 //!< threshold for chroma coeffs, used to be 7 +#define _LUMA_MB_COEFF_COST_ 5 //!< threshold for luma coeffs of inter Macroblocks +#define _LUMA_8x8_COEFF_COST_ 5 //!< threshold for luma coeffs of 8x8 Inter Partition + +//#define IMG_PAD_SIZE 20 //!< Number of pixels padded around the reference frame (>=4) +//#define IMG_PAD_SIZE_TIMES4 80 //!< Number of pixels padded around the reference frame in subpel units(>=16) +#define IMG_PAD_SIZE_X 32 //!< Number of pixels padded around the reference frame (>=4) +#define IMG_PAD_SIZE_Y 20 //!< Number of pixels padded around the reference frame (>=4) + +#define MAX_VALUE 999999 //!< used for start value for some variables +#define INVALIDINDEX (-135792468) + +#define DUMMY 14 +#define ET_SIZE 300 //!< size of error text buffer + +#define LAMBDA_ACCURACY_BITS 5 +#define LAMBDA_FACTOR(lambda) ((int)((double)(1 << LAMBDA_ACCURACY_BITS) * lambda + 0.5)) + +#if (IMGTYPE == 0) +#define DISTBLK_MAX INT_MAX +#else +#define DISTBLK_MAX ((distblk) INT_MAX << LAMBDA_ACCURACY_BITS) +#endif + +#define MAXSLICEPERPICTURE 500 +#define MAX_REFERENCE_PICTURES 32 + +#define BLOCK_SHIFT 2 +#define BLOCK_SIZE 4 +#define BLOCK_SIZE_8x8 8 +#define SMB_BLOCK_SIZE 8 +#define BLOCK_PIXELS 16 +#define MB_BLOCK_SIZE 16 +#define MB_PIXELS 256 // MB_BLOCK_SIZE * MB_BLOCK_SIZE +#define MB_PIXELS_SHIFT 8 // log2(MB_BLOCK_SIZE * MB_BLOCK_SIZE) +#define MB_BLOCK_SHIFT 4 +#define BLOCK_MULTIPLE 4 // (MB_BLOCK_SIZE/BLOCK_SIZE) +#define MB_BLOCK_PARTITIONS 16 // (BLOCK_MULTIPLE * BLOCK_MULTIPLE) +#define BLOCK_CONTEXT 64 // (4 * MB_BLOCK_PARTITIONS) +// These variables relate to the subpel accuracy supported by the software (1/4) +#define BLOCK_SIZE_SP 16 // BLOCK_SIZE << 2 +#define BLOCK_SIZE_8x8_SP 32 // BLOCK_SIZE8x8 << 2 + +// wavelet based weighted PSNR wavelet levels +#define NUM_WAVELET_LEVEL 4 + +// RDOQ +#define MAX_PREC_COEFF 25 + +// Joao Carreira - Useful information +// Available MB modes +enum { + PSKIP = 0, + BSKIP_DIRECT = 0, + P16x16 = 1, + P16x8 = 2, + P8x16 = 3, + SMB8x8 = 4, + SMB8x4 = 5, + SMB4x8 = 6, + SMB4x4 = 7, + P8x8 = 8, + I4MB = 9, + I16MB = 10, + IBLOCK = 11, + SI4MB = 12, + I8MB = 13, + IPCM = 14, + MAXMODE = 15 +} MBModeTypes; + +// number of intra prediction modes +#define NO_INTRA_PMODE 9 + +// Direct Mode types +enum { + DIR_TEMPORAL = 0, //!< Temporal Direct Mode + DIR_SPATIAL = 1 //!< Spatial Direct Mode +} DirectModes; + +// CAVLC block types +enum { + LUMA = 0, + LUMA_INTRA16x16DC = 1, + LUMA_INTRA16x16AC = 2, + CB = 3, + CB_INTRA16x16DC = 4, + CB_INTRA16x16AC = 5, + CR = 8, + CR_INTRA16x16DC = 9, + CR_INTRA16x16AC = 10 +} CAVLCBlockTypes; + +// CABAC block types +enum { + LUMA_16DC = 0, + LUMA_16AC = 1, + LUMA_8x8 = 2, + LUMA_8x4 = 3, + LUMA_4x8 = 4, + LUMA_4x4 = 5, + CHROMA_DC = 6, + CHROMA_AC = 7, + CHROMA_DC_2x4 = 8, + CHROMA_DC_4x4 = 9, + CB_16DC = 10, + CB_16AC = 11, + CB_8x8 = 12, + CB_8x4 = 13, + CB_4x8 = 14, + CB_4x4 = 15, + CR_16DC = 16, + CR_16AC = 17, + CR_8x8 = 18, + CR_8x4 = 19, + CR_4x8 = 20, + CR_4x4 = 21 +} CABACBlockTypes; + +// Color components +enum { + Y_COMP = 0, // Y Component + U_COMP = 1, // U Component + V_COMP = 2, // V Component + R_COMP = 3, // R Component + G_COMP = 4, // G Component + B_COMP = 5, // B Component + T_COMP = 6 +} ColorComponent; + + +#define IS_INTRA(MB) ((MB)->mb_type==SI4MB || (MB)->mb_type==I4MB || (MB)->mb_type==I16MB || (MB)->mb_type==I8MB || (MB)->mb_type==IPCM) + +#define LEVEL_NUM 6 +#define TOTRUN_NUM 15 +#define RUNBEFORE_NUM 7 +#define RUNBEFORE_NUM_M1 6 + +// Quantization parameter range +#define MIN_QP 0 +#define MAX_QP 51 +#define SHIFT_QP 12 + +// 4x4 intra prediction modes +enum { + VERT_PRED = 0, + HOR_PRED = 1, + DC_PRED = 2, + DIAG_DOWN_LEFT_PRED = 3, + DIAG_DOWN_RIGHT_PRED = 4, + VERT_RIGHT_PRED = 5, + HOR_DOWN_PRED = 6, + VERT_LEFT_PRED = 7, + HOR_UP_PRED = 8 +} I4x4PredModes; + +// 16x16 intra prediction modes +enum { + VERT_PRED_16 = 0, + HOR_PRED_16 = 1, + DC_PRED_16 = 2, + PLANE_16 = 3 +} I16x16PredModes; + +// 8x8 chroma intra prediction modes +enum { + DC_PRED_8 = 0, + HOR_PRED_8 = 1, + VERT_PRED_8 = 2, + PLANE_8 = 3 +} I8x8PredModes; + +#define INIT_FRAME_RATE 30 +enum { + EOS = 1, //!< End Of Sequence + SOP = 2, //!< Start Of Picture + SOS = 3 //!< Start Of Slice +}; + +// MV Prediction types +enum { + MVPRED_MEDIAN = 0, + MVPRED_L = 1, + MVPRED_U = 2, + MVPRED_UR = 3 +} MVPredTypes; + +#define MAX_SYMBOLS_PER_MB 1200 //!< Maximum number of different syntax elements for one MB + // CAVLC needs more symbols per MB + + +#define MAX_PART_NR 3 /*!< Maximum number of different data partitions. + Some reasonable number which should reflect + what is currently defined in the SE2Partition map (elements.h) */ + +//Start code and Emulation Prevention need this to be defined in identical manner at encoder and decoder +#define ZEROBYTES_SHORTSTARTCODE 2 //indicates the number of zero bytes in the short start-code prefix + +#define Q_BITS 15 +#define DQ_BITS 6 + +#define Q_BITS_8 16 +#define DQ_BITS_8 6 + +// Context Adaptive Lagrange Multiplier (CALM) +#define CALM_MF_FACTOR_THRESHOLD 512.0 + +#define MAX_PLANE 3 + +#define MAXSLICEGROUPIDS 8 + + +#define NUM_MB_TYPE_CTX 11 +#define NUM_B8_TYPE_CTX 9 +#define NUM_MV_RES_CTX 10 +#define NUM_REF_NO_CTX 6 +#define NUM_DELTA_QP_CTX 4 +#define NUM_MB_AFF_CTX 4 + +#define NUM_TRANSFORM_SIZE_CTX 3 + +#define NUM_IPR_CTX 2 +#define NUM_CIPR_CTX 4 +#define NUM_CBP_CTX 4 +#define NUM_BCBP_CTX 4 +#define NUM_MAP_CTX 15 +#define NUM_LAST_CTX 15 +#define NUM_ONE_CTX 5 +#define NUM_ABS_CTX 5 + +enum // JLT : on-the-fly levels/modes +{ + OTF_L0 = 0, // Disable, interpolate & store all positions + OTF_L1 = 1, // Store full pel & interpolated 1/2 pel positions; 1/4 pel positions interpolate on-the-fly + OTF_L2 = 2 // Store only full pell positions; 1/2 & 1/4 pel positions interpolate on-the-fly +} OTFMode; + +enum +{ + OTF_ME = 0, + OTF_MC = 1 +} OTFFunction; + +#if IMGTYPE +#if JM_MEM_DISTORTION +#pragma message("JM_MEM_DISTORTION must be zero!") +#endif +#endif + + +#endif + diff --git a/lencod/inc/elements.h b/lencod/inc/elements.h new file mode 100644 index 0000000..0733424 --- /dev/null +++ b/lencod/inc/elements.h @@ -0,0 +1,89 @@ + +/*! + ************************************************************************** + * \file elements.h + * \brief Header file for elements in H.264 streams + * \date 6.10.2000, + * \version + * 1.1 + * + * \note + * Version 1.0 included three partition modes, no DP, 2 partitionsper slice + * and 4 partitions per slice. As per document VCEG-N72 this is changed + * in version 1.1 to only two partition modes, one without DP and one with + * 3 partition per slice + * + * \author Sebastian Purreiter + * \author Stephan Wenger + * + ************************************************************************** + */ + +#ifndef _ELEMENTS_H_ +#define _ELEMENTS_H_ + +/*! + * definition of H.264 syntax elements + * order of elements follow dependencies for picture reconstruction + */ + +#define MAXPARTITIONMODES 2 //!< maximum possible partition modes as defined in assignSE2partition[][] + +/*! + * \brief lookup-table to assign different elements to partition + * + * \note here we defined up to 6 different partitions similar to + * document Q15-k-18 described in the PROGFRAMEMODE. + * The Sliceheader contains the PSYNC information. \par + * + * Elements inside a partition are not ordered. They are + * ordered by occurence in the stream. + * Assumption: Only partitionlosses are considered. \par + * + * The texture elements luminance and chrominance are + * not ordered in the progressive form + * This may be changed in image.c \par + * + * -IMPORTANT: + * Picture- or Sliceheaders must be assigned to partition 0. \par + * Furthermore partitions must follow syntax dependencies as + * outlined in document Q15-J-23. + */ + + +// A note on this table: +// +// While the assignment of values in enum data types is specified in C, it is not +// very ood style to have an "elementnumber", not even as a comment. +// +// Hence a copy of the relevant structure from global.h here +/* +typedef enum { + 0 SE_HEADER, + 1 SE_PTYPE, + 2 SE_MBTYPE, + 3 SE_REFFRAME, + 4 SE_INTRAPREDMODE, + 5 SE_MVD, + 6 SE_CBP + 7 SE_LUM_DC_INTRA, + 8 SE_CHR_DC_INTRA, + 9 SE_LUM_AC_INTRA, +10 SE_CHR_AC_INTRA, +12 SE_LUM_DC_INTER, +13 SE_CHR_DC_INTER, +14 SE_LUM_AC_INTER, +15 SE_CHR_AC_INTER, +16 SE_DELTA_QUANT, +18 SE_BFRAME, +19 SE_EOS, +20 SE_MAX_ELEMENTS */ // number of maximum syntax elements +//} SE_type; + + +extern const int * assignSE2partition[2]; +extern const int assignSE2partition_NoDP[SE_MAX_ELEMENTS]; +extern const int assignSE2partition_DP[SE_MAX_ELEMENTS]; + +#endif + diff --git a/lencod/inc/errdo.h b/lencod/inc/errdo.h new file mode 100644 index 0000000..efe56a8 --- /dev/null +++ b/lencod/inc/errdo.h @@ -0,0 +1,123 @@ +/*! + ************************************************************************** + * \file errdo.h + * \brief Header file for error resilient RDO (name of file should change) + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Peshala Pahalawatta + * - Zhifeng Chen + * - Alexis Michael Tourapis + * + ************************************************************************** + */ + +#ifndef _ERRDO_H_ +#define _ERRDO_H_ + + +typedef enum +{ + LLN = 0, + ROPE = 1, + RMPC = 2, +} DE_Type; + +struct distortion_estimation +{ + //To support slice data partitioing, residual and motion vector should use their own buffers (used if rdopt==3) + int ** res_con_diff_Y; //!< for storing the residual concealment difference for component Y in rmpc algorithm + int *** res_con_diff_UV; //!< for storing the residual concealment difference for component UV in rmpc algorithm + int ** p_res_con_diff[MAX_PLANE]; //!< pointer array for accessing res_con_error_Y / res_con_error_UV[] + int ** MV_con_diff_Y; //!< for storing the MV concealment difference for component Y in rmpc algorithm + int *** MV_con_diff_UV; //!< for storing the MV concealment difference for component UV in rmpc algorithm + int ** p_MV_con_diff[MAX_PLANE]; //!< pointer array for accessing MV_con_diff_Y / MV_con_diff_UV[] + byte ** error_sign_flag_Y; //!< to indicate the sign of transmission error for component Y in rmpc algorithm + byte ***error_sign_flag_UV; //!< to indicate the sign of transmission error for component UV in rmpc algorithm + byte ** p_error_sign_flag[MAX_PLANE]; //!< pointer array for accessing error_sign_flag_Y / error_sign_flag_UV[] + int ** transmission_dist_Y; //!< for storing the transmission distortion for component Y in rmpc algorithm + int *** transmission_dist_UV; //!< for storing the transmission distortion for component UV in rmpc algorithm + int ** p_transmission_dist[MAX_PLANE]; //!< pointer array for accessing transmission_dist_Y / transmission_dist_UV[] + int ** transmission_err_Y; //!< for storing the transmission distortion for component Y in rmpc algorithm + int *** transmission_err_UV; //!< for storing the transmission distortion for component UV in rmpc algorithm + int ** p_transmission_err[MAX_PLANE]; //!< pointer array for accessing transmission_dist_Y / transmission_dist_UV[] + + //Multiple Decoder Buffers (used if rdopt==3) + imgpel *** dec_imgY; //!< Decoded Y component in multiple hypothetical decoders + imgpel **** dec_imgUV; //!< Decoded U and V components in multiple hypothetical decoders + imgpel *** p_dec_img[MAX_PLANE]; //!< pointer array for accessing decoded pictures in hypothetical decoders + byte *** mb_error_map; //!< Map of macroblock errors in hypothetical decoders. + + //(used if rdopt==3) + imgpel ** first_moment_Y; //!< for storing the estimated first moment for component Y in rope algorithm + imgpel *** first_moment_UV; //!< for storing the estimated first moment for component Y in rope algorithm + imgpel ** p_first_moment[MAX_PLANE]; //!< pointer array for accessing first_moment_Y / first_moment_UV[] + uint16 ** second_moment_Y; //!< for storing the estimated second moment for component Y in rope algorithm + uint16 *** second_moment_UV; //!< for storing the estimated second moment for component Y in rope algorithm + uint16 ** p_second_moment[MAX_PLANE]; //!< pointer array for accessing second_moment_Y / first_moment_UV[] +}; + + +//! Info for the "decoders-in-the-encoder" used for rdoptimization with packet losses +struct decoders +{ + int ***res_img; //!< Residual values for macroblock + int ***res_mb_best8x8; //!< Residual values for the best b8x8 to be used in P8x8 mode decision + + //for RMPC algorithm + int **RCD_bestY_mb; + int ***RCD_bestY_b8x8; + int **MVCD_bestY_mb; + int ***MVCD_bestY_b8x8; + byte **flag_bestY_mb; + byte ***flag_bestY_b8x8; + byte **flag_wo_res; + byte ***flag_wo_res_bestY_b8x8; + int **trans_dist_bestY_mb; + int ***trans_dist_bestY_b8x8; + int **trans_dist_wo_res; + int ***trans_dist_wo_res_bestY_b8x8; + int **trans_err_bestY_mb; + int ***trans_err_bestY_b8x8; + int **trans_err_wo_res; + int ***trans_err_wo_res_bestY_b8x8; + + //for LLN algorithm + imgpel ***dec_mbY_best; //!< Best reconstructed macroblock pixel values + imgpel ****dec_mbY_best8x8; //!< Best reconstructed 8x8 mode pixel values + imgpel ****dec_mb_pred_best8x8; //!< Predicted pixel values for best 8x8 modes + imgpel ***dec_mb_pred; //!< Predicted pixel values for macroblock + int rec_type; + + //for ROPE algorithm + imgpel **first_moment_bestY_mb; + imgpel ***first_moment_bestY_b8x8; + imgpel ***first_moment_pred_bestY_b8x8; + imgpel **first_moment_pred; + uint16 **second_moment_bestY_mb; + uint16 ***second_moment_bestY_b8x8; + uint16 ***second_moment_pred_bestY_b8x8; + uint16 **second_moment_pred; +}; + +typedef struct decoders Decoders; + +//============= rate-distortion opt with packet losses =========== + +extern void init_error_conceal (VideoParameters *p_Vid, int concealment_type); +extern void errdo_compute_residue (Macroblock *currMB, imgpel **imgY, int **res_img, imgpel **mb_pred, int b8block, int block_size); +extern int allocate_errdo_mem (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void free_errdo_mem (VideoParameters *p_Vid); + +extern void init_distortion_estimation (VideoParameters *p_Vid, int de_algorithm); +extern void errdo_store_best_b8x8(Macroblock *currMB, int transform8x8, int block); +extern void errdo_get_best_b8x8(Macroblock *currMB, int transform8x8, int block); +extern void errdo_store_best_MB(Macroblock *currMB); +extern void errdo_get_best_MB(Macroblock *currMB); +extern void errdo_get_best_P8x8(Macroblock *currMB, int transform8x8); +extern void errdo_alloc_storable_picture(StorablePicture *s, VideoParameters *p_Vid, InputParameters *p_Inp, int size_x, int size_y, int size_x_cr, int size_y_cr); +extern void errdo_free_storable_picture(StorablePicture* p); +extern StorablePicture* find_nearest_ref_picture(DecodedPictureBuffer *p_Dpb, int poc); + +#endif + diff --git a/lencod/inc/errdo_dist_mhyp.h b/lencod/inc/errdo_dist_mhyp.h new file mode 100644 index 0000000..8a64f60 --- /dev/null +++ b/lencod/inc/errdo_dist_mhyp.h @@ -0,0 +1,21 @@ +/*! + ************************************************************************** + * \file errdo_dist_mhyp.h + * \brief + * Header file for distortion estimation with multiple decoder based method + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Zhifeng Chen + * + ************************************************************************** + */ + +#ifndef _ERRDO_DIST_MHYP_H_ +#define _ERRDO_DIST_MHYP_H_ + +extern void errdo_store_best_block_multihyp (InputParameters *p_Inp, imgpel*** mbY, imgpel*** dec_img, int block, int img_i, int img_j, int block_size); +extern void errdo_get_best_block_multihyp (Macroblock *currMB, imgpel*** dec_img, imgpel*** mbY, int block, int block_size); +extern distblk errdo_distortion_estimation_multihyp(Macroblock *currMB, int block, int block_size, short mode, short pdir, distblk min_rdcost); +extern void copy_conceal_picture (VideoParameters *p_Vid, StorablePicture *enc_pic, int decoder); +#endif diff --git a/lencod/inc/explicit_gop.h b/lencod/inc/explicit_gop.h new file mode 100644 index 0000000..06150b8 --- /dev/null +++ b/lencod/inc/explicit_gop.h @@ -0,0 +1,23 @@ + +/*! + ************************************************************************************* + * \file explicit_gop.h + * + * \brief + * Functions for explicit gop and hierarchy support + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#ifndef _EXPLICIT_GOP_H_ +#define _EXPLICIT_GOP_H_ + +// GOP Hierarchy +extern void init_gop_structure (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void interpret_gop_structure(VideoParameters *p_Vid, InputParameters *p_Inp); +extern void clear_gop_structure (VideoParameters *p_Vid); + +#endif diff --git a/lencod/inc/explicit_seq.h b/lencod/inc/explicit_seq.h new file mode 100644 index 0000000..18baba1 --- /dev/null +++ b/lencod/inc/explicit_seq.h @@ -0,0 +1,39 @@ + +/*! + ************************************************************************************* + * \file explicit_seq.h + * + * \brief + * Functions for explicit sequence support + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#ifndef _EXPLICIT_SEQ_H_ +#define _EXPLICIT_SEQ_H_ + +// Definition of structures used for explicit sequence representation +typedef struct +{ + int seq_number; + int slice_type; + int is_idr; + int reference_idc; + int frame_qp; + int deblocking; + int is_field; +} ExpFrameInfo; + +typedef struct exp_seq_info +{ + int no_frames; + ExpFrameInfo *info; +} ExpSeqInfo; + +extern void ReadExplicitSeqFile (ExpSeqInfo *seq_info, FILE *exp_file, int coding_index); +extern void OpenExplicitSeqFile (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void CloseExplicitSeqFile (VideoParameters *p_Vid); +#endif diff --git a/lencod/inc/filehandle.h b/lencod/inc/filehandle.h new file mode 100644 index 0000000..922587a --- /dev/null +++ b/lencod/inc/filehandle.h @@ -0,0 +1,25 @@ + +/*! + *************************************************************************** + * + * \file filehandle.h + * + * \brief + * + * \date + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * + **************************************************************************/ + +#ifndef _FILEHANDLE_H_ +#define _FILEHANDLE_H_ + +extern int rewrite_paramsets (VideoParameters *p_Vid); +extern int start_sequence (VideoParameters *p_Vid, InputParameters *p_Inp); +extern int terminate_sequence(VideoParameters *p_Vid, InputParameters *p_Inp); +extern int write_PPS (VideoParameters *p_Vid, int len, int PPS_id); +extern int end_of_stream (VideoParameters *p_Vid); + +#endif diff --git a/lencod/inc/fmo.h b/lencod/inc/fmo.h new file mode 100644 index 0000000..273b052 --- /dev/null +++ b/lencod/inc/fmo.h @@ -0,0 +1,35 @@ + +/*! + *************************************************************************** + * + * \file fmo.h + * + * \brief + * Support for Flexible Macroblock Ordering + * + * \date + * 16 June 2002 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + **************************************************************************/ + +#ifndef _FMO_H_ +#define _FMO_H_ + +extern int FmoInit (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps, seq_parameter_set_rbsp_t * sps); +extern void FmoUninit (VideoParameters *p_Vid); +extern int FmoFinit (seq_parameter_set_rbsp_t * sps); +extern int FmoMB2SliceGroup (VideoParameters *p_Vid, int mb); +extern int FmoGetFirstMBOfSliceGroup (VideoParameters *p_Vid, int SliceGroupID); +extern int FmoGetFirstMacroblockInSlice (VideoParameters *p_Vid, int SliceGroup); +extern int FmoGetNextMBNr (VideoParameters *p_Vid, int CurrentMbNr); +extern int FmoGetPreviousMBNr (VideoParameters *p_Vid, int CurrentMbNr); +extern int FmoGetLastCodedMBOfSliceGroup (VideoParameters *p_Vid, int SliceGroupID); +extern int FmoStartPicture (VideoParameters *p_Vid); +extern int FmoEndPicture (void); +extern int FmoSliceGroupCompletelyCoded (VideoParameters *p_Vid, int SliceGroupID); +extern void FmoSetLastMacroblockInSlice (VideoParameters *p_Vid, int mb); + + +#endif diff --git a/lencod/inc/get_block_otf.h b/lencod/inc/get_block_otf.h new file mode 100644 index 0000000..e6a24ab --- /dev/null +++ b/lencod/inc/get_block_otf.h @@ -0,0 +1,95 @@ +/*! + ************************************************************************************* + * \file get_block_otf.h + * + * \brief + * get predicted (chroma|luma) block with subpel interpolation computes on-the-fly + * + * + ************************************************************************************* + */ + + +#ifndef _GET_BLOCK_OTF_H_ +#define _GET_BLOCK_OTF_H_ + +void get_block_luma_otf_L2( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array of prediction values (row by row) + int* tmp_pred, //!< array of temporary prediction values (row by row), used for some hal-pel interpolations + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical coordinate of block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int pl //!< plane + ); + +void get_block_luma_otf_L1( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array of prediction values (row by row) + int* tmp_pred, //!< array of temporary prediction values (row by row), used for some hal-pel interpolations + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical coordinate of block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int pl //!< plane + ) ; + + +void get_block_chroma_otf_L2 ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv //!< chroma component + ) ; + +void me_get_block_chroma_otf_L1 ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv //!< chroma component + ) ; + +void mc_get_block_chroma_otf_L1 ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv //!< chroma component + ) ; + + + + +//static inline int is_pel( int x, int y, int bx, int by ) +//{ +// return ( (((x & bx)==0) && ((y & by)==0)) ? (1):(0) ); +//} +// +//static inline int is_hpel( int x, int y, int bx, int by ) +//{ +// return ( ((( (x & bx)==2)&&((y & by)==2)) || (((x & bx)==2)&&((y & by)==0)) || (((x & bx)==0)&&((y & by)==2)) ) ? (1):(0) ); +//} +// +//static inline int is_qpel( int x, int y, int bx, int by ) +//{ +// return ( !is_pel(x,y,bx,by) && !is_hpel(x,y,bx,by) ); +//} + +static inline int is_qpel( int x, int y, int bx, int by ) +{ + return ( ((x&bx)%2) || ((y&by)%2) ) ? (1):(0) ; +} + +#endif \ No newline at end of file diff --git a/lencod/inc/global.h b/lencod/inc/global.h new file mode 100644 index 0000000..c1228bc --- /dev/null +++ b/lencod/inc/global.h @@ -0,0 +1,1635 @@ +/*! + ************************************************************************ + * \file + * global.h + * + * \brief + * global definitions for H.264 encoder. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * + ************************************************************************ + */ +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ + +#include "defines.h" +#include "win32.h" +#include "typedefs.h" +#include "parsetcommon.h" +#include "ifunctions.h" +#include "frame.h" +#include "io_video.h" +#include "io_image.h" +#include "nalucommon.h" +#include "params.h" +#include "distortion.h" +#include "lagrangian.h" +#include "quant_params.h" +#include "rc_types.h" + +typedef struct bit_stream_enc Bitstream; + +#include "pred_struct_types.h" + + +/*********************************************************************** + * D a t a t y p e s f o r C A B A C + *********************************************************************** + */ +typedef struct inp_par_enc InputParameters; + +// structures that will be declared somewhere else +struct storable_picture; +struct coding_state; +struct pic_motion_params_old; +struct pic_motion_params; + +typedef struct image_structure ImageStructure; +typedef struct info_8x8 Info8x8; +typedef struct search_window SearchWindow; +typedef struct block_pos BlockPos; +typedef struct bit_counter BitCounter; +typedef struct encoding_environment EncodingEnvironment; +typedef EncodingEnvironment *EncodingEnvironmentPtr; +typedef struct bi_context_type BiContextType; +typedef BiContextType *BiContextTypePtr; + +struct image_structure +{ + FrameFormat format; //!< ImageStructure format Information + imgpel **data[3]; //!< ImageStructure pixel data +}; + +//! block 8x8 temporary RD info +struct info_8x8 +{ + char mode; + char pdir; + char ref[2]; + char bipred; +}; + +struct search_window { + int min_x; + int max_x; + int min_y; + int max_y; +}; + +struct block_pos +{ + short x; + short y; +}; + +//! bit counter for a macroblock. Note that it seems safe to change all to unsigned short for 16x16 MBs. May be an issue if MB > 32x32 +struct bit_counter +{ + int mb_total; + unsigned short mb_mode; + unsigned short mb_inter; + unsigned short mb_cbp; + unsigned short mb_delta_quant; + int mb_y_coeff; + int mb_uv_coeff; + int mb_cb_coeff; + int mb_cr_coeff; + int mb_stuffing; +}; + +//! struct to characterize the state of the arithmetic coding engine +struct encoding_environment +{ + struct video_par *p_Vid; + unsigned int Elow, Erange; + unsigned int Ebuffer; + unsigned int Ebits_to_go; + unsigned int Echunks_outstanding; + int Epbuf; + byte *Ecodestrm; + int *Ecodestrm_len; + int C; + int E; +}; + +//! struct for context management +struct bi_context_type +{ + unsigned long count; + byte state; //uint16 state; // index into state-table CP + unsigned char MPS; // Least Probable Symbol 0/1 CP +}; + + + +/********************************************************************** + * C O N T E X T S F O R T M L S Y N T A X E L E M E N T S + ********************************************************************** + */ + +typedef struct +{ + BiContextType mb_type_contexts [3][NUM_MB_TYPE_CTX]; + BiContextType b8_type_contexts [2][NUM_B8_TYPE_CTX]; + BiContextType mv_res_contexts [2][NUM_MV_RES_CTX]; + BiContextType ref_no_contexts [2][NUM_REF_NO_CTX]; +} MotionInfoContexts; + +typedef struct +{ + BiContextType transform_size_contexts [NUM_TRANSFORM_SIZE_CTX]; + BiContextType ipr_contexts [NUM_IPR_CTX]; + BiContextType cipr_contexts[NUM_CIPR_CTX]; + BiContextType cbp_contexts [3][NUM_CBP_CTX]; + BiContextType bcbp_contexts[NUM_BLOCK_TYPES][NUM_BCBP_CTX]; + BiContextType delta_qp_contexts [NUM_DELTA_QP_CTX]; + BiContextType one_contexts [NUM_BLOCK_TYPES][NUM_ONE_CTX]; + BiContextType abs_contexts [NUM_BLOCK_TYPES][NUM_ABS_CTX]; +#if ENABLE_FIELD_CTX + BiContextType mb_aff_contexts [NUM_MB_AFF_CTX]; + BiContextType map_contexts [2][NUM_BLOCK_TYPES][NUM_MAP_CTX]; + BiContextType last_contexts[2][NUM_BLOCK_TYPES][NUM_LAST_CTX]; +#else + BiContextType map_contexts [1][NUM_BLOCK_TYPES][NUM_MAP_CTX]; + BiContextType last_contexts[1][NUM_BLOCK_TYPES][NUM_LAST_CTX]; +#endif +} TextureInfoContexts; + +//*********************** end of data type definition for CABAC ******************* + +//! Pixel position for checking neighbors +typedef struct pix_pos +{ + int available; + int mb_addr; + short x; + short y; + short pos_x; + short pos_y; +} PixelPos; + +//! Motion Vector structure +typedef struct +{ + short mv_x; + short mv_y; +} MotionVector; + +//! Bipred Motion Vector structure +typedef struct +{ + short refIdx[2]; + MotionVector mv[2]; + distblk dist; + distblk sad; +} BiPredMVInfo; + +static const MotionVector zero_mv = {0, 0}; + +typedef struct rd_8x8_data +{ + distblk mb_p8x8_cost; + distblk smb_p8x8_cost[4]; + distblk smb_p8x8_rdcost[4]; + Info8x8 part[4]; + + int cbp8x8; + int cbp_blk8x8; + int cnt_nonz_8x8; + + int **lrec; // transform and quantized coefficients will be stored here for SP frames + imgpel **mpr8x8; + imgpel ***mpr8x8CbCr; + imgpel **rec_mbY8x8; + imgpel ***rec_mb8x8_cr; +} RD_8x8DATA; + +typedef struct rd_params +{ + double lambda_md; //!< Mode decision Lambda +//#if JCOST_CALC_SCALEUP + int lambda_mdfp; //!< Fixed point mode decision lambda; +//#endif + double lambda_me[3]; //!< Motion Estimation Lambda + int lambda_mf[3]; //!< Integer formatted Motion Estimation Lambda + int best_mcost[2]; + + short valid[MAXMODE]; + short curr_mb_field; +} RD_PARAMS; + + +//! Set Explicit GOP Parameters. +//! Currently only supports Enhancement GOP but could be easily extended +typedef struct +{ + int slice_type; //! Slice type + int display_no; //! GOP Display order + int reference_idc; //! Is reference? + int slice_qp_off; //! Assigned QP offset + int hierarchy_layer; //! Hierarchy layer (used with GOP Hierarchy option 2) + int hierarchyPocDelta; //! Currently unused + int temporal_layer; //! Temporal layer; + // This information is used for hierarchical coding with temporal scalability feature + // If ReferenceReorder = 2, then + // reference reordering is applied based on POC and then frames of higher temporal layer are prevented from being referenced + // If PocMemoryManagement = 2, then + // after encoding a reference frame with temporal layer T, a list of MMCO commands to delete higher temporal layer frames is created + +} GOP_DATA; + +//! Buffer structure for decoded reference picture marking commands +typedef struct DecRefPicMarking_s +{ + int memory_management_control_operation; + int difference_of_pic_nums_minus1; + int long_term_pic_num; + int long_term_frame_idx; + int max_long_term_frame_idx_plus1; + struct DecRefPicMarking_s *Next; +} DecRefPicMarking_t; + +typedef struct me_block +{ + struct video_par *p_Vid; + + short pos_x_padded; //!< position x in image + short pos_y_padded; //!< position y in image + + short blocktype; + short blocksize_x; //!< block size x dimension + short blocksize_y; //!< block size y dimension + short blocksize_cr_x; //!< block size x dimension + short blocksize_cr_y; //!< block size y dimension + + short block_x; //!< position x in MB (subpartitions) + short block_y; //!< position y in MB + + short pos_x; //!< position x in image + short pos_y; //!< position y in image + short pos_x2; //!< position x >> 2 in image + short pos_y2; //!< position y >> 2 in image + + short pos_cr_x; //!< position x in image + short pos_cr_y; //!< position y in image + + short hme_level; //!< level for HME search; + int hme_ref_size_y_pad; + int hme_ref_size_x_pad; + int hme_ref_size_y_max; + int hme_ref_size_x_max; + char list; //!< current list (list 0 or list 1). This is needed for bipredictive ME + char ref_idx; //!< current reference index + MotionVector mv[2]; //!< motion vectors (L0/L1) + PixelPos block[4]; + struct slice *p_Slice; + struct search_window searchRange; + int cost; //!< Rate Distortion cost + imgpel **orig_pic; //!< Block Data + int ChromaMEEnable; + int ChromaMEWeight; + // use weighted prediction based ME + int apply_weights; + int apply_bi_weights; + // 8x8 transform + int test8x8; + // Single List Prediction weights + short weight_luma; + short weight_cr[2]; + short offset_luma; + short offset_cr[2]; + + // Biprediction weights + short weight1; + short weight2; + short offsetBi; + short weight1_cr[2]; + short weight2_cr[2]; + short offsetBi_cr[2]; + int search_pos2; // <-- search positions for half-pel search (default: 9) + int search_pos4; // <-- search positions for quarter-pel search (default: 9) + int iteration_no; // <-- bi pred iteration number + + // functions + distblk (*computePredFPel) (struct storable_picture *, struct me_block *, distblk , MotionVector * ); + distblk (*computePredHPel) (struct storable_picture *, struct me_block *, distblk , MotionVector * ); + distblk (*computePredQPel) (struct storable_picture *, struct me_block *, distblk , MotionVector * ); + distblk (*computeBiPredFPel) (struct storable_picture *, struct storable_picture *, struct me_block *, distblk , MotionVector *, MotionVector *); + distblk (*computeBiPredHPel) (struct storable_picture *, struct storable_picture *, struct me_block *, distblk , MotionVector *, MotionVector *); + distblk (*computeBiPredQPel) (struct storable_picture *, struct storable_picture *, struct me_block *, distblk , MotionVector *, MotionVector *); +} MEBlock; + +//! Syntax Element +typedef struct syntaxelement_enc +{ + int type; //!< type of syntax element for data part. + int value1; //!< numerical value of syntax element + int value2; //!< for blocked symbols, e.g. run/level + int len; //!< length of code + int inf; //!< info part of UVLC code + unsigned int bitpattern; //!< UVLC bitpattern + int context; //!< CABAC context + +#if TRACE + #define TRACESTRING_SIZE 100 //!< size of trace string + char tracestring[TRACESTRING_SIZE]; //!< trace string +#endif + + //!< for mapping of syntaxElement to UVLC + void (*mapping)(int value1, int value2, int* len_ptr, int* info_ptr); + +} SyntaxElement; + +typedef struct wp_params +{ + short weight[3]; + short offset[3]; +} WPParams; + +//! Macroblock +typedef struct macroblock_enc +{ + struct slice *p_Slice; //!< pointer to the current slice + struct video_par *p_Vid; //!< pointer to VideoParameters + InputParameters *p_Inp; + int mbAddrX; //!< current MB address + short mb_type; //!< current MB mode type + short slice_nr; //!< current MB slice id + short mb_x; //!< current MB horizontal + short mb_y; //!< current MB vertical + short block_x; //!< current block horizontal + short block_y; //!< current block vertical + + short pix_x; //!< current pixel horizontal + short pix_y; //!< current pixel vertical + short pix_c_x; //!< current pixel chroma horizontal + short pix_c_y; //!< current pixel chroma vertical + + short opix_y; //!< current original picture pixel vertical + short opix_c_y; //!< current original picture pixel chroma vertical + + short subblock_x; //!< current subblock horizontal + short subblock_y; //!< current subblock vertical + + short list_offset; + Boolean prev_recode_mb; + Boolean DeblockCall; + + int mbAddrA, mbAddrB, mbAddrC, mbAddrD; + byte mbAvailA, mbAvailB, mbAvailC, mbAvailD; + + short qp; //!< QP luma + short qpc[2]; //!< QP chroma + short qp_scaled[MAX_PLANE]; //!< QP scaled for all comps. + short qpsp; + int cbp; + short prev_qp; + short prev_dqp; + int prev_cbp; + int cr_cbp[3]; // 444. Should be added in an external structure + int c_nzCbCr[3]; + + short i16offset; + + BitCounter bits; + + short ar_mode; //!< mb type to store adaptive rounding parameters + short mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][2]; //!< indices correspond to [list][block_y][block_x][x,y] + char c_ipred_mode; //!< chroma intra prediction mode + char i16mode; + + Info8x8 b8x8[4]; + //imgpel intra4x4_pred[16][17]; //!< 4x4 Intra prediction samples + imgpel **intra4x4_pred; //[3][17]; //!< 4x4 Intra prediction samples + imgpel **intra4x4_pred_buf[2]; //[3][17]; //!< 4x4 Intra prediction samples + imgpel **intra8x8_pred; //[3][25]; //!< 8x8 Intra prediction samples + imgpel **intra8x8_pred_buf[2]; //[3][25]; //!< 8x8 Intra prediction samples + imgpel **intra16x16_pred; //[3][33]; //!< 8x8 Intra prediction samples + imgpel **intra16x16_pred_buf[2]; //[3][33]; //!< 8x8 Intra prediction samples + + char IntraChromaPredModeFlag; + byte mb_field; + byte is_field_mode; + byte luma_transform_size_8x8_flag; + byte temp_transform_size_8x8_flag; + byte NoMbPartLessThan8x8Flag; + byte valid_8x8; + byte valid_4x4; + byte write_mb; + byte is_intra_block; + + char DFDisableIdc; + char DFAlphaC0Offset; + char DFBetaOffset; + + int skip_flag; + + char intra_pred_modes [MB_BLOCK_PARTITIONS]; + char intra_pred_modes8x8[MB_BLOCK_PARTITIONS]; //!< four 8x8 blocks in a macroblock + + int64 cbp_blk ; //!< 1 bit set for every 4x4 block with coefs (not implemented for INTRA) + int64 cbp_bits[3]; + int64 cbp_bits_8x8[3]; + + distblk min_rdcost; + distblk min_dcost; + distblk min_rate; + int min_bits; + + short best_mode; + short best_i16offset; + char best_i16mode; + char best_c_imode; + int best_cbp; + + //For residual DPCM + short ipmode_DPCM; + + + + struct macroblock_enc *mb_up; //!< pointer to neighboring MB (CABAC) + struct macroblock_enc *mb_left; //!< pointer to neighboring MB (CABAC) + struct macroblock_enc *PrevMB; + + // Functions + void (*GetMVPredictor) (struct macroblock_enc *currMB, PixelPos *block, MotionVector *pmv, short ref_frame, + struct pic_motion_params **mv_info, int list, int mb_x, int mb_y, int blockshape_x, int blockshape_y); + distblk (*IntPelME) (struct macroblock_enc *currMB, MotionVector *, struct me_block *mv_block, distblk, int); + distblk (*SubPelBiPredME) (struct macroblock_enc *currMB, struct me_block *, int list, + MotionVector *pred_mv1, MotionVector *pred_mv2, MotionVector *mv1, MotionVector *mv2, distblk min_mcost, int* lambda_factor); + distblk (*SubPelME) (struct macroblock_enc *currMB, + MotionVector *pred_mv, struct me_block *mv_block, distblk min_mcost, int* lambda_factor); + distblk (*BiPredME) (struct macroblock_enc *currMB, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, struct me_block *, int, distblk, int); + int (*residual_transform_quant_luma_4x4) (struct macroblock_enc *currMB, ColorPlane pl, int block_x, int block_y, int *coeff_cost, int intra); + int (*residual_transform_quant_luma_16x16) (struct macroblock_enc *currMB, ColorPlane pl); + int (*residual_transform_quant_luma_8x8) (struct macroblock_enc *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra); + int (*residual_transform_quant_chroma_4x4[2])(struct macroblock_enc *currMB, int uv,int i11); + void (*p_SetupFastFullPelSearch) (struct macroblock_enc *, MEBlock *, int ) ; + + void (*cbp_linfo_intra)(int cbp, int dummy, int *len,int *info); + void (*cbp_linfo_inter)(int cbp, int dummy, int *len,int *info); +} Macroblock; + +//! Bitstream +struct bit_stream_enc +{ + int buffer_size; //!< Buffer size + int byte_pos; //!< current position in bitstream; + int bits_to_go; //!< current bitcounter + + int stored_byte_pos; //!< storage for position in bitstream; + int stored_bits_to_go; //!< storage for bitcounter + int byte_pos_skip; //!< storage for position in bitstream; + int bits_to_go_skip; //!< storage for bitcounter + int write_flag; //!< Bitstream contains data and needs to be written + + byte byte_buf; //!< current buffer for last written byte + byte stored_byte_buf; //!< storage for buffer of last written byte + byte byte_buf_skip; //!< current buffer for last written byte + byte *streamBuffer; //!< actual buffer for written bytes + +#if TRACE + Boolean trace_enabled; +#endif +}; + + +//! DataPartition +typedef struct datapartition_enc +{ + struct slice *p_Slice; + struct video_par *p_Vid; + InputParameters *p_Inp; //!< pointer to the input parameters + Bitstream *bitstream; + NALU_t *nal_unit; + EncodingEnvironment ee_cabac; + EncodingEnvironment ee_recode; +} DataPartition; + +/*! For MB level field/frame coding tools + temporary structure to store MB data for field/frame coding */ +typedef struct rd_data +{ + double min_rdcost; + double min_dcost; + double min_rate; + + imgpel ***rec_mb; //!< hold the components of reconstructed MB + int ****cofAC; + int ***cofDC; + int *****cofAC_new; + short mb_type; + int64 cbp_blk; + int cbp; + int prev_cbp; + int mode; + short i16offset; + char i16mode; + Boolean NoMbPartLessThan8x8Flag; + + char c_ipred_mode; + short qp; + short prev_qp; + short prev_dqp; + byte luma_transform_size_8x8_flag; + Info8x8 block; + Info8x8 b8x8[4]; + + MotionVector *****all_mv; //!< all modes motion vectors + MotionVector ******bipred_mv; //!< Bipredictive motion vectors + + char intra_pred_modes[16]; + char intra_pred_modes8x8[16]; + char **ipredmode; + char ***refar; //!< reference frame array [list][y][x] +} RD_DATA; + + //! Slice +typedef struct slice +{ + struct video_par *p_Vid; // pointer to the original video structure + InputParameters *p_Inp; // pointer to the input parameters + pic_parameter_set_rbsp_t *active_pps; + seq_parameter_set_rbsp_t *active_sps; + + int flag_Force_InterView; + + struct decoded_picture_buffer *p_Dpb; + + int layer_id; + int picture_id; + int qp; + int qs; + short slice_type; //!< picture type + unsigned int frame_num; + unsigned int max_frame_num; + signed int framepoc; //!< min (toppoc, bottompoc) + signed int ThisPOC; //!< current picture POC + short slice_nr; + int model_number; + int colour_plane_id; //!< colour plane id for 4:4:4 profile + int lossless_qpprime_flag; + int P444_joined; + int disthres; + int Transform8x8Mode; + int rdoq_motion_copy; + // RDOQ at the slice level (note this allows us to reduce passed parameters, + // but also could enable RDOQ control at the slice level. + int UseRDOQuant; + int RDOQ_QP_Num; + + char num_ref_idx_active[2]; + int ref_pic_list_reordering_flag[2]; + int *modification_of_pic_nums_idc[2]; + int *abs_diff_pic_num_minus1[2]; + int *long_term_pic_idx[2]; +#if (MVC_EXTENSION_ENABLE) + int *abs_diff_view_idx_minus1[2]; +#endif + int view_id; + int width_blk; //!< Number of columns in blocks + int height_blk; //!< Number of lines in blocks + + PictureStructure structure; + Boolean mb_aff_frame_flag; + + int start_mb_nr; + int max_part_nr; //!< number of different partitions + int num_mb; //!< number of MBs in the slice + + int cmp_cbp[3]; + int curr_cbp[2]; + char symbol_mode; + short NoResidueDirect; + short partition_mode; + short idr_flag; + int frame_no; + unsigned int PicSizeInMbs; + int num_blk8x8_uv; + int nal_reference_idc; //!< nal_reference_idc from NAL unit + + // Bit depth related information + short bitdepth_luma; + short bitdepth_chroma; + int bitdepth_scale[2]; + int bitdepth_luma_qp_scale; + int bitdepth_chroma_qp_scale; + int bitdepth_lambda_scale; + + DataPartition *partArr; //!< array of partitions + MotionInfoContexts *mot_ctx; //!< pointer to struct of context models for use in CABAC + TextureInfoContexts *tex_ctx; //!< pointer to struct of context models for use in CABAC + + int mvscale[6][MAX_REFERENCE_PICTURES]; + char direct_spatial_mv_pred_flag; //!< Direct Mode type to be used (0: Temporal, 1: Spatial) + // Deblocking filter parameters + char DFDisableIdc; //!< Deblocking Filter Disable indicator + char DFAlphaC0Offset; //!< Deblocking Filter Alpha offset + char DFBetaOffset; //!< Deblocking Filter Beta offset + + byte weighted_prediction; //!< Use of weighted prediction + byte weighted_bipred_idc; //!< Use of weighted biprediction (note that weighted_pred_flag is probably not needed here) + + short luma_log_weight_denom; + short chroma_log_weight_denom; + short wp_luma_round; + short wp_chroma_round; + + short max_num_references; //!< maximum number of reference pictures that may occur + // Motion vectors for a macroblock + // These need to be changed to MotionVector parameters + MotionVector *****all_mv; //!< replaces local all_mv + MotionVector ******bipred_mv; //!< Biprediction MVs + //Weighted prediction + short ***wp_weight; //!< weight in [list][index][component] order + short ***wp_offset; //!< offset in [list][index][component] order + short ****wbp_weight; //!< weight in [list][fwd_index][bwd_idx][component] order + + int *****cofAC_new; //!< AC coefficients [comp][8x8block][4x4block][level/run][scan_pos] + + int ****cofAC; //!< AC coefficients [8x8block][4x4block][level/run][scan_pos] + int *** cofDC; //!< DC coefficients [yuv][level/run][scan_pos] + + // For rate control + int diffy[16][16]; + + int64 cur_cbp_blk[MAX_PLANE]; + int coeff_cost_cr[MAX_PLANE]; + + + int **tblk16x16; //!< Transform related array + int **tblk4x4; //!< Transform related array + int ****i16blk4x4; + + RD_DATA *rddata; + // RD_DATA data. Moved here to enable parallelization at the slice level + // of RDOQ + RD_DATA rddata_trellis_best; + RD_DATA rddata_trellis_curr; + //!< For MB level field/frame coding tools + RD_DATA rddata_top_frame_mb; + RD_DATA rddata_bot_frame_mb; + RD_DATA rddata_top_field_mb; + RD_DATA rddata_bot_field_mb; + + Boolean si_frame_indicator; + Boolean sp2_frame_indicator; + + char ***direct_ref_idx; //!< direct mode reference index buffer + char **direct_pdir; //!< direct mode direction buffer + + MotionVector ****tmp_mv8; + MotionVector ****tmp_mv4; + + distblk ***motion_cost8; + distblk ***motion_cost4; + int deltaQPTable[9]; + + // RDOQ + struct est_bits_cabac *estBitsCabac; // [NUM_BLOCK_TYPES] + double norm_factor_4x4; + double norm_factor_8x8; + int norm_shift_4x4; + int norm_shift_8x8; + + imgpel ****mpr_4x4; //!< prediction samples for 4x4 intra prediction modes + imgpel ****mpr_8x8; //!< prediction samples for 8x8 intra prediction modes + imgpel ****mpr_16x16; //!< prediction samples for 16x16 intra prediction modes (and chroma) + imgpel ***mb_pred; //!< current best prediction mode + int ***mb_rres; //!< the diff pixel values between the original macroblock/block and its prediction (reconstructed) + int ***mb_ores; //!< the diff pixel values between the original macroblock/block and its prediction (original) + + // Residue Color Transform + char b8_ipredmode8x8[4][4]; + char b8_intra_pred_modes8x8[16]; + char b4_ipredmode[16]; + char b4_intra_pred_modes[16]; + + struct rdo_structure *p_RDO; + struct epzs_params *p_EPZS; + + // This should be the right location for this + struct storable_picture **listX[6]; + char listXsize[6]; + + // Some Cabac related parameters (could be put in a different structure so we can dynamically allocate them when needed) + int coeff[64]; + int coeff_ctr; + int pos; + + int default_pic_num[2][MAX_REFERENCE_PICTURES]; + int default_view_id[2][MAX_REFERENCE_PICTURES]; + + // Function pointers + int (*mode_decision_for_I16x16_MB) (Macroblock *currMB, int lambda); + int (*mode_decision_for_I4x4_blocks) (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost); + int (*mode_decision_for_I8x8_blocks) (Macroblock *currMB, int b8, int lambda, distblk *min_cost); + distblk (*rdcost_for_4x4_intra_blocks) (Macroblock *currMB, int *c_nz, int b8, int b4, int ipmode, int lambda, int mostProbableMode, distblk min_rdcost); + distblk (*rdcost_for_8x8_intra_blocks) (Macroblock *currMB, int *c_nz, int b8, int ipmode, int lambda, distblk min_rdcost, int mostProbableMode); + void (*submacroblock_mode_decision) (Macroblock *currMB, RD_PARAMS *, RD_8x8DATA *, int ****, int, distblk *); + void (*intra_chroma_RD_decision) (Macroblock *currMB, RD_PARAMS *); + + void (*set_intrapred_4x4) (Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *all_available); + void (*set_intrapred_8x8) (Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *all_available); + void (*set_intrapred_16x16) (Macroblock *currMB, ColorPlane pl, int *left_available, int *up_available, int *all_available); + void (*intra_chroma_prediction) (Macroblock *currMB, int*, int*, int*); + void (*rdo_low_intra_chroma_decision) (Macroblock *currMB, int mb_available_up, int mb_available_left[2], int mb_available_up_left); + + void (*Get_Direct_Motion_Vectors) (Macroblock *currMB); + Boolean (*slice_too_big) (int bits_slice); //!< for use of callback functions + void (*set_motion_vectors_mb) (Macroblock *currMB); + void (*encode_one_macroblock) (Macroblock *currMB); + void (*set_stored_mb_parameters) (Macroblock *currMB); + void (*set_ref_and_motion_vectors) (Macroblock *currMB, struct pic_motion_params **motion, Info8x8 *part, int block); + + void (*luma_residual_coding) (Macroblock *currMB); + int (*luma_residual_coding_8x8) (Macroblock* currMB, int*, int64*, int, short, int[2], char *); + void (*chroma_residual_coding) (Macroblock *currMB); + + distblk (*compute_cost8x8) (struct video_par *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost); + distblk (*compute_cost4x4) (struct video_par *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost); + distblk (*find_sad_16x16) (Macroblock *currMB); + distblk (*distI16x16) (Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost); + + void (*set_lagrangian_multipliers) (struct slice *currSlice); + + void (*set_modes_and_refs_for_blocks) (Macroblock *currMB, short mode); + void (*set_coeff_and_recon_8x8 ) (Macroblock *currMB); + // Write MB info function pointers + void (*writeMB_typeInfo) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeMB_Skip) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeIntraPredMode) (SyntaxElement *se, DataPartition *dP); + void (*writeB8_typeInfo) (SyntaxElement *se, DataPartition *dP); + void (*writeRefFrame[6]) (Macroblock* currMB, SyntaxElement *se, DataPartition *dP); + int (*writeMotionInfo2NAL) (Macroblock* currMB); + int (*write_MB_layer) (Macroblock *currMB, int rdopt, int *coeff_rate); + void (*writeMVD) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeCBP) (Macroblock* currMB, SyntaxElement *se, DataPartition *dP); + void (*writeDquant) (Macroblock* currMB, SyntaxElement *se, DataPartition *dP); + void (*writeCIPredMode) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeFieldModeInfo) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeMB_transform_size)(Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + int (*writeCoeff16x16) (Macroblock* currMB, ColorPlane); + int (*writeCoeff4x4_CAVLC) (Macroblock* currMB, int block_type, int b8, int b4, int param); + void (*write_and_store_CBP_block_bit) (Macroblock* currMB, EncodingEnvironmentPtr eep_dp, int type, int cbp_bit, TextureInfoContexts* tex_ctx); + + // Coding state + void (*reset_coding_state) (Macroblock *currMB, struct coding_state *); + void (*store_coding_state) (Macroblock *currMB, struct coding_state *); + + // List initialization / reordering + void (*init_lists ) (struct slice *currSlice); + void (*reorder_lists ) (struct slice *currSlice); + void (*poc_ref_pic_reorder_frame) (struct slice *currSlice, unsigned num_ref_idx_lX_active, int list_no ); + + + // Quantization + int (*quant_4x4) (Macroblock *currMB, int **tblock, struct quant_methods *q_method); + int (*quant_ac4x4cr) (Macroblock *currMB, int **tblock, struct quant_methods *q_method); + int (*quant_dc4x4) (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]); + int (*quant_ac4x4) (Macroblock *currMB, int **tblock, struct quant_methods *q_method); + int (*quant_8x8) (Macroblock *currMB, int **tblock, struct quant_methods *q_method); + int (*quant_8x8cavlc)(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC); + + int (*quant_dc_cr) (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]); + void (*rdoq_4x4) (Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[16]); + + void (*rdoq_dc) (Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, + const byte (*pos_scan)[2], int levelTrellis[16], int type); + + void (*rdoq_ac4x4) (Macroblock *currMB, int **tblock , struct quant_methods *q_method, int levelTrellis[16]); + + void (*rdoq_dc_cr) (Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, + const byte (*pos_scan)[2], int levelTrellis[16], int type); + + void (*set_modes_and_reframe) (Macroblock *currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx); + void (*store_8x8_motion_vectors) (struct slice *currSlice, int dir, int block8x8, Info8x8 *B8x8Info); + distblk (*getDistortion) ( Macroblock *currMB ); + +} Slice; + +#if (MVC_EXTENSION_ENABLE) +typedef struct prev_coding_stats +{ + int frm_no_in_file; + char pic_type[256]; + int view_id; + int cur_bits; + int wp_method; + int AverageFrameQP; + int lambda; + float psnr_value[3]; + float ssim_value[3]; + int tmp_time; + int me_time; + int fld_flag; + int intras; + int direct_mode; + int num_ref_idx_l0_active; + int num_ref_idx_l1_active; + int rd_pass; + int nal_reference_idc; + +} PrevCodingStats; +#endif + +//! DistortionParams +typedef struct distortion_metric +{ + float value[3]; //!< current frame distortion + float average[3]; //!< average frame distortion + float avslice[NUM_SLICE_TYPES][3]; //!< average frame type distortion +} DistMetric; + +typedef struct distortion_params +{ + int frame_ctr; //!< number of coded frames + DistMetric metric[TOTAL_DIST_TYPES]; //!< Distortion metrics +#if (MVC_EXTENSION_ENABLE) + int frame_ctr_v[2]; //!< number of coded frames for each view + DistMetric metric_v[2][TOTAL_DIST_TYPES]; //!< Distortion metrics for each view +#endif +} DistortionParams; + +typedef struct picture +{ + int no_slices; + int bits_per_picture; + struct slice *slices[MAXSLICEPERPICTURE]; + + DistMetric distortion; + byte idr_flag; +} Picture; + +//! block 8x8 temporary RD info +typedef struct block_8x8_info +{ + Info8x8 best[MAXMODE][4]; +} Block8x8Info; + +typedef struct coding_par +{ + int layer_id; + ColorFormat yuv_format; + int P444_joined; + + short bitdepth_luma; + short bitdepth_chroma; + int bitdepth_scale[2]; + int bitdepth_luma_qp_scale; + int bitdepth_chroma_qp_scale; + int bitdepth_lambda_scale; + + uint32 dc_pred_value_comp[MAX_PLANE]; //!< component value for DC prediction (depends on component pel bit depth) + int max_pel_value_comp [MAX_PLANE]; //!< max value that one picture element (pixel) can take (depends on pic_unit_bitdepth) + int max_imgpel_value_comp_sq [MAX_PLANE]; //!< max value that one picture element (pixel) can take (depends on pic_unit_bitdepth) + + int num_blk8x8_uv; + int num_cdc_coeff; + + short mb_cr_size_x; + short mb_cr_size_y; + int mb_size[MAX_PLANE][2]; + + int max_bitCount; + int width; //!< Number of pels + int width_padded; //!< Width in pels of padded picture + int width_blk; //!< Number of columns in blocks + int width_cr; //!< Number of pels chroma + int height; //!< Number of lines + int height_padded; //!< Number in lines of padded picture + int height_blk; //!< Number of lines in blocks + int height_cr; //!< Number of lines chroma + int height_cr_frame; //!< Number of lines chroma frame + int size; //!< Luma Picture size in pels + int size_cr; //!< Chroma Picture size in pels + + int padded_size_x; + int padded_size_x_m8x8; + int padded_size_x_m4x4; + int cr_padded_size_x; + int cr_padded_size_x_m8; + int cr_padded_size_x2; + int cr_padded_size_x4; + + int pad_size_uv_x; + int pad_size_uv_y; + unsigned char chroma_mask_mv_y; + unsigned char chroma_mask_mv_x; + int chroma_shift_x; + int chroma_shift_y; + int shift_cr_x; + int shift_cr_y; + + unsigned int PicWidthInMbs; + unsigned int PicHeightInMapUnits; + unsigned int FrameHeightInMbs; + unsigned int FrameSizeInMbs; + + unsigned int frame_num; + unsigned int prevFrameNum; + unsigned int FrameNumOffset; + unsigned int prevFrameNumOffset; + int last_ref_idc; + + //uint32 dc_pred_value; //!< DC prediction value for current component + //short max_imgpel_value; //!< max value that one picture element (pixel) can take (depends on pic_unit_bitdepth) + char md5String[2][33]; +}CodingParameters; + +//! VideoParameters +typedef struct video_par +{ + InputParameters *p_Inp; + pic_parameter_set_rbsp_t *active_pps; + seq_parameter_set_rbsp_t *active_sps; + struct sei_params *p_SEI; + struct decoders *p_decs; + CodingParameters *p_CurrEncodePar; + CodingParameters *p_EncodePar[MAX_NUM_DPB_LAYERS]; + + int number; //!< current image number to be encoded (in first layer) + int LevelIndex; //!< mapped level idc + int MaxVmvR[6]; //!< maximum vertical motion vector + int MaxHmvR[6]; //!< maximum horizontal motion vector + int current_mb_nr; + short current_slice_nr; + short type; + PictureStructure structure; //!< picture structure + int base_dist; + int num_ref_frames; //!< number of reference frames to be used + int max_num_references; //!< maximum number of reference pictures that may occur + int masterQP; //!< Master quantization parameter + int qp; //!< quant for the current frame + int qpsp; //!< quant for the prediction frame of SP-frame + + int prev_frame_no; // POC200301 + int consecutive_non_reference_pictures; // POC200301 + + // prediction structure + int frm_struct_buffer; //!< length of the frame struct buffer (this may also be a define) + int last_idr_code_order; + int last_idr_disp_order; + int last_mmco_5_code_order; //!< it is a good idea to re-initialize POCs after such a frame: while seemingly not required it is critical for good implicit WP performance (I *THINK*) since POCs are set internally to zero after an MMCO=5 command. + int last_mmco_5_disp_order; + int curr_frm_idx; //!< frame we wish to code in coding order (points also to p_frm) + int FrameNumOffset; //!< POC type 1 + int prevFrameNumOffset; //!< POC type 1 + unsigned int prevFrameNum; //!< POC type 1 + SeqStructure *p_pred; + FrameUnitStruct *p_curr_frm_struct; + PicStructure *p_curr_pic; + SliceStructure *p_curr_slice; + int pic_struct; + struct search_window searchRange; + ImageData imgData; //!< Image data to be encoded + ImageData imgData0; //!< Input Image Data + ImageData imgData1; + ImageData imgData2; + ImageData imgData3; + // Data needed for 3:2 pulldown or temporal interleaving + ImageData imgData32; //!< Image data to be encoded + ImageData imgData4; + ImageData imgData5; + ImageData imgData6; + ImageData imgRefData; + ImageData origData0; + ImageData origData1; + + ImageData imgDataOpt1; + ImageData imgDataOpt2; + + + int num_slices_wp; + int wp_parameters_set; + short ****wp_weights; // explicit WP weights + short ****wp_offsets; // explicit WP offsets + short *****wbp_weight; // implicit WP weights + + struct image_structure imgSRC; + struct image_structure imgREF; + struct image_structure imgREF0; + struct image_structure imgREF1; + struct image_structure imgRGB_src; + struct image_structure imgRGB_ref; + int **imgY_sub_tmp; //!< Y picture temporary component (Quarter pel) + imgpel **imgY_com; //!< Encoded luma images + imgpel **imgUV_com[2]; //!< Encoded croma images + + imgpel **imgY_com_buf[2]; //!< Encoded luma images + imgpel **imgUV_com_buf[2][2]; //!< Encoded croma images + + imgpel **pCurImg; //!< Reference image. Luma for other profiles, can be any component for 4:4:4 + // global picture format dependend buffers, mem allocation in image.c + imgpel **pImgOrg[MAX_PLANE]; + + imgpel **pCurImgRef; + imgpel **pImgOrgRef[MAX_PLANE]; + + Picture *p_frame_pic; + Picture **frame_pic; +#if (MVC_EXTENSION_ENABLE) + Picture **field_pic_ptr; + Picture **field_pic1; + Picture **field_pic2; +#else + Picture **field_pic; +#endif + + Picture *frame_pic_si; + + byte *MapUnitToSliceGroupMap; + + byte *buf; + byte *ibuf; + +#ifdef _LEAKYBUCKET_ + long *Bit_Buffer; + unsigned long total_frame_buffer; +#endif + + unsigned int log2_max_frame_num_minus4; + unsigned int log2_max_pic_order_cnt_lsb_minus4; + unsigned int max_frame_num; + unsigned int max_pic_order_cnt_lsb; + + int64 me_tot_time; + int64 tot_time; + int64 me_time; + + byte mixedModeEdgeFlag; + + int *RefreshPattern; + int *IntraMBs; + int WalkAround; + int NumberOfMBs; + int NumberIntraPerPicture; + + short start_me_refinement_hp; //!< if set then recheck the center position when doing half-pel motion refinement + short start_me_refinement_qp; //!< if set then recheck the center position when doing quarter-pel motion refinement + + // Motion Estimation + struct umhex_struct *p_UMHex; + struct umhex_smp_struct *p_UMHexSMP; + struct me_full_fast *p_ffast_me; + + struct search_window *p_search_window; + + // EPZS + struct epzs_struct *sdiamond; + struct epzs_struct *square; + struct epzs_struct *ediamond; + struct epzs_struct *ldiamond; + struct epzs_struct *sbdiamond; + struct epzs_struct *pmvfast; + struct epzs_struct *search_rpu_square; + struct epzs_struct *SP_M2DRPU; + struct epzs_struct *SP_M2DRPU4MM; + + // RDOQ + int precalcUnaryLevelTab[128][MAX_PREC_COEFF]; + int AdaptRndWeight; + int AdaptRndCrWeight; + + + ////////////////////////////////////////////////////////////////////////// + // B pictures + // motion vector : forward, backward, direct + byte MBPairIsField; //!< For MB level field/frame coding tools + + // Buffers for rd optimization with packet losses, Dim. Kontopodis + byte **pixel_map; //!< Shows the latest reference frame that is reliable for each pixel + byte **refresh_map; //!< Stores the new values for pixel_map + int intras; //!< Counts the intra updates in each frame. + int iInterViewMBs; + int RCMinQP; + int RCMaxQP; + + float framerate; + + int is_v_block; + int mb_y_upd; + int mb_y_intra; //!< which GOB to intra code + char **ipredmode; //!< intra prediction mode + char **ipredmode8x8; //!< help storage for 8x8 modes, inserted by YV + //fast intra prediction; + char **ipredmode4x4_line; //!< intra prediction mode + char **ipredmode8x8_line; //!< help storage for 8x8 modes, inserted by YV + + int cod_counter; //!< Current count of number of skipped macroblocks in a row + int ***nz_coeff; //!< number of coefficients per block (CAVLC) + int ***nz_coeff_buf[2]; + int pix_x; //!< current pixel horizontal + int pix_y; //!< current pixel vertical + + + imgpel min_IPCM_value; + // Cabac related parameters (we can put these in a structure) + int pic_bin_count; + + // Adaptive rounding + int ****ARCofAdj4x4; //!< Transform coefficients for 4x4 luma/chroma. + int ****ARCofAdj8x8; //!< Transform coefficients for 4x4 luma/chroma. + + ImageData tempData1, tempData2, tempData3, tempData4; + imgpel **tempImg; + + Picture *currentPicture; //!< The coded picture currently in the works (typically p_frame_pic, p_Vid->field_pic[0], or p_Vid->field_pic[1]) + struct slice *currentSlice; //!< pointer to current Slice data struct + Macroblock *mb_data; //!< array containing all MBs of a whole frame + Block8x8Info *b8x8info; //!< block 8x8 information for RDopt + + //FAST_REFPIC_DECISION + int mb_refpic_used; //=FREXT_HP || profile_idc == FREXT_CAVLC444 ); +} + + +static inline int is_MVC_profile(unsigned int profile_idc) +{ + return ( (0) +#if (MVC_EXTENSION_ENABLE) + || (profile_idc == MULTIVIEW_HIGH) || (profile_idc == STEREO_HIGH) +#endif + ); +} + + +#endif + diff --git a/lencod/inc/header.h b/lencod/inc/header.h new file mode 100644 index 0000000..bc896bb --- /dev/null +++ b/lencod/inc/header.h @@ -0,0 +1,20 @@ + +/*! + ************************************************************************************* + * \file header.h + * + * \brief + * Prototypes for header.c + ************************************************************************************* + */ + +#ifndef _HEADER_H_ +#define _HEADER_H_ + +extern int SliceHeader (Slice* currSlice); +extern int Partition_BC_Header(Slice *currSlice, int PartNo); +extern int writeERPS (SyntaxElement *sym, DataPartition *partition); +extern int dec_ref_pic_marking(Bitstream *bitstream, DecRefPicMarking_t *p_drpm, int idr_flag, int no_output_of_prior_pics_flag, int long_term_reference_flag ); + +#endif + diff --git a/lencod/inc/image.h b/lencod/inc/image.h new file mode 100644 index 0000000..7972745 --- /dev/null +++ b/lencod/inc/image.h @@ -0,0 +1,59 @@ + +/*! + ************************************************************************ + * \file image.h + * + * \brief + * headers for image processing + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Inge Lille-Langoy + * - Alexis Michael Tourapis + * + ************************************************************************ + */ +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + +#include "mbuffer.h" + +typedef struct coding_info { + short type; + int intras; + int sumFrameQP; + int num_ref_idx_l0; + int num_ref_idx_l1; + pic_parameter_set_rbsp_t *active_pps; +} CodingInfo; + +extern int encode_one_frame ( VideoParameters *p_Vid, InputParameters *p_Inp); +extern Boolean dummy_slice_too_big ( int bits_slice); +extern void copy_rdopt_data ( Macroblock *currMB); // For MB level field/frame coding tools +extern void UnifiedOneForthPix ( VideoParameters *p_Vid, StorablePicture *s); +// For 4:4:4 independent mode +extern void UnifiedOneForthPix_JV ( VideoParameters *p_Vid, int nplane, StorablePicture *s); +extern void frame_picture ( VideoParameters *p_Vid, Picture *frame, ImageData *imgData, int rd_pass); +extern byte get_idr_flag ( VideoParameters *p_Vid ); +extern byte get_random_access_flag( VideoParameters *p_Vid ); +extern void write_non_vcl_nalu ( VideoParameters *p_Vid); +extern void write_non_vcl_nalu_bot_fld( VideoParameters *p_Vid ); +#if (MVC_EXTENSION_ENABLE) +extern void write_non_vcl_nalu_mvc( VideoParameters *p_Vid); +#endif + +extern void frame_picture_mp ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void restore_coding_info ( VideoParameters *p_Vid, CodingInfo *coding_info ); +extern void store_coding_info ( VideoParameters *p_Vid, CodingInfo *coding_info ); +extern void store_coding_and_rc_info( VideoParameters *p_Vid, CodingInfo *coding_info ); +extern void swap_frame_buffer ( VideoParameters *p_Vid, int a, int b ); +extern void frame_picture_mp_exit ( VideoParameters *p_Vid, CodingInfo *coding_info ); + +extern void GenerateImagePyramid(VideoParameters *p_Vid, int size_x, int size_y, imgpel ***p_hme_int_img, int offset_x, int offset_y); +extern void OutputImage(char *pcPrefix, int iFrameNo, int iLevel, imgpel **pImg, int iWidth, int iHeight, int iXOffset, int iYOffset); +extern void copy_params(VideoParameters *p_Vid, StorablePicture *enc_picture, seq_parameter_set_rbsp_t *active_sps); +extern void OtfCompatibility_copyWithPadding ( imgpel **dstImg, imgpel **srcImg, int size_x, int size_y, int padding_x, int padding_y ); // JLT + +#endif + diff --git a/lencod/inc/img_chroma.h b/lencod/inc/img_chroma.h new file mode 100644 index 0000000..8f3774d --- /dev/null +++ b/lencod/inc/img_chroma.h @@ -0,0 +1,23 @@ +/*! + *************************************************************************** + * \file + * img_chroma.h + * + * \author + * Athanasios Leontaris + * Alexis Michael Tourapis + * + * \date + * 4. October 2006 + * + * \brief + * Headerfile for luma interpolation functions + ************************************************************************** + */ + +#ifndef _IMG_CHROMA_H_ +#define _IMG_CHROMA_H_ + +extern void getSubImagesChroma( VideoParameters *p_Vid, StorablePicture *s ); + +#endif // _IMG_CHROMA_H_ diff --git a/lencod/inc/img_dist_ms_ssim.h b/lencod/inc/img_dist_ms_ssim.h new file mode 100644 index 0000000..31fc6a7 --- /dev/null +++ b/lencod/inc/img_dist_ms_ssim.h @@ -0,0 +1,25 @@ +/*! + *************************************************************************** + * \file + * img_dist_ms_ssim.h + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + * - Alexis Michael Tourapis + * + * \date + * 18 July 2008 + * + * \brief + * Headerfile to calculate multi-scale structural similarity (SSIM) index + ************************************************************************** + */ + +#ifndef _IMG_DIST_MS_SSIM_H_ +#define _IMG_DIST_MS_SSIM_H_ +#include "img_distortion.h" + +extern void find_ms_ssim (VideoParameters *p_Vid, InputParameters *p_Inp, ImageStructure *imgREF, ImageStructure *imgSRC, DistMetric metricMS_SSIM[3]); + +#endif diff --git a/lencod/inc/img_dist_snr.h b/lencod/inc/img_dist_snr.h new file mode 100644 index 0000000..2b89497 --- /dev/null +++ b/lencod/inc/img_dist_snr.h @@ -0,0 +1,24 @@ +/*! + *************************************************************************** + * \file + * img_dist_snr.h + * + * \author + * Woo-Shik Kim + * + * \date + * 29 May 2008 + * + * \brief + * Headerfile to calculate signal to noise ratio (SNR) + ************************************************************************** + */ + +#ifndef _IMG_DIST_SNR_H_ +#define _IMG_DIST_SNR_H_ +#include "img_distortion.h" + +extern void find_snr(VideoParameters *p_Vid, ImageStructure *imgREF, ImageStructure *imgSRC, DistMetric metricSSE[3], DistMetric metricPSNR[3]); + +#endif + diff --git a/lencod/inc/img_dist_ssim.h b/lencod/inc/img_dist_ssim.h new file mode 100644 index 0000000..52111b9 --- /dev/null +++ b/lencod/inc/img_dist_ssim.h @@ -0,0 +1,26 @@ +/*! + *************************************************************************** + * \file + * img_dist_ssim.h + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + * - Alexis Michael Tourapis + * + * \date + * 29 May 2008 + * + * \brief + * Headerfile to calculate structural similarity (SSIM) index + ************************************************************************** + */ + +#ifndef _IMG_DIST_SSIM_H_ +#define _IMG_DIST_SSIM_H_ +#include "img_distortion.h" + +extern void find_ssim (VideoParameters *p_Vid, InputParameters *p_Inp, ImageStructure *imgREF, ImageStructure *imgSRC, DistMetric metricSSIM[3]); + +#endif + diff --git a/lencod/inc/img_distortion.h b/lencod/inc/img_distortion.h new file mode 100644 index 0000000..6a6fbdb --- /dev/null +++ b/lencod/inc/img_distortion.h @@ -0,0 +1,27 @@ + +/*! + ************************************************************************ + * \file img_distortion.h + * + * \brief + * Distortion related definitions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Woo-Shik Kim + * + ************************************************************************ + */ + +#ifndef _IMG_DISTORTION_H_ +#define _IMG_DISTORTION_H_ + +extern void accumulate_avslice(DistMetric metric[3], int slice_type, int frames); +extern void accumulate_average(DistMetric metric[3], int frames); +extern void find_distortion (VideoParameters *p_Vid, ImageData *imgData); +extern void select_img (VideoParameters *p_Vid, ImageStructure *imgSRC, ImageStructure *imgREF, ImageData *imgData); +extern void compute_distortion(VideoParameters *p_Vid, ImageData *imgData); + +#endif + diff --git a/lencod/inc/img_luma.h b/lencod/inc/img_luma.h new file mode 100644 index 0000000..91a7d6a --- /dev/null +++ b/lencod/inc/img_luma.h @@ -0,0 +1,39 @@ +/*! + *************************************************************************** + * \file + * img_luma.h + * + * \author + * Athanasios Leontaris + * Alexis Michael Tourapis + * + * \date + * 4. October 2006 + * + * \brief + * Headerfile for luma interpolation functions + ************************************************************************** + */ + +#ifndef _IMG_LUMA_H_ +#define _IMG_LUMA_H_ + +static const int ONE_FOURTH_TAP[2][3] = +{ + {20, -5, 1}, // AVC Interpolation taps + {20,-4, 0}, // Experimental - not valid +}; + +extern void getSubImagesLuma ( VideoParameters *p_Vid, StorablePicture *s ); +/* +extern void getSubImageInteger ( StorablePicture *s, imgpel **dstImg, imgpel **srcImg); +extern void getSubImageInteger_s ( StorablePicture *s, imgpel **dstImg, imgpel **srcImg); +extern void getHorSubImageSixTap ( VideoParameters *p_Vid, StorablePicture *s, imgpel **dst_imgY, imgpel **ref_imgY); +extern void getVerSubImageSixTap ( VideoParameters *p_Vid, StorablePicture *s, imgpel **dst_imgY, imgpel **ref_imgY); +extern void getVerSubImageSixTapTmp( VideoParameters *p_Vid, StorablePicture *s, imgpel **dst_imgY); +extern void getSubImageBiLinear ( StorablePicture *s, imgpel **dstImg, imgpel **srcImgL, imgpel **srcImgR); +extern void getHorSubImageBiLinear ( StorablePicture *s, imgpel **dstImg, imgpel **srcImgL, imgpel **srcImgR); +extern void getVerSubImageBiLinear ( StorablePicture *s, imgpel **dstImg, imgpel **srcImgT, imgpel **srcImgB); +extern void getDiagSubImageBiLinear( StorablePicture *s, imgpel **dstImg, imgpel **srcImgT, imgpel **srcImgB); +*/ +#endif // _IMG_LUMA_H_ diff --git a/lencod/inc/intra16x16.h b/lencod/inc/intra16x16.h new file mode 100644 index 0000000..fb174b0 --- /dev/null +++ b/lencod/inc/intra16x16.h @@ -0,0 +1,30 @@ +/*! + *************************************************************************** + * + * \file intra16x16.h + * + * \brief + * prototypes of 16x16 intra prediction + * + * \date + * 26 September 2009 + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * Alexis Michael Tourapis + **************************************************************************/ + +#ifndef _INTRA16X16_H_ +#define _INTRA16X16_H_ + +extern distblk distI16x16_sad (Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost); +extern distblk distI16x16_sse (Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost); +extern distblk distI16x16_satd (Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost); + +extern distblk find_sad_16x16_JM (Macroblock *currMB); + +extern void set_intrapred_16x16_mbaff (Macroblock *currMB, ColorPlane pl, int *left_available, int *up_available, int *all_available); +extern void set_intrapred_16x16 (Macroblock *currMB, ColorPlane pl, int *left_available, int *up_available, int *all_available); +extern void get_intrapred_16x16 (Macroblock *currMB, ColorPlane pl, int i16x16_mode, int left_available, int up_available); + +#endif //_INTRA16X16_H_ diff --git a/lencod/inc/intra4x4.h b/lencod/inc/intra4x4.h new file mode 100644 index 0000000..612abbf --- /dev/null +++ b/lencod/inc/intra4x4.h @@ -0,0 +1,26 @@ + +/*! + ************************************************************************ + * \file intra4x4.h + * + * \brief + * intra 4x4 functions + * + * \author + * - Alexis Michael Tourapis + * + ************************************************************************ + */ + +#ifndef _INTRA4x4_H_ +#define _INTRA4x4_H_ + +// intra 4x4 generation function +extern void set_intrapred_4x4_mbaff(Macroblock *currMB, ColorPlane pl, int img_x, int img_y, int *left_available, int *up_available, int *all_available); +extern void set_intrapred_4x4 (Macroblock *currMB, ColorPlane pl, int img_x, int img_y, int *left_available, int *up_available, int *all_available); +extern void get_intrapred_4x4 (Macroblock *currMB, ColorPlane pl, int i4x4_mode, int img_x, int img_y, int left_available, int up_available); + +// 4x4 residual generation +extern void generate_pred_error_4x4(imgpel **cur_img, imgpel **prd_img, imgpel **cur_prd, int **mb_rres, int pic_opix_x, int block_x); +#endif + diff --git a/lencod/inc/intra8x8.h b/lencod/inc/intra8x8.h new file mode 100644 index 0000000..383d04e --- /dev/null +++ b/lencod/inc/intra8x8.h @@ -0,0 +1,27 @@ +/*! + *************************************************************************** + * + * \file intra8x8.h + * + * \brief +* prototypes of 8x8 intra prediction + * + * \date + * 5. February 2009 + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * Alexis Michael Tourapis + **************************************************************************/ + +#ifndef _INTRA8X8_H_ +#define _INTRA8X8_H_ + +extern void set_intrapred_8x8_mbaff (Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *up_left_available); +extern void set_intrapred_8x8 (Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *up_left_available); +extern void get_intrapred_8x8 (Macroblock *currMB, ColorPlane pl, int i8x8_mode, int left_available, int up_available); +extern void LowPassForIntra8x8Pred (imgpel *PredPel, int block_up_left, int block_up, int block_left); + +extern void generate_pred_error_8x8 (imgpel **cur_img, imgpel **prd_img, imgpel **cur_prd, int **mb_rres, int pic_opix_x, int block_x); + +#endif //_TRANSFORM8X8_H_ diff --git a/lencod/inc/intrarefresh.h b/lencod/inc/intrarefresh.h new file mode 100644 index 0000000..eb6a422 --- /dev/null +++ b/lencod/inc/intrarefresh.h @@ -0,0 +1,26 @@ + +/*! + *************************************************************************** + * + * \file intrarefresh.h + * + * \brief + * Pseudo-Raqndom Intra macroblock refresh support + * + * \date + * 16 June 2002 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + **************************************************************************/ + +#ifndef _INTRAREFRESH_H_ +#define _INTRAREFRESH_H_ + +extern void RandomIntraInit(VideoParameters *p_Vid, int xsize, int ysize, int refresh); +extern void RandomIntraUninit(VideoParameters *p_Vid); +extern int RandomIntra (VideoParameters *p_Vid, int mb); //! returns 1 for MBs that need forced Intra +extern void RandomIntraNewPicture (VideoParameters *p_Vid); //! to be called once per picture + + +#endif //_INTRAREFRESH_H_ diff --git a/lencod/inc/lambda.h b/lencod/inc/lambda.h new file mode 100644 index 0000000..97358ee --- /dev/null +++ b/lencod/inc/lambda.h @@ -0,0 +1,31 @@ +/*! + *************************************************************************** + * \file + * lambda.h + * + * \date + * 13 September 2009 + * + * \brief + * Headerfile for lagrangian lambda related computations + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + + ************************************************************************** + */ + +#ifndef _LAMBDA_H_ +#define _LAMBDA_H_ + +#include "global.h" + +extern void get_implicit_lambda_p_slice (Slice *currSlice); +extern void get_implicit_lambda_b_slice (Slice *currSlice); +extern void get_implicit_lambda_i_slice (Slice *currSlice); +extern void get_implicit_lambda_sp_slice(Slice *currSlice); +extern void get_explicit_lambda (Slice *currSlice); +extern void get_fixed_lambda (Slice *currSlice); +extern void set_rdoq_lambda (Slice *currSlice); + +#endif diff --git a/lencod/inc/leaky_bucket.h b/lencod/inc/leaky_bucket.h new file mode 100644 index 0000000..60d0691 --- /dev/null +++ b/lencod/inc/leaky_bucket.h @@ -0,0 +1,29 @@ + +/*! + *************************************************************************** + * + * \file leaky_bucket.h + * + * \brief + * Header for Leaky Buffer parameters + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Shankar Regunathan + **************************************************************************/ + +#ifndef _LEAKY_BUCKET_H_ +#define _LEAKY_BUCKET_H_ + + +/* Leaky Bucket Parameter Optimization */ +#ifdef _LEAKYBUCKET_ +extern int get_LeakyBucketRate(InputParameters *p_Inp, unsigned long NumberLeakyBuckets, unsigned long *Rmin); +extern void PutBigDoubleWord (unsigned long dw, FILE *fp); +extern void write_buffer (InputParameters *p_Inp, unsigned long NumberLeakyBuckets, unsigned long Rmin[], unsigned long Bmin[], unsigned long Fmin[]); +extern void Sort (unsigned long NumberLeakyBuckets, unsigned long *Rmin); +extern void calc_buffer (VideoParameters *p_Vid, InputParameters *p_Inp); +#endif + +#endif + diff --git a/lencod/inc/list_reorder.h b/lencod/inc/list_reorder.h new file mode 100644 index 0000000..9af6f50 --- /dev/null +++ b/lencod/inc/list_reorder.h @@ -0,0 +1,39 @@ +/*! + *************************************************************************** + * \file + * list_reorder.h + * + * \date + * 25 Feb 2009 + * + * \brief + * Headerfile for slice-related functions + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Athanasios Leontaris + * - Karsten Suehring + * - Alexis Michael Tourapis + ************************************************************************** + */ + +#ifndef _LIST_REORDER_H_ +#define _LIST_REORDER_H_ + +#include "global.h" +#include "mbuffer.h" + +extern void init_ref_pic_list_reordering( Slice *currSlice, int refReorderMethod ); +extern void reorder_lists ( Slice *currSlice ); +extern void wp_mcprec_reorder_lists ( Slice *currSlice ); + + +extern void poc_ref_pic_reorder_frame_default( Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no ); +extern void poc_ref_pic_reorder_field ( Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no ); +extern void poc_ref_pic_reorder_field_enh ( Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no ); + +extern void tlyr_ref_pic_reorder_frame_default( Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no ); +extern void reorder_against_default_ref_pic_lists( Slice *currSlice, int cur_list ); +extern void poc_ref_pic_reorder_frame_enh( Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no ); +extern void set_default_ref_pic_lists( Slice *currSlice ); + +#endif diff --git a/lencod/inc/lln_mc_prediction.h b/lencod/inc/lln_mc_prediction.h new file mode 100644 index 0000000..52aa62e --- /dev/null +++ b/lencod/inc/lln_mc_prediction.h @@ -0,0 +1,35 @@ +/*! + ************************************************************************************* + * \file lln_mc_prediction.h + * + * \brief + * definitions for motion compensated prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * - Modified for use in hypothetical decoders at encoder + * by Peshala V. Pahalawatta + * + ************************************************************************************* + */ + +#ifndef _LLN_MC_PREDICTION_H_ +#define _LLN_MC_PREDICTION_H_ + +#include "global.h" +#include "mbuffer.h" + + +extern void get_block_luma (Macroblock *currMB, int decoder, ColorPlane pl, StorablePicture *dec_picture, StorablePicture *list, int x_pos, int y_pos, int block_size_y, int block_size_x, imgpel block[MB_BLOCK_SIZE][MB_BLOCK_SIZE]); +extern void get_block_chroma(Macroblock *currMb, int decoder, int uv, StorablePicture *dec_picture, StorablePicture *list, int x_pos, int y_pos, int block_size_x, int block_size_y, imgpel block[MB_BLOCK_SIZE][MB_BLOCK_SIZE]); + +//extern void intra_cr_decoding(Macroblock *currMB, int yuv, int smb); +//extern void prepare_direct_params(Macroblock *currMB, StorablePicture *dec_picture, MotionVector *pmvl0, MotionVector *pmvl1,char *l0_rFrame, char *l1_rFrame); + +extern void perform_mc (Macroblock* currMB, int decoder, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int l0_mode, int l1_mode, PicMotionParams **mv_info, int i, int j, int block_size_x, int block_size_y, short bipred_me); +extern void perform_mc_concealment(Macroblock* currMB, int decoder, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int l0_mode, int l1_mode, PicMotionParams **mv_info, int i, int j, int block_size_x, int block_size_y); + +#endif + diff --git a/lencod/inc/loop_filter.h b/lencod/inc/loop_filter.h new file mode 100644 index 0000000..a093b01 --- /dev/null +++ b/lencod/inc/loop_filter.h @@ -0,0 +1,67 @@ +/*! + *************************************************************************** + * \file + * loop_filter.h + * + * \date + * 25 April 2010 + * + * \brief + * Headerfile for loopfilter processing + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + + ************************************************************************** + */ + +#ifndef _LOOP_FILTER_H_ +#define _LOOP_FILTER_H_ + +#include "global.h" + +#define GROUP_SIZE 1 + +/*********************************************************************************************************/ + +// NOTE: In principle, the alpha and beta tables are calculated with the formulas below +// Alpha( qp ) = 0.8 * (2^(qp/6) - 1) +// Beta ( qp ) = 0.5 * qp - 7 + +// The tables actually used have been "hand optimized" though (by Anthony Joch). So, the +// table values might be a little different to formula-generated values. Also, the first +// few values of both tables is set to zero to force the filter off at low qp’s + +static const byte ALPHA_TABLE[52] = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,4,4,5,6, 7,8,9,10,12,13,15,17, 20,22,25,28,32,36,40,45, 50,56,63,71,80,90,101,113, 127,144,162,182,203,226,255,255} ; +static const byte BETA_TABLE[52] = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,2,2,3, 3,3,3, 4, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9,10,10, 11,11,12,12,13,13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18} ; +static const byte CLIP_TAB[52][5] = +{ + { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 1, 1, 1, 1}, + { 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 2, 3, 3}, + { 0, 1, 2, 3, 3},{ 0, 2, 2, 3, 3},{ 0, 2, 2, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 3, 3, 5, 5},{ 0, 3, 4, 6, 6},{ 0, 3, 4, 6, 6}, + { 0, 4, 5, 7, 7},{ 0, 4, 5, 8, 8},{ 0, 4, 6, 9, 9},{ 0, 5, 7,10,10},{ 0, 6, 8,11,11},{ 0, 6, 8,13,13},{ 0, 7,10,14,14},{ 0, 8,11,16,16}, + { 0, 9,12,18,18},{ 0,10,13,20,20},{ 0,11,15,23,23},{ 0,13,17,25,25} +} ; + +static const char chroma_edge[2][4][4] = //[dir][edge][yuv_format] +{ { {-4, 0, 0, 0}, + {-4,-4,-4, 4}, + {-4, 4, 4, 8}, + {-4,-4,-4, 12}}, + + { {-4, 0, 0, 0}, + {-4,-4, 4, 4}, + {-4, 4, 8, 8}, + {-4,-4, 12, 12}}}; + +static const int pelnum_cr[2][4] = {{0,8,16,16}, {0,8, 8,16}}; //[dir:0=vert, 1=hor.][yuv_format] + + +static inline int compare_mvs(const MotionVector *mv0, const MotionVector *mv1, int mvlimit) +{ + return ((iabs( mv0->mv_x - mv1->mv_x) >= 4) | (iabs( mv0->mv_y - mv1->mv_y) >= mvlimit)); +} + +#endif diff --git a/lencod/inc/macroblock.h b/lencod/inc/macroblock.h new file mode 100644 index 0000000..0e7ab05 --- /dev/null +++ b/lencod/inc/macroblock.h @@ -0,0 +1,128 @@ + +/*! + ************************************************************************ + * \file + * macroblock.h + * + * \brief + * Arrays for macroblock processing + * + * \author + * Inge Lille-Langoy \n + * Telenor Satellite Services \n + * P.O.Box 6914 St.Olavs plass \n + * N-0130 Oslo, Norway + * + ************************************************************************/ + +#ifndef _MACROBLOCK_H_ +#define _MACROBLOCK_H_ + +#include "block.h" +#include "macroblock_p444.h" + +static const int block8x8_idx[3][4][4] = +{ + { + {0, 1, 0, 0}, + {2, 3, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {2, 3, 0, 0}, + {2, 3, 0, 0} + }, + { + {0, 0, 1, 1}, + {0, 0, 1, 1}, + {2, 2, 3, 3}, + {2, 2, 3, 3} + } +}; + +static const short part_size[8][2] = +{ + {4, 4}, + {4, 4}, + {4, 2}, + {2, 4}, + {2, 2}, + {2, 1}, + {1, 2}, + {1, 1} +}; + +static const short block_size[8][2] = +{ + {16, 16}, + {16, 16}, + {16, 8}, + {8, 16}, + {8, 8}, + {8, 4}, + {4, 8}, + {4, 4} +}; + +extern void next_macroblock (Macroblock* currMB); +extern void start_macroblock (Slice *currSlice, Macroblock** currMB, int mb_addr, Boolean mb_field); +extern void reset_macroblock (Macroblock *currMB); +extern void end_macroblock (Macroblock* currMB, Boolean *end_of_slice, Boolean *recode_macroblock); +extern void write_macroblock (Macroblock* currMB, int eos_bit); + + +extern int reset_block(Macroblock* currMB, int *cbp, int64 *cbp_blk, int block8x8); + +extern int luma_residual_coding_16x16 (Macroblock *, int, int[2]); +extern int luma_residual_coding_8x8 (Macroblock *, int*, int64*, int, short, int[2], char *); +extern void luma_residual_coding (Macroblock *); +extern void luma_residual_coding_sp (Macroblock *); +extern void chroma_residual_coding (Macroblock *); +extern void chroma_residual_coding_sp (Macroblock *); +extern void chroma_residual_coding_si (Macroblock *); +extern void intra_chroma_RD_decision (Macroblock *, RD_PARAMS *); +extern void intra_chroma_RD_decision_mbaff (Macroblock *, RD_PARAMS *); + +extern byte transform_decision (Macroblock *, int, distblk*); +extern int B8Mode2Value (Slice *, short, short); + +extern int write_p_slice_MB_layer (Macroblock *, int , int *); +extern int write_b_slice_MB_layer (Macroblock *, int , int *); +extern int write_i_slice_MB_layer (Macroblock *, int , int *); + +extern void write_terminating_bit (Slice* currSlice, int bit); + +extern int writeMotionInfo2NAL (Macroblock* currMB); +extern int write_p_slice_motion_info_to_NAL (Macroblock* currMB); +extern int write_b_slice_motion_info_to_NAL (Macroblock* currMB); +extern int write_p_slice_motion_info_to_NAL (Macroblock* currMB); +extern int writeReferenceFrame (Macroblock *currMB, int i, int j, int list_idx, int ref); +extern int writeMotionVector8x8 (Macroblock *currMB, int i0, int j0, int i1, int j1, int refframe, int list_idx, int mv_mode, short bipred_me); + +extern int writeCoeff4x4_CABAC (Macroblock *currMB, ColorPlane, int, int, int); +extern int writeCoeff8x8_CABAC (Macroblock* currMB, ColorPlane, int, int); +extern int writeCoeff8x8 (Macroblock* currMB, ColorPlane, int, int, int); +extern int writeCoeff16x16_CABAC (Macroblock* currMB, ColorPlane); +extern int writeCoeff16x16_CAVLC (Macroblock* currMB, ColorPlane); + +extern int writeCoeff4x4_CAVLC_normal (Macroblock* currMB, int block_type, int b8, int b4, int param); +extern int writeCoeff4x4_CAVLC_444 (Macroblock* currMB, int block_type, int b8, int b4, int param); + +extern int predict_nnz (Macroblock *currMB, int block_type, int i,int j); +extern int predict_nnz_chroma(Macroblock *currMB, int i,int j); + +extern void set_modes_and_reframe (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx); +extern void set_modes_and_reframe_i_slice (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx); +extern void set_modes_and_reframe_b_slice (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx); +extern void set_modes_and_reframe_p_slice (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx); +extern Macroblock *alloc_mbs(VideoParameters *p_Vid, int mb_num, int layers); +extern void free_mbs(Macroblock *pMBs, int mb_num); +extern void setup_mbs(Macroblock *pMBs, int mb_num, int layer_id); + + + +#endif + diff --git a/lencod/inc/macroblock_p444.h b/lencod/inc/macroblock_p444.h new file mode 100644 index 0000000..2d11003 --- /dev/null +++ b/lencod/inc/macroblock_p444.h @@ -0,0 +1,24 @@ + +/*! + ************************************************************************ + * \file + * macroblock_p444.h + * + * \brief + * Arrays for macroblock processing (P444 mode) + * + * \author + * + ************************************************************************/ + +#ifndef _MACROBLOCK_P444_H_ +#define _MACROBLOCK_P444_H_ + +#include "block.h" + +extern int luma_residual_coding_p444_16x16 (Macroblock* currMB, int, short, int[2], char *); +extern int luma_residual_coding_p444_8x8 (Macroblock* currMB, int*, int64*, int, short, int[2], char *); +extern void luma_residual_coding_p444 (Macroblock *currMB); + +#endif + diff --git a/lencod/inc/mbuffer.h b/lencod/inc/mbuffer.h new file mode 100644 index 0000000..c54028e --- /dev/null +++ b/lencod/inc/mbuffer.h @@ -0,0 +1,258 @@ + +/*! + *********************************************************************** + * \file + * mbuffer.h + * + * \brief + * Frame buffer functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + * - Yuwen He + *********************************************************************** + */ +#ifndef _MBUFFERENC_H_ +#define _MBUFFERENC_H_ + +#include "global.h" +#include "enc_statistics.h" + +#define MAX_LIST_SIZE 33 + +typedef struct frame_store FrameStore; +typedef struct distortion_estimation Dist_Estm; +typedef struct picture_stats PictureStats; +typedef struct pic_motion_params_old PicMotionParamsOld; + +struct picture_stats +{ + double dsum[3]; + double dvar[3]; +}; + + +//! definition of pic motion parameters +struct pic_motion_params_old +{ + byte * mb_field; //!< field macroblock indicator +}; + + +//! definition of pic motion parameters +typedef struct pic_motion_params +{ + struct storable_picture *ref_pic[2]; //!< referrence picture pointer + char ref_idx[2]; //!< reference picture [list][subblock_y][subblock_x] + MotionVector mv[2]; //!< motion vector + byte field_frame; //!< indicates if co_located is field or frame. Will be removed at some point +} PicMotionParams; + + +//! definition a picture (field or frame) +typedef struct storable_picture +{ + PictureStructure structure; + + int poc; + int top_poc; + int bottom_poc; + int frame_poc; + int order_num; + unsigned frame_num; + int pic_num; + int long_term_pic_num; + int long_term_frame_idx; + int temporal_layer; + + byte is_long_term; + int used_for_reference; + int is_output; + int non_existing; + + int size_x, size_y, size_x_cr, size_y_cr; + int size_x_padded, size_y_padded; + int size_x_pad, size_y_pad; + int size_x_cr_pad, size_y_cr_pad; + int pad_size_uv_y, pad_size_uv_x; + int chroma_vector_adjustment; + int coded_frame; + int mb_aff_frame_flag; + + imgpel ** imgY; //!< Y picture component + imgpel **** imgY_sub; //!< Y picture component upsampled (Quarter pel) + imgpel *** imgUV; //!< U and V picture components + imgpel *****imgUV_sub; //!< UV picture component upsampled (Quarter/One-Eighth pel) + + imgpel *** p_dec_img[MAX_PLANE]; //!< pointer array for accessing decoded pictures in hypothetical decoders + + imgpel ** p_img[MAX_PLANE]; //!< pointer array for accessing imgY/imgUV[] + imgpel **** p_img_sub[MAX_PLANE]; //!< pointer array for storing top address of imgY_sub/imgUV_sub[] + imgpel ** p_curr_img; //!< current int-pel ref. picture area to be used for motion estimation + imgpel **** p_curr_img_sub; //!< current sub-pel ref. picture area to be used for motion estimation + //hme; + imgpel *** p_hme_int_img; //!< [level][y][x]; + imgpel ***** p_hme_sub_img; //!< [level][y_frac][x_frac][y][x]; + + Dist_Estm * de_mem; + + PicMotionParams **mv_info; //!< Motion info + PicMotionParams **JVmv_info[MAX_PLANE]; //!< Motion info for 4:4:4 independent coding + PicMotionParamsOld motion; //!< Motion info + PicMotionParamsOld JVmotion[MAX_PLANE]; //!< Motion info for 4:4:4 independent coding + + int colour_plane_id; //!< colour_plane_id to be used for 4:4:4 independent mode encoding + + struct storable_picture *top_field; // for mb aff, if frame for referencing the top field + struct storable_picture *bottom_field; // for mb aff, if frame for referencing the bottom field + struct storable_picture *frame; // for mb aff, if field for referencing the combined frame + + int chroma_format_idc; + int chroma_mask_mv_x; + int chroma_mask_mv_y; + int chroma_shift_y; + int chroma_shift_x; + int frame_mbs_only_flag; + int frame_cropping_flag; + int frame_crop_left_offset; + int frame_crop_right_offset; + int frame_crop_top_offset; + int frame_crop_bottom_offset; + + PictureStats p_stats; + StatParameters stats; + + int type; + +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag[2]; + int anchor_pic_flag[2]; +#endif + + int bInterpolated; + int ref_pic_na[6]; + int otf_flag; + //int separate_colour_plane_flag; +} StorablePicture; + +typedef StorablePicture *StorablePicturePtr; + +//! Frame Stores for Decoded Picture Buffer +struct frame_store +{ + int is_used; //!< 0=empty; 1=top; 2=bottom; 3=both fields (or frame) + int is_reference; //!< 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used + int is_long_term; //!< 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used + int is_orig_reference; //!< original marking by nal_ref_idc: 0=not used for ref; 1=top used; 2=bottom used; 3=both fields (or frame) used + + int is_non_existent; + + unsigned frame_num; + int frame_num_wrap; + int long_term_frame_idx; + int is_output; + int poc; + + StorablePicture *frame; + StorablePicture *top_field; + StorablePicture *bottom_field; + + Boolean is_inter_layer; + +#if (MVC_EXTENSION_ENABLE) + int view_id; + int inter_view_flag[2]; + int anchor_pic_flag[2]; +#endif +}; + + + +//! Decoded Picture Buffer +typedef struct decoded_picture_buffer +{ + VideoParameters *p_Vid; + InputParameters *p_Inp; + FrameStore **fs; + FrameStore **fs_ref; + FrameStore **fs_ltref; + FrameStore **fs_ilref; + int num_ref_frames; + unsigned size; + unsigned used_size; + unsigned ref_frames_in_buffer; + unsigned ltref_frames_in_buffer; + int last_output_poc; +#if (MVC_EXTENSION_ENABLE) + int last_output_view_id; +#endif + int max_long_term_pic_idx; + + int init_done; + + FrameStore *last_picture; + int layer_id; + unsigned used_size_il; + + FrameFormat storage_format; + + void (*pf_luma_prediction) ( Macroblock* currMB, int, int, int, int, int, int[2], char *, short ); + void (*pf_luma_prediction_bi) ( Macroblock* currMB, int, int, int, int, int, int, short, short, int ); + void (*pf_chroma_prediction) ( Macroblock* currMB, int, int, int, int, int, int, int, int, short, short, short ); + void (*pf_get_block_luma) ( struct video_par *, imgpel*, int*, int, int, int, int, struct storable_picture*, int ); + void (*pf_get_block_chroma[2]) ( struct video_par *, imgpel*, int*, int, int, int, int, struct storable_picture*, int ); + void (*pf_OneComponentChromaPrediction4x4_regenerate)(Macroblock *currMB, imgpel* , int , int , MotionVector ** , StorablePicture *listX, int ); + void (*pf_OneComponentChromaPrediction4x4_retrieve) (Macroblock *currMB, imgpel* , int , int , MotionVector ** , StorablePicture *listX, int ); + distblk (*pf_computeSAD) (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + distblk (*pf_computeSADWP) (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + distblk (*pf_computeSATD) (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + distblk (*pf_computeSATDWP) (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + distblk (*pf_computeBiPredSAD1)(StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + distblk (*pf_computeBiPredSAD2)(StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + distblk (*pf_computeBiPredSATD1) (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + distblk (*pf_computeBiPredSATD2) (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + distblk (*pf_computeSSE) (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + distblk (*pf_computeSSEWP) (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + distblk (*pf_computeBiPredSSE1) (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + distblk (*pf_computeBiPredSSE2) (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +}DecodedPictureBuffer; + +extern void init_dpb (VideoParameters *p_Vid, DecodedPictureBuffer *dpb); +extern void free_dpb (DecodedPictureBuffer *p_Dpb); +extern FrameStore* alloc_frame_store(void); +extern void free_frame_store (VideoParameters *p_Vid, FrameStore* f); +extern StorablePicture* alloc_storable_picture (VideoParameters *p_Vid, PictureStructure type, int size_x, int size_y, int size_x_cr, int size_y_cr); +extern void free_storable_picture (VideoParameters *p_Vid, StorablePicture* p); +extern void store_picture_in_dpb (DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output); +extern void replace_top_pic_with_frame(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output); +extern void flush_dpb (DecodedPictureBuffer *p_Dpb, FrameFormat *output); +extern void dpb_split_field (VideoParameters *p_Vid, FrameStore *fs); +extern void dpb_combine_field (VideoParameters *p_Vid, FrameStore *fs); +extern void dpb_combine_field_yuv (VideoParameters *p_Vid, FrameStore *fs); +extern void init_lists_p_slice (Slice *currSlice); +extern void init_lists_b_slice (Slice *currSlice); +extern void init_lists_i_slice (Slice *currSlice); +extern void update_pic_num (Slice *currSlice); +extern void reorder_ref_pic_list (Slice *currSlice, int cur_list); +extern void init_mbaff_lists (Slice *currSlice); +extern void alloc_ref_pic_list_reordering_buffer (Slice *currSlice); +extern void free_ref_pic_list_reordering_buffer (Slice *currSlice); +extern void fill_frame_num_gap (VideoParameters *p_Vid, FrameFormat *output); +extern void compute_colocated (Slice *currSlice, StorablePicture **listX[6]); +extern void reorder_short_term(Slice *currSlice, DecodedPictureBuffer *p_Dpb, int cur_list, int picNumLX, int *refIdxLX); + +extern void unmark_for_reference(FrameStore* fs); +extern void unmark_for_long_term_reference(FrameStore* fs); +extern void remove_frame_from_dpb(DecodedPictureBuffer *p_Dpb, int pos); + +#if (MVC_EXTENSION_ENABLE) +void check_num_ref(DecodedPictureBuffer *p_Dpb); +extern void replace_top_proc_pic_with_frame(DecodedPictureBuffer *p_Dpb, StorablePicture* p); +extern void store_proc_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output); +#endif + +#endif + diff --git a/lencod/inc/mc_prediction.h b/lencod/inc/mc_prediction.h new file mode 100644 index 0000000..6b41dd9 --- /dev/null +++ b/lencod/inc/mc_prediction.h @@ -0,0 +1,38 @@ + +/*! + ************************************************************************ + * \file + * mc_prediction.h + * + * \brief + * motion compensation header + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#ifndef _MC_PREDICTION_H_ +#define _MC_PREDICTION_H_ +#include "mbuffer.h" + +extern void luma_prediction ( Macroblock* currMB, int, int, int, int, int, int[2], char *, short ); +extern void luma_prediction_bi ( Macroblock* currMB, int, int, int, int, int, int, short, short, int ); +extern void chroma_prediction ( Macroblock* currMB, int, int, int, int, int, int, int, int, short, short, short ); +extern void chroma_prediction_4x4 ( Macroblock* currMB, int, int, int, int, int, int, short, short, short); + +extern void rdo_low_intra_chroma_decision (Macroblock *currMB, int mb_available_up, int mb_available_left[2], int mb_available_up_left); +extern void rdo_low_intra_chroma_decision_mbaff (Macroblock *currMB, int mb_available_up, int mb_available_left[2], int mb_available_up_left); +extern void OneComponentChromaPrediction4x4_regenerate (Macroblock *currMB, imgpel* , int , int , MotionVector ** , StorablePicture *listX, int ); +extern void OneComponentChromaPrediction4x4_retrieve (Macroblock *currMB, imgpel* , int , int , MotionVector ** , StorablePicture *listX, int ); + +extern void intra_chroma_prediction_mbaff(Macroblock *currMB, int*, int*, int*); +extern void intra_chroma_prediction (Macroblock *currMB, int*, int*, int*); +extern void IntraChromaPrediction4x4 (Macroblock* currMB, int uv, int block_x, int block_y); +extern void get_difference_4x4(imgpel **src, imgpel **prd, short *diff, int pos_x, int block_x); + +#endif + diff --git a/lencod/inc/mc_prediction_otf.h b/lencod/inc/mc_prediction_otf.h new file mode 100644 index 0000000..337bdc9 --- /dev/null +++ b/lencod/inc/mc_prediction_otf.h @@ -0,0 +1,43 @@ +#ifndef _MC_PREDICTION_OTF_H_ +#define _MC_PREDICTION_OTF_H_ + +#include "global.h" + +void luma_prediction_otf ( Macroblock* currMB, //!< Current Macroblock + int block_x, //!< relative horizontal block coordinate of block + int block_y, //!< relative vertical block coordinate of block + int block_size_x, //!< relative horizontal block coordinate of block + int block_size_y, //!< relative vertical block coordinate of block + int p_dir, //!< prediction direction (0=list0, 1=list1, 2=bipred) + int list_mode[2], //!< list prediction mode (1-7, 0=DIRECT) + char *ref_idx, //!< reference pictures + short bipred_me //!< use bi prediction mv (0=no bipred, 1 = use set 1, 2 = use set 2) + ) ; + +void luma_prediction_bi_otf ( Macroblock* currMB, //!< Current Macroblock + int block_x, //!< relative horizontal block coordinate of 4x4 block + int block_y, //!< relative vertical block coordinate of 4x4 block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + int l0_mode, //!< list0 prediction mode (1-7, 0=DIRECT if l1_mode=0) + int l1_mode, //!< list1 prediction mode (1-7, 0=DIRECT if l0_mode=0) + short l0_ref_idx, //!< reference frame for list0 prediction (-1: Intra4x4 pred. with l0_mode) + short l1_ref_idx, //!< reference frame for list1 prediction + int list //!< current list for prediction. + ); + +void chroma_prediction_otf ( Macroblock* currMB, // <-- Current Macroblock + int uv, // <-- colour component + int block_x, // <-- relative horizontal block coordinate of block + int block_y, // <-- relative vertical block coordinate of block + int block_size_x, // <-- relative horizontal block coordinate of block + int block_size_y, // <-- relative vertical block coordinate of block + int p_dir, // <-- prediction direction (0=list0, 1=list1, 2=bipred) + int l0_mode, // <-- list0 prediction mode (1-7, 0=DIRECT if l1_mode=0) + int l1_mode, // <-- list1 prediction mode (1-7, 0=DIRECT if l0_mode=0) + short l0_ref_idx, // <-- reference frame for list0 prediction (if (<0) -> intra prediction) + short l1_ref_idx, // <-- reference frame for list1 prediction + short bipred_me // <-- use bi prediction mv (0=no bipred, 1 = use set 1, 2 = use set 2) + ) ; + +#endif \ No newline at end of file diff --git a/lencod/inc/md_common.h b/lencod/inc/md_common.h new file mode 100644 index 0000000..2ac12d5 --- /dev/null +++ b/lencod/inc/md_common.h @@ -0,0 +1,38 @@ +/*! + *************************************************************************** + * \file + * md_common.h + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + * \date + * 4. October 2008 + * + * \brief + * Headerfile for common mode functions + ************************************************************************** + */ + +#ifndef _MD_COMMON_H_ +#define _MD_COMMON_H_ +#include "mv_search.h" +#include "me_distortion.h" + +extern void SetMotionVectorsMBPSlice (Macroblock* currMB); +extern void SetMotionVectorsMBBSlice (Macroblock* currMB); +extern void SetMotionVectorsMBISlice (Macroblock* currMB); +extern void copy_image_data (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2, int width, int height); +extern void copy_image_data_16x16 (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2); +extern void copy_image_data_8x8 (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2); +extern void copy_image_data_4x4 (imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2); +extern void ResetRD8x8Data (VideoParameters *p_Vid, RD_8x8DATA *rd_data); +extern void set_chroma_pred_mode (Macroblock *currMB, RD_PARAMS enc_mb, int *mb_available, char chroma_pred_mode_range[2]); + + +extern Info8x8 init_best (void); + + +#endif + diff --git a/lencod/inc/md_distortion.h b/lencod/inc/md_distortion.h new file mode 100644 index 0000000..9762bb6 --- /dev/null +++ b/lencod/inc/md_distortion.h @@ -0,0 +1,31 @@ +/*! + *************************************************************************** + * \file + * md_distortion.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 7. February 2009 + * + * \brief + * Headerfile for distortion functions + ************************************************************************** + */ + +#ifndef _MD_DISTORTION_H_ +#define _MD_DISTORTION_H_ + +#include "global.h" + +// Functions +extern void setupDistortion (Slice *currSlice); +extern int64 compute_SSE (imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, int ySize, int xSize); +extern distblk compute_SSE_cr (imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, int ySize, int xSize); +extern distblk compute_SSE16x16(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc); +extern distblk compute_SSE8x8 (imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc); +extern distblk compute_SSE4x4 (imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc); +extern distblk compute_SSE16x16_thres(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, distblk min_cost); + +#endif diff --git a/lencod/inc/me_distortion.h b/lencod/inc/me_distortion.h new file mode 100644 index 0000000..8ab5407 --- /dev/null +++ b/lencod/inc/me_distortion.h @@ -0,0 +1,92 @@ +/*! + *************************************************************************** + * \file + * me_distortion.h + * + * \author + * Alexis Michael Tourapis + * Athanasios Leontaris + * + * \date + * 11. August 2006 + * + * \brief + * Headerfile for motion estimation distortion + ************************************************************************** + */ + +#ifndef _ME_DISTORTION_H_ +#define _ME_DISTORTION_H_ + +extern distblk distortion4x4SAD(short* diff, distblk min_mcost); +extern distblk distortion4x4SSE(short* diff, distblk min_mcost); +extern distblk distortion4x4SATD(short* diff, distblk min_cost); +extern distblk distortion8x8SAD(short* diff, distblk min_mcost); +extern distblk distortion8x8SSE(short* diff, distblk min_mcost); +extern distblk distortion8x8SATD(short* diff, distblk min_cost); + +extern int HadamardSAD4x4(short* diff); +extern int HadamardSAD8x8(short* diff); +// SAD functions +extern distblk computeSAD (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD16x16 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD16x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD8x16 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD8x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD8x4 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD4x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAD4x4 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// Weighted Prediction SAD functions +extern distblk computeSADWP (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP16x16 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP16x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP8x16 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP8x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP8x4 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP4x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSADWP4x4 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// SATD +extern distblk computeSATD (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSATDWP (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT8x8D16x16(StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT4x4D16x16(StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT8x8D16x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT4x4D16x8 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT8x8D8x16 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT4x4D8x16 (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT8x8D (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSAT4x4D (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// SSE +extern distblk computeSSE (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSSEWP (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// Bipred SAD +extern distblk computeBiPredSAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred16x16SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred16x8SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred8x16SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred8x8SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred8x4SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred4x8SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred4x4SAD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPredSAD2 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + +// Bipred SATD +extern distblk computeBiPredSATD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPredSATD2 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred16x16SATD1(StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred16x8SATD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred8x8SATD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPred8x16SATD1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + +// Bipred SSE +extern distblk computeBiPredSSE1 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPredSSE2 (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + +extern void select_distortion (VideoParameters *p_Vid, InputParameters *p_Inp); + +extern void calcDifference(imgpel **origImg, int ox, int oy, imgpel **predImg, int px, int py, int width, int height, short *diff); +#endif diff --git a/lencod/inc/me_distortion_otf.h b/lencod/inc/me_distortion_otf.h new file mode 100644 index 0000000..3656387 --- /dev/null +++ b/lencod/inc/me_distortion_otf.h @@ -0,0 +1,40 @@ +/*! + ****************************************************************************************** + * \file + * me_distortion_otf.h + * + * \brief + * Headerfile for motion estimation distortion with subpel interpolation on-the-fly + ****************************************************************************************** + */ + +#ifndef _ME_DISTORTION_OTF_H_ +#define _ME_DISTORTION_OTF_H_ + +// SAD functions +extern distblk computeSAD_otf (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// Weighted Prediction SAD functions +extern distblk computeSADWP_otf (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// SATD +extern distblk computeSATD_otf (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSATDWP_otf (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// SSE +extern distblk computeSSE_otf (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); +extern distblk computeSSEWP_otf (StorablePicture *ref1, MEBlock*, distblk, MotionVector *); + +// Bipred SAD +extern distblk computeBiPredSAD1_otf (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPredSAD2_otf (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + +// Bipred SATD +extern distblk computeBiPredSATD1_otf (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPredSATD2_otf (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + +// Bipred SSE +extern distblk computeBiPredSSE1_otf (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); +extern distblk computeBiPredSSE2_otf (StorablePicture *ref1, StorablePicture *ref2, MEBlock*, distblk, MotionVector *, MotionVector *); + +#endif diff --git a/lencod/inc/me_epzs.h b/lencod/inc/me_epzs.h new file mode 100644 index 0000000..bbde6b0 --- /dev/null +++ b/lencod/inc/me_epzs.h @@ -0,0 +1,53 @@ + +/*! +************************************************************************ +* \file +* me_epzs.h +* +* \author +* Alexis Michael Tourapis +* +* \date +* 11. August 2006 +* +* \brief +* Headerfile for EPZS motion estimation +************************************************************************** +*/ + + +#ifndef _ME_EPZS_H_ +#define _ME_EPZS_H_ +#include "me_epzs_common.h" + +static const int next_start_pos[5][5] = +{ + {0, 8, 5, 6, 7}, + {8, 0, 5, 8, 8}, + {5, 5, 0, 6, 5}, + {6, 6, 6, 0, 7}, + {7, 8, 7, 7, 0} +}; + +static const int next_end_pos[5][5] = +{ + {0, 10, 7, 8, 9}, + {10, 0, 6, 10, 9}, + {7, 6, 0, 7, 7}, + {8, 8, 7, 0, 8}, + {9, 9, 9, 8, 0} +}; + +static const MotionVector search_point_hp[10] = {{0,0},{-2,0}, {0,2}, {2,0}, {0,-2}, {-2,2}, {2,2}, {2,-2}, {-2,-2}, {-2,2}}; +static const MotionVector search_point_qp[10] = {{0,0},{-1,0}, {0,1}, {1,0}, {0,-1}, {-1,1}, {1,1}, {1,-1}, {-1,-1}, {-1,1}}; + +// Functions +extern distblk EPZS_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int); +extern distblk EPZS_subMB_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int); +extern distblk EPZS_sub_pel_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int*); +extern distblk EPZS_sub_pel_bipred_motion_estimation (Macroblock *, MEBlock *, int list, MotionVector *, MotionVector *, MotionVector *, MotionVector *, distblk, int *); +extern distblk EPZS_bipred_motion_estimation (Macroblock *, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, MEBlock *, int, distblk, int); + + +#endif + diff --git a/lencod/inc/me_epzs_common.h b/lencod/inc/me_epzs_common.h new file mode 100644 index 0000000..533be01 --- /dev/null +++ b/lencod/inc/me_epzs_common.h @@ -0,0 +1,155 @@ + +/*! +************************************************************************ +* \file +* me_epzs_common.h +* +* \author +* Alexis Michael Tourapis +* +* \date +* 11. August 2006 +* +* \brief +* Headerfile for common functions for the EPZS motion estimation +************************************************************************** +*/ + + +#ifndef _ME_EPZS_COMMON_H_ +#define _ME_EPZS_COMMON_H_ + + +// Structure definitions +typedef struct +{ + int mb_adaptive_frame_field_flag; + int size_x, size_y; + + // Frame + MotionVector ***frame; //!< motion vector [list][subblock_x][subblock_y] + // Top field + MotionVector ***top; //!< motion vector [list][subblock_x][subblock_y] + // Bottom field + MotionVector ***bot; //!< motion vector [list][subblock_x][subblock_y] +} EPZSColocParams; + +typedef struct +{ + MotionVector motion; + int start_nmbr; + int next_points; +} +SPoint; + +struct epzs_struct +{ + int searchPoints; + SPoint *point; + int stopSearch; + int nextLast; + struct epzs_struct *nextpattern; +}; + +typedef struct epzs_struct EPZSStructure; + +typedef enum +{ + SDIAMOND = 0, + SQUARE = 1, + EDIAMOND = 2, + LDIAMOND = 3, + SBDIAMOND = 4 +} EPZSPatterns; + +typedef struct epzs_params { + VideoParameters *p_Vid; + uint16 BlkCount; + int searcharray; + + distblk medthres[8]; + distblk maxthres[8]; + distblk minthres[8]; + distblk subthres[8]; + + int mv_scale [6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES]; + int mv_scale_update[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES]; + + uint16 **EPZSMap; //!< Memory Map definition + +#if EPZSREF + MotionVector *****p_motion; //!< Array for storing Motion Vectors +#else + MotionVector ****p_motion; //!< Array for storing Motion Vectors +#endif + distblk ***distortion; //!< Array for storing SAD Values + distblk ***bi_distortion; //!< Array for storing SAD Values + distblk ***distortion_hpel; //!< Array for storing SAD Values + + // + EPZSStructure *searchPattern; + EPZSStructure *searchPatternD; + EPZSStructure *predictor; + // Window predictors + EPZSStructure *window_predictor; + EPZSStructure *window_predictor_ext; + // Co-located helper + EPZSColocParams *p_colocated; +} EPZSParameters; + + +extern void EPZSBlockTypePredictorsMB (Slice *currSlice, MEBlock *mv_block, SPoint *point, int *prednum); +extern short EPZS_spatial_predictors (EPZSParameters *p_EPZS, MEBlock *mv_block, int list, int list_offset, short ref, struct pic_motion_params **mv_info); +extern void EPZS_temporal_predictors (Macroblock *currMB, StorablePicture *ref_picture, EPZSParameters *p_EPZS, MEBlock *mv_block, int *prednum, distblk stopCriterion, distblk min_mcost); +extern distblk EPZSDetermineStopCriterion(EPZSParameters *p_EPZS, distblk* prevSad, MEBlock *mv_block ,distblk lambda_dist); +extern void EPZSBlockTypePredictors (Slice *currSlice, MEBlock *mv_block, SPoint *point, int *prednum); +extern void EPZSWindowPredictors (MotionVector *mv, EPZSStructure *predictor, int *prednum, EPZSStructure *windowPred); +extern void EPZS_spatial_memory_predictors (EPZSParameters *p_EPZS, MEBlock *mv_block, int list, int *prednum, int img_width); + +extern void EPZSDelete (VideoParameters *p_Vid); +extern void EPZSStructDelete (Slice *currSlice); +extern void EPZSSliceInit (Slice *currSlice); +extern int EPZSInit (VideoParameters *p_Vid); +extern int EPZSStructInit (Slice *currSlice); +extern void EPZSOutputStats (InputParameters *p_Inp, FILE * stat, short stats_file); +extern void EPZS_setup_engine (Macroblock *, InputParameters *); +/*! +*********************************************************************** +* \brief +* Add Predictor/normalize function +* Returns if succesfully added (i.e. if not 0) +* +* +*********************************************************************** +*/ +static inline int add_predictor(MotionVector *cur_mv, MotionVector prd_mv, int mvScale, int shift_mv) +{ + *cur_mv = prd_mv; + cur_mv->mv_x = (short) rshift_rnd_sf((mvScale * cur_mv->mv_x), shift_mv); + cur_mv->mv_y = (short) rshift_rnd_sf((mvScale * cur_mv->mv_y), shift_mv); + return (*((int*) cur_mv) != 0); +} + +static inline void scale_mv(MotionVector *out_mv, int scale, const MotionVector *mv, int shift_mv) +{ + out_mv->mv_x = (short) rshift_rnd_sf((scale * mv->mv_x), shift_mv); + out_mv->mv_y = (short) rshift_rnd_sf((scale * mv->mv_y), shift_mv); +} + +static inline void scale_mv_xy(MotionVector *out_mv, int *scale, const MotionVector *mv, int shift_mv) +{ + out_mv->mv_x = (short) rshift_rnd_sf((scale[0] * mv->mv_x), shift_mv); + out_mv->mv_y = (short) rshift_rnd_sf((scale[1] * mv->mv_y), shift_mv); +} + +static inline void compute_scaled(MotionVector *MotionVector0, MotionVector *MotionVector1, int tempmv_scale[2], const MotionVector *mv, int invmv_precision) +{ + MotionVector0->mv_x = (short) iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * mv->mv_x), invmv_precision)); + MotionVector0->mv_y = (short) iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_0] * mv->mv_y), invmv_precision)); + MotionVector1->mv_x = (short) iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * mv->mv_x), invmv_precision)); + MotionVector1->mv_y = (short) iClip3 (-32768, 32767, rshift_rnd_sf((tempmv_scale[LIST_1] * mv->mv_y), invmv_precision)); +} + +#endif + + diff --git a/lencod/inc/me_epzs_int.h b/lencod/inc/me_epzs_int.h new file mode 100644 index 0000000..772474d --- /dev/null +++ b/lencod/inc/me_epzs_int.h @@ -0,0 +1,29 @@ + +/*! + ************************************************************************ + * \file + * me_epzs_int.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 11. August 2006 + * + * \brief + * Headerfile for EPZS motion estimation + ************************************************************************** + */ + + +#ifndef _ME_EPZS_INT_H_ +#define _ME_EPZS_INT_H_ + +#include "me_epzs.h" + +// Functions +extern distblk EPZS_integer_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int); +extern distblk EPZS_integer_subMB_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int); +extern distblk EPZS_integer_bipred_motion_estimation (Macroblock *, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, MEBlock *, int, distblk, int); +#endif + diff --git a/lencod/inc/me_fullfast.h b/lencod/inc/me_fullfast.h new file mode 100644 index 0000000..fdb2981 --- /dev/null +++ b/lencod/inc/me_fullfast.h @@ -0,0 +1,39 @@ + +/*! + ************************************************************************ + * \file + * me_fullfast.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 9 September 2006 + * + * \brief + * Headerfile for Fast Full Search motion estimation + ************************************************************************** + */ + + +#ifndef _ME_FULLFAST_H_ +#define _ME_FULLFAST_H_ +typedef struct me_full_fast +{ + int **search_setup_done; //!< flag if all block SAD's have been calculated yet + MotionVector **search_center; //!< absolute search center for fast full motion search + MotionVector **search_center_padded; //!< absolute search center for fast full motion search + int **pos_00; //!< position of (0,0) vector + distpel *****BlockSAD; //!< SAD for all blocksize, ref. frames and motion vectors + int **max_search_range; +} MEFullFast; + +extern distblk fast_full_search_motion_estimation ( Macroblock *, MotionVector *, MEBlock *, distblk, int ); +extern void initialize_fast_full_search ( VideoParameters *, InputParameters * ); +extern void reset_fast_full_search ( VideoParameters * ); +extern void clear_fast_full_search ( VideoParameters * ); +extern void setup_fast_full_search ( Macroblock *, MEBlock *, int ); +extern void update_full_search_large_blocks ( MEFullFast *, int, int, int ); + +#endif + diff --git a/lencod/inc/me_fullfast_otf.h b/lencod/inc/me_fullfast_otf.h new file mode 100644 index 0000000..096b055 --- /dev/null +++ b/lencod/inc/me_fullfast_otf.h @@ -0,0 +1,17 @@ +/*! + ***************************************************************************************** + * \file + * me_fullfast_otf.h + * + * \brief + * Headerfile for Fast Full Search motion estimation extention on-the-fly interpolation + ***************************************************************************************** + */ + + +#ifndef _ME_FULLFAST_OTF_H_ +#define _ME_FULLFAST_OTF_H_ + +void SetupFastFullPelSearch_otf (Macroblock *, MEBlock *, int ) ; + +#endif \ No newline at end of file diff --git a/lencod/inc/me_fullsearch.h b/lencod/inc/me_fullsearch.h new file mode 100644 index 0000000..ccf1caa --- /dev/null +++ b/lencod/inc/me_fullsearch.h @@ -0,0 +1,28 @@ + +/*! + ************************************************************************ + * \file + * me_fullsearch.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 9 September 2006 + * + * \brief + * Headerfile for Full Search motion estimation + ************************************************************************** + */ + + +#ifndef _ME_FULLSEARCH_H_ +#define _ME_FULLSEARCH_H_ +extern distblk full_search_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int ); +extern distblk full_search_bipred_motion_estimation (Macroblock *, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, MEBlock *, int, distblk, int ); +extern distblk sub_pel_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int *); +extern distblk sub_pel_bipred_motion_estimation (Macroblock *, MEBlock *, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, distblk, int *); +extern distblk full_sub_pel_motion_estimation (Macroblock *, MotionVector *, MEBlock *, distblk, int *); +extern distblk full_sub_pel_bipred_motion_estimation (Macroblock *, MEBlock *, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, distblk, int *); +#endif + diff --git a/lencod/inc/me_umhex.h b/lencod/inc/me_umhex.h new file mode 100644 index 0000000..3f0295e --- /dev/null +++ b/lencod/inc/me_umhex.h @@ -0,0 +1,147 @@ + +/*! + ************************************************************************ + * + * \file me_umhex.h + * + * \brief + * Macro definitions and global variables for UMHEX fast + * integer pel motion estimation and fractional pel motion estimation + * + * \author + * Main contributors: (see contributors.h for copyright, address and affiliation details) + * - Zhibo Chen + * - JianFeng Xu + * - Wenfang Fu + * - Xiaozhong Xu + * + * \date + * 2006.1 + ************************************************************************ + */ + +#ifndef _ME_UMHEX_H_ +#define _ME_UMHEX_H_ + +#include "mbuffer.h" + +struct umhex_struct { + float AlphaFourth_1[8]; + float AlphaFourth_2[8]; + // for bipred mode + int pred_MV_ref_flag; + int BlockType_LUT[4][4]; + distblk Median_Pred_Thd_MB[8]; + distblk Big_Hexagon_Thd_MB[8]; + distblk Multi_Ref_Thd_MB[8]; + distblk Threshold_DSR_MB[8]; //!< Threshold for usage of DSR. DSR refer to JVT-Q088 + byte **McostState; //!< state for integer pel search + byte **SearchState; //!< state for fractional pel search + distblk ****fastme_ref_cost; //!< store SAD information needed for forward ref-frame prediction + distblk ***fastme_l0_cost; //!< store SAD information needed for forward median and uplayer prediction + distblk ***fastme_l1_cost; //!< store SAD information needed for backward median and uplayer prediction + distblk **fastme_best_cost; //!< for multi ref early termination threshold + distblk ***fastme_l0_cost_bipred; //!< store SAD information for bipred mode + distblk ***fastme_l1_cost_bipred; //!< store SAD information for bipred mode + distblk pred_SAD; //!< SAD prediction in use. + distblk SAD_a,SAD_b,SAD_c,SAD_d; + int bipred_flag; //!< flag for bipred + int pred_MV_ref[2], pred_MV_uplayer[2]; //!< pred motion vector by space or temporal correlation,Median is provided + + int UMHEX_blocktype; //!< blocktype for UMHEX SetMotionVectorPredictor + int predict_point[5][2]; + //for early termination + float Bsize[8]; + + byte *flag_intra; + int flag_intra_SAD; +}; + +typedef struct umhex_struct UMHexStruct; + +#define EARLY_TERMINATION \ + if ((min_mcost - p_UMHex->pred_SAD)pred_SAD * betaFourth_2) \ + goto fourth_2_step; \ + else if((min_mcost - p_UMHex->pred_SAD) < p_UMHex->pred_SAD * betaFourth_1) \ + goto fourth_1_step; + +#define SEARCH_ONE_PIXEL \ + if((iabs(cand.mv_x - center.mv_x)>>2) < search_range && (iabs(cand.mv_y - center.mv_y)>>2)< search_range)\ + { \ + if(!p_UMHex->McostState[((cand.mv_y - center.mv_y) >> 2)+ search_range][((cand.mv_x-center.mv_x)>>2)+search_range]) \ + { \ + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); \ + if(mcostcomputePredFPel(ref_picture, mv_block, \ + min_mcost - mcost, &cand); \ + p_UMHex->McostState[((cand.mv_y - center.mv_y) >> 2) + search_range][((cand.mv_x - center.mv_x) >> 2) + search_range] = 1; \ + if (mcost < min_mcost) \ + { \ + best = cand; \ + min_mcost = mcost; \ + } \ + } \ + } \ + } + +#define SEARCH_ONE_PIXEL_BIPRED \ +if((iabs(cand.mv_x - center2.mv_x) >> 2) < search_range && (iabs(cand.mv_y - center2.mv_y) >> 2) < search_range) \ +{ \ + if(!p_UMHex->McostState[((cand.mv_y - center2.mv_y) >> 2) + search_range][((cand.mv_x-center2.mv_x) >> 2)+search_range]) \ + { \ + mcost = mv_cost (p_Vid, lambda_factor, ¢er1, &pred1); \ + mcost += mv_cost (p_Vid, lambda_factor, &cand, &pred2); \ + if(mcostcomputeBiPredFPel(ref_picture1, ref_picture2, \ + mv_block, min_mcost - mcost, ¢er1, &cand); \ + p_UMHex->McostState[((cand.mv_y - center2.mv_y) >> 2) + search_range][((cand.mv_x - center2.mv_x) >> 2) + search_range] = 1; \ + if (mcost < min_mcost) \ + { \ + best = cand; \ + min_mcost = mcost; \ + } \ + } \ + } \ +} \ + + +extern void UMHEX_DefineThreshold (VideoParameters *p_Vid); +extern void UMHEX_DefineThresholdMB(VideoParameters *p_Vid, InputParameters *p_Inp); +extern int UMHEX_get_mem (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void UMHEX_free_mem (VideoParameters *p_Vid, InputParameters *p_Inp); + +extern void UMHEX_decide_intrabk_SAD(Macroblock *currMB); +extern void UMHEX_skip_intrabk_SAD (Macroblock *currMB, int ref_max); +extern void UMHEX_setup (Macroblock *currMB, short ref, int list, int block_y, int block_x, int blocktype, MotionVector *****all_mv); + +extern distblk // ==> minimum motion cost after search +UMHEXIntegerPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred, // <-- motion vector predictor (x) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ); +extern distblk UMHEXSubPelBlockME ( // ==> minimum motion cost after search + Macroblock *currMB, // <-- Current Macroblock + MotionVector *pred, // <-- motion vector predictor (x) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ); +extern distblk UMHEXSubPelBlockMotionSearch ( // ==> minimum motion cost after search + Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // < <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ); +extern distblk UMHEXBipredIntegerPelBlockMotionSearch (Macroblock *, int, + MotionVector *, MotionVector *, MotionVector *, MotionVector *, + MEBlock *, int, distblk, int); + +extern void UMHEXSetMotionVectorPredictor (Macroblock *currMB, MotionVector *pmv, struct pic_motion_params **mv_info, + short ref_frame, int list, int mb_x, int mb_y, int bl_x, int bl_y, MEBlock *mv_block); + +#endif diff --git a/lencod/inc/me_umhexsmp.h b/lencod/inc/me_umhexsmp.h new file mode 100644 index 0000000..5e2da48 --- /dev/null +++ b/lencod/inc/me_umhexsmp.h @@ -0,0 +1,61 @@ + +/*! + ************************************************************************************* + * + * \file me_umhexsmp.h + * + * \brief + * Fast integer pixel and sub pixel motion estimation + * Improved and simplified from the original UMHexagonS algorithms + * See JVT-P021 for details + * + * \author + * Main contributors: (see contributors.h for copyright, address and affiliation details) + * - Zhibo Chen + * - JianFeng Xu + * - Wenfang Fu + * + * - Xiaoquan Yi + * - Jun Zhang + * + * \date + * 6. Nov. 2006 + ************************************************************************************* + */ + +#ifndef _ME_UMHEXSMP_H_ +#define _ME_UMHEXSMP_H_ + +#include "mbuffer.h" + +struct umhex_smp_struct { + distblk SymmetricalCrossSearchThreshold1; + distblk SymmetricalCrossSearchThreshold2; + distblk ConvergeThreshold; + distblk SubPelThreshold1; + distblk SubPelThreshold3; + byte **SearchState; //state for fractional pel search + distblk ***l0_cost; //store SAD information needed for forward median and uplayer prediction + distblk ***l1_cost; //store SAD information needed for backward median and uplayer prediction + distblk pred_SAD_uplayer; // Up layer SAD prediction + byte *flag_intra; + int flag_intra_SAD; + + short pred_MV_uplayer_X; // Up layer MV predictor X-component + short pred_MV_uplayer_Y; // Up layer MV predictor Y-component +}; + +typedef struct umhex_smp_struct UMHexSMPStruct; + +extern void smpUMHEX_init (VideoParameters *p_Vid); +extern int smpUMHEX_get_mem (VideoParameters *p_Vid); +extern void smpUMHEX_free_mem (VideoParameters *p_Vid); +extern void smpUMHEX_decide_intrabk_SAD(Macroblock *currMB); +extern void smpUMHEX_skip_intrabk_SAD (Macroblock *currMB); +extern void smpUMHEX_setup (Macroblock *currMB, short, int, int, int, int, MotionVector *****); +extern distblk smpUMHEXBipredIntegerPelBlockMotionSearch (Macroblock *, int, MotionVector *, MotionVector *, MotionVector *, MotionVector *, MEBlock *, int, distblk, int); +extern distblk smpUMHEXIntegerPelBlockMotionSearch (Macroblock *currMB, MotionVector *pred_mv, MEBlock *mv_block, distblk min_mcost, int lambda_factor); +extern distblk smpUMHEXSubPelBlockMotionSearch (Macroblock *currMB, MotionVector *pred_mv, MEBlock *mv_block, distblk min_mcost, int lambda_factor); +extern distblk smpUMHEXFullSubPelBlockMotionSearch (Macroblock *currMB, MotionVector *pred_mv, MEBlock *mv_block, distblk min_mcost, int lambda_factor); +extern distblk smpUMHEXSubPelBlockME (Macroblock *currMB, MotionVector *pred_mv, MEBlock *mv_block, distblk min_mcost, int *lambda); +#endif diff --git a/lencod/inc/mmco.h b/lencod/inc/mmco.h new file mode 100644 index 0000000..7b57565 --- /dev/null +++ b/lencod/inc/mmco.h @@ -0,0 +1,32 @@ +/*! + ************************************************************************************** + * \file + * mmco.h + * \brief + * MMCO example operations. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Athanasios Leontaris + *************************************************************************************** + */ + +#ifndef _MMCO_H_ +#define _MMCO_H_ + +extern void mmco_long_term(VideoParameters *p_Vid, int current_pic_num); +extern void poc_based_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num); +#if CRA +extern void cra_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num); +#endif +#if HM50_LIKE_MMCO +extern void hm50_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num); +#endif +#if LD_REF_SETTING +extern void low_delay_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num); +#endif +extern void poc_based_ref_management_field_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num); +extern void tlyr_based_ref_management_frame_pic(VideoParameters *p_Vid, int current_pic_num); + +#endif diff --git a/lencod/inc/mode_decision.h b/lencod/inc/mode_decision.h new file mode 100644 index 0000000..be322e9 --- /dev/null +++ b/lencod/inc/mode_decision.h @@ -0,0 +1,64 @@ +/*! + *************************************************************************** + * \file + * mode_decision.h + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + * \date + * 21. February 2005 + * + * \brief + * Headerfile for mode decision + ************************************************************************** + */ + +#ifndef _MODE_DECISION_H_ +#define _MODE_DECISION_H_ + +//==== MODULE PARAMETERS ==== +static const int b8_mode_table[6] = {0, 4, 5, 6, 7}; // DO NOT CHANGE ORDER !!! +static const char mb_mode_table[10] = {0, 1, 2, 3, P8x8, I16MB, I4MB, I8MB, IPCM, SI4MB}; // DO NOT CHANGE ORDER !!! +extern distblk BIDPartitionCost (Macroblock *currMB, int, int, char[2], int); +extern distblk BPredPartitionCost (Macroblock *currMB, int, int, short, short, int, int); +extern void StoreMV8x8 (Slice *currSlice, int dir); +extern void RestoreMV8x8 (Slice *currSlice, int dir); +extern void store_macroblock_parameters (Macroblock *currMB, int); +extern void StoreNewMotionVectorsBlock8x8 (Slice *currSlice, int, int, Info8x8 *); +extern void assign_enc_picture_params (Macroblock *currMB, int mode, Info8x8 *best, int block); +extern void set_subblock8x8_info (Block8x8Info*, int, int, RD_8x8DATA*); +extern void set_block8x8_info (Block8x8Info*, int, int, Info8x8 *best); +extern void update_refresh_map (Macroblock *currMB, int intra, int intra1); +extern void get_bipred_cost (Macroblock *currMB, int mode, int block, int i, int j, Info8x8 *best, RD_PARAMS *enc_mb, distblk bmcost[5]); +extern short I16Offset (int, short); +extern int CheckReliabilityOfRef (Macroblock *currMB, int block, int list_idx, int ref, int mode); +extern int RDCost_for_macroblocks (Macroblock *currMB, int, short); +extern int mode_decision_for_I4x4_MB (Macroblock *currMB, int, distblk*); +extern distblk rdcost_for_8x8blocks (Macroblock *currMB, RD_8x8DATA *dataTr, int*, int64*, int, int, short, Info8x8 *, distblk); + +extern void rc_store_diff (int diff[16][16], imgpel **p_curImg, int cpix_x,imgpel **prediction); + +extern void init_enc_mb_params (Macroblock* currMB, RD_PARAMS *enc_mb, int intra); +extern void list_prediction_cost (Macroblock *currMB, int list, int block, int mode, RD_PARAMS *enc_mb, distblk bmcost[5], char best_ref[2]); +extern void determine_prediction_list (distblk [5], Info8x8 *, distblk *); +extern void compute_mode_RD_cost (Macroblock *currMB, RD_PARAMS *enc_mb, short mode, short *inter_skip); + +extern int transform_termination_control (Macroblock* currMB, int mode); +extern int bslice_16x16_termination_control(InputParameters *p_Inp, Block8x8Info *b8x8info, int *ctr16x16, int mode, int bslice); + +distblk distblkminarray ( distblk arr[], int size, int *minind ); +extern int iminarray ( int arr[], int size, int *minind ); + +extern void update_lambda_costs(Macroblock *currMB, RD_PARAMS *enc_mb, int lambda_mf[3]); + +extern void get_initial_mb16x16_cost(Macroblock *currMB); +extern void adjust_mb16x16_cost (Macroblock *currMB, distblk cost); +extern void reset_adaptive_rounding(VideoParameters *p_Vid); + +extern distblk distortionSSE ( Macroblock *currMB ); + + +#endif + diff --git a/lencod/inc/mode_decision_p8x8.h b/lencod/inc/mode_decision_p8x8.h new file mode 100644 index 0000000..ae5c43e --- /dev/null +++ b/lencod/inc/mode_decision_p8x8.h @@ -0,0 +1,31 @@ +/*! + *************************************************************************** + * \file + * mode_decision_p8x8.h + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + * \date + * 1 September 2009 + * + * \brief + * Headerfile for 8x8 mode decision + ************************************************************************** + */ + +#ifndef _MODE_DECISION_P8x8_H_ +#define _MODE_DECISION_P8x8_H_ + +//==== MODULE PARAMETERS ==== +//static const int b8_mode_table[6] = {0, 4, 5, 6, 7}; // DO NOT CHANGE ORDER !!! +//static const char mb_mode_table[10] = {0, 1, 2, 3, P8x8, I16MB, I4MB, I8MB, IPCM, SI4MB}; // DO NOT CHANGE ORDER !!! + +extern void submacroblock_mode_decision_p_slice (Macroblock *currMB, RD_PARAMS *, RD_8x8DATA *, int ****, int, distblk *); +extern void submacroblock_mode_decision_b_slice (Macroblock *currMB, RD_PARAMS *, RD_8x8DATA *, int ****, int, distblk *); +extern void submacroblock_mode_decision_low(Macroblock *currMB, RD_PARAMS *, RD_8x8DATA *, int ****, int *, int, distblk *, distblk *, distblk *, int); +extern void copy_part_info(Info8x8 *b8x8, Info8x8 *part); + +#endif + diff --git a/lencod/inc/mv_search.h b/lencod/inc/mv_search.h new file mode 100644 index 0000000..58908bb --- /dev/null +++ b/lencod/inc/mv_search.h @@ -0,0 +1,140 @@ + +/*! + ************************************************************************ + * \file mv_search.h + * + * \brief + * array definition for motion search + * + * \author + * Inge Lille-Langoy \n + * Alexis Michael Tourapis \n + * + ************************************************************************ + */ + +#ifndef _MV_SEARCH_H_ +#define _MV_SEARCH_H_ + +#if 1 +#define dist_scale_f(x) (min_mcost) +#else +#define dist_scale_f(x) dist_scale(x) +#endif + + +extern void get_neighbors(Macroblock *currMB, PixelPos *block, int mb_x, int mb_y, int blockshape_x); +extern void set_access_method(int *access_method, MotionVector *blk, int min_x, int min_y, int max_x, int max_y); + +extern void PrepareMEParams (Slice *currSlice, MEBlock *mv_block, int ChromaMEEnable, int list, int ref); +extern void PrepareBiPredMEParams(Slice *currSlice, MEBlock *mv_block, int ChromaMEEnable, int list, int list_offset, int ref); + +extern void init_motion_search_module (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void clear_motion_search_module (VideoParameters *p_Vid, InputParameters *p_Inp); + +extern void PartitionMotionSearch (Macroblock *currMB, int, int, int*); +extern void SubPartitionMotionSearch (Macroblock *currMB, int, int, int*); + +extern void Get_Direct_MV_Spatial_MBAFF (Macroblock *currMB); +extern void Get_Direct_MV_Spatial_Normal (Macroblock *currMB); +extern void Get_Direct_MV_Temporal (Macroblock *currMB); + +extern void FindSkipModeMotionVector (Macroblock *currMB); + +extern void init_ME_engine (Macroblock *currMB); +extern distblk BlockMotionSearch (Macroblock *currMB, MEBlock *mv_block, int,int, int*); +extern void init_mv_block (Macroblock *currMB, MEBlock *mv_block, short blocktype, int list, char ref_idx, short mb_x, short mb_y); +extern void get_original_block(VideoParameters *p_Vid, MEBlock *mv_block); +extern void free_mv_block (MEBlock *mv_block); +extern void update_mv_block (Macroblock *currMB, MEBlock *mv_block, int h, int v); +extern void get_search_range(MEBlock *mv_block, InputParameters *p_Inp, short ref, int blocktype); + +static inline void add_mvs(MotionVector *mv0, const MotionVector *mv1) +{ + mv0->mv_x = (short) (mv0->mv_x + mv1->mv_x); + mv0->mv_y = (short) (mv0->mv_y + mv1->mv_y); +} + +static inline MotionVector add_MVs(MotionVector mv0, const MotionVector *mv1) +{ + mv0.mv_x = (short) (mv0.mv_x + mv1->mv_x); + mv0.mv_y = (short) (mv0.mv_y + mv1->mv_y); + + return (mv0); +} + +static inline MotionVector pad_MVs(MotionVector mv0, MEBlock *mv_block) +{ + mv0.mv_x = (short) (mv0.mv_x + mv_block->pos_x_padded); + mv0.mv_y = (short) (mv0.mv_y + mv_block->pos_y_padded); + + return (mv0); +} + +static inline int64 overflow_weight_cost(int lambda, int bits) +{ +#if JCOST_CALC_SCALEUP + return ( ((int64)lambda) * ((int64)(bits)) ); +#else +#if (USE_RND_COST) + return (i64_rshift_rnd_sf(((int64)lambda) * ((int64)(bits)) , LAMBDA_ACCURACY_BITS)); +#else + return (((int64)lambda) * ((int64)(bits)) >> LAMBDA_ACCURACY_BITS); +#endif +#endif +} + +static inline distblk weight_cost(int lambda, int bits) +{ +#if JCOST_CALC_SCALEUP + return ( ((distblk)lambda) * ((distblk)(bits)) ); +#else +#if (USE_RND_COST) + return (rshift_rnd_sf((lambda) * (bits), LAMBDA_ACCURACY_BITS)); +#else + return (((lambda) * (bits)) >> LAMBDA_ACCURACY_BITS); +#endif +#endif +} + +static inline distblk mv_cost(const VideoParameters *p_Vid, int lambda, const MotionVector *mv, const MotionVector *pmv) +{ +#if JCOST_CALC_SCALEUP + int *mvbits = p_Vid->mvbits; + return ( ((distblk)lambda) *((distblk)(mvbits[mv->mv_x - pmv->mv_x] + mvbits[mv->mv_y - pmv->mv_y])) ); +#else +#if (USE_RND_COST) + return (rshift_rnd_sf((lambda *(p_Vid->mvbits[mv->mv_x - pmv->mv_x] + p_Vid->mvbits[mv->mv_y - pmv->mv_y])), LAMBDA_ACCURACY_BITS)); +#else + return ((lambda *(p_Vid->mvbits[mv->mv_x - pmv->mv_x] + p_Vid->mvbits[mv->mv_y - pmv->mv_y]))>> LAMBDA_ACCURACY_BITS); +#endif +#endif +} + +static inline distblk ref_cost(const Slice *currSlice, int lambda, short ref, int list_offset) +{ + if (currSlice->listXsize[list_offset] <= 1) + return 0; + else + { + VideoParameters *p_Vid = currSlice->p_Vid; +#if JCOST_CALC_SCALEUP + return ( ((distblk)lambda) *((distblk)(p_Vid->refbits[(ref)])) ); +#else +#if (USE_RND_COST) + return (rshift_rnd_sf((lambda) * (p_Vid->refbits[(ref)]), LAMBDA_ACCURACY_BITS)); +#else + return ((lambda *(p_Vid->refbits[(ref)]))>> LAMBDA_ACCURACY_BITS); +#endif +#endif + } +} + +static inline int GetMaxMVD(MotionVector *pMV, MotionVector *pRefMV) +{ + int i32MVx = iabs(pMV->mv_x - pRefMV->mv_x); + int i32MVy = iabs(pMV->mv_y - pRefMV->mv_y); + return imax(i32MVx, i32MVy); +} +#endif + diff --git a/lencod/inc/nal.h b/lencod/inc/nal.h new file mode 100644 index 0000000..47237b2 --- /dev/null +++ b/lencod/inc/nal.h @@ -0,0 +1,28 @@ + +/*! + ************************************************************************************** + * \file + * nal.h + * \brief + * NAL related headers + * + * \date 4 Agust 2008 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + *************************************************************************************** + */ + + +#ifndef _NAL_H_ +#define _NAL_H_ + +#include "nalucommon.h" +#include "enc_statistics.h" + +extern int addCabacZeroWords(VideoParameters *p_Vid, NALU_t *nalu, StatParameters *cur_stats); +extern void SODBtoRBSP (Bitstream *currStream); +extern int RBSPtoEBSP(byte *NaluBuffer, unsigned char *rbsp, int rbsp_size); + +#endif diff --git a/lencod/inc/nalu.h b/lencod/inc/nalu.h new file mode 100644 index 0000000..9ae854e --- /dev/null +++ b/lencod/inc/nalu.h @@ -0,0 +1,26 @@ + +/*! + ************************************************************************************** + * \file + * nalu.h + * \brief + * Common NALU support functions + * + * \date 25 November 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + *************************************************************************************** + */ + + +#ifndef _NALU_H_ +#define _NALU_H_ + +#include "nalucommon.h" + +extern int RBSPtoNALU (unsigned char *rbsp, NALU_t *nalu, int rbsp_size, int nal_unit_type, int nal_reference_idc, int UseAnnexbLongStartcode); +extern int Write_AUD_NALU( VideoParameters *p_Vid ); +extern int Write_Filler_Data_NALU( VideoParameters *p_Vid, int num_bytes ); + +#endif diff --git a/lencod/inc/output.h b/lencod/inc/output.h new file mode 100644 index 0000000..867ff8f --- /dev/null +++ b/lencod/inc/output.h @@ -0,0 +1,26 @@ + +/*! + ************************************************************************************** + * \file + * output.h + * \brief + * Picture writing routine headers + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + *************************************************************************************** + */ + +#ifndef _OUTPUT_H_ +#define _OUTPUT_H_ + +extern void flush_direct_output(VideoParameters *p_Vid, FrameFormat *output, int p_out); +extern void write_out_picture ( StorablePicture *p, FrameFormat *output, int p_out); +extern void write_stored_frame (VideoParameters *p_Vid, FrameStore *fs, FrameFormat *output, int p_out); +extern void direct_output (VideoParameters *p_Vid, StorablePicture *p, FrameFormat *output, int p_out); +extern void direct_output_paff (VideoParameters *p_Vid, StorablePicture *p, FrameFormat *output, int p_out); +extern void init_out_buffer (VideoParameters *p_Vid); +extern void uninit_out_buffer (VideoParameters *p_Vid); + + +#endif //_OUTPUT_H_ diff --git a/lencod/inc/params.h b/lencod/inc/params.h new file mode 100644 index 0000000..4ca3372 --- /dev/null +++ b/lencod/inc/params.h @@ -0,0 +1,453 @@ +/*! +************************************************************************ +* \file params.h +* +* \brief +* Input parameters related definitions +* +* \author +* +************************************************************************ +*/ + +#ifndef _PARAMS_H_ +#define _PARAMS_H_ + +#include "defines.h" +#include "types.h" +#include "vui_params.h" +#include "frame.h" +#include "io_video.h" + +//! all input parameters +struct inp_par_enc +{ + int ProfileIDC; //!< value of syntax element profile_idc + int LevelIDC; //!< value of syntax element level_idc + int IntraProfile; //!< Enable Intra profiles + + int no_frames; //!< number of frames to be encoded + int qp[NUM_SLICE_TYPES]; //!< QP values for all slice types + int qp2frame; //!< frame in display order from which to apply the Change QP offsets + int qp2off[NUM_SLICE_TYPES]; //!< Change QP offset values for all slice types + int qpsp; //!< QPSP quantization value + int frame_skip; //!< number of frames to skip in input sequence (e.g 2 takes frame 0,3,6,9...) + int jumpd; /*!< number of frames to skip in input sequence including intermediate pictures + (e.g 2 takes frame 0,3,6,9...) */ + int DisableSubpelME[2]; //!< Disable sub-pixel motion estimation + int search_range[2]; /*!< search range - integer pel search and 16x16 blocks. The search window is + generally around the predicted vector. Max vector is 2xmcrange. */ + int num_ref_frames; //!< number of reference frames to be used + int P_List0_refs[2]; //!< number of reference picture in list 0 in P pictures + int B_List0_refs[2]; //!< number of reference picture in list 0 in B pictures + int B_List1_refs[2]; //!< number of reference picture in list 1 in B pictures + int num_ref_frames_org; + int P_List0_refs_org[2]; //!< number of reference picture in list 0 in P pictures + int B_List0_refs_org[2]; //!< number of reference picture in list 0 in B pictures + int B_List1_refs_org[2]; //!< number of reference picture in list 1 in B pictures + int Log2MaxFNumMinus4; //!< value of syntax element log2_max_frame_num + int Log2MaxPOCLsbMinus4; //!< value of syntax element log2_max_pic_order_cnt_lsb_minus4 + + // Input/output sequence format related variables + FrameFormat source; //!< source related information + FrameFormat output; //!< output related information + int is_interleaved; + int src_resize; //!< Control if input sequence will be resized (currently only cropping is supported) + int src_BitDepthRescale; //!< Control if input sequence bitdepth should be adjusted + int yuv_format; //!< YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4) + int intra_upd; /*!< For error robustness. 0: no special action. 1: One GOB/frame is intra coded + as regular 'update'. 2: One GOB every 2 frames is intra coded etc. + In connection with this intra update, restrictions is put on motion vectors + to prevent errors to propagate from the past */ + + int slice_mode; //!< Indicate what algorithm to use for setting slices + int slice_argument; //!< Argument to the specified slice algorithm + int UseConstrainedIntraPred; //!< 0: Inter MB pixels are allowed for intra prediction 1: Not allowed + int SetFirstAsLongTerm; //!< Support for temporal considerations for CB plus encoding + int infile_header; //!< If input file has a header set this to the length of the header + int MultiSourceData; + VideoDataFile input_file2; //!< Input video file2 + VideoDataFile input_file3; //!< Input video file3 + int num_of_views; //!< number of views to encode (1=1view, 2=2views) +#if (MVC_EXTENSION_ENABLE) + char View1ConfigName[FILE_NAME_SIZE]; //! + *************************************************************************************** + */ + + +#ifndef _PARSET_H_ +#define _PARSET_H_ + +#include "parsetcommon.h" +#include "nalu.h" +#include "sei.h" + +extern void generate_parameter_sets (VideoParameters *p_Vid); +extern void FreeParameterSets (VideoParameters *p_Vid); + +extern NALU_t *GenerateSeq_parameter_set_NALU (VideoParameters *p_Vid); +extern NALU_t *GeneratePic_parameter_set_NALU (VideoParameters *p_Vid, int); +extern NALU_t *GenerateSEImessage_NALU(InputParameters *p_Inp); +#if (MVC_EXTENSION_ENABLE) +extern NALU_t *GenerateSubsetSeq_parameter_set_NALU (VideoParameters *p_Vid); +#endif + +// The following are local helpers, but may come handy in the future, hence public +extern void GenerateSequenceParameterSet(seq_parameter_set_rbsp_t *sps, VideoParameters *p_Vid, int SPS_id); +extern void GeneratePictureParameterSet( pic_parameter_set_rbsp_t *pps, seq_parameter_set_rbsp_t *sps, + VideoParameters *p_Vid, + InputParameters *p_Inp, int PPS_id, + int WeightedPrediction, int WeightedBiprediction, + int cb_qp_index_offset, int cr_qp_index_offset); + +extern int Scaling_List(short *scalingListinput, short *scalingList, int sizeOfScalingList, short *UseDefaultScalingMatrix, Bitstream *bitstream); +#if (MVC_EXTENSION_ENABLE) +extern int GenerateSeq_parameter_set_rbsp (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps, byte *buf, short Is_Subset); +#else +extern int GenerateSeq_parameter_set_rbsp (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps, byte *buf); +#endif +extern int GeneratePic_parameter_set_rbsp (VideoParameters *p_Vid, pic_parameter_set_rbsp_t *pps, byte *buf); +extern int GenerateSEImessage_rbsp (InputParameters *p_Inp, int id, byte *buf); +extern void FreeSPS (seq_parameter_set_rbsp_t *sps); +extern void FreePPS (pic_parameter_set_rbsp_t *pps); + +extern int WriteHRDParameters(seq_parameter_set_rbsp_t *sps, Bitstream *bitstream); +extern void GenerateVUIParameters(seq_parameter_set_rbsp_t *sps, InputParameters *p_Inp); + +extern pic_parameter_set_rbsp_t *AllocPPS (void); +extern seq_parameter_set_rbsp_t *AllocSPS (void); + + +#endif diff --git a/lencod/inc/pred_struct.h b/lencod/inc/pred_struct.h new file mode 100644 index 0000000..111e2dd --- /dev/null +++ b/lencod/inc/pred_struct.h @@ -0,0 +1,35 @@ +/*! + *************************************************************************** + * \file + * pred_struct.h + * + * \author + * Athanasios Leontaris + * + * \date + * June 8, 2009 + * + * \brief + * Header file for prediction structure function headers + ************************************************************************** + */ + +#ifndef _PRED_STRUCT_H_ +#define _PRED_STRUCT_H_ + +#include "global.h" +#include "pred_struct_types.h" +#include "explicit_seq.h" + +extern void get_poc_type_zero( VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_frm_struct ); +extern void get_poc_type_one( VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_frm_struct ); +extern void init_poc(VideoParameters *p_Vid); +extern SeqStructure * init_seq_structure( VideoParameters *p_Vid, InputParameters *p_Inp, int *memory_size ); +extern void free_seq_structure( SeqStructure *p_seq_struct ); +extern void populate_frm_struct( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_to_populate, int init_frames_to_code ); +extern void populate_frame_explicit( ExpFrameInfo *info, InputParameters *p_Inp, FrameUnitStruct *p_frm_struct, int num_slices ); +extern void populate_frame_slice_type( InputParameters *p_Inp, FrameUnitStruct *p_frm_struct, int slice_type, int num_slices ); +extern void populate_reg_pic( InputParameters *p_Inp, PicStructure *p_pic, FrameUnitStruct *p_frm_struct, int num_slices, int is_bot_fld ); +extern void populate_frm_struct_mvc( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, int start, int end ); + +#endif diff --git a/lencod/inc/pred_struct_adapt.h b/lencod/inc/pred_struct_adapt.h new file mode 100644 index 0000000..8ead686 --- /dev/null +++ b/lencod/inc/pred_struct_adapt.h @@ -0,0 +1,23 @@ +/*! + *************************************************************************** + * \file + * pred_struct_adapt.h + * + * \author + * Athanasios Leontaris + * + * \date + * July 21, 2009 + * + * \brief + * Header file for adaptive prediction structure function headers + ************************************************************************** + */ + +#ifndef _PRED_STRUCT_ADAPT_H_ +#define _PRED_STRUCT_ADAPT_H_ + +#include "global.h" + + +#endif diff --git a/lencod/inc/pred_struct_adapt_types.h b/lencod/inc/pred_struct_adapt_types.h new file mode 100644 index 0000000..83c8044 --- /dev/null +++ b/lencod/inc/pred_struct_adapt_types.h @@ -0,0 +1,22 @@ +/*! + *************************************************************************** + * \file + * pred_struct_adapt_types.h + * + * \author + * Athanasios Leontaris + * + * \date + * July 21, 2009 + * + * \brief + * Header file for adaptive prediction structure types + ************************************************************************** + */ + +#ifndef _PRED_STRUCT_ADAPT_TYPES_H_ +#define _PRED_STRUCT_ADAPT_TYPES_H_ + + + +#endif diff --git a/lencod/inc/pred_struct_types.h b/lencod/inc/pred_struct_types.h new file mode 100644 index 0000000..565de23 --- /dev/null +++ b/lencod/inc/pred_struct_types.h @@ -0,0 +1,143 @@ +/*! + *************************************************************************** + * \file + * pred_struct_types.h + * + * \author + * Athanasios Leontaris + * + * \date + * June 8, 2009 + * + * \brief + * Header file for prediction structure types + ************************************************************************** + */ + +#ifndef _PRED_STRUCT_TYPES_H_ +#define _PRED_STRUCT_TYPES_H_ + +// default coding structures +// these are utilized to compress the current sequence when they are not pre-defined +// sizes are 1 to 4 frames: if a length 4 structure does not *fit* then we try a length 3, 2, or 1 structure. +// One can define also structures > length 4. If these structures do not fit then we attempt to replace them 4, 3, 2, or 1. +// We do not define default structures > 4 since the coding gains are questionable and the increase in memory and +// computational compleity is usually prohibitive (e.g. Blu-Ray can do up to length 4 in HD resolution). + +// After a prediction structure atom has been coded and the coding order of next frame to code is "code_order" +// then all frames with frame_no lesser or equal to "code_order" times (frame_skip + 1) have been coded. + +// non idr atoms +// idr atoms (for intra_delay) + +typedef enum +{ + POP_IDR = 1, + POP_INTRA = 2, + POP_SP = 3 +} SliceTypeToPop; + +// prediction frame structure +typedef struct pred_struct_frm +{ + int disp_offset; + int slice_type; + int nal_ref_idc; + int layer; // the lower the higher the priority + int slice_qp_off; + int random_access; + int temporal_layer; +} PredStructFrm; + +// prediction structure +typedef struct pred_struct_atom +{ + int length; + int gop_levels; + PredStructFrm *p_frm; +} PredStructAtom; + +// slice structure +typedef struct slice_struct +{ + int type; + int qp; + int deblock; + int weighted_pred; + int num_refs; +} SliceStructure; + +// picture structure (frame, top field, bottom field) +typedef struct pic_struct +{ + int idr_flag; + int nal_ref_idc; + int random_access; // to support open GOPs + int num_slices; + SliceStructure *p_Slice; +} PicStructure; + +// frame structure +typedef struct frame_struct +{ + int type; // dominant + int idr_flag; + int nal_ref_idc; + int frame_no; + int field_pic_flag; + int mod_qp; // QP modifier with respect to the slice type default QP + int qp; // QP used to code this frame unit + int layer; + int num_refs; + int random_access; // random access point (IDR or Intra-coded picture that precludes future pictures in display order to reference pictures decoded prior to this picture) + int atom_idx; // index in the prediction structure pointed to be *p_atom + int temporal_layer; +#if (MVC_EXTENSION_ENABLE) + int view_id; +#endif + PicStructure *p_frame_pic; + PicStructure *p_top_fld_pic; + PicStructure *p_bot_fld_pic; + PredStructAtom *p_atom; // pointer to the prediction structure type to which this frame belongs +} FrameUnitStruct; // here "frame" is as in the real thing: the displayed frame; not as "frame" in "frame picture" in H.264 + +// sequence structure +typedef struct seq_struct +{ + int num_frames; + int num_prds; + int num_gops; + int num_intra_gops; + + // frame indices based on *coding* order + int last_random_access_frame; + int last_idr_frame; + int last_intra_frame; + int last_mmco_5_frame; // values during building the structure: have *not* happened yet! + int last_sp_frame; + // frame indices based on *display* order + int last_rand_access_disp; + int last_idr_disp; + int last_intra_disp; + int last_sp_disp; + int last_bl_frm_disposable; // check whether the last frame with layer == 0 (highest priority) + + int curr_num_to_populate; // number of future frames in coding order to populate with each iteration of function populate_frm_struct (note that there are cases that fewer than "num_to_populate" frames may be populated + int pop_start_frame; // frame index (in coding order) from which frame structure population commences + + int max_num_slices; + int pop_flag; + +#if (MVC_EXTENSION_ENABLE) + int num_frames_mvc; + FrameUnitStruct *p_frm_mvc; // frame struct store for num_views > 1 +#endif + + FrameUnitStruct *p_frm; + + PredStructAtom *p_prd; // regular prediction structure + PredStructAtom *p_gop; // IDR GOPs + PredStructAtom *p_intra_gop; // Intra GOPs +} SeqStructure; + +#endif diff --git a/lencod/inc/q_around.h b/lencod/inc/q_around.h new file mode 100644 index 0000000..f0c9d18 --- /dev/null +++ b/lencod/inc/q_around.h @@ -0,0 +1,26 @@ +/*! + *************************************************************************** + * \file + * q_around.h + * + * \author + * Alexis Michael Tourapis + * + * \brief + * Headerfile for Quantization Adaptive Rounding + ************************************************************************** + */ + +#ifndef _Q_AROUND_H_ +#define _Q_AROUND_H_ + +extern void update_adaptive_rounding_8x8 (VideoParameters *p_Vid, InputParameters *p_Inp, RD_8x8DATA* dataTr, int**** ARCofAdj); +extern void store_adaptive_rounding_4x4 (VideoParameters *p_Vid, int****ARCofAdj, int mode, int block_y, int block_x); +extern void update_adaptive_rounding_4x4 (VideoParameters *p_Vid, int****ARCofAdj , int mode, int block_y, int block_x); +extern void update_adaptive_rounding_16x16(VideoParameters *p_Vid, int****ARCofAdj , int mode); +extern void store_adaptive_rounding_16x16 (VideoParameters *p_Vid, int****ARCofAdj, int mode); +extern void reset_adaptive_rounding_direct(VideoParameters *p_Vid); +extern void update_offset_params (Macroblock *currMB, int mode, byte luma_transform_size_8x8_flag); + +#endif + diff --git a/lencod/inc/q_matrix.h b/lencod/inc/q_matrix.h new file mode 100644 index 0000000..e7e8fef --- /dev/null +++ b/lencod/inc/q_matrix.h @@ -0,0 +1,33 @@ + +/*! + *************************************************************************** + * \file + * q_matrix.h + * + * \brief + * Headerfile for q_matrix array + * + * \date + * 07. Apr 2004 + *************************************************************************** + */ + +#ifndef _Q_MATRIX_H_ +#define _Q_MATRIX_H_ + +struct scaling_list { + short ScalingList4x4input[6][16]; + short ScalingList8x8input[6][64]; + short ScalingList4x4[6][16]; + short ScalingList8x8[6][64]; + + short UseDefaultScalingMatrix4x4Flag[6]; + short UseDefaultScalingMatrix8x8Flag[6]; +}; + +extern void init_qmatrix (VideoParameters *p_Vid, InputParameters *p_Inp); +extern void CalculateQuant4x4Param (VideoParameters *p_Vid); +extern void CalculateQuant8x8Param (VideoParameters *p_Vid); +extern void free_QMatrix(QuantParameters *p_Quant); + +#endif diff --git a/lencod/inc/q_offsets.h b/lencod/inc/q_offsets.h new file mode 100644 index 0000000..d566e6b --- /dev/null +++ b/lencod/inc/q_offsets.h @@ -0,0 +1,25 @@ + +/*! + *************************************************************************** + * \file + * q_offsets.h + * + * \brief + * Headerfile for q_offsets array + * + * \date + * 18. Nov 2004 + *************************************************************************** + */ + +#ifndef _Q_OFFSETS_H_ +#define _Q_OFFSETS_H_ + +static const int OffsetBits = 11; + +extern void init_qoffset (VideoParameters *p_Vid); +extern void CalculateOffset4x4Param (VideoParameters *p_Vid); +extern void CalculateOffset8x8Param (VideoParameters *p_Vid); +extern void free_QOffsets (QuantParameters *p_Quant, InputParameters *p_Inp); +extern void InitOffsetParam (QuantParameters *p_Quant, InputParameters *p_Inp); +#endif diff --git a/lencod/inc/quant4x4.h b/lencod/inc/quant4x4.h new file mode 100644 index 0000000..fcdfdb4 --- /dev/null +++ b/lencod/inc/quant4x4.h @@ -0,0 +1,53 @@ + +/*! +************************************************************************ +* \file quant4x4.h +* +* \brief +* Quantization process header file +* +* \author +* Limin Liu +* Alexis Michael Tourapis +* +************************************************************************ +*/ + +#ifndef _QUANT4x4_H_ +#define _QUANT4x4_H_ + +extern void init_quant_4x4 (Slice *currSlice); + +extern int quant_4x4_normal (Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_4x4_around (Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_4x4_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_dc4x4_normal (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]); + +extern int quant_dc4x4_around (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]); + +extern int quant_dc4x4_trellis(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]); + +extern int quant_ac4x4_normal (Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_ac4x4_around (Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_ac4x4_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method); + +extern void rdoq_4x4_CAVLC (Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[16]); + +extern void rdoq_4x4_CABAC (Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[16]); + +extern void rdoq_dc_CAVLC (Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, + const byte (*pos_scan)[2], int levelTrellis[16], int type); + +extern void rdoq_dc_CABAC (Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, + const byte (*pos_scan)[2], int levelTrellis[16], int type); + +extern void rdoq_ac4x4_CAVLC (Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[16]); + +extern void rdoq_ac4x4_CABAC (Macroblock *currMB, int **tblock , struct quant_methods *q_method, int levelTrellis[16]); + + +#endif + diff --git a/lencod/inc/quant8x8.h b/lencod/inc/quant8x8.h new file mode 100644 index 0000000..1f05fba --- /dev/null +++ b/lencod/inc/quant8x8.h @@ -0,0 +1,29 @@ + +/*! +************************************************************************ +* \file quant8x8.h +* +* \brief +* Quantization process header file +* +* \author +* Alexis Michael Tourapis +* +************************************************************************ +*/ + +#ifndef _QUANT8x8_H_ +#define _QUANT8x8_H_ + +extern void init_quant_8x8 (Slice *currSlice); + +extern int quant_8x8_normal (Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_8x8_around (Macroblock *currMB, int **tblock, struct quant_methods *q_method); +extern int quant_8x8_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method); + +extern int quant_8x8cavlc_around (Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC); +extern int quant_8x8cavlc_normal (Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC); +extern int quant_8x8cavlc_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC); + +#endif + diff --git a/lencod/inc/quantChroma.h b/lencod/inc/quantChroma.h new file mode 100644 index 0000000..18105fa --- /dev/null +++ b/lencod/inc/quantChroma.h @@ -0,0 +1,47 @@ + +/*! +************************************************************************ +* \file quantChroma.h +* +* \brief +* Quantization process for chroma header file +* +* \author +* Limin Liu +* Alexis Michael Tourapis +* +************************************************************************ +*/ + +#ifndef _QUANT_CR_H_ +#define _QUANT_CR_H_ + +extern void init_quant_Chroma(Slice *currSlice); + +extern int quant_dc2x2_normal (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust2x2, const byte (*pos_scan)[2]); + +extern int quant_dc2x2_around (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust2x2, const byte (*pos_scan)[2]); + +extern int quant_dc2x2_trellis(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]); + +extern int quant_dc4x2_normal (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]); + +extern int quant_dc4x2_around (Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]); + +extern int quant_dc4x2_trellis(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]); + +extern void rdoq_dc_cr_CAVLC (Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params_4x4, + const byte (*pos_scan)[2], int levelTrellis[16], int type); + +extern void rdoq_dc_cr_CABAC (Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2], int levelTrellis[16], int type); + +#endif + diff --git a/lencod/inc/ratectl.h b/lencod/inc/ratectl.h new file mode 100644 index 0000000..21b9891 --- /dev/null +++ b/lencod/inc/ratectl.h @@ -0,0 +1,44 @@ + +/*! + *************************************************************************** + * \file + * ratectl.h + * + * \author + * Zhengguo LI + * Athanasios Leontaris + * + * \date + * 14 Jan 2003 + * + * \brief + * Headerfile for rate control + ************************************************************************** + */ + +#ifndef _RATE_CTL_H_ +#define _RATE_CTL_H_ + +#include "global.h" +#include "rc_quadratic.h" + + +// generic functions +extern int Qstep2QP ( double Qstep, int qp_offset ); +extern double QP2Qstep ( int QP ); +extern int ComputeMBMAD ( int diff[16][16] ); +extern double ComputeFrameMAD ( VideoParameters *p_Vid ); +extern void rc_store_mad ( Macroblock *currMB ); + +// rate control functions +// init/copy +extern void rc_alloc_generic ( VideoParameters *p_Vid, RCGeneric **p_quad ); +extern void rc_free_generic ( RCGeneric **p_quad ); +extern void rc_copy_generic ( VideoParameters *p_Vid, RCGeneric *dst, RCGeneric *src ); +extern void rc_init_gop_params ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void rc_init_frame ( VideoParameters *p_Vid, InputParameters *p_Inp); +extern void rc_init_sequence ( VideoParameters *p_Vid, InputParameters *p_Inp); +extern void rc_store_slice_header_bits ( VideoParameters *p_Vid, InputParameters *p_Inp, int len); + +#endif + diff --git a/lencod/inc/rc_quadratic.h b/lencod/inc/rc_quadratic.h new file mode 100644 index 0000000..1672b2f --- /dev/null +++ b/lencod/inc/rc_quadratic.h @@ -0,0 +1,76 @@ + +/*! + *************************************************************************** + * \file + * rc_quadratic.h + * + * \author + * Zhengguo LI + * Athanasios Leontaris + * + * \date + * 14 Jan 2003 + * + * \brief + * Headerfile for rate control + ************************************************************************** + */ + +#ifndef _RC_QUADRATIC_H_ +#define _RC_QUADRATIC_H_ + +#include "rc_types.h" + +// rate control functions +// init/copy +extern void rc_alloc_quadratic( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic **p_quad ); +extern void rc_free_quadratic ( RCQuadratic **p_quad ); +extern void rc_copy_quadratic ( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *dst, RCQuadratic *src ); + +// rate control (externally visible) +extern void rc_init_seq (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen); +extern void rc_init_GOP (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int np, int nb); +extern void rc_update_pict_frame (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int nbits); +extern void rc_init_pict (VideoParameters *p_Vid, InputParameters *p_Inp, + RCQuadratic *p_quad, RCGeneric *p_gen, int fieldpic, int topfield, int targetcomputation, float mult); +extern void rc_update_pict (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int nbits); +extern void rc_update_picture (VideoParameters *p_Vid, InputParameters *p_Inp, int bits); + +extern int updateQPRC0(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield); +extern int updateQPRC1(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield); +extern int updateQPRC2(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield); +extern int updateQPRC3(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield); + +// internal functions +extern void updateQPInterlace ( RCQuadratic *p_quad, RCGeneric *p_gen ); +extern void updateQPNonPicAFF ( seq_parameter_set_rbsp_t *active_sps, RCQuadratic *p_quad ); +extern void updateBottomField ( InputParameters *p_Inp, RCQuadratic *p_quad ); +extern int updateFirstP ( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield ); +extern int updateNegativeTarget( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield, int m_Qp ); +extern int updateFirstBU ( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield ); +extern void updateLastBU ( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield ); +extern void predictCurrPicMAD ( InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen ); +extern void updateModelQPBU ( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, int m_Qp ); +extern void updateQPInterlaceBU ( RCQuadratic *p_quad, RCGeneric *p_gen ); +extern void updateModelQPFrame ( RCQuadratic *p_quad, int m_Bits ); + +extern void updateRCModel (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen); +extern void updateMADModel (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen); +extern void RCModelEstimator (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, int n_windowSize, Boolean *m_rgRejected); +extern void MADModelEstimator(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, int n_windowSize, Boolean *PictureRejected); +extern int updateComplexity (VideoParameters *p_Vid, RCQuadratic *p_quad, RCGeneric *p_gen, Boolean is_updated, int nbits ); +extern void updatePparams (RCQuadratic *p_quad, RCGeneric *p_gen, int complexity ); +extern void updateBparams (RCQuadratic *p_quad, RCGeneric *p_gen, int complexity ); + +// external generic functions +extern int rc_handle_mb ( Macroblock *currMB, int prev_mb); +extern void rc_init_top_field ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void rc_init_bottom_field ( VideoParameters *p_Vid, InputParameters *p_Inp, int TopFieldBits ); +extern void rc_init_frame_rdpic ( VideoParameters *p_Vid, InputParameters *p_Inp, float rateRatio ); +extern void rc_allocate_memory ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void rc_free_memory ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void rc_update_mb_stats ( Macroblock *currMB); +extern void rc_save_state ( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void rc_restore_state ( VideoParameters *p_Vid, InputParameters *p_Inp ); + +#endif diff --git a/lencod/inc/rc_types.h b/lencod/inc/rc_types.h new file mode 100644 index 0000000..9394f49 --- /dev/null +++ b/lencod/inc/rc_types.h @@ -0,0 +1,156 @@ + +/*! + *************************************************************************** + * \file + * rc_types.h + * + * \author + * Zhengguo LI + * Athanasios Leontaris + * + * \date + * 14 Jan 2003 + * 27 Apr 2009 + * + * \brief + * Headerfile for basic rate control structures + ************************************************************************** + */ + +#ifndef _RC_TYPES_H_ +#define _RC_TYPES_H_ + +#define RC_MODEL_HISTORY 21 + +/* generic rate control variables */ +typedef struct rc_generic +{ + // RC flags + int TopFieldFlag; + int FieldControl; + int FieldFrame; + int NoGranularFieldRC; + // bits stats + int NumberofHeaderBits; + int NumberofTextureBits; + int NumberofBasicUnitHeaderBits; + int NumberofBasicUnitTextureBits; + // frame stats + int NumberofGOP; + int NumberofCodedBFrame; + // MAD stats + int64 TotalMADBasicUnit; + int *MADofMB; + // buffer and budget + int64 CurrentBufferFullness; //LIZG 25/10/2002 + int64 RemainingBits; + // bit allocations for RC_MODE_3 + int RCPSliceBits; + int RCISliceBits; + int RCBSliceBits[RC_MAX_TEMPORAL_LEVELS]; + int temporal_levels; + int hierNb[RC_MAX_TEMPORAL_LEVELS]; + int NPSlice; + int NISlice; +} RCGeneric; + +typedef struct rc_quadratic +{ + float bit_rate; + float frame_rate; + float PrevBitRate; //LIZG 25/10/2002 + double GAMMAP; //LIZG, JVT019r1 + double BETAP; //LIZG, JVT019r1 + double GOPTargetBufferLevel; + double TargetBufferLevel; //LIZG 25/10/2002 + double AveWp; + double AveWb; + int MyInitialQp; + int PAverageQp; + double PreviousPictureMAD; + double MADPictureC1; + double MADPictureC2; + double PMADPictureC1; + double PMADPictureC2; + double PPictureMAD [RC_MODEL_HISTORY]; + double PictureMAD [RC_MODEL_HISTORY]; + double ReferenceMAD[RC_MODEL_HISTORY]; + double m_rgQp [RC_MODEL_HISTORY]; + double m_rgRp [RC_MODEL_HISTORY]; + double Pm_rgQp [RC_MODEL_HISTORY]; + double Pm_rgRp [RC_MODEL_HISTORY]; + + double m_X1; + double m_X2; + double Pm_X1; + double Pm_X2; + int Pm_Qp; + int Pm_Hp; + + int MADm_windowSize; + int m_windowSize; + int m_Qc; + + int PPreHeader; + int PrevLastQP; // QP of the second-to-last coded frame in the primary layer + int CurrLastQP; // QP of the last coded frame in the primary layer + int NumberofBFrames; + // basic unit layer rate control + int TotalFrameQP; + int NumberofBasicUnit; + int PAveHeaderBits1; + int PAveHeaderBits2; + int PAveHeaderBits3; + int PAveFrameQP; + int TotalNumberofBasicUnit; + int CodedBasicUnit; + + int NumberofCodedPFrame; + int TotalQpforPPicture; + int NumberofPPicture; + + double CurrentFrameMAD; + double CurrentBUMAD; + double TotalBUMAD; + double PreviousFrameMAD; + double PreviousWholeFrameMAD; + + int DDquant; + unsigned int MBPerRow; + int QPLastPFrame; + int QPLastGOP; + + // adaptive field/frame coding + int FieldQPBuffer; + int FrameQPBuffer; + int FrameAveHeaderBits; + int FieldAveHeaderBits; + double *BUPFMAD; + double *BUCFMAD; + double *FCBUCFMAD; + double *FCBUPFMAD; + + Boolean GOPOverdue; + int64 Pprev_bits; + + // rate control variables + int Xp, Xb; + int Target; + int TargetField; + int Np, Nb, bits_topfield; + // HRD consideration + int UpperBound1, UpperBound2, LowerBound; + double Wp, Wb; // complexity weights + double DeltaP; + int TotalPFrame; + int PMaxQpChange; + + int bitdepth_qp_scale; // support negative QPs (bitdepth > 8-bits per component) + + // simple encoder buffer simulation + int enc_buf_curr; + +} RCQuadratic; + +#endif + diff --git a/lencod/inc/rd_intra_jm.h b/lencod/inc/rd_intra_jm.h new file mode 100644 index 0000000..d480e82 --- /dev/null +++ b/lencod/inc/rd_intra_jm.h @@ -0,0 +1,27 @@ +/*! + *************************************************************************** + * \file + * rd_intra_jm.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 2 January 2008 + * + * \brief + * Headerfile for JM rd based intra mode decision + ************************************************************************** + */ + +#ifndef _RD_INTRA_JM_H_ +#define _RD_INTRA_JM_H_ + +extern int mode_decision_for_I16x16_MB_RDO (Macroblock *currMB, int lambda); +extern int mode_decision_for_I16x16_MB (Macroblock *currMB, int lambda); +extern int mode_decision_for_I4x4_blocks_JM_High (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost); +extern int mode_decision_for_I4x4_blocks_JM_Low (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost); +extern int find_best_mode_I16x16_MB (Macroblock *currMB, int lambda, distblk min_cost); + +#endif + diff --git a/lencod/inc/rd_intra_jm444.h b/lencod/inc/rd_intra_jm444.h new file mode 100644 index 0000000..e43c7af --- /dev/null +++ b/lencod/inc/rd_intra_jm444.h @@ -0,0 +1,24 @@ +/*! + *************************************************************************** + * \file + * rd_intra_jm444.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 2 January 2008 + * + * \brief + * Headerfile for JM rd based intra mode decision (High444) + ************************************************************************** + */ + +#ifndef _RD_INTRA_JM444_H_ +#define _RD_INTRA_JM444_H_ + +extern int mode_decision_for_I16x16_MB_444 (Macroblock *currMB, int lambda); +extern int mode_decision_for_I4x4_blocks_JM_High444 (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost); +extern int mode_decision_for_I4x4_blocks_JM_Low444 (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost); +#endif + diff --git a/lencod/inc/rdopt.h b/lencod/inc/rdopt.h new file mode 100644 index 0000000..d3bb79c --- /dev/null +++ b/lencod/inc/rdopt.h @@ -0,0 +1,132 @@ +/*! + *************************************************************************** + * \file + * rdopt.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 2 January 2008 + * + * \brief + * Headerfile for RDO + ************************************************************************** + */ + +#ifndef _RDO_H_ +#define _RDO_H_ + +#include "global.h" +#include "rdopt_coding_state.h" + +// Motion Vector structure +typedef struct +{ + double rdcost; + double dcost; + double rate; // why is rate a double? Could we use int64 or even simply int given that this is for a MB? Could a MB require int64 bits (answer is no)? + int cbp; + distblk cost; + short c_imode; + short i16offset; + byte mode; +} BestMode; + +struct rdo_structure +{ + RD_8x8DATA *tr4x4; + RD_8x8DATA *tr8x8; + imgpel ***rec8x8; + imgpel ***rec4x4; + imgpel **pred; + imgpel ***rec_mb; + int **lrec_rec; + int ***lrec_rec_uv; + + int ****cofAC; + int ***cofDC; + int **cofAC4x4; + int ****cofAC4x4intern; + + MotionVector ****all_mv8x8; + + int *****cofAC4x4CbCrintern; + int *****cofAC8x8ts; // [plane][8x8block][4x4block][level/run][scan_pos] + int *****coefAC8x8; + int *****coefAC8x8intra; + int **cofAC4x4CbCr[2]; + + + int cbp; + char **l0_refframe; + char **l1_refframe; + + Info8x8 best8x8[4]; + + CSobj *cs_mb; + CSobj *cs_b8; + CSobj *cs_cm; + CSobj *cs_tmp; + + BestMode mode_best; + +// adaptive langrangian parameters + double lambda_mf_factor; +}; + + +extern byte field_flag_inference (Macroblock *currMB); +extern int valid_intra_mode(Slice *currSlice, int ipmode); + +extern void init_md_best(BestMode *best); + +//============= rate-distortion optimization =================== +extern void clear_rdopt (Slice *currSlice); +extern void init_rdopt (Slice *currSlice); + +extern void UpdatePixelMap(VideoParameters *p_Vid, InputParameters *p_Inp); + +extern void update_qp_cbp (Macroblock *currMB); +extern void update_qp_cbp_tmp (Macroblock *currMB, int cbp); + +extern void alloc_rd8x8data (RD_8x8DATA *rd_data); +extern void free_rd8x8data (RD_8x8DATA *rd_data); + +extern void restore_nz_coeff(Macroblock *currMB); + +extern void end_encode_one_macroblock(Macroblock *currMB); + +extern void encode_one_macroblock_low (Macroblock *currMB); +extern void encode_one_macroblock_high (Macroblock *currMB); +extern void encode_one_macroblock_highfast (Macroblock *currMB); +extern void encode_one_macroblock_highloss (Macroblock *currMB); + +extern void store_8x8_motion_vectors_p_slice (Slice *currSlice, int dir, int block8x8, Info8x8 *B8x8Info); +extern void store_8x8_motion_vectors_b_slice (Slice *currSlice, int dir, int block8x8, Info8x8 *B8x8Info); + +extern void set_modes_and_refs_for_blocks_p_slice(Macroblock *currMB, short mode); +extern void set_modes_and_refs_for_blocks_b_slice(Macroblock *currMB, short mode); +extern void set_modes_and_refs_for_blocks_i_slice(Macroblock *currMB, short mode); + +extern void set_coeff_and_recon_8x8_p_slice (Macroblock* currMB); +extern void set_coeff_and_recon_8x8_b_slice (Macroblock* currMB); + +extern Info8x8 init_info_8x8_struct(void); + +/*! + ************************************************************************************* + * \brief + * copy data in iblock to oblock + ************************************************************************************* + */ +static inline void copy_4x4block(imgpel **oblock, imgpel **iblock, int o_xoffset, int i_xoffset) +{ + int y; + for (y = 0; y < BLOCK_SIZE; y++) + { + memcpy(&oblock[y][o_xoffset],&iblock[y][i_xoffset], BLOCK_SIZE * sizeof(imgpel)); + } +} +#endif + diff --git a/lencod/inc/rdopt_coding_state.h b/lencod/inc/rdopt_coding_state.h new file mode 100644 index 0000000..b028f75 --- /dev/null +++ b/lencod/inc/rdopt_coding_state.h @@ -0,0 +1,53 @@ + +/*! + *************************************************************************** + * \file + * rdopt_coding_state.h + * + * \author + * Heiko Schwarz + * + * \date + * 17. April 2001 + * + * \brief + * Headerfile for storing/restoring coding state + * (for rd-optimized mode decision) + ************************************************************************** + */ + +#ifndef _RD_OPT_CS_H_ +#define _RD_OPT_CS_H_ + +struct coding_state { + + // important variables of data partition array + int no_part; + Bitstream *bitstream; + EncodingEnvironment *encenv; + + // contexts for binary arithmetic coding + MotionInfoContexts *mot_ctx; + TextureInfoContexts *tex_ctx; + + // bit counter + BitCounter bits; + + // elements of current macroblock + short mvd[2][BLOCK_MULTIPLE][BLOCK_MULTIPLE][2]; + int64 cbp_bits[3]; + int64 *cbp_bits_8x8; +}; + +typedef struct coding_state CSobj; + +extern void delete_coding_state (CSobj *); //!< delete structure +extern CSobj *create_coding_state (InputParameters *p_Inp); //!< create structure + +extern void init_coding_state_methods(Slice *currSlice); //!< Init methods given entropy coding + +extern void store_coding_state_cavlc (Macroblock *currMB, CSobj *cs); +extern void reset_coding_state_cavlc (Macroblock *currMB, CSobj *cs); + +#endif + diff --git a/lencod/inc/rdoq.h b/lencod/inc/rdoq.h new file mode 100644 index 0000000..8a5bcf7 --- /dev/null +++ b/lencod/inc/rdoq.h @@ -0,0 +1,202 @@ + +/*! + *************************************************************************** + * \file + * rdoq.h + * + * \brief + * Headerfile for trellis based mode decision + * + * \author + * Limin Liu + * Alexis Michael Tourapis + *************************************************************************** + */ + + +#ifndef _RDOQ_H_ +#define _RDOQ_H_ + +#include + + +#define SIGN_BITS 1 + +static const int estErr4x4[6][4][4] = +{ + { + {25600, 27040, 25600, 27040}, + {27040, 25600, 27040, 25600}, + {25600, 27040, 25600, 27040}, + {27040, 25600, 27040, 25600} + }, + { + {30976, 31360, 30976, 31360}, + {31360, 32400, 31360, 32400}, + {30976, 31360, 30976, 31360}, + {31360, 32400, 31360, 32400} + }, + { + {43264, 40960, 43264, 40960}, + {40960, 40000, 40960, 40000}, + {43264, 40960, 43264, 40960}, + {40960, 40000, 40960, 40000} + }, + { + {50176, 51840, 50176, 51840}, + {51840, 52900, 51840, 52900}, + {50176, 51840, 50176, 51840}, + {51840, 52900, 51840, 52900} + }, + { + {65536, 64000, 65536, 64000}, + {64000, 62500, 64000, 62500}, + {65536, 64000, 65536, 64000}, + {64000, 62500, 64000, 62500} + }, + { + {82944, 84640, 82944, 84640}, + {84640, 84100, 84640, 84100}, + {82944, 84640, 82944, 84640}, + {84640, 84100, 84640, 84100} + } +}; + +static const int estErr8x8[6][8][8]={ + { + {6553600, 6677056, 6400000, 6677056, 6553600, 6677056, 6400000, 6677056}, + {6677056, 6765201, 6658560, 6765201, 6677056, 6765201, 6658560, 6765201}, + {6400000, 6658560, 6553600, 6658560, 6400000, 6658560, 6553600, 6658560}, + {6677056, 6765201, 6658560, 6765201, 6677056, 6765201, 6658560, 6765201}, + {6553600, 6677056, 6400000, 6677056, 6553600, 6677056, 6400000, 6677056}, + {6677056, 6765201, 6658560, 6765201, 6677056, 6765201, 6658560, 6765201}, + {6400000, 6658560, 6553600, 6658560, 6400000, 6658560, 6553600, 6658560}, + {6677056, 6765201, 6658560, 6765201, 6677056, 6765201, 6658560, 6765201} + }, + { + {7929856, 8156736, 8028160, 8156736, 7929856, 8156736, 8028160, 8156736}, + {8156736, 7537770, 7814560, 7537770, 8156736, 7537770, 7814560, 7537770}, + {8028160, 7814560, 7840000, 7814560, 8028160, 7814560, 7840000, 7814560}, + {8156736, 7537770, 7814560, 7537770, 8156736, 7537770, 7814560, 7537770}, + {7929856, 8156736, 8028160, 8156736, 7929856, 8156736, 8028160, 8156736}, + {8156736, 7537770, 7814560, 7537770, 8156736, 7537770, 7814560, 7537770}, + {8028160, 7814560, 7840000, 7814560, 8028160, 7814560, 7840000, 7814560}, + {8156736, 7537770, 7814560, 7537770, 8156736, 7537770, 7814560, 7537770} + }, + { + {11075584, 10653696, 11151360, 10653696, 11075584, 10653696, 11151360, 10653696}, + {10653696, 11045652, 11109160, 11045652, 10653696, 11045652, 11109160, 11045652}, + {11151360, 11109160, 11289600, 11109160, 11151360, 11109160, 11289600, 11109160}, + {10653696, 11045652, 11109160, 11045652, 10653696, 11045652, 11109160, 11045652}, + {11075584, 10653696, 11151360, 10653696, 11075584, 10653696, 11151360, 10653696}, + {10653696, 11045652, 11109160, 11045652, 10653696, 11045652, 11109160, 11045652}, + {11151360, 11109160, 11289600, 11109160, 11151360, 11109160, 11289600, 11109160}, + {10653696, 11045652, 11109160, 11045652, 10653696, 11045652, 11109160, 11045652} + }, + { + {12845056, 12503296, 12544000, 12503296, 12845056, 12503296, 12544000, 12503296}, + {12503296, 13050156, 12588840, 13050156, 12503296, 13050156, 12588840, 13050156}, + {12544000, 12588840, 12960000, 12588840, 12544000, 12588840, 12960000, 12588840}, + {12503296, 13050156, 12588840, 13050156, 12503296, 13050156, 12588840, 13050156}, + {12845056, 12503296, 12544000, 12503296, 12845056, 12503296, 12544000, 12503296}, + {12503296, 13050156, 12588840, 13050156, 12503296, 13050156, 12588840, 13050156}, + {12544000, 12588840, 12960000, 12588840, 12544000, 12588840, 12960000, 12588840}, + {12503296, 13050156, 12588840, 13050156, 12503296, 13050156, 12588840, 13050156} + }, + { + {16777216, 16646400, 16384000, 16646400, 16777216, 16646400, 16384000, 16646400}, + {16646400, 16370116, 16692640, 16370116, 16646400, 16370116, 16692640, 16370116}, + {16384000, 16692640, 16646400, 16692640, 16384000, 16692640, 16646400, 16692640}, + {16646400, 16370116, 16692640, 16370116, 16646400, 16370116, 16692640, 16370116}, + {16777216, 16646400, 16384000, 16646400, 16777216, 16646400, 16384000, 16646400}, + {16646400, 16370116, 16692640, 16370116, 16646400, 16370116, 16692640, 16370116}, + {16384000, 16692640, 16646400, 16692640, 16384000, 16692640, 16646400, 16692640}, + {16646400, 16370116, 16692640, 16370116, 16646400, 16370116, 16692640, 16370116} + }, + { + {21233664, 21381376, 21667840, 21381376, 21233664, 21381376, 21667840, 21381376}, + {21381376, 21381376, 21374440, 21381376, 21381376, 21381376, 21374440, 21381376}, + {21667840, 21374440, 21529600, 21374440, 21667840, 21374440, 21529600, 21374440}, + {21381376, 21381376, 21374440, 21381376, 21381376, 21381376, 21374440, 21381376}, + {21233664, 21381376, 21667840, 21381376, 21233664, 21381376, 21667840, 21381376}, + {21381376, 21381376, 21374440, 21381376, 21381376, 21381376, 21374440, 21381376}, + {21667840, 21374440, 21529600, 21374440, 21667840, 21374440, 21529600, 21374440}, + {21381376, 21381376, 21374440, 21381376, 21381376, 21381376, 21374440, 21381376} + } +}; + + +struct est_bits_cabac +{ + int significantBits[16][2]; + int lastBits[16][2]; + int greaterOneBits[2][5][2]; // c1 and c2 + int greaterOneState[5]; + int blockCbpBits[4][2]; // c1 and c2 +}; +typedef struct est_bits_cabac estBitsCabacStruct; + +typedef struct level_data_struct +{ + int level[3]; + int levelDouble; + double errLevel[3]; + int noLevels; + int coeff_ctr; + int pre_level; + int sign; +} levelDataStruct; + + +extern void init_rdoq_slice(Slice *currSlice); + +/*----------CAVLC related functions----------*/ +extern void est_RunLevel_CAVLC(Macroblock *currMB, levelDataStruct *levelData, int *levelTrellis, int block_type, + int b8, int b4, int coeff_num, double lambda); +extern int est_CAVLC_bits (VideoParameters *p_Vid, int level_to_enc[16], int sign_to_enc[16], int nnz, int block_type); + +/*----------CABAC related functions----------*/ +extern void precalculate_unary_exp_golomb_level(VideoParameters *p_Vid); +extern int est_unary_exp_golomb_level_bits(unsigned int symbol, int bits0, int bits1); +extern int est_exp_golomb_encode_eq_prob (unsigned int symbol); + +extern void estRunLevel_CABAC (Macroblock* currMB, int context); + + + +extern int est_write_and_store_CBP_block_bit(Macroblock* currMB, int type); +extern void est_writeRunLevel_CABAC(Macroblock *currMB, levelDataStruct levelData[], int levelTabMin[], int type, double lambda, int kStart, + int kStop, int noCoeff, int estCBP); +extern void init_trellis_data_4x4_CAVLC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, + LevelQuantParams **q_params_4x4, const byte *p_scan, + levelDataStruct *dataLevel, int type); +extern int init_trellis_data_4x4_CABAC(Macroblock *currMB, int **tblock, + struct quant_methods *q_method, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop, int type); +extern void init_trellis_data_8x8_CAVLC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, + LevelQuantParams **q_params_8x8, const byte *p_scan, + levelDataStruct levelData[4][16]); +extern int init_trellis_data_8x8_CABAC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, + LevelQuantParams **q_params_8x8, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop); +extern void init_trellis_data_DC_CAVLC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params_4x4, const byte *p_scan, + levelDataStruct *dataLevel); +extern int init_trellis_data_DC_CABAC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params_4x4, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop); +extern int init_trellis_data_DC_cr_CAVLC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params_4x4, const byte *p_scan, + levelDataStruct *dataLevel); +extern int init_trellis_data_DC_cr_CABAC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params_4x4, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop); + +extern void RDOQ_update_mode (Slice *currSlice, RD_PARAMS *enc_mb); +extern void copy_rddata_trellis (Macroblock *currMB, RD_DATA *dest, RD_DATA *src); +extern void updateMV_mp (Macroblock *currMB, distblk *m_cost, short ref, int list, int h, int v, int blocktype, int block8x8); +extern void trellis_coding (Macroblock *currMB); +extern void get_dQP_table (Slice *currSlice); + +#endif // _RDOQ_H_ + diff --git a/lencod/inc/refbuf.h b/lencod/inc/refbuf.h new file mode 100644 index 0000000..9a1aad5 --- /dev/null +++ b/lencod/inc/refbuf.h @@ -0,0 +1,82 @@ + +/*! + ************************************************************************ + * \file refbuf.h + * + * \brief + * Declarations of the reference frame buffer types and functions + ************************************************************************ + */ +#ifndef _REBUF_H_ +#define _REBUF_H_ + +#include "mbuffer.h" + +/*! + ************************************************************************ + * \brief + * Yields a pel line _pointer_ from one of the 16 sub-images + * Input does not require subpixel image indices + ************************************************************************ + */ +static inline imgpel *UMVLine4X (StorablePicture *ref, int y, int x) +{ + //return &(ref->p_curr_img_sub[(y & 0x03)][(x & 0x03)][iClip3( 0, ref->size_y_pad, y >> 2)][iClip3( 0, ref->size_x_pad, x >> 2)]); + return &(ref->p_curr_img_sub[(y & 0x03)][(x & 0x03)][iClip3( -IMG_PAD_SIZE_Y, ref->size_y_pad, y >> 2)][iClip3(-IMG_PAD_SIZE_X, ref->size_x_pad, x >> 2)]); +} + +/*! + ************************************************************************ + * \brief + * Yields a pel line _pointer_ from one of the 16 sub-images + * Input does not require subpixel image indices + ************************************************************************ + */ +static inline imgpel *UMVLine4Xcr (StorablePicture *ref, int cmp, int y, int x) +{ + //return &(ref->p_img_sub[cmp][(y & 0x03)][(x & 0x03)][iClip3( 0, ref->size_y_cr_pad, y >> 2)][iClip3( 0, ref->size_x_cr_pad, x >> 2)]); + return &(ref->p_img_sub[cmp][(y & 0x03)][(x & 0x03)][iClip3(-ref->pad_size_uv_y, ref->size_y_cr_pad, y >> 2)][iClip3(-ref->pad_size_uv_x, ref->size_x_cr_pad, x >> 2)]); +} + +/*! + ************************************************************************ + * \brief + * Yields a pel line _pointer_ from one of the 16 sub-images + * Input does not require subpixel image indices + ************************************************************************ + */ +static inline imgpel *FastLine4X (StorablePicture *ref, int y, int x) +{ + return &(ref->p_curr_img_sub[(y & 0x03)][(x & 0x03)][y >> 2][x >> 2]); +} + +/*! + ************************************************************************ + * \brief + * Yields a pel line _pointer_ from one of the 16 (4:4:4), 32 (4:2:2), + * or 64 (4:2:0) sub-images + * Input does not require subpixel image indices + ************************************************************************ + */ +static inline imgpel *UMVLine8X_chroma (StorablePicture *ref, int cmp, int y, int x) +{ + //return &(ref->p_img_sub[cmp][y & ref->chroma_mask_mv_y][x & ref->chroma_mask_mv_x][iClip3 (0, ref->size_y_cr_pad, y >> ref->chroma_shift_y)][iClip3 (0, ref->size_x_cr_pad, x >> ref->chroma_shift_x)]); + return &(ref->p_img_sub[cmp][y & ref->chroma_mask_mv_y][x & ref->chroma_mask_mv_x][iClip3 (-ref->pad_size_uv_y, ref->size_y_cr_pad, y >> ref->chroma_shift_y)][iClip3 (-ref->pad_size_uv_x, ref->size_x_cr_pad, x >> ref->chroma_shift_x)]); +} + +/*! + ************************************************************************ + * \brief + * Yields a pel line _pointer_ from one of the 16 (4:4:4), 32 (4:2:2), + * or 64 (4:2:0) sub-images + * Input does not require subpixel image indices + ************************************************************************ + */ +static inline imgpel *FastLine8X_chroma (StorablePicture *ref, int cmp, int y, int x) +{ + return &(ref->p_img_sub[cmp][y & ref->chroma_mask_mv_y][x & ref->chroma_mask_mv_x][y >> ref->chroma_shift_y][x >> ref->chroma_shift_x]); +} + + +#endif + diff --git a/lencod/inc/refbuf_otf.h b/lencod/inc/refbuf_otf.h new file mode 100644 index 0000000..e89d4a4 --- /dev/null +++ b/lencod/inc/refbuf_otf.h @@ -0,0 +1,32 @@ + +/*! + ************************************************************************ + * \file refbuf_otf.h + * + * \brief + * Declarations of the reference frame buffer types and functions for on-the-fly interpolations + ************************************************************************ + */ +#ifndef _REBUF_OTF_H_ +#define _REBUF_OTF_H_ + +#include "mbuffer.h" + +static inline imgpel *UMVLine4X_otf (StorablePicture *ref, int y, int x ) +{ + return &(ref->p_curr_img_sub[(y & 0x03)>>1][(x & 0x03)>>1][iClip3( -IMG_PAD_SIZE_Y, ref->size_y_pad, y >> 2)][iClip3(-IMG_PAD_SIZE_X, ref->size_x_pad, x >> 2)]); +} + +static inline imgpel *UMVLine4Xcr_otf (StorablePicture *ref, int cmp, int y, int x) +{ + return &(ref->p_img_sub[cmp][(y & 0x03)>>1][(x & 0x03)>>1][iClip3(-ref->pad_size_uv_y, ref->size_y_cr_pad, y >> 2)][iClip3(-ref->pad_size_uv_x, ref->size_x_cr_pad, x >> 2)]); +} + +static inline imgpel *UMVLine8X_chroma_otf (StorablePicture *ref, int cmp, int y, int x) +{ + return &(ref->p_img_sub[cmp][(y & ref->chroma_mask_mv_y)>>1][(x & ref->chroma_mask_mv_x)>>1][iClip3 (-ref->pad_size_uv_y, ref->size_y_cr_pad, y >> ref->chroma_shift_y)][iClip3 (-ref->pad_size_uv_x, ref->size_x_cr_pad, x >> ref->chroma_shift_x)]); +} + + +#endif + diff --git a/lencod/inc/rtp.h b/lencod/inc/rtp.h new file mode 100644 index 0000000..cbb344b --- /dev/null +++ b/lencod/inc/rtp.h @@ -0,0 +1,56 @@ + +/*! + *************************************************************************** + * + * \file rtp.h + * + * \brief + * Definition of structures and functions to handle RTP headers. For a + * description of RTP see RFC1889 on http://www.ietf.org + * + * \date + * 30 September 2001 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + **************************************************************************/ + +#ifndef _RTP_H_ +#define _RTP_H_ + +#include "nalu.h" + +#define MAXRTPPAYLOADLEN (65536 - 40) //!< Maximum payload size of an RTP packet +#define MAXRTPPACKETSIZE (65536 - 28) //!< Maximum size of an RTP packet incl. header +#define H264PAYLOADTYPE 105 //!< RTP paylaod type fixed here for simplicity +#define H264SSRC 0x12345678 //!< SSRC, chosen to simplify debugging +#define RTP_TR_TIMESTAMP_MULT 1000 //!< should be something like 27 Mhz / 29.97 Hz + +typedef struct +{ + unsigned int v; //!< Version, 2 bits, MUST be 0x2 + unsigned int p; //!< Padding bit, Padding MUST NOT be used + unsigned int x; //!< Extension, MUST be zero + unsigned int cc; /*!< CSRC count, normally 0 in the absence + of RTP mixers */ + unsigned int m; //!< Marker bit + unsigned int pt; //!< 7 bits, Payload Type, dynamically established + unsigned int seq; /*!< RTP sequence number, incremented by one for + each sent packet */ + unsigned int timestamp; //!< timestamp, 27 MHz for H.264 + unsigned int ssrc; //!< Synchronization Source, chosen randomly + byte * payload; //!< the payload including payload headers + unsigned int paylen; //!< length of payload in bytes + byte * packet; //!< complete packet including header and payload + unsigned int packlen; //!< length of packet, typically paylen+12 +} RTPpacket_t; + +extern void RTPUpdateTimestamp (VideoParameters *p_Vid, int tr); +extern void OpenRTPFile (char *Filename, FILE **f_rtp); +extern void CloseRTPFile (FILE *f_rtp); +extern int WriteRTPNALU (VideoParameters *p_Vid, NALU_t *n, FILE **f_rtp); + + + +#endif + diff --git a/lencod/inc/sei.h b/lencod/inc/sei.h new file mode 100644 index 0000000..8fb6cba --- /dev/null +++ b/lencod/inc/sei.h @@ -0,0 +1,433 @@ + +/*! + ************************************************************************ + * \file + * sei.h + * \brief + * definitions for Supplemental Enhanced Information + * \author(s) + * - Dong Tian + * - TBD + * + * ************************************************************************ + */ + +#ifndef SEI_H +#define SEI_H + +#define MAX_LAYER_NUMBER 2 +#define MAX_DEPENDENT_SUBSEQ 5 +// tone mapping information +#define MAX_CODED_BIT_DEPTH 12 +#define MAX_SEI_BIT_DEPTH 12 +#define MAX_NUM_PIVOTS (1< + * - Karsten Suehring + * - Alexis Michael Tourapis + + ************************************************************************** + */ + +#ifndef _SLICE_H_ +#define _SLICE_H_ + +#include "global.h" +#include "mbuffer.h" +#include "rdopt_coding_state.h" + +static const int QP2QUANT[40]= +{ + 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 4, 4, 4, 5, 6, + 6, 7, 8, 9,10,11,13,14, + 16,18,20,23,25,29,32,36, + 40,45,51,57,64,72,81,91 +}; + + +extern int encode_one_slice ( VideoParameters *p_Vid, int SliceGroupId, int TotalCodedMBs ); +extern int encode_one_slice_MBAFF ( VideoParameters *p_Vid, int SliceGroupId, int TotalCodedMBs ); +extern void init_slice ( VideoParameters *p_Vid, Slice **currSlice, int start_mb_addr ); +extern void init_slice_lite ( VideoParameters *p_Vid, Slice **currSlice, int start_mb_addr ); +extern void free_slice_list ( Picture *currPic ); + +extern void SetLagrangianMultipliersOn (Slice *currSlice); +extern void SetLagrangianMultipliersOff(Slice *currSlice); +extern void free_slice (Slice *currSlice); + + +#endif diff --git a/lencod/inc/symbol.h b/lencod/inc/symbol.h new file mode 100644 index 0000000..313539e --- /dev/null +++ b/lencod/inc/symbol.h @@ -0,0 +1,27 @@ + +/*! +*************************************************************************** +* +* \file symbol.h +* +* \brief +* Generic Symbol writing interface +* +* \date +* 18 Jan 2006 +* +* \author +* Karsten Suehring +**************************************************************************/ +struct writeMB { + void (*writeMB_typeInfo) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeIntraPredMode) (SyntaxElement *se, DataPartition *dP); + void (*writeB8_typeInfo) (SyntaxElement *se, DataPartition *dP); + void (*writeRefFrame[6]) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeMVD) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeCBP) (Macroblock* currMB, SyntaxElement *se, DataPartition *dP); + void (*writeDquant) (Macroblock* currMB, SyntaxElement *se, DataPartition *dP); + void (*writeCIPredMode) (Macroblock* currMB, SyntaxElement *se, DataPartition *dP); + void (*writeFieldModeInfo) (Macroblock *currMB, SyntaxElement *se, DataPartition *dP); + void (*writeMB_transform_size)(Macroblock *currMB, SyntaxElement *se, DataPartition *dP); +}; diff --git a/lencod/inc/transcode_enc.h b/lencod/inc/transcode_enc.h new file mode 100644 index 0000000..7956191 --- /dev/null +++ b/lencod/inc/transcode_enc.h @@ -0,0 +1,25 @@ +/*! +************************************************************************ +* \file transcode_enc.h +* +* \brief +* Functions to use trancoding information from decoder +* +* \author +* - João Carreira +* +************************************************************************ +*/ + +#ifndef _TRANSCODE_ENC_H +#define _TRANSCODE_ENC_H + +#include "global.h" +#include "mbuffer.h" + +extern void initTranscodeModule( VideoParameters *p_Vid ); +extern void closeTranscodeModule( VideoParameters *p_Vid ); + +extern void readTranscodingInfo( VideoParameters *p_Vid ); + +#endif \ No newline at end of file diff --git a/lencod/inc/transform8x8.h b/lencod/inc/transform8x8.h new file mode 100644 index 0000000..b081471 --- /dev/null +++ b/lencod/inc/transform8x8.h @@ -0,0 +1,37 @@ + +/*! + *************************************************************************** + * + * \file transform8x8.h + * + * \brief + * prototypes of 8x8 transform functions + * + * \date + * 9. October 2003 + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * Yuri Vatis + **************************************************************************/ + +#ifndef _TRANSFORM8X8_H_ +#define _TRANSFORM8X8_H_ +extern int mode_decision_for_I8x8_MB (Macroblock *currMB, int lambda, distblk *min_cost); +extern int mode_decision_for_I8x8_blocks_JM_Low (Macroblock *currMB, int b8, int lambda, distblk *min_cost); +extern int mode_decision_for_I8x8_blocks_JM_High (Macroblock *currMB, int b8, int lambda, distblk *min_cost); +extern int mode_decision_for_I8x8_blocks_JM_Low444 (Macroblock *currMB, int b8, int lambda, distblk *min_cost); +extern int mode_decision_for_I8x8_blocks_JM_High444(Macroblock *currMB, int b8, int lambda, distblk *min_cost); + +extern distblk rdcost_for_8x8_intra_blocks (Macroblock *currMB, int *c_nz, int b8, int ipmode, int lambda, distblk min_rdcost, int mostProbableMode); +extern distblk rdcost_for_8x8_intra_blocks_444 (Macroblock *currMB, int *c_nz, int b8, int ipmode, int lambda, distblk min_rdcost, int mostProbableMode); +extern distblk compute_satd8x8_cost (VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost); +extern distblk compute_sse8x8_cost (VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost); +extern distblk compute_sad8x8_cost (VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost); +extern distblk compute_comp8x8_cost (VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost); + +extern int residual_transform_quant_luma_8x8 (Macroblock *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra); +extern int residual_transform_quant_luma_8x8_cavlc (Macroblock *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra); +extern int residual_transform_quant_luma_8x8_ls (Macroblock *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra); + +#endif //_TRANSFORM8X8_H_ diff --git a/lencod/inc/vlc.h b/lencod/inc/vlc.h new file mode 100644 index 0000000..d0647f9 --- /dev/null +++ b/lencod/inc/vlc.h @@ -0,0 +1,72 @@ + +/*! + ************************************************************************************* + * \file vlc.h + * + * \brief + * Prototypes for VLC coding funtions + * \author + * Karsten Suehring + ************************************************************************************* + */ + +#ifndef _VLC_H_ +#define _VLC_H_ + +#include "enc_statistics.h" + +extern Boolean write_u_1 (char *tracestring, int value, Bitstream *bitstream); +extern int write_se_v (char *tracestring, int value, Bitstream *bitstream); +extern int write_ue_v (char *tracestring, int value, Bitstream *bitstream); +extern int write_u_v (int n, char *tracestring, int value, Bitstream *bitstream); + +extern void levrun_linfo_c2x2(int level,int run,int *len,int *info); +extern void levrun_linfo_inter(int level,int run,int *len,int *info); + +extern void writeSE_Fix (SyntaxElement *se, Bitstream *bitstream); +extern void writeSE_UVLC (SyntaxElement *se, DataPartition *dp); +extern void writeSE_SVLC (SyntaxElement *se, DataPartition *dp); +extern void writeSE_Flag (SyntaxElement *se, DataPartition *dp); +extern void writeSE_invFlag (SyntaxElement *se, DataPartition *dp); +extern void writeSE_Dummy (SyntaxElement *se, DataPartition *dp); + +extern void writeRefPic_NRef_CAVLC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeRefPic_2Ref_CAVLC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeRefPic_Dummy (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); + +extern void writeCBP_VLC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeIntraPredMode_CAVLC (SyntaxElement *se, DataPartition *dp); +extern int writeSyntaxElement2Buf_UVLC (SyntaxElement *se, Bitstream* this_streamBuffer ); +extern void writeUVLC2buffer (SyntaxElement *se, Bitstream *currStream); +extern void writeVlcByteAlign (VideoParameters *p_Vid, Bitstream* currStream, StatParameters *cur_stats); +extern int writeSyntaxElement2Buf_Fixed(SyntaxElement *se, Bitstream* this_streamBuffer ); +extern int symbol2uvlc (SyntaxElement *se); +extern void ue_linfo (int n, int dummy, int *len,int *info); +extern void se_linfo (int mvd, int dummy, int *len,int *info); +extern void cbp_linfo_intra_normal(int cbp, int dummy, int *len,int *info); +extern void cbp_linfo_intra_other (int cbp, int dummy, int *len,int *info); +extern void cbp_linfo_inter_normal(int cbp, int dummy, int *len,int *info); +extern void cbp_linfo_inter_other (int cbp, int dummy, int *len,int *info); + +extern int writeSyntaxElement_VLC(SyntaxElement *se, DataPartition *this_dataPart); +extern int writeSyntaxElement_TotalZeros(SyntaxElement *se, DataPartition *this_dataPart); +extern int writeSyntaxElement_TotalZerosChromaDC(VideoParameters *p_Vid, SyntaxElement *se, DataPartition *this_dataPart); +extern int writeSyntaxElement_Run(SyntaxElement *se, DataPartition *this_dataPart); +extern int writeSyntaxElement_NumCoeffTrailingOnes(SyntaxElement *se, DataPartition *this_dataPart); +extern int writeSyntaxElement_NumCoeffTrailingOnesChromaDC(VideoParameters *p_Vid, SyntaxElement *se, DataPartition *this_dataPart); +extern int writeSyntaxElement_Level_VLC1(SyntaxElement *se, DataPartition *this_dataPart, int profile_idc); +extern int writeSyntaxElement_Level_VLCN(SyntaxElement *se, int vlc, DataPartition *this_dataPart, int profile_idc); + +extern void writeUVLC_CAVLC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeSVLC_CAVLC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); +extern void writeFlag_CAVLC (Macroblock *currMB, SyntaxElement *se, DataPartition *dp); + +extern void reset_mb_nz_coeff(VideoParameters *p_Vid, int mb_number); +extern int bs_bitlength(Bitstream *bitstream); +extern int GetBits(byte *buffer, + int totbitoffset, + int *info, + int bitcount, + int numbits); +#endif + diff --git a/lencod/inc/wp.h b/lencod/inc/wp.h new file mode 100644 index 0000000..636bf8f --- /dev/null +++ b/lencod/inc/wp.h @@ -0,0 +1,56 @@ +/*! + *************************************************************************** + * \file + * wp.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 22. February 2008 + * + * \brief + * Headerfile for weighted prediction support + ************************************************************************** + */ + +#ifndef _WP_H_ +#define _WP_H_ + +#include "wp_lms.h" +#include "wp_mcprec.h" +#include "wp_mciter.h" + +#define DEBUG_WP 0 + +void InitWP (VideoParameters *p_Vid, InputParameters *p_Inp, int force_wp_method); +void ResetWP (VideoParameters *p_Vid, InputParameters *p_Inp); + +extern void EstimateWPBSliceAlg0 (Slice *currSlice); +extern void EstimateWPPSliceAlg0 (Slice *currSlice, int offset); +extern int TestWPPSliceAlg0 (Slice *currSlice, int offset); +extern int TestWPBSliceAlg0 (Slice *currSlice, int method); +extern double ComputeImgSum (imgpel **CurrentImage, int height, int width); +extern void ComputeImgSumBlockBased(imgpel **CurrentImage, int height_in_blk, int width_in_blk, int blk_size_y, int blk_size_x, int start_blk, int end_blk, double *dc); +extern int64 ComputeSumBlockBased (imgpel **CurrentImage, int height_in_blk, int width_in_blk, int blk_size_y, int blk_size_x, int start_blk, int end_blk); + +extern void ComputeImplicitWeights (Slice *currSlice, + short default_weight[3], + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]); +extern void ComputeExplicitWPParamsLMS(Slice *currSlice, + int select_offset, + int start_mb, + int end_mb, + short default_weight[3], + short weight[6][MAX_REFERENCE_PICTURES][3], + short offset[6][MAX_REFERENCE_PICTURES][3]); +extern void ComputeExplicitWPParamsJNT(Slice *currSlice, + int start_mb, + int end_mb, + short default_weight[3], + short weight[6][MAX_REFERENCE_PICTURES][3], + short offset[6][MAX_REFERENCE_PICTURES][3]); + + +#endif + diff --git a/lencod/inc/wp_lms.h b/lencod/inc/wp_lms.h new file mode 100644 index 0000000..c584be3 --- /dev/null +++ b/lencod/inc/wp_lms.h @@ -0,0 +1,26 @@ +/*! + *************************************************************************** + * \file + * wp_lms.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 22. February 2008 + * + * \brief + * Headerfile for weighted prediction support using LMS + ************************************************************************** + */ + +#ifndef _WP_LMS_H_ +#define _WP_LMS_H_ + +extern void EstimateWPPSliceAlg1(Slice *currSlice, int offset); +extern void EstimateWPBSliceAlg1(Slice *currSlice); +extern int TestWPPSliceAlg1 (Slice *currSlice, int offset); +extern int TestWPBSliceAlg1 (Slice *currSlice, int method); + +#endif + diff --git a/lencod/inc/wp_mciter.h b/lencod/inc/wp_mciter.h new file mode 100644 index 0000000..bbf72bc --- /dev/null +++ b/lencod/inc/wp_mciter.h @@ -0,0 +1,29 @@ +/*! + *************************************************************************** + * \file + * wp_mciter.h + * + * \author + * Alexis Michael Tourapis + * + * \date + * 22. February 2008 + * + * \brief + * Headerfile for weighted prediction support + ************************************************************************** + */ + +#ifndef _WP_MCITERM_H_ +#define _WP_MCITERM_H_ + + +extern void EstimateWPBSliceAlg2(Slice *currSlice); +extern void EstimateWPPSliceAlg2(Slice *currSlice, int offset); +extern int TestWPPSliceAlg2 (Slice *currSlice, int offset); +extern int TestWPBSliceAlg2 (Slice *currSlice, int method); + +extern void compute_offset (Slice *currSlice); + +#endif + diff --git a/lencod/inc/wp_mcprec.h b/lencod/inc/wp_mcprec.h new file mode 100644 index 0000000..64f5719 --- /dev/null +++ b/lencod/inc/wp_mcprec.h @@ -0,0 +1,52 @@ +/*! + *************************************************************************** + * \file + * wp_mcprec.h + * + * \brief + * Headerfile for Improved Motion Compensatation Precision Scheme using Weighted Prediction + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Athanasios Leontaris + * + * \date + * 16 July 2008 + * + ************************************************************************** + */ + +#ifndef _WP_MCPREC_H_ +#define _WP_MCPREC_H_ + +typedef struct +{ + int PicNum; // PicNum/FrameNum + int POCNum; // POC +} +WeightedPredRefX; + +typedef struct +{ + int algorithm; +} +WPXPass; + +typedef struct wpx_object +{ + int num_wp_ref_list[2]; // num of elements in each of the above matrices [LIST] + WeightedPredRefX *wp_ref_list[2]; // structure with reordering and WP information for ref frames [LIST] + WPXPass *curr_wp_rd_pass; + WPXPass wp_rd_passes[3]; // frame_picture [0...4] (MultiRefWeightedPred == 2) +} +WPXObject; + +extern void wpxInitWPXObject( VideoParameters *p_Vid ); +extern void wpxFreeWPXObject( VideoParameters *p_Vid ); +extern void wpxInitWPXPasses( VideoParameters *p_Vid, InputParameters *p_Inp ); +extern void wpxModifyRefPicList( Slice *currSlice ); +// Note that at some point, InputParameters p_Inp contents should be copied into VideoParameters *p_Vid. +// This would eliminate need of having to use both structures +extern int wpxDetermineWP( Slice *currSlice, int clist, int n ); +extern void wpxAdaptRefNum( Slice *currSlice ); + +#endif diff --git a/lencod/src/annexb.c b/lencod/src/annexb.c new file mode 100644 index 0000000..d662ca3 --- /dev/null +++ b/lencod/src/annexb.c @@ -0,0 +1,199 @@ + +/*! +************************************************************************************* +* \file annexb.c +* +* \brief +* Annex B Byte Stream format NAL Unit writing routines +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Stephan Wenger +************************************************************************************* +*/ + +#include "global.h" +#include "nalucommon.h" + +#include "annexb_split.h" + +/*! +******************************************************************************************** +* \brief +* Writes a NALU to the Annex B Byte Stream +* +* \return +* number of bits written +* +******************************************************************************************** +*/ +int WriteAnnexbNALU (VideoParameters *p_Vid, NALU_t *n, FILE **f_annexb) +{ + int BitsWritten = 0; + int offset = 0; + int length = 4; + static const byte startcode[] = {0,0,0,1}; + byte first_byte; + + assert (n != NULL); + assert (n->forbidden_bit == 0); + assert ((*f_annexb) != NULL); + assert (n->startcodeprefix_len == 3 || n->startcodeprefix_len == 4); + + // printf ("WriteAnnexbNALU: writing %d bytes w/ startcode_len %d\n", n->len+1, n->startcodeprefix_len); + if (n->startcodeprefix_len < 4) + { + offset = 1; + length = 3; + } + + if ( length != (int) fwrite (startcode+offset, 1, length, *f_annexb)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", length); + exit (-1); + } + BitsWritten = (length) << 3; + + //! Edited by Joao Carreira + split_annexb_files( p_Vid, n->nal_unit_type, (void*)(startcode+offset), length ); + + + first_byte = (unsigned char) ((n->forbidden_bit << 7) | (n->nal_reference_idc << 5) | n->nal_unit_type); + + if ( 1 != fwrite (&first_byte, 1, 1, *f_annexb)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", 1); + exit (-1); + } + BitsWritten += 8; + + //! Edited by Joao Carreira + split_annexb_files( p_Vid, n->nal_unit_type, &first_byte, 1 ); + + + // printf ("First Byte %x, nal_ref_idc %x, nal_unit_type %d\n", first_byte, n->nal_reference_idc, n->nal_unit_type); +#if (MVC_EXTENSION_ENABLE) + if(n->nal_unit_type==NALU_TYPE_PREFIX || n->nal_unit_type==NALU_TYPE_SLC_EXT) + { + int view_id = p_Vid->p_Inp->MVCFlipViews ? !(n->view_id) : n->view_id; + + first_byte = (unsigned char) ((n->svc_extension_flag << 7) | (n->non_idr_flag << 6) | n->priority_id); + if ( 1 != fwrite (&first_byte, 1, 1, *f_annexb)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", 1); + exit (-1); + } + BitsWritten += 8; + + //! Edited by Joao Carreira + split_annexb_files( p_Vid, n->nal_unit_type, &first_byte, 1 ); + + first_byte = (unsigned char) (view_id >> 2); + if ( 1 != fwrite (&first_byte, 1, 1, *f_annexb)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", 1); + exit (-1); + } + BitsWritten += 8; + + //! Edited by Joao Carreira + split_annexb_files( p_Vid, n->nal_unit_type, &first_byte, 1 ); + + first_byte = (unsigned char) (((view_id&3) << 6) | (n->temporal_id << 3) | (n->anchor_pic_flag << 2) | (n->inter_view_flag << 1) | n->reserved_one_bit); + if ( 1 != fwrite (&first_byte, 1, 1, *f_annexb)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", 1); + exit (-1); + } + BitsWritten += 8; + + //! Edited by Joao Carreira + split_annexb_files( p_Vid, n->nal_unit_type, &first_byte, 1 ); + } +#endif + + if (n->len != fwrite (n->buf, 1, n->len, *f_annexb)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", n->len); + exit (-1); + } + BitsWritten += n->len * 8; + + //! Edited by Joao Carreira + split_annexb_files( p_Vid, n->nal_unit_type, n->buf, n->len ); + + //! Edited by Joao Carreira + fflush_split_files( p_Vid ); + + fflush (*f_annexb); +#if TRACE + //fprintf (p_Enc->p_trace, "\nAnnex B NALU w/ %s startcode, len %d, forbidden_bit %d, nal_reference_idc %d, nal_unit_type %d\n\n\n", + // n->startcodeprefix_len == 4?"long":"short", n->len + 1, n->forbidden_bit, n->nal_reference_idc, n->nal_unit_type); + fprintf (p_Enc->p_trace, "\nAnnex B NALU w/ %s startcode, len %d,", n->startcodeprefix_len == 4?"long":"short", n->len + 1); + fprintf (p_Enc->p_trace, "\n forbidden_bit %d,", n->forbidden_bit); + fprintf (p_Enc->p_trace, "\n nal_reference_idc %d,", n->nal_reference_idc); + fprintf (p_Enc->p_trace, "\n nal_unit_type %d ", n->nal_unit_type); +#if (MVC_EXTENSION_ENABLE) + if(n->nal_unit_type==NALU_TYPE_PREFIX || n->nal_unit_type==NALU_TYPE_SLC_EXT) + { + fprintf (p_Enc->p_trace, "\n svc_extension_flag %d ", n->svc_extension_flag); + fprintf (p_Enc->p_trace, "\n non_idr_flag %d ", n->non_idr_flag); + fprintf (p_Enc->p_trace, "\n priority_id %d ", n->priority_id); + + fprintf (p_Enc->p_trace, "\n view_id %d ", p_Vid->p_Inp->MVCFlipViews ? !(n->view_id) : n->view_id); + fprintf (p_Enc->p_trace, "\n temporal_id %d ", n->temporal_id); + fprintf (p_Enc->p_trace, "\n anchor_pic_flag %d ", n->anchor_pic_flag); + fprintf (p_Enc->p_trace, "\n inter_view_flag %d ", n->inter_view_flag); + fprintf (p_Enc->p_trace, "\n reserved_one_bit %d ", n->reserved_one_bit); + } +#endif + fprintf (p_Enc->p_trace, "\n----------------------------------------------------------------------------\n\n\n"); + fflush (p_Enc->p_trace); +#endif + return BitsWritten; +} + + +/*! +******************************************************************************************** +* \brief +* Opens the output file for the bytestream +* +* \param p_Vid +* VideoParameters structure +* \param Filename +* The filename of the file to be opened +* +* \return +* none. Function terminates the program in case of an error +* +******************************************************************************************** +*/ +void OpenAnnexbFile (char *Filename, FILE **f_annexb) +{ + if (((*f_annexb) = fopen (Filename, "wb")) == NULL) + { + printf ("Fatal: cannot open Annex B bytestream file '%s', exit (-1)\n", Filename); + exit (-1); + } +} + + +/*! +******************************************************************************************** +* \brief +* Closes the output bit stream file +* +* \return +* none. Function terminates the program in case of an error +******************************************************************************************** +*/ +void CloseAnnexbFile(FILE *f_annexb) +{ + if (fclose (f_annexb)) + { + printf ("Fatal: cannot close Annex B bytestream file, exit (-1)\n"); + exit (-1); + } +} + diff --git a/lencod/src/annexb_split.c b/lencod/src/annexb_split.c new file mode 100644 index 0000000..b04b118 --- /dev/null +++ b/lencod/src/annexb_split.c @@ -0,0 +1,197 @@ +/*! +************************************************************************************* +* \file annexb_split.c +* +* \brief +* +* \date +* 03-02-2012 +* +* \version +* 1.0 +* +* \author +* João Carreira +* +************************************************************************************* +*/ + +#include "global.h" +#include "nalucommon.h" +#include "memalloc.h" +#include "mbuffer.h" +#include "ifunctions.h" + + +//Define wich nal units are write on each stream +#define NALU_COMMON NALU_TYPE_SPS, NALU_TYPE_PPS, NALU_TYPE_SUB_SPS, NALU_TYPE_AUD, NALU_TYPE_EOSEQ, NALU_TYPE_EOSTREAM, NALU_TYPE_FILL +#define NALU_BASE_VIEW {NALU_COMMON, NALU_TYPE_IDR, NALU_TYPE_SLICE} +#define NALU_AUX_VIEW {NALU_COMMON, NALU_TYPE_IDR, NALU_TYPE_PREFIX, NALU_TYPE_SLC_EXT, NALU_TYPE_VDRD} + + +static inline int WriteNALUBaseView (NaluType nalu_type) +{ + NaluType Write_NAL [] = NALU_BASE_VIEW; + int n_nalu = sizeof (Write_NAL)/sizeof (NaluType); + int i; + + for (i=0; if_annexb_base && p_Vid->f_annexb_aux) + { + if ( WriteNALUBaseView(nalu_type) ) + if ( length != (int) fwrite (data_pointer, 1, length, p_Vid->f_annexb_base)) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", length); + exit (-1); + } + if ( WriteNALUAuxView(nalu_type) ) + if ( length != (int) fwrite (data_pointer, 1, length, p_Vid->f_annexb_aux )) + { + printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", length); + exit (-1); + } + } +} + +/*! +******************************************************************************************** +* \brief +* Flush both bitstreams after the writing operations +* +******************************************************************************************** +*/ +void fflush_split_files( VideoParameters *p_Vid ) +{ + if (p_Vid->f_annexb_base ) + { + fflush(p_Vid->f_annexb_base); + } + if( p_Vid->f_annexb_aux) + { + fflush(p_Vid->f_annexb_aux); + } +} + +/*! +******************************************************************************************** +* \brief +* Opens the output file for the bytestream separatly for base and auxiliary views +* +* \param p_Vid +* VideoParameters structure +* \param Filename +* The filename of the file to be opened +* +* \return +* none. Function terminates the program in case of an error +* +******************************************************************************************** +*/ +void OpenAnnexbFileBaseView (VideoParameters *p_Vid, char *Filename) +{ + if (Filename[0] != 0) + { + if ((p_Vid->f_annexb_base = fopen (Filename, "wb")) == NULL) + { + printf ("Fatal: cannot open Annex B bytestream file '%s', exit (-1)\n", Filename); + exit (-1); + } + } +} +void OpenAnnexbFileAuxView (VideoParameters *p_Vid, char *Filename) +{ + if (Filename[0] != 0) + { + if ((p_Vid->f_annexb_aux = fopen (Filename, "wb")) == NULL) + { + printf ("Fatal: cannot open Annex B bytestream file '%s', exit (-1)\n", Filename); + exit (-1); + } + } +} + +/*! +******************************************************************************************** +* \brief +* Closes the output bit stream file for the base and auxiliary view +* +* \return +* none. Function terminates the program in case of an error +******************************************************************************************** +*/ +void CloseAnnexbFileBaseView(VideoParameters *p_Vid) +{ + if (p_Vid->f_annexb_base) + { + if (fclose (p_Vid->f_annexb_base)) + { + printf ("Fatal: cannot close Annex B bytestream file, exit (-1)\n"); + exit (-1); + } + } +} + +void CloseAnnexbFileAuxView(VideoParameters *p_Vid) +{ + if (p_Vid->f_annexb_aux) + { + if (fclose (p_Vid->f_annexb_aux)) + { + printf ("Fatal: cannot close Annex B bytestream file, exit (-1)\n"); + exit (-1); + } + } +} + + + + +#else +void split_annexb_files( VideoParameters *p_Vid, NaluType nalu_type, void *data_pointer, size_t length ) +{ + return; +} + +void fflush_split_files( VideoParameters *p_Vid ) +{ + return; +} +#endif \ No newline at end of file diff --git a/lencod/src/biariencode.c b/lencod/src/biariencode.c new file mode 100644 index 0000000..a851a9e --- /dev/null +++ b/lencod/src/biariencode.c @@ -0,0 +1,572 @@ + +/*! + ************************************************************************************* + * \file biariencode.c + * + * \brief + * Routines for binary arithmetic encoding. + * + * This modified implementation of the M Coder is based on JVT-U084 + * with the choice of M_BITS = 16. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Gabi Blaettermann + * - Gunnar Marten + ************************************************************************************* + */ + +#include "global.h" +#include "biariencode.h" + +// Range table for LPS +static const byte renorm_table_32[32]={6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + + +void reset_pic_bin_count(VideoParameters *p_Vid) +{ + p_Vid->pic_bin_count = 0; +} + +int get_pic_bin_count(VideoParameters *p_Vid) +{ + return p_Vid->pic_bin_count; +} + +/*! + ************************************************************************ + * \brief + * Allocates memory for the EncodingEnvironment struct + ************************************************************************ + */ +EncodingEnvironmentPtr arienco_create_encoding_environment(void) +{ + EncodingEnvironmentPtr eep; + + if ( (eep = (EncodingEnvironmentPtr) calloc(1,sizeof(EncodingEnvironment))) == NULL) + no_mem_exit("arienco_create_encoding_environment: eep"); + + return eep; +} + +/*! + ************************************************************************ + * \brief + * Frees memory of the EncodingEnvironment struct + ************************************************************************ + */ +void arienco_delete_encoding_environment(EncodingEnvironmentPtr eep) +{ + free_pointer(eep); +} + +/*! + ************************************************************************ + * inline functions for writing bytes of code + *********************************************************************** + */ + +static inline void put_one_byte_final(EncodingEnvironmentPtr eep, unsigned int b) +{ + eep->Ecodestrm[(*eep->Ecodestrm_len)++] = (byte) b; +} + +static forceinline void put_buffer(EncodingEnvironmentPtr eep) +{ + while(eep->Epbuf>=0) + { + eep->Ecodestrm[(*eep->Ecodestrm_len)++] = (byte) ((eep->Ebuffer>>((eep->Epbuf--)<<3))&0xFF); + } + while(eep->C > 7) + { + eep->C-=8; + ++(eep->E); + } + eep->Ebuffer = 0; +} + +static inline void put_one_byte(EncodingEnvironmentPtr eep, int b) +{ + if(eep->Epbuf == 3) + { + put_buffer(eep); + } + eep->Ebuffer <<= 8; + eep->Ebuffer += (b); + + ++(eep->Epbuf); +} + +static inline void put_one_word(EncodingEnvironmentPtr eep, int b) +{ + if (eep->Epbuf >= 3) + { + put_buffer(eep); + } + eep->Ebuffer <<= 16; + eep->Ebuffer += (b); + + eep->Epbuf += 2; +} + +static forceinline void propagate_carry(EncodingEnvironmentPtr eep) +{ + ++(eep->Ebuffer); + while (eep->Echunks_outstanding > 0) + { + put_one_word(eep, 0); + --(eep->Echunks_outstanding); + } +} + +static inline void put_last_chunk_plus_outstanding(EncodingEnvironmentPtr eep, unsigned int l) +{ + while (eep->Echunks_outstanding > 0) + { + put_one_word(eep, 0xFFFF); + --(eep->Echunks_outstanding); + } + put_one_word(eep, l); +} + +static inline void put_last_chunk_plus_outstanding_final(EncodingEnvironmentPtr eep, unsigned int l) +{ + while (eep->Echunks_outstanding > 0) + { + put_one_word(eep, 0xFFFF); + --(eep->Echunks_outstanding); + } + put_one_byte(eep, l); +} + +/*! +************************************************************************ +* \brief +* Initializes the EncodingEnvironment E and C values to zero +************************************************************************ +*/ +void arienco_reset_EC(EncodingEnvironmentPtr eep) +{ + eep->E = 0; + eep->C = 0; +} + +/*! + ************************************************************************ + * \brief + * Initializes the EncodingEnvironment for the arithmetic coder + ************************************************************************ + */ +void arienco_start_encoding(EncodingEnvironmentPtr eep, + unsigned char *code_buffer, + int *code_len ) +{ + eep->Elow = 0; + eep->Echunks_outstanding = 0; + eep->Ebuffer = 0; + eep->Epbuf = -1; // to remove redundant chunk ^^ + eep->Ebits_to_go = BITS_TO_LOAD + 1; // to swallow first redundant bit + + eep->Ecodestrm = code_buffer; + eep->Ecodestrm_len = code_len; + + eep->Erange = HALF; +} + +/*! +************************************************************************ +* \brief +* add slice bin number to picture bin counter +* should be only used when slice is terminated +************************************************************************ +*/ +void set_pic_bin_count(VideoParameters *p_Vid, EncodingEnvironmentPtr eep) +{ + p_Vid->pic_bin_count += (eep->E << 3) + eep->C; // no of processed bins +} + +/*! + ************************************************************************ + * \brief + * Terminates the arithmetic codeword, writes stop bit and stuffing bytes (if any) + ************************************************************************ + */ +void arienco_done_encoding(Macroblock *currMB, EncodingEnvironmentPtr eep) +{ + unsigned int low = eep->Elow; + int remaining_bits = BITS_TO_LOAD - eep->Ebits_to_go; // output (2 + remaining) bits for terminating the codeword + one stop bit + unsigned char mask; + BitCounter *mbBits = &currMB->bits; + + //p_Vid->pic_bin_count += eep->E*8 + eep->C; // no of processed bins + + if (remaining_bits <= 5) // one terminating byte + { + mbBits->mb_stuffing += (5 - remaining_bits); + mask = (unsigned char) (255 - ((1 << (6 - remaining_bits)) - 1)); + low = (low >> (MASK_BITS)) & mask; // mask out the (2+remaining_bits) MSBs + low += (32 >> remaining_bits); // put the terminating stop bit '1' + + put_last_chunk_plus_outstanding_final(eep, low); + put_buffer(eep); + } + else if(remaining_bits <= 13) // two terminating bytes + { + mbBits->mb_stuffing += (13 - remaining_bits); + put_last_chunk_plus_outstanding_final(eep, ((low >> (MASK_BITS)) & 0xFF)); // mask out the 8 MSBs for output + + put_buffer(eep); + if (remaining_bits > 6) + { + mask = (unsigned char) (255 - ((1 << (14 - remaining_bits)) - 1)); + low = (low >> (B_BITS)) & mask; + low += (0x2000 >> remaining_bits); // put the terminating stop bit '1' + put_one_byte_final(eep, low); + } + else + { + put_one_byte_final(eep, 128); // second byte contains terminating stop bit '1' only + } + } + else // three terminating bytes + { + put_last_chunk_plus_outstanding(eep, ((low >> B_BITS) & B_LOAD_MASK)); // mask out the 16 MSBs for output + put_buffer(eep); + mbBits->mb_stuffing += (21 - remaining_bits); + + if (remaining_bits > 14) + { + mask = (unsigned char) (255 - ((1 << (22 - remaining_bits)) - 1)); + low = (low >> (MAX_BITS - 24)) & mask; + low += (0x200000 >> remaining_bits); // put the terminating stop bit '1' + put_one_byte_final(eep, low); + } + else + { + put_one_byte_final(eep, 128); // third byte contains terminating stop bit '1' only + } + } + eep->Ebits_to_go = 8; +} + + +/*! + ************************************************************************ + * \brief + * Actually arithmetic encoding of one binary symbol by using + * the probability estimate of its associated context model + ************************************************************************ + */ +void biari_encode_symbol(EncodingEnvironmentPtr eep, int symbol, BiContextTypePtr bi_ct ) +{ + static const byte rLPS_table_64x4[64][4]= + { + { 128, 176, 208, 240}, + { 128, 167, 197, 227}, + { 128, 158, 187, 216}, + { 123, 150, 178, 205}, + { 116, 142, 169, 195}, + { 111, 135, 160, 185}, + { 105, 128, 152, 175}, + { 100, 122, 144, 166}, + { 95, 116, 137, 158}, + { 90, 110, 130, 150}, + { 85, 104, 123, 142}, + { 81, 99, 117, 135}, + { 77, 94, 111, 128}, + { 73, 89, 105, 122}, + { 69, 85, 100, 116}, + { 66, 80, 95, 110}, + { 62, 76, 90, 104}, + { 59, 72, 86, 99}, + { 56, 69, 81, 94}, + { 53, 65, 77, 89}, + { 51, 62, 73, 85}, + { 48, 59, 69, 80}, + { 46, 56, 66, 76}, + { 43, 53, 63, 72}, + { 41, 50, 59, 69}, + { 39, 48, 56, 65}, + { 37, 45, 54, 62}, + { 35, 43, 51, 59}, + { 33, 41, 48, 56}, + { 32, 39, 46, 53}, + { 30, 37, 43, 50}, + { 29, 35, 41, 48}, + { 27, 33, 39, 45}, + { 26, 31, 37, 43}, + { 24, 30, 35, 41}, + { 23, 28, 33, 39}, + { 22, 27, 32, 37}, + { 21, 26, 30, 35}, + { 20, 24, 29, 33}, + { 19, 23, 27, 31}, + { 18, 22, 26, 30}, + { 17, 21, 25, 28}, + { 16, 20, 23, 27}, + { 15, 19, 22, 25}, + { 14, 18, 21, 24}, + { 14, 17, 20, 23}, + { 13, 16, 19, 22}, + { 12, 15, 18, 21}, + { 12, 14, 17, 20}, + { 11, 14, 16, 19}, + { 11, 13, 15, 18}, + { 10, 12, 15, 17}, + { 10, 12, 14, 16}, + { 9, 11, 13, 15}, + { 9, 11, 12, 14}, + { 8, 10, 12, 14}, + { 8, 9, 11, 13}, + { 7, 9, 11, 12}, + { 7, 9, 10, 12}, + { 7, 8, 10, 11}, + { 6, 8, 9, 11}, + { 6, 7, 9, 10}, + { 6, 7, 8, 9}, + { 2, 2, 2, 2} + }; + static const byte AC_next_state_MPS_64[64] = + { + 1,2,3,4,5,6,7,8,9,10, + 11,12,13,14,15,16,17,18,19,20, + 21,22,23,24,25,26,27,28,29,30, + 31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50, + 51,52,53,54,55,56,57,58,59,60, + 61,62,62,63 + }; + + static const byte AC_next_state_LPS_64[64] = + { + 0, 0, 1, 2, 2, 4, 4, 5, 6, 7, + 8, 9, 9,11,11,12,13,13,15,15, + 16,16,18,18,19,19,21,21,22,22, + 23,24,24,25,26,26,27,27,28,29, + 29,30,30,30,31,32,32,33,33,33, + 34,34,35,35,35,36,36,36,37,37, + 37,38,38,63 + }; + + unsigned int low = eep->Elow; + unsigned int range = eep->Erange; + int bl = eep->Ebits_to_go; + unsigned int rLPS = rLPS_table_64x4[bi_ct->state][(range>>6) & 3]; + + range -= rLPS; + + ++(eep->C); + bi_ct->count += eep->p_Vid->cabac_encoding; + + /* covers all cases where code does not bother to shift down symbol to be + * either 0 or 1, e.g. in some cases for cbp, mb_Type etc the code simply + * masks off the bit position and passes in the resulting value */ + //symbol = (short) (symbol != 0); + + if ((symbol != 0) == bi_ct->MPS) //MPS + { + bi_ct->state = AC_next_state_MPS_64[bi_ct->state]; // next state + + if( range >= QUARTER ) // no renorm + { + eep->Erange = range; + return; + } + else + { + range<<=1; + if( --bl > MIN_BITS_TO_GO ) // renorm once, no output + { + eep->Erange = range; + eep->Ebits_to_go = bl; + return; + } + } + } + else //LPS + { + unsigned int renorm = renorm_table_32[(rLPS >> 3) & 0x1F]; + + low += range << bl; + range = (rLPS << renorm); + bl -= renorm; + + if (!bi_ct->state) + bi_ct->MPS ^= 0x01; // switch MPS if necessary + + bi_ct->state = AC_next_state_LPS_64[bi_ct->state]; // next state + + if (low >= ONE) // output of carry needed + { + low -= ONE; + propagate_carry(eep); + } + + if( bl > MIN_BITS_TO_GO ) + { + eep->Elow = low; + eep->Erange = range; + eep->Ebits_to_go = bl; + return; + } + } + + //renorm needed + eep->Elow = (low << BITS_TO_LOAD )& (ONE_M1); + low = (low >> B_BITS) & B_LOAD_MASK; // mask out the 8/16 MSBs for output + + if (low < B_LOAD_MASK) // no carry possible, output now + { + put_last_chunk_plus_outstanding(eep, low); + } + else // low == "FF.."; keep it, may affect future carry + { + ++(eep->Echunks_outstanding); + } + eep->Erange = range; + eep->Ebits_to_go = bl + BITS_TO_LOAD; +} + +/*! + ************************************************************************ + * \brief + * Arithmetic encoding of one binary symbol assuming + * a fixed prob. distribution with p(symbol) = 0.5 + ************************************************************************ + */ +void biari_encode_symbol_eq_prob(EncodingEnvironmentPtr eep, int symbol) +{ + unsigned int low = eep->Elow; + --(eep->Ebits_to_go); + ++(eep->C); + + if (symbol != 0) + { + low += eep->Erange << eep->Ebits_to_go; + if (low >= ONE) // output of carry needed + { + low -= ONE; + propagate_carry(eep); + } + } + if(eep->Ebits_to_go == MIN_BITS_TO_GO) // renorm needed + { + eep->Elow = (low << BITS_TO_LOAD )& (ONE_M1); + low = (low >> B_BITS) & B_LOAD_MASK; // mask out the 8/16 MSBs for output + if (low < B_LOAD_MASK) // no carry possible, output now + { + put_last_chunk_plus_outstanding(eep, low);} + else // low == "FF"; keep it, may affect future carry + { + ++(eep->Echunks_outstanding); + } + + eep->Ebits_to_go = BITS_TO_LOAD; + return; + } + else // no renorm needed + { + eep->Elow = low; + return; + } +} + +/*! + ************************************************************************ + * \brief + * Arithmetic encoding for last symbol before termination + ************************************************************************ + */ +void biari_encode_symbol_final(EncodingEnvironmentPtr eep, int symbol) +{ + unsigned int range = eep->Erange - 2; + unsigned int low = eep->Elow; + int bl = eep->Ebits_to_go; + + ++(eep->C); + + if (symbol == 0) // MPS + { + if( range >= QUARTER ) // no renorm + { + eep->Erange = range; + return; + } + else + { + range<<=1; + if( --bl > MIN_BITS_TO_GO ) // renorm once, no output + { + eep->Erange = range; + eep->Ebits_to_go = bl; + return; + } + } + } + else // LPS + { + low += (range << bl); + range = 2; + + if (low >= ONE) // output of carry needed + { + low -= ONE; // remove MSB, i.e., carry bit + propagate_carry(eep); + } + bl -= 7; // 7 left shifts needed to renormalize + + range <<= 7; + if( bl > MIN_BITS_TO_GO ) + { + eep->Erange = range; + eep->Elow = low; + eep->Ebits_to_go = bl; + return; + } + } + + + //renorm needed + eep->Elow = (low << BITS_TO_LOAD ) & (ONE_M1); + low = (low >> B_BITS) & B_LOAD_MASK; // mask out the 8/16 MSBs + if (low < B_LOAD_MASK) + { // no carry possible, output now + put_last_chunk_plus_outstanding(eep, low); + } + else + { // low == "FF"; keep it, may affect future carry + ++(eep->Echunks_outstanding); + } + + eep->Erange = range; + bl += BITS_TO_LOAD; + eep->Ebits_to_go = bl; +} + +/*! + ************************************************************************ + * \brief + * Initializes a given context with some pre-defined probability state + ************************************************************************ + */ +void biari_init_context (int qp, BiContextTypePtr ctx, const char* ini) +{ + int pstate = ((ini[0]* qp) >> 4) + ini[1]; + + if ( pstate >= 64 ) + { + pstate = imin(126, pstate); + ctx->state = (uint8) (pstate - 64); + ctx->MPS = 1; + } + else + { + pstate = imax(1, pstate); + ctx->state = (uint8) (63 - pstate); + ctx->MPS = 0; + } + + ctx->count = 0; +} + diff --git a/lencod/src/block.c b/lencod/src/block.c new file mode 100644 index 0000000..2388296 --- /dev/null +++ b/lencod/src/block.c @@ -0,0 +1,2463 @@ + +/*! + ************************************************************************************* + * \file block.c + * + * \brief + * Process one block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langoy + * - Rickard Sjoberg + * - Stephan Wenger + * - Jani Lainema + * - Detlev Marpe + * - Thomas Wedi + * - Ragip Kurceren + * - Greg Conklin + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "blk_prediction.h" +#include "enc_statistics.h" +#include "memalloc.h" +#include "image.h" +#include "mb_access.h" +#include "block.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant4x4.h" +#include "quantChroma.h" +#include "md_common.h" +#include "transform8x8.h" + + +// Notation for comments regarding prediction and predictors. +// The pels of the 4x4 block are labelled a..p. The predictor pels above +// are labelled A..H, from the left I..P, and from above left X, as follows: +// +// X A B C D E F G H +// I a b c d +// J e f g h +// K i j k l +// L m n o p +// + +// Predictor array index definitions +#define P_X (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) + +//! array used to find expensive coefficients +static const byte COEFF_COST4x4[2][16] = +{ + {3,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0}, + {9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9} +}; + +static const byte SCAN_YUV420 [4][2] = +{ + {0,0}, + {0,1}, + {0,2}, + {0,3} +}; + +//! single scan pattern +static const byte SCAN_YUV422 [8][2] = +{ + {0,0},{0,1}, + {1,0},{0,2}, + {0,3},{1,1}, + {1,2},{1,3} +}; + +//! look up tables for FRExt-chroma support +static const unsigned char hor_offset[4][4][4] = { + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 4, 0, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 4, 0, 4}, + {0, 4, 0, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 4, 0, 4}, + {8,12, 8,12}, + {0, 4, 0, 4}, + {8,12, 8,12} + } +}; + +static const unsigned char ver_offset[4][4][4] = { + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {8, 8,12,12}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {0, 0, 4, 4}, + {0, 0, 4, 4}, + {8, 8,12,12}, + {8, 8,12,12} + } +}; + +static const int A[4][4] = { + { 16, 20, 16, 20}, + { 20, 25, 20, 25}, + { 16, 20, 16, 20}, + { 20, 25, 20, 25} +}; + +static const unsigned char cbp_blk_chroma[8][4] = { + {16, 17, 18, 19}, + {20, 21, 22, 23}, + {24, 25, 26, 27}, + {28, 29, 30, 31}, + {32, 33, 34, 35}, + {36, 37, 38, 39}, + {40, 41, 42, 43}, + {44, 45, 46, 47} +}; + +//! single scan pattern +static const byte SNGL_SCAN[16][2] = +{ + {0,0},{1,0},{0,1},{0,2}, + {1,1},{2,0},{3,0},{2,1}, + {1,2},{0,3},{1,3},{2,2}, + {3,1},{3,2},{2,3},{3,3} +}; + +//! field scan pattern +static const byte FIELD_SCAN[16][2] = +{ + {0,0},{0,1},{1,0},{0,2}, + {0,3},{1,1},{1,2},{1,3}, + {2,0},{2,1},{2,2},{2,3}, + {3,0},{3,1},{3,2},{3,3} +}; + + +//For residual DPCM +static int Residual_DPCM_16x16(int **mb_ores, int ipmode); +static int Inv_Residual_DPCM_16x16(int **mb_ores, int ipmode); +static int Residual_DPCM_4x4(int ipmode, int **mb_ores, int **mb_rres, int block_y, int block_x); +static int Inv_Residual_DPCM_4x4 (Macroblock *currMB, int **m7, int block_y, int block_x); +static int Residual_DPCM_Chroma(int ipmode, int **ores, int **rres, int width, int height); +static int Inv_Residual_DPCM_Chroma(int ipmode, int **m7, int width, int height); + +/*! + ************************************************************************ + * \brief + * For new intra pred routines + * + * \par Input: + * Image par, 16x16 based intra mode + * + * \par Output: + * none + ************************************************************************ + */ +int residual_transform_quant_luma_16x16(Macroblock *currMB, ColorPlane pl) +{ + int i,j; + int ii,jj; + + int ac_coef = 0; + imgpel *img_Y, *predY; + int nonzero = FALSE; + + int jpos, ipos; + int b8, b4; + + //begin the changes + int pl_off = pl<<2; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + + int* DCLevel = currSlice->cofDC[pl][0]; + int* DCRun = currSlice->cofDC[pl][1]; + int ****cofAC = &currSlice->cofAC[pl_off]; + int coeff_cost; + int new_intra_mode = currMB->i16mode; + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + int max_imgpel_value = p_Vid->max_imgpel_value; + int qp = (p_Vid->yuv_format==YUV444 && !currSlice->P444_joined)? currMB->qp_scaled[(int)(p_Vid->colour_plane_id)]: currMB->qp_scaled[pl]; //currMB->qp_scaled[pl]; + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[pl]; + + int qp_per = p_Quant->qp_per_matrix[qp]; + + // select scaling parameters + // needs a fix for 444 modes (pl should be current color plane) + + QuantMethods quant_methods; + // set quantization parameters + + quant_methods.qp = qp; + quant_methods.q_params = p_Quant->q_params_4x4[pl][1][qp]; + quant_methods.fadjust = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj4x4[pl][I16MB][0]): NULL; + quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + quant_methods.c_cost = COEFF_COST4x4[currSlice->disthres]; + quant_methods.coeff_cost = &coeff_cost; + quant_methods.type = LUMA_16AC; + + + for (j = 0; j < 16; ++j) + { + predY = curr_mpr_16x16[new_intra_mode][j]; + img_Y = &p_Vid->pCurImg[currMB->opix_y + j][currMB->pix_x]; + for (i = 0; i < 16; ++i) + { + currSlice->tblk16x16[j][i] = img_Y[i] - predY[i]; + } + } + + // forward 4x4 integer transform + for (j = 0; j < 16; j+=4) + { + for (i = 0;i < 16; i+=4) + { + forward4x4(currSlice->tblk16x16, currSlice->tblk16x16, j, i); + } + } + + // pick out DC coeff + for (j = 0; j < 4; ++j) + for (i = 0; i < 4; ++i) + currSlice->tblk4x4[j][i]= currSlice->tblk16x16[j << 2][i << 2]; + + // hadamard of DC coefficients + hadamard4x4(currSlice->tblk4x4, currSlice->tblk4x4); + + nonzero = currSlice->quant_dc4x4(currMB, &currSlice->tblk4x4[0], qp, DCLevel, DCRun, &quant_methods.q_params[0][0], pos_scan); + + + // inverse DC transform + if (nonzero) + { + ihadamard4x4(currSlice->tblk4x4, currSlice->tblk4x4); + + // inverse quantization for the DC coefficients + for (j = 0; j < MB_BLOCK_SIZE; j += BLOCK_SIZE) + { + for (i = 0; i < MB_BLOCK_SIZE;i += BLOCK_SIZE) + { + currSlice->tblk16x16[j][i] = rshift_rnd_sf(((currSlice->tblk4x4[j>>2][i>>2]) * quant_methods.q_params[0][0].InvScaleComp) << qp_per, 6); + } + } + } + else // All DC equal to 0. + { + for (j = 0; j < MB_BLOCK_SIZE; j += BLOCK_SIZE) + { + for (i = 0; i < MB_BLOCK_SIZE; i += BLOCK_SIZE) + { + currSlice->tblk16x16[j][i] = 0; + } + } + } + + // AC processing for MB + for (jj=0;jj<4;++jj) + { + jpos = (jj << 2); + currMB->subblock_y = (short) jpos; + for (ii=0;ii<4;++ii) + { + ipos = (ii << 2); + currMB->subblock_x = (short) ipos; + + b8 = 2*(jj >> 1) + (ii >> 1); + b4 = 2*(jj & 0x01) + (ii & 0x01); + quant_methods.block_x = ipos; + quant_methods.block_y = jpos; + + quant_methods.ACLevel = cofAC[b8][b4][0]; + quant_methods.ACRun = cofAC[b8][b4][1]; + + // Quantization process + nonzero = currSlice->quant_ac4x4(currMB, &currSlice->tblk16x16[jpos], &quant_methods); + + if (nonzero) + ac_coef = 15; + + //inverse transform + if (currSlice->tblk16x16[jpos][ipos]!= 0 || nonzero) + inverse4x4(currSlice->tblk16x16, currSlice->tblk16x16, jpos, ipos); + } + } + + + // Reconstruct samples + sample_reconstruct (&img_enc[currMB->pix_y], curr_mpr_16x16[new_intra_mode], currSlice->tblk16x16, 0, currMB->pix_x, 16, 16, max_imgpel_value, DQ_BITS); + + if(currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + for (j = currMB->pix_y; j < currMB->pix_y + 16;++j) + for (i = currMB->pix_x; i < currMB->pix_x + 16;++i) + p_Vid->lrec[j][i]=-16; //signals an I16 block in the SP frame + } + + return ac_coef; +} + +static int Residual_DPCM_16x16(int **m7, int ipmode) +{ + int i,j; + int temp[16][16]; + + if(ipmode==VERT_PRED_16) + { + for (i=1; i<16; ++i) + for (j=0; j<16; ++j) + temp[i][j] = m7[i][j] - m7[i-1][j]; + + for (i=1; i<16; ++i) + for (j=0; j<16; ++j) + m7[i][j] = temp[i][j]; + } + else //HOR_PRED_16 + { + for (i=0; i<16; ++i) + for (j=1; j<16; ++j) + temp[i][j] = m7[i][j] - m7[i][j-1]; + + for (i=0; i<16; ++i) + for (j=1; j<16; ++j) + m7[i][j] = temp[i][j]; + } + return 0; +} + +static int Inv_Residual_DPCM_16x16(int **m7, int ipmode) +{ + int i; + int temp[16][16]; + + if(ipmode==VERT_PRED_16) + { + for (i=0; i<16; ++i) + { + temp[0][i] = m7[0][i]; + temp[1][i] = m7[1][i] + temp[0][i]; + temp[2][i] = m7[2][i] + temp[1][i]; + temp[3][i] = m7[3][i] + temp[2][i]; + temp[4][i] = m7[4][i] + temp[3][i]; + temp[5][i] = m7[5][i] + temp[4][i]; + temp[6][i] = m7[6][i] + temp[5][i]; + temp[7][i] = m7[7][i] + temp[6][i]; + temp[8][i] = m7[8][i] + temp[7][i]; + temp[9][i] = m7[9][i] + temp[8][i]; + temp[10][i] = m7[10][i] + temp[9][i]; + temp[11][i] = m7[11][i] + temp[10][i]; + temp[12][i] = m7[12][i] + temp[11][i]; + temp[13][i] = m7[13][i] + temp[12][i]; + temp[14][i] = m7[14][i] + temp[13][i]; + temp[15][i] = m7[15][i] + temp[14][i]; + } + // These could now just use a memcpy + for (i=0; i<16; ++i) + { + m7[1][i] = temp[1][i]; + m7[2][i] = temp[2][i]; + m7[3][i] = temp[3][i]; + m7[4][i] = temp[4][i]; + m7[5][i] = temp[5][i]; + m7[6][i] = temp[6][i]; + m7[7][i] = temp[7][i]; + m7[8][i] = temp[8][i]; + m7[9][i] = temp[9][i]; + m7[10][i] = temp[10][i]; + m7[11][i] = temp[11][i]; + m7[12][i] = temp[12][i]; + m7[13][i] = temp[13][i]; + m7[14][i] = temp[14][i]; + m7[15][i] = temp[15][i]; + } + } + else //HOR_PRED_16 + { + for(i=0; i<16; ++i) + { + temp[i][0] = m7[i][0]; + temp[i][1] = m7[i][1] + temp[i][0]; + temp[i][2] = m7[i][2] + temp[i][1]; + temp[i][3] = m7[i][3] + temp[i][2]; + temp[i][4] = m7[i][4] + temp[i][3]; + temp[i][5] = m7[i][5] + temp[i][4]; + temp[i][6] = m7[i][6] + temp[i][5]; + temp[i][7] = m7[i][7] + temp[i][6]; + temp[i][8] = m7[i][8] + temp[i][7]; + temp[i][9] = m7[i][9] + temp[i][8]; + temp[i][10] = m7[i][10] + temp[i][9]; + temp[i][11] = m7[i][11] + temp[i][10]; + temp[i][12] = m7[i][12] + temp[i][11]; + temp[i][13] = m7[i][13] + temp[i][12]; + temp[i][14] = m7[i][14] + temp[i][13]; + temp[i][15] = m7[i][15] + temp[i][14]; + } + for (i=0; i<16; ++i) + { + m7[i][1] = temp[i][1]; + m7[i][2] = temp[i][2]; + m7[i][3] = temp[i][3]; + m7[i][4] = temp[i][4]; + m7[i][5] = temp[i][5]; + m7[i][6] = temp[i][6]; + m7[i][7] = temp[i][7]; + m7[i][8] = temp[i][8]; + m7[i][9] = temp[i][9]; + m7[i][10] = temp[i][10]; + m7[i][11] = temp[i][11]; + m7[i][12] = temp[i][12]; + m7[i][13] = temp[i][13]; + m7[i][14] = temp[i][14]; + m7[i][15] = temp[i][15]; + } + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * For new intra pred routines + * + * \par Input: + * Image par, 16x16 based intra mode + * + * \par Output: + * none + ************************************************************************ + */ +int residual_transform_quant_luma_16x16_ls(Macroblock *currMB, ColorPlane pl) +{ + int i,j; + int ii,jj; + + int run,scan_pos,coeff_ctr; + int ac_coef = 0; + imgpel *img_Y, *predY; + + int b8, b4; + + //begin the changes + int pl_off = pl<<2; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int* DCLevel = currSlice->cofDC[pl][0]; + int* DCRun = currSlice->cofDC[pl][1]; + int* ACLevel; + int* ACRun; + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + int *m7; + int new_intra_mode = currMB->i16mode; + + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[pl]; + + for (j = 0; j < 16; ++j) + { + predY = curr_mpr_16x16[new_intra_mode][j]; + img_Y = &p_Vid->pCurImg[currMB->opix_y + j][currMB->pix_x]; + for (i = 0; i < 16; ++i) + { + currSlice->tblk16x16[j][i] = img_Y[i] - predY[i]; + } + } + + if (new_intra_mode < 2) + { + Residual_DPCM_16x16(currSlice->tblk16x16, new_intra_mode); + } + + // pick out DC coeff + for (j = 0; j < 4;++j) + for (i = 0; i < 4;++i) + currSlice->tblk4x4[j][i]= currSlice->tblk16x16[j << 2][i << 2]; + + run=-1; + scan_pos=0; + + for (coeff_ctr=0;coeff_ctr<16;++coeff_ctr) + { + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + ++run; + + m7 = &currSlice->tblk4x4[j][i]; + + if (*m7 != 0) + { + if (is_cavlc) + *m7 = iClip3(-CAVLC_LEVEL_LIMIT, CAVLC_LEVEL_LIMIT, *m7); + + DCLevel[scan_pos ] = *m7; + DCRun [scan_pos++] = run; + run=-1; + } + } + DCLevel[scan_pos]=0; + + // replace DC coeff. This is needed in case of out of limits for CAVLC. Could be done only for CAVLC + for (j = 0; j < 4;++j) + for (i = 0; i < 4;++i) + currSlice->tblk16x16[j << 2][i << 2] = currSlice->tblk4x4[j][i]; + + // AC inverse trans/quant for MB + for (jj = 0; jj < 4; ++jj) + { + for (ii = 0; ii < 4; ++ii) + { + for (j=0;j<4;++j) + { + memcpy(currSlice->tblk4x4[j],&currSlice->tblk16x16[(jj<<2)+j][(ii<<2)], BLOCK_SIZE * sizeof(int)); + } + + run = -1; + scan_pos = 0; + b8 = 2*(jj >> 1) + (ii >> 1); + b4 = 2*(jj & 0x01) + (ii & 0x01); + ACLevel = currSlice->cofAC [b8+pl_off][b4][0]; + ACRun = currSlice->cofAC [b8+pl_off][b4][1]; + + for (coeff_ctr=1;coeff_ctr<16;coeff_ctr++) // set in AC coeff + { + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + run++; + m7 = &currSlice->tblk4x4[j][i]; + + if (*m7 != 0) + { + if (is_cavlc) + *m7 = iClip3(-CAVLC_LEVEL_LIMIT, CAVLC_LEVEL_LIMIT, *m7); + + ac_coef = 15; + ACLevel[scan_pos ] = *m7; + ACRun [scan_pos++] = run; + run=-1; + } + // set adaptive rounding p_Inp to 0 since process is not meaningful here. + } + ACLevel[scan_pos] = 0; + + for (j=0;j<4;++j) + memcpy(&currSlice->tblk16x16[(jj<<2)+j][(ii<<2)],currSlice->tblk4x4[j], BLOCK_SIZE * sizeof(int)); + } + } + + if (new_intra_mode < 2) + { + Inv_Residual_DPCM_16x16(currSlice->tblk16x16, new_intra_mode); + } + + + for (j = 0; j < 16; ++j) + { + img_Y = &img_enc[currMB->pix_y + j][currMB->pix_x]; + predY = curr_mpr_16x16[new_intra_mode][j]; + for (i = 0; i < 16; ++i) + img_Y[i]=(imgpel)(currSlice->tblk16x16[j][i] + predY[i]); + } + + if(currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + for (j = currMB->pix_y; j < currMB->pix_y + 16;++j) + for (i = currMB->pix_x; i < currMB->pix_x + 16;++i) + p_Vid->lrec[j][i]=-16; //signals an I16 block in the SP frame + } + + return ac_coef; +} + +static inline int check_zero(int **mb_ores, int block_x) +{ + int i, j, k = 0; + + for (j = 0; (j < BLOCK_SIZE) && (k == 0); ++j) + { + for (i = block_x; (i< block_x + BLOCK_SIZE) && (k == 0); ++i) + { + //k |= (mb_ores[j][i] != 0); + k |= mb_ores[j][i]; + } + } + return k; +} + +/*! +************************************************************************ +* \brief +* The routine performs transform,quantization,inverse transform, +* adds the diff to the prediction and writes the result to the +* decoded luma frame. +* +* \par Input: +* currMB: Current macroblock. +* pl: Color plane for 4:4:4 coding. +* block_x,block_y: Block position inside a macro block (0,4,8,12). +* intra: Intra block indicator. +* +* \par Output_ +* nonzero: 0 if no levels are nonzero. \n +* 1 if there are nonzero levels.\n +* coeff_cost: Coeff coding cost for thresholding consideration.\n +************************************************************************ +*/ +int residual_transform_quant_luma_4x4(Macroblock *currMB, ColorPlane pl, int block_x,int block_y, int *coeff_cost, int intra) +{ + int nonzero = FALSE; + + int pos_x = block_x >> BLOCK_SHIFT; + int pos_y = block_y >> BLOCK_SHIFT; + int b8 = 2*(pos_y >> 1) + (pos_x >> 1) + (pl<<2); + int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01); + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + + if (check_zero(&mb_ores[block_y], block_x) != 0) // check if any coefficients in block + { + int **mb_rres = currSlice->mb_rres[pl]; + int max_imgpel_value = p_Vid->max_imgpel_value; + int qp = (p_Vid->yuv_format==YUV444 && !currSlice->P444_joined)? currMB->qp_scaled[(int)(p_Vid->colour_plane_id)]: currMB->qp_scaled[pl]; + QuantParameters *p_Quant = p_Vid->p_Quant; + QuantMethods quant_methods; + quant_methods.ACLevel = currSlice->cofAC[b8][b4][0]; + quant_methods.ACRun = currSlice->cofAC[b8][b4][1]; + + quant_methods.block_x = block_x; + quant_methods.block_y = block_y; + quant_methods.qp = qp; + quant_methods.q_params = p_Quant->q_params_4x4[pl][intra][qp]; + quant_methods.fadjust = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj4x4[pl][currMB->ar_mode][block_y]) : NULL; + quant_methods.coeff_cost = coeff_cost; + quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + quant_methods.c_cost = COEFF_COST4x4[currSlice->disthres]; + + currMB->subblock_x = ((b8&0x1)==0) ? (((b4&0x1)==0)? 0: 4) : (((b4&0x1)==0)? 8: 12); // horiz. position for coeff_count context + currMB->subblock_y = (b8<2) ? ((b4<2) ? 0: 4) : ((b4<2) ? 8: 12); // vert. position for coeff_count context + + // Forward 4x4 transform + forward4x4(mb_ores, currSlice->tblk16x16, block_y, block_x); + + // Quantization process + nonzero = currSlice->quant_4x4(currMB, &currSlice->tblk16x16[block_y], &quant_methods); + + // Decoded block moved to frame memory + if (nonzero) + { + // Inverse 4x4 transform + inverse4x4(currSlice->tblk16x16, mb_rres, block_y, block_x); + + // generate final block + sample_reconstruct (&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], &mb_rres[block_y], block_x, currMB->pix_x + block_x, BLOCK_SIZE, BLOCK_SIZE, max_imgpel_value, DQ_BITS); + } + else // if (nonzero) => No transformed residual. Just use prediction. + { + copy_image_data_4x4(&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], currMB->pix_x + block_x, block_x); + } + } + else + { + currSlice->cofAC[b8][b4][0][0] = 0; + copy_image_data_4x4(&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], currMB->pix_x + block_x, block_x); + } + + return nonzero; +} + + + +/*! +************************************************************************ +* \brief +* Process for lossless coding of coefficients. +* The routine performs transform, quantization,inverse transform, +* adds the diff to the prediction and writes the result to the +* decoded luma frame. +* +* \par Input: +* currMB: Current macroblock. +* pl: Color plane for 4:4:4 coding. +* block_x,block_y: Block position inside a macro block (0,4,8,12). +* intra: Intra block indicator. +* +* \par Output_ +* nonzero: 0 if no levels are nonzero. \n +* 1 if there are nonzero levels.\n +* coeff_cost: Coeff coding cost for thresholding consideration.\n +************************************************************************ +*/ +int residual_transform_quant_luma_4x4_ls(Macroblock *currMB, ColorPlane pl, int block_x,int block_y,int *coeff_cost, int intra) +{ + int i,j, coeff_ctr; + int run = -1; + int nonzero = FALSE; + + int pos_x = block_x >> BLOCK_SHIFT; + int pos_y = block_y >> BLOCK_SHIFT; + int b8 = 2*(pos_y >> 1) + (pos_x >> 1) + (pl<<2); + int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01); + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int* ACL = &currSlice->cofAC[b8][b4][0][0]; + int* ACR = &currSlice->cofAC[b8][b4][1][0]; + + int pix_y, pix_x; + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + int *m7; + + const byte *p_scan = currMB->is_field_mode ? &FIELD_SCAN[0][0] : &SNGL_SCAN[0][0]; + + // select scaling parameters + int **fadjust4x4 = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj4x4[pl][currMB->ar_mode][block_y]) : NULL; + + if( (currMB->ipmode_DPCM < 2) && (intra)) + { + Residual_DPCM_4x4(currMB->ipmode_DPCM, mb_ores, mb_rres, block_y, block_x); + } + else + { + for (j=block_y; j < block_y + BLOCK_SIZE; ++j) + for (i=block_x; i < block_x + BLOCK_SIZE; ++i) + mb_rres[j][i] = mb_ores[j][i]; + } + + for (coeff_ctr=0;coeff_ctr < 16;coeff_ctr++) + { + i = *p_scan++; + j = *p_scan++; + + run++; + + m7 = &mb_rres[block_y + j][block_x + i]; + + if (p_Vid->AdaptiveRounding) + fadjust4x4[j][block_x+i] = 0; + + if (*m7 != 0) + { + if (is_cavlc) + *m7 = iClip3(-CAVLC_LEVEL_LIMIT, CAVLC_LEVEL_LIMIT, *m7); + + nonzero=TRUE; + *coeff_cost += MAX_VALUE; + *ACL++ = *m7; + *ACR++ = run; + run=-1; // reset zero level counter + } + } + *ACL = 0; + + if( (currMB->ipmode_DPCM < 2) && (intra)) + { + Inv_Residual_DPCM_4x4(currMB, mb_rres, block_y, block_x); + } + + for (j=0; j < BLOCK_SIZE; ++j) + { + pix_y = currMB->pix_y + block_y + j; + pix_x = currMB->pix_x+block_x; + for (i=0; i < BLOCK_SIZE; ++i) + { + img_enc[pix_y][pix_x+i] = (imgpel) (mb_rres[j+block_y][i+block_x] + mb_pred[j+block_y][i+block_x]); + } + } + + return nonzero; +} + +/*! +************************************************************************ +* \brief +* Residual DPCM for Intra lossless coding +* +* \par Input: +* block_x,block_y: Block position inside a macro block (0,4,8,12). +************************************************************************ +*/ +static int Residual_DPCM_4x4(int ipmode, int **mb_ores, int **mb_rres, int block_y, int block_x) +{ + int i; + int temp[4][4]; + + if(ipmode==VERT_PRED) + { + for (i=0; i<4; ++i) + { + temp[0][i] = mb_ores[block_y + 0][block_x + i]; + temp[1][i] = mb_ores[block_y + 1][block_x + i] - mb_ores[block_y ][block_x + i]; + temp[2][i] = mb_ores[block_y + 2][block_x + i] - mb_ores[block_y + 1][block_x + i]; + temp[3][i] = mb_ores[block_y + 3][block_x + i] - mb_ores[block_y + 2][block_x + i]; + } + + for (i = 0; i < 4; ++i) + { + mb_rres[block_y + 0][block_x + i] = temp[0][i]; + mb_rres[block_y + 1][block_x + i] = temp[1][i]; + mb_rres[block_y + 2][block_x + i] = temp[2][i]; + mb_rres[block_y + 3][block_x + i] = temp[3][i]; + } + } + else //HOR_PRED + { + for (i=0; i<4; ++i) + { + temp[i][0] = mb_ores[block_y + i][block_x]; + temp[i][1] = mb_ores[block_y + i][block_x + 1] - mb_ores[block_y + i][block_x ]; + temp[i][2] = mb_ores[block_y + i][block_x + 2] - mb_ores[block_y + i][block_x + 1]; + temp[i][3] = mb_ores[block_y + i][block_x + 3] - mb_ores[block_y + i][block_x + 2]; + } + + for (i=0; i<4; ++i) + { + mb_rres[block_y + i][block_x + 0] = temp[i][0]; + mb_rres[block_y + i][block_x + 1] = temp[i][1]; + mb_rres[block_y + i][block_x + 2] = temp[i][2]; + mb_rres[block_y + i][block_x + 3] = temp[i][3]; + } + } + return 0; +} + +/*! +************************************************************************ +* \brief +* Inverse residual DPCM for Intra lossless coding +* +* \par Input: +* block_x,block_y: Block position inside a macro block (0,4,8,12). +************************************************************************ +*/ +//For residual DPCM +static int Inv_Residual_DPCM_4x4(Macroblock *currMB, int **m7, int block_y, int block_x) +{ + int i; + int temp[4][4]; + + if(currMB->ipmode_DPCM == VERT_PRED) + { + for(i=0; i<4; ++i) + { + temp[0][i] = m7[block_y + 0][block_x + i]; + temp[1][i] = m7[block_y + 1][block_x + i] + temp[0][i]; + temp[2][i] = m7[block_y + 2][block_x + i] + temp[1][i]; + temp[3][i] = m7[block_y + 3][block_x + i] + temp[2][i]; + } + for(i=0; i<4; ++i) + { + m7[block_y + 0][block_x + i] = temp[0][i]; + m7[block_y + 1][block_x + i] = temp[1][i]; + m7[block_y + 2][block_x + i] = temp[2][i]; + m7[block_y + 3][block_x + i] = temp[3][i]; + } + } + else //HOR_PRED + { + for(i=0; i<4; ++i) + { + temp[i][0] = m7[block_y + i][block_x + 0]; + temp[i][1] = m7[block_y + i][block_x + 1] + temp[i][0]; + temp[i][2] = m7[block_y + i][block_x + 2] + temp[i][1]; + temp[i][3] = m7[block_y + i][block_x + 3] + temp[i][2]; + } + for(i=0; i<4; ++i) + { + m7[block_y+i][block_x ] = temp[i][0]; + m7[block_y+i][block_x+1] = temp[i][1]; + m7[block_y+i][block_x+2] = temp[i][2]; + m7[block_y+i][block_x+3] = temp[i][3]; + } + } + return 0; +} + +/*! + ************************************************************************ + * \brief + * Transform,quantization,inverse transform for chroma. + * The main reason why this is done in a separate routine is the + * additional 2x2 transform of DC-coeffs. This routine is called + * once for each of the chroma components. + * + * \par Input: + * uv : Make difference between the U and V chroma component \n + * cr_cbp: chroma coded block pattern + * + * \par Output: + * cr_cbp: Updated chroma coded block pattern. + ************************************************************************ + */ +int residual_transform_quant_chroma_4x4(Macroblock *currMB, int uv, int cr_cbp) +{ + int i, j, n2, n1, coeff_ctr; + int *m1; + int coeff_cost = 0; + int cr_cbp_tmp = 0; + int DCzero = FALSE; + int nonzero[4][4] = {{FALSE}}; + int nonezero = FALSE; + //int empty_block = TRUE; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + + int b4; + int* DCLevel = currSlice->cofDC[uv+1][0]; + int* DCRun = currSlice->cofDC[uv+1][1]; + int intra = IS_INTRA (currMB); + int uv_scale = uv * (p_Vid->num_blk8x8_uv >> 1); + + //FRExt + static const int64 cbpblk_pattern[4]={0, 0xf0000, 0xff0000, 0xffff0000}; + int yuv = p_Vid->yuv_format; + int b8; + + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + int cur_qp = currMB->qpc[uv] + currSlice->bitdepth_chroma_qp_scale; + + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[uv + 1]; + + int **mb_rres = currSlice->mb_rres[uv + 1]; + int **mb_ores = currSlice->mb_ores[uv + 1]; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + + QuantMethods quant_methods; + // set quantization parameters + quant_methods.qp = cur_qp; + quant_methods.q_params = p_Quant->q_params_4x4[uv + 1][intra][cur_qp]; + quant_methods.type = CHROMA_AC; + if (currMB->mb_type == P8x8 && currMB->luma_transform_size_8x8_flag) + { + //P8x8, transform 8x8 chroma adjustments must be stored in a different array to avoid conflict with transform 4x4 + quant_methods.fadjust = p_Vid->AdaptiveRounding ? p_Vid->ARCofAdj4x4[uv + 1][4] : NULL; + } + else + { + quant_methods.fadjust = p_Vid->AdaptiveRounding ? p_Vid->ARCofAdj4x4[uv + 1][currMB->ar_mode] : NULL; + } + + quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + quant_methods.c_cost = COEFF_COST4x4[currSlice->disthres]; + quant_methods.coeff_cost = &coeff_cost; + + + p_Vid->is_v_block = uv; + + //============= integer transform =============== + for (n2=0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE) + { + for (n1=0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE) + { + if (check_zero(&mb_ores[n2], n1) == 0) // check if any coefficients in block + { + for (j = n2; j < n2 + BLOCK_SIZE; j++) + for (i = n1; i < n1 + BLOCK_SIZE; i++) + mb_rres[j][i] = 0; + } + else + { + forward4x4(mb_ores, mb_rres, n2, n1); + //empty_block = FALSE; + } + } + } + + if (yuv == YUV420) + { + int **fadjust2x2 = NULL; + + m1 = currSlice->tblk4x4[0]; + //================== CHROMA DC YUV420 =================== + + // forward 2x2 hadamard + hadamard2x2(mb_rres, m1); + + // Quantization process of chroma 2X2 hadamard transformed DC coeffs. + DCzero = currSlice->quant_dc_cr(currMB, &m1, cur_qp, DCLevel, DCRun, &quant_methods.q_params[0][0], fadjust2x2, SCAN_YUV420); + + if (DCzero) + { + currMB->cbp_blk |= 0xf0000 << (uv << 2) ; // if one of the 2x2-DC levels is != 0 set the + cr_cbp=imax(1,cr_cbp); // coded-bit all 4 4x4 blocks (bit 16-19 or 20-23) + } + + // Inverse transform of 2x2 DC levels + ihadamard2x2(m1, m1); + + mb_rres[0][0] = m1[0] >> 5; + mb_rres[0][4] = m1[1] >> 5; + mb_rres[4][0] = m1[2] >> 5; + mb_rres[4][4] = m1[3] >> 5; + } + else if (yuv == YUV422) + { + int **fadjust4x2 = NULL; // note that this is in fact 2x4 but the coefficients have been transposed for better memory access + //for YUV422 only + int cur_qp_dc = currMB->qpc[uv] + 3 + currSlice->bitdepth_chroma_qp_scale; + + LevelQuantParams **quant_paramsDC = p_Quant->q_params_4x4[uv + 1][intra][cur_qp_dc]; + + //================== CHROMA DC YUV422 =================== + //pick out DC coeff + for (j=0; j < p_Vid->mb_cr_size_y; j+=BLOCK_SIZE) + { + for (i=0; i < p_Vid->mb_cr_size_x; i+=BLOCK_SIZE) + currSlice->tblk4x4[i>>2][j>>2]= mb_rres[j][i]; + } + + // forward hadamard transform. Note that coeffs have been transposed (4x2 instead of 2x4) which makes transform a bit faster + hadamard4x2(currSlice->tblk4x4, currSlice->tblk4x4); + + // Quantization process of chroma transformed DC coeffs. + DCzero = currSlice->quant_dc_cr(currMB, currSlice->tblk4x4, cur_qp_dc, DCLevel, DCRun, &quant_paramsDC[0][0], fadjust4x2, SCAN_YUV422); + + if (DCzero) + { + currMB->cbp_blk |= 0xff0000 << (uv << 3) ; // if one of the DC levels is != 0 set the + cr_cbp=imax(1,cr_cbp); // coded-bit all 4 4x4 blocks (bit 16-31 or 32-47) //YUV444 + } + + //inverse DC transform. Note that now currSlice->tblk4x4 is transposed back + ihadamard4x2(currSlice->tblk4x4, currSlice->tblk4x4); + + // This code assumes sizeof(int) > 16. Therefore, no need to have conditional + for (j = 0; j < 4; ++j) + { + mb_rres[j << 2 ][0] = rshift_rnd_sf(currSlice->tblk4x4[j][0], 6); + mb_rres[j << 2 ][4] = rshift_rnd_sf(currSlice->tblk4x4[j][1], 6); + } + } + + // Quant of chroma AC-coeffs. + for (b8=0; b8 < (p_Vid->num_blk8x8_uv >> 1); b8++) + { + for (b4=0; b4 < 4; b4++) + { + int64 uv_cbpblk = ((int64)1) << cbp_blk_chroma[b8 + uv_scale][b4]; + n1 = hor_offset[yuv][b8][b4]; + n2 = ver_offset[yuv][b8][b4]; + quant_methods.ACLevel = currSlice->cofAC[4 + b8 + uv_scale][b4][0]; + quant_methods.ACRun = currSlice->cofAC[4 + b8 + uv_scale][b4][1]; + quant_methods.block_x = n1; + quant_methods.block_y = n2; + + currMB->subblock_y = subblk_offset_y[p_Vid->yuv_format - 1][b8][b4]; + currMB->subblock_x = subblk_offset_x[p_Vid->yuv_format - 1][b8][b4]; + if (p_Vid->AdaptiveRounding) + { + if (currMB->mb_type == P8x8 && currMB->luma_transform_size_8x8_flag) + { + //P8x8, transform 8x8 chroma adjustments must be stored in a different array to avoid conflict with transform 4x4 + quant_methods.fadjust = &p_Vid->ARCofAdj4x4[uv + 1][4][n2]; + } + else + { + quant_methods.fadjust = &p_Vid->ARCofAdj4x4[uv + 1][currMB->ar_mode][n2]; + } + } + else + { + quant_methods.fadjust = NULL; + } + + // Quantization process + nonzero[n2>>2][n1>>2] = currSlice->quant_ac4x4cr(currMB, &mb_rres[n2], &quant_methods); + + if (nonzero[n2>>2][n1>>2]) + { + currMB->cbp_blk |= uv_cbpblk; + cr_cbp_tmp = 2; + nonezero = TRUE; + } + } + } + + // Perform thresholding + // * reset chroma coeffs + if(nonezero && coeff_cost < _CHROMA_COEFF_COST_) + { + int64 uv_cbpblk = ((int64)cbpblk_pattern[yuv] << (uv << (1+yuv))); + cr_cbp_tmp = 0; + + for (b8 = 0; b8 < (p_Vid->num_blk8x8_uv >> 1); b8++) + { + for (b4 = 0; b4 < 4; b4++) + { + n1 = hor_offset[yuv][b8][b4]; + n2 = ver_offset[yuv][b8][b4]; + if (nonzero[n2>>2][n1>>2] == TRUE) + { + nonzero[n2>>2][n1>>2] = FALSE; + quant_methods.ACLevel = currSlice->cofAC[4 + b8 + uv_scale][b4][0]; + quant_methods.ACRun = currSlice->cofAC[4 + b8 + uv_scale][b4][1]; + + if (DCzero == 0) + currMB->cbp_blk &= ~(uv_cbpblk); // if no chroma DC's: then reset coded-bits of this chroma subblock + + quant_methods.ACLevel[0] = 0; + + for (coeff_ctr=1; coeff_ctr < 16; coeff_ctr++)// ac coeff + { + mb_rres[n2 + pos_scan[coeff_ctr][1]][n1 + pos_scan[coeff_ctr][0]] = 0; + quant_methods.ACLevel[coeff_ctr] = 0; + } + } + } + } + } + + // inverse transform. + // Horizontal. + if(cr_cbp_tmp == 2) + cr_cbp = 2; + + nonezero = FALSE; + for (n2=0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE) + { + for (n1=0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE) + { + if (mb_rres[n2][n1] != 0 || nonzero[n2>>2][n1>>2] == TRUE) + { + inverse4x4(mb_rres, mb_rres, n2, n1); + nonezero = TRUE; + } + } + } + + // Decoded block moved to memory + if (nonezero == TRUE) + { + sample_reconstruct (&p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y], mb_pred, mb_rres, 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y, max_imgpel_value_uv, DQ_BITS); + } + else + { + copy_image_data(&p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y], mb_pred, currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + return cr_cbp; +} + +static int Residual_DPCM_Chroma(int ipmode, int **ores, int **rres, int width, int height) +{ + int i,j; + int temp[16][16]; + + if(ipmode==VERT_PRED_8) + { + for (j=0; jp_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int* DCLevel = currSlice->cofDC[uv+1][0]; + int* DCRun = currSlice->cofDC[uv+1][1]; + int* ACLevel; + int* ACRun; + int uv_scale = uv * (p_Vid->num_blk8x8_uv >> 1); + + //FRExt + int yuv = p_Vid->yuv_format; + int b8; + int *m7; + int m3[4][4]; + + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + int **mb_rres = currSlice->mb_rres[uv + 1]; + int **mb_ores = currSlice->mb_ores[uv + 1]; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + int **fadjust4x4; + + int intra = ((currMB->mb_type == I4MB) || (currMB->mb_type == I8MB) || (currMB->mb_type == I16MB)); + + + if (currMB->mb_type == P8x8 && currMB->luma_transform_size_8x8_flag) + { + //P8x8, transform 8x8 chroma adjustments must be stored in a different array to avoid conflict with transform 4x4 + fadjust4x4 = p_Vid->AdaptiveRounding ? p_Vid->ARCofAdj4x4[uv + 1][4] : NULL; + } + else + { + fadjust4x4 = p_Vid->AdaptiveRounding ? p_Vid->ARCofAdj4x4[uv + 1][currMB->ar_mode] : NULL; + } + + if((currMB->c_ipred_mode == HOR_PRED_8 || currMB->c_ipred_mode == VERT_PRED_8) && (intra)) + { + Residual_DPCM_Chroma(currMB->c_ipred_mode, mb_ores, mb_rres, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + else + { + for (j=0; j < p_Vid->mb_cr_size_y; j++) + { + for (i=0; i < p_Vid->mb_cr_size_x; i++) + { + mb_rres[j][i] = mb_ores[j][i]; + } + } + } + + if (yuv == YUV420) + { + //================== CHROMA DC YUV420 =================== + // 2X2 transform of DC coeffs. + run=-1; + scan_pos=0; + m1[0] = mb_rres[0][0] ; + m1[1] = mb_rres[0][4] ; + m1[2] = mb_rres[4][0] ; + m1[3] = mb_rres[4][4] ; + + for (coeff_ctr=0; coeff_ctr < 4; coeff_ctr++) + { + run++; + + level =iabs(m1[coeff_ctr]); + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + currMB->cbp_blk |= 0xf0000 << (uv << 2) ; // if one of the 2x2-DC levels is != 0 set the + cr_cbp=imax(1, cr_cbp); // coded-bit all 4 4x4 blocks (bit 16-19 or 20-23) + level = isignab(level, m1[coeff_ctr]); + DCLevel[scan_pos ] = level; + DCRun [scan_pos++] = run; + run=-1; + } + } + DCLevel[scan_pos] = 0; + } + else if(yuv == YUV422) + { + //================== CHROMA DC YUV422 =================== + //transform DC coeff + //horizontal + + //pick out DC coeff + for (j=0; j < p_Vid->mb_cr_size_y; j+=BLOCK_SIZE) + { + for (i=0; i < p_Vid->mb_cr_size_x; i+=BLOCK_SIZE) + { + m3[i>>2][j>>2] = mb_rres[j][i]; + } + } + + + run=-1; + scan_pos=0; + + //quant of chroma DC-coeffs + for (coeff_ctr=0;coeff_ctr<8;coeff_ctr++) + { + i=SCAN_YUV422[coeff_ctr][0]; + j=SCAN_YUV422[coeff_ctr][1]; + + run++; + + level = iabs(m3[i][j]); + currSlice->tblk4x4[i][j]=m3[i][j]; + + if (level != 0) + { + //YUV422 + currMB->cbp_blk |= 0xff0000 << (uv << 3) ; // if one of the DC levels is != 0 set the + cr_cbp=imax(1,cr_cbp); // coded-bit all 4 4x4 blocks (bit 16-31 or 32-47) //YUV444 + + DCLevel[scan_pos ] = isignab(level,currSlice->tblk4x4[i][j]); + DCRun [scan_pos++] = run; + run=-1; + } + } + DCLevel[scan_pos]=0; + + //inverse DC transform + //horizontal + } + + // Quant of chroma AC-coeffs. + coeff_cost=0; + + for (b8=0; b8 < (p_Vid->num_blk8x8_uv >> 1); b8++) + { + for (b4=0; b4 < 4; b4++) + { + int64 uv_cbpblk = ((int64)1) << cbp_blk_chroma[b8 + uv_scale][b4]; + n1 = hor_offset[yuv][b8][b4]; + n2 = ver_offset[yuv][b8][b4]; + ACLevel = currSlice->cofAC[4 + b8 + uv_scale][b4][0]; + ACRun = currSlice->cofAC[4 + b8 + uv_scale][b4][1]; + run=-1; + scan_pos=0; + + for (coeff_ctr=1; coeff_ctr < 16; coeff_ctr++)// start change rd_quant + { + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + ++run; + + level = iabs(mb_rres[n2+j][n1+i]); + + if (p_Vid->AdaptiveRounding) + { + fadjust4x4[n2+j][n1+i] = 0; + } + + if (level != 0) + { + cr_cbp=imax(2, cr_cbp); + + currMB->cbp_blk |= uv_cbpblk; + coeff_cost += MAX_VALUE; // set high cost, shall not be discarded + + ACLevel[scan_pos ] = isignab(level, mb_rres[n2+j][n1+i]); + ACRun [scan_pos++] = run; + run=-1; + + level = isignab(level, mb_rres[n2+j][n1+i]); + } + } + ACLevel[scan_pos] = 0; + } + } + + if((currMB->c_ipred_mode == HOR_PRED_8 || currMB->c_ipred_mode == VERT_PRED_8) && intra) + { + Inv_Residual_DPCM_Chroma(currMB->c_ipred_mode, mb_rres, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y) ; + } + + for (j=0; j < p_Vid->mb_cr_size_y; ++j) + { + orig_img = &p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y + j][currMB->pix_c_x]; + m7 = mb_rres[j]; + pred_img = mb_pred[j]; + for (i=0; i < p_Vid->mb_cr_size_x; ++i) + { + orig_img[i] = (imgpel) m7[i] + pred_img[i]; + } + } + + return cr_cbp; +} + +/*! + ************************************************************************ + * \brief + * The routine performs transform,quantization,inverse transform, adds the diff. + * to the prediction and writes the result to the decoded luma frame. Includes the + * RD constrained quantization also. + * + * \par Input: + * block_x,block_y: Block position inside a macro block (0,4,8,12). + * + * \par Output: + * nonzero: 0 if no levels are nonzero. 1 if there are nonzero levels. \n + * coeff_cost: Counter for nonzero coefficients, used to discard expensive levels. + * + * + ************************************************************************ + */ +int residual_transform_quant_luma_4x4_sp(Macroblock *currMB, ColorPlane pl, int block_x,int block_y,int *coeff_cost, int intra) +{ + int i,j,coeff_ctr; + int qp_const,ilev, level,scan_pos = 0,run = -1; + int nonzero = FALSE; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + int c_err,qp_const2; + + int qp = currMB->qp_scaled[pl]; + int qp_sp = (currMB->qpsp); + + const byte *c_cost = COEFF_COST4x4[p_Inp->disthres]; + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + + int pos_x = block_x >> BLOCK_SHIFT; + int pos_y = block_y >> BLOCK_SHIFT; + int b8 = 2*(pos_y >> 1) + (pos_x >> 1); + int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01); + int* ACLevel = currSlice->cofAC[b8][b4][0]; + int* ACRun = currSlice->cofAC[b8][b4][1]; + + // For encoding optimization + int c_err1, c_err2, level1, level2; + double D_dis1, D_dis2; + int len, info; + double lambda_mode = 0.85 * pow (2, (qp - SHIFT_QP)/3.0) * 4; + + QuantParameters *p_Quant = p_Vid->p_Quant; + + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + int qp_per_sp = p_Quant->qp_per_matrix[qp_sp]; + int q_bits_sp = Q_BITS + qp_per_sp; + + LevelQuantParams **q_params_4x4 = p_Quant->q_params_4x4[pl][intra][qp]; + LevelQuantParams **quant_params_sp = p_Quant->q_params_4x4[pl][intra][qp_sp]; + + //QuantMethods quant_methods; + //quant_methods.ACLevel = currSlice->cofAC[b8][b4][0]; + //quant_methods.ACRun = currSlice->cofAC[b8][b4][1]; + + //quant_methods.block_x = block_x; + //quant_methods.block_y = block_y; + //quant_methods.qp = qp; + + //quant_methods.q_params = p_Quant->q_params_4x4[pl][intra][qp]; + //quant_methods.fadjust = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj4x4[pl][currMB->ar_mode][block_y]) : NULL; + //quant_methods.coeff_cost = coeff_cost; + //quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + //quant_methods.c_cost = COEFF_COST4x4[currSlice->disthres]; + + qp_const = (1<>1; //sp_pred + + // Horizontal transform + for (j=block_y; j< block_y + BLOCK_SIZE; ++j) + { + for (i=block_x; i< block_x + BLOCK_SIZE; ++i) + { + mb_rres[j][i] = mb_ores[j][i]; + mb_rres[j][i]+=mb_pred[j][i]; + currSlice->tblk16x16[j][i] = mb_pred[j][i]; + } + } + + // 4x4 transform + forward4x4(mb_rres, mb_rres, block_y, block_x); + forward4x4(currSlice->tblk16x16, currSlice->tblk16x16, block_y, block_x); + + for (coeff_ctr = 0;coeff_ctr < 16;coeff_ctr++) + { + i = pos_scan[coeff_ctr][0]; + j = pos_scan[coeff_ctr][1]; + + run++; + ilev=0; + + // decide prediction + + // case 1 + level1 = (iabs (currSlice->tblk16x16[j+block_y][i+block_x]) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp; + level1 = (level1 << q_bits_sp) / quant_params_sp[j][i].ScaleComp; + c_err1 = mb_rres[j+block_y][i+block_x] - isignab(level1, currSlice->tblk16x16[j+block_y][i+block_x]); + level1 = (iabs (c_err1) * q_params_4x4[j][i].ScaleComp + qp_const) >> q_bits; + + // case 2 + c_err2 = mb_rres[j+block_y][i+block_x] - currSlice->tblk16x16[j+block_y][i+block_x]; + level2 = (iabs (c_err2) * q_params_4x4[j][i].ScaleComp + qp_const) >> q_bits; + + // select prediction + if ((level1 != level2) && (level1 != 0) && (level2 != 0)) + { + D_dis1 = mb_rres[j+block_y][i+block_x] - + ((isignab(level1,c_err1) * (q_params_4x4[j][i].InvScaleComp >> 4) * A[j][i]<< qp_per) >>6) + - currSlice->tblk16x16[j+block_y][i+block_x]; + levrun_linfo_inter(level1, run, &len, &info); + D_dis1 = D_dis1 * D_dis1 + lambda_mode * len; + + D_dis2 = mb_rres[j+block_y][i+block_x] - + ((isignab(level2,c_err2)* (q_params_4x4[j][i].InvScaleComp >> 4)* A[j][i]<< qp_per) >>6) + - currSlice->tblk16x16[j+block_y][i+block_x]; + levrun_linfo_inter(level2, run, &len, &info); + D_dis2 = D_dis2 * D_dis2 + lambda_mode * len; + + if (D_dis1 == D_dis2) + level = (iabs(level1) < iabs(level2)) ? level1 : level2; + else if (D_dis1 < D_dis2) + level = level1; + else + level = level2; + + c_err = (level == level1) ? c_err1 : c_err2; + } + else if (level1 == level2) + { + level = level1; + c_err = c_err1; + } + else + { + level = (level1 == 0) ? level1 : level2; + c_err = (level1 == 0) ? c_err1 : c_err2; + } + + if (level != 0) + { + nonzero = TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level,c_err); + ACLevel[scan_pos] = level; + ACRun [scan_pos] = run; + ++scan_pos; + run=-1; // reset zero level counter + ilev=((level * (q_params_4x4[j][i].InvScaleComp >> 4)* A[j][i] << qp_per) >>6); + } + + ilev += currSlice->tblk16x16[j+block_y][i+block_x]; + + if(currSlice->slice_type != SI_SLICE && !p_Vid->sp2_frame_indicator)//stores the SP frame coefficients in p_Vid->lrec, will be useful to encode these and create SI or SP switching frame + { + p_Vid->lrec[currMB->pix_y+block_y+j][currMB->pix_x+block_x+i]= + isignab((iabs(ilev) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp, ilev); + } + + // Yrec Qs and DeQs + mb_rres[j+block_y][i+block_x] = isignab((iabs(ilev) * quant_params_sp[j][i].ScaleComp + qp_const2)>> q_bits_sp, ilev) * (quant_params_sp[j][i].InvScaleComp >> 4) << qp_per_sp; + } + ACLevel[scan_pos] = 0; + + // inverse transform + inverse4x4(mb_rres, mb_rres, block_y, block_x); + // inverse4x4(currSlice->tblk16x16, mb_rres, 0, 0); + + + for (j=block_y; j < block_y+BLOCK_SIZE; ++j) + { + for (i=block_x; i < block_x+BLOCK_SIZE; ++i) + { + //printf("%d ",mb_rres[j][i]); + mb_rres[j][i] = iClip1 (p_Vid->max_imgpel_value, rshift_rnd_sf(mb_rres[j][i], DQ_BITS)); + //printf("%d\n",mb_rres[j][i]); + } + } + + // Decoded block moved to frame memory + for (j=0; j < BLOCK_SIZE; ++j) + { + for (i=0; i < BLOCK_SIZE; ++i) + { + img_enc[currMB->pix_y+block_y+j][currMB->pix_x+block_x+i]= (imgpel) mb_rres[block_y+j][block_x+i]; + + //printf("%d\n",mb_rres[j][i]); + } + } + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Transform,quantization,inverse transform for chroma. + * The main reason why this is done in a separate routine is the + * additional 2x2 transform of DC-coeffs. This routine is called + * once for each of the chroma components. + * + * \par Input: + * uv : Make difference between the U and V chroma component + * cr_cbp: chroma coded block pattern + * + * \par Output: + * cr_cbp: Updated chroma coded block pattern. + ************************************************************************ + */ +int residual_transform_quant_chroma_4x4_sp(Macroblock *currMB, int uv,int cr_cbp) +{ + int i,j,ilev,n2,n1,coeff_ctr,c_err,level ,scan_pos,run; + int m1[BLOCK_SIZE]; + int coeff_cost; + int cr_cbp_tmp; + int mp1[BLOCK_SIZE]; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + const byte *c_cost = COEFF_COST4x4[currSlice->disthres]; + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + + int intra = IS_INTRA (currMB); + + int b4; + int* DCLevel = currSlice->cofDC[uv+1][0]; + int* DCRun = currSlice->cofDC[uv+1][1]; + + int c_err1, c_err2, level1, level2; + int len, info; + double D_dis1, D_dis2; + double lambda_mode = 0.85 * pow (2, (currMB->qp -SHIFT_QP)/3.0) * 4; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + int qpChroma = currMB->qpc[uv] + currSlice->bitdepth_chroma_qp_scale; + int qpc_sp = iClip3(-currSlice->bitdepth_chroma_qp_scale, 51, currMB->qpsp + p_Vid->active_pps->chroma_qp_index_offset); + int qpChromaSP = qpc_sp < 0 ? qpc_sp : QP_SCALE_CR[qpc_sp]; + + int **mb_rres = currSlice->mb_rres[uv + 1]; + int **mb_ores = currSlice->mb_ores[uv + 1]; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + + QuantMethods quant_methods; + QuantParameters *p_Quant = p_Vid->p_Quant; + + int qp_per = p_Quant->qp_per_matrix[qpChroma]; + int q_bits = Q_BITS + qp_per; + int qp_const = (1<qp_per_matrix[qpChromaSP]; + int q_bits_sp = Q_BITS + qp_per_sp; + int qp_const2 = (1<>1; //sp_pred + + LevelQuantParams **q_params_4x4 = p_Quant->q_params_4x4[uv + 1][intra][qpChroma]; + + LevelQuantParams **quant_params_sp = p_Quant->q_params_4x4[uv + 1][intra][qpChromaSP]; + + quant_methods.type = CHROMA_AC; + + for (j=0; j < p_Vid->mb_cr_size_y; ++j) + { + for (i=0; i < p_Vid->mb_cr_size_x; ++i) + { + mb_rres[j][i] = mb_ores[j][i]; + mb_rres[j][i] += mb_pred[j][i]; + currSlice->tblk16x16[j][i] = mb_pred[j][i]; + } + } + + for (n2=0; n2 < p_Vid->mb_cr_size_y; n2 += BLOCK_SIZE) + { + for (n1=0; n1 < p_Vid->mb_cr_size_x; n1 += BLOCK_SIZE) + { + forward4x4(mb_rres, mb_rres, n2, n1); + forward4x4(currSlice->tblk16x16, currSlice->tblk16x16, n2, n1); + } + } + + // 2X2 transform of DC coeffs. + hadamard2x2(mb_rres, m1); + hadamard2x2(currSlice->tblk16x16, mp1); + + run=-1; + scan_pos=0; + + for (coeff_ctr = 0; coeff_ctr < 4; coeff_ctr++) + { + run++; + ilev=0; + + // case 1 + c_err1 = (iabs (mp1[coeff_ctr]) * quant_params_sp[0][0].ScaleComp + 2 * qp_const2) >> (q_bits_sp + 1); + c_err1 = (c_err1 << (q_bits_sp + 1)) / quant_params_sp[0][0].ScaleComp; + c_err1 = m1[coeff_ctr] - isignab(c_err1, mp1[coeff_ctr]); + level1 = (iabs(c_err1) * q_params_4x4[0][0].ScaleComp + 2 * qp_const) >> (q_bits+1); + + // case 2 + c_err2 = m1[coeff_ctr] - mp1[coeff_ctr]; + level2 = (iabs(c_err2) * q_params_4x4[0][0].ScaleComp + 2 * qp_const) >> (q_bits+1); + + if (level1 != level2 && level1 != 0 && level2 != 0) + { + D_dis1 = m1[coeff_ctr] - ((isignab(level1,c_err1)* (q_params_4x4[0][0].InvScaleComp >> 4) * A[0][0]<< qp_per) >>5)- mp1[coeff_ctr]; + levrun_linfo_c2x2(level1, run, &len, &info); + D_dis1 = D_dis1 * D_dis1 + lambda_mode * len; + + D_dis2 = m1[coeff_ctr] - ((isignab(level2,c_err2)* (q_params_4x4[0][0].InvScaleComp >> 4) * A[0][0]<< qp_per) >>5)- mp1[coeff_ctr]; + levrun_linfo_c2x2(level2, run, &len, &info); + D_dis2 = D_dis2 * D_dis2 + lambda_mode * len; + + if (D_dis1 == D_dis2) + level = (iabs(level1) < iabs(level2)) ? level1 : level2; + else if (D_dis1 < D_dis2) + level = level1; + else + level = level2; + + c_err = (level == level1) ? c_err1 : c_err2; + } + else if (level1 == level2) + { + level = level1; + c_err = c_err1; + } + else + { + level = (level1 == 0) ? level1 : level2; + c_err = (level1 == 0) ? c_err1 : c_err2; + } + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + currMB->cbp_blk |= 0xf0000 << (uv << 2) ; // if one of the 2x2-DC levels is != 0 the coded-bit + cr_cbp = imax(1, cr_cbp); + DCLevel[scan_pos ] = isignab(level ,c_err); + DCRun [scan_pos++] = run; + run=-1; + ilev=((isignab(level,c_err)* (q_params_4x4[0][0].InvScaleComp*A[0][0] >> 4) << qp_per) >>5); + } + + ilev+= mp1[coeff_ctr]; + m1[coeff_ctr]=isignab((iabs(ilev) * quant_params_sp[0][0].ScaleComp + 2 * qp_const2) >> (q_bits_sp+1), ilev) * (quant_params_sp[0][0].InvScaleComp >> 4) << qp_per_sp; + if(currSlice->slice_type != SI_SLICE && !p_Vid->sp2_frame_indicator) + p_Vid->lrec_uv[uv][currMB->pix_c_y + 4*(coeff_ctr & 0x01)][currMB->pix_c_x + 4*(coeff_ctr>>1)]=isignab((iabs(ilev) * quant_params_sp[0][0].ScaleComp + 2 * qp_const2) >> (q_bits_sp+1), ilev);// stores the SP frames coefficients, will be useful to encode SI or switching SP frame + } + DCLevel[scan_pos] = 0; + + // Inverse transform of 2x2 DC levels + ihadamard2x2(m1, m1); + + mb_rres[0][0]=(m1[0])>>1; + mb_rres[0][4]=(m1[1])>>1; + mb_rres[4][0]=(m1[2])>>1; + mb_rres[4][4]=(m1[3])>>1; + + // Quant of chroma AC-coeffs. + coeff_cost=0; + cr_cbp_tmp=0; + + for (n2=0; n2 <= BLOCK_SIZE; n2 += BLOCK_SIZE) + { + for (n1=0; n1 <= BLOCK_SIZE; n1 += BLOCK_SIZE) + { + b4 = 2*(n2 >> 2) + (n1 >> 2); + quant_methods.ACLevel = currSlice->cofAC[uv+4][b4][0]; + quant_methods.ACRun = currSlice->cofAC[uv+4][b4][1]; + + run = -1; + scan_pos = 0; + + for (coeff_ctr=1; coeff_ctr < 16; coeff_ctr++)// start change rd_quant + { + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + ++run; + ilev=0; + + // quantization on prediction + c_err1 = (iabs(currSlice->tblk16x16[n2+j][n1+i]) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp; + c_err1 = (c_err1 << q_bits_sp) / quant_params_sp[j][i].ScaleComp; + c_err1 = mb_rres[n2+j][n1+i] - isignab(c_err1, currSlice->tblk16x16[n2+j][n1+i]); + level1 = (iabs(c_err1) * q_params_4x4[j][i].ScaleComp + qp_const) >> q_bits; + + // no quantization on prediction + c_err2 = mb_rres[n2+j][n1+i] - currSlice->tblk16x16[n2+j][n1+i]; + level2 = (iabs(c_err2) * q_params_4x4[j][i].ScaleComp + qp_const) >> q_bits; + + if (level1 != level2 && level1 != 0 && level2 != 0) + { + D_dis1 = mb_rres[n2+j][n1+i] - ((isignab(level1,c_err1) * (q_params_4x4[j][i].InvScaleComp >> 4) * A[j][i]<< qp_per) >>6) - currSlice->tblk16x16[n2+j][n1+i]; + + levrun_linfo_inter(level1, run, &len, &info); + D_dis1 = D_dis1 * D_dis1 + lambda_mode * len; + + D_dis2 = mb_rres[n2+j][n1+i] - ((isignab(level2,c_err2)* (q_params_4x4[j][i].InvScaleComp*A[j][i] >> 4) << qp_per) >>6) - currSlice->tblk16x16[n2+j][n1+i]; + levrun_linfo_inter(level2, run, &len, &info); + D_dis2 = D_dis2 * D_dis2 + lambda_mode * len; + + if (D_dis1 == D_dis2) + level = (iabs(level1) < iabs(level2)) ? level1 : level2; + else + { + if (D_dis1 < D_dis2) + level = level1; + else + level = level2; + } + c_err = (level == level1) ? c_err1 : c_err2; + } + else if (level1 == level2) + { + level = level1; + c_err = c_err1; + } + else + { + level = (level1 == 0) ? level1 : level2; + c_err = (level1 == 0) ? c_err1 : c_err2; + } + + if (level != 0) + { + currMB->cbp_blk |= (int64)1 << (16 + (uv << 2) + ((n2 >> 1) + (n1 >> 2))) ; + + coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; // set high cost, shall not be discarded + + cr_cbp_tmp=2; + level = isignab(level,c_err); + quant_methods.ACLevel[scan_pos] = level; + quant_methods.ACRun [scan_pos] = run; + ++scan_pos; + run=-1; + ilev=((level * (q_params_4x4[j][i].InvScaleComp*A[j][i] >> 4) << qp_per) >>6); + } + ilev+=currSlice->tblk16x16[n2+j][n1+i]; + if(currSlice->slice_type != SI_SLICE && !p_Vid->sp2_frame_indicator) + if(!( ((n2+j) & 0x03)==0 && ((n1+i) & 0x03) ==0 )) + p_Vid->lrec_uv[uv][currMB->pix_c_y + n2+j][currMB->pix_c_x + n1 + i]=isignab((iabs(ilev) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp,ilev);//stores the SP frames coefficients, will be useful to encode SI or switching SP frame + mb_rres[n2+j][n1+i] = isignab((iabs(ilev) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp,ilev) * (quant_params_sp[j][i].InvScaleComp >> 4) << qp_per_sp; + } + quant_methods.ACLevel[scan_pos] = 0; + } + } + + // * reset chroma coeffs + + if(cr_cbp_tmp==2) + cr_cbp=2; + + // inverse transform. + // Horizontal. + for (n2=0; n2 <= BLOCK_SIZE; n2 += BLOCK_SIZE) + { + for (n1=0; n1 <= BLOCK_SIZE; n1 += BLOCK_SIZE) + { + inverse4x4(mb_rres, mb_rres, n2, n1); + + for (j=0; j < BLOCK_SIZE; ++j) + for (i=0; i < BLOCK_SIZE; ++i) + { + mb_rres[n2+j][n1+i] = iClip1 (max_imgpel_value_uv,rshift_rnd_sf(mb_rres[n2+j][n1+i], DQ_BITS)); + } + } + } + + // Decoded block moved to memory + for (j=0; j < BLOCK_SIZE*2; ++j) + for (i=0; i < BLOCK_SIZE*2; ++i) + { + p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y + j][currMB->pix_c_x + i]= (imgpel) mb_rres[j][i]; + } + + return cr_cbp; +} + + +/*! + ************************************************************************ + * \brief + * The routine performs transform,quantization,inverse transform, adds the diff. + * to the prediction and writes the result to the decoded luma frame. Includes the + * RD constrained quantization also. + * + * \par Input: + * block_x,block_y: Block position inside a macro block (0,4,8,12). + * + * \par Output: + * nonzero: 0 if no levels are nonzero. 1 if there are nonzero levels. \n + * coeff_cost: Counter for nonzero coefficients, used to discard expensive levels. + ************************************************************************ + */ +void copyblock_sp(Macroblock *currMB, ColorPlane pl, int block_x,int block_y) +{ + int i, j; + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + int cur_qp = currMB->qpsp + p_Vid->bitdepth_luma_qp_scale; + int qp_per = p_Quant->qp_per_matrix[cur_qp]; + int q_bits = Q_BITS + qp_per; + int qp_const2 = (1 << q_bits) >> 1; //sp_pred + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + + LevelQuantParams **q_params_4x4 = p_Quant->q_params_4x4[pl][0][cur_qp]; + + // Horizontal transform + for (j=0; j< BLOCK_SIZE; ++j) + { + for (i=0; i< BLOCK_SIZE; ++i) + { + mb_rres[j][i] = mb_ores[j+block_y][i+block_x]; + currSlice->tblk16x16[j][i]=mb_pred[j+block_y][i+block_x]; + } + } + + forward4x4(currSlice->tblk16x16, currSlice->tblk16x16, 0, 0); + + // Quant + for (j=0;j < BLOCK_SIZE; ++j) + { + for (i=0; i < BLOCK_SIZE; ++i) + { + mb_rres[j][i]=isignab((iabs(currSlice->tblk16x16[j][i])* q_params_4x4[j][i].ScaleComp+qp_const2)>> q_bits, + currSlice->tblk16x16[j][i]) * (q_params_4x4[j][i].InvScaleComp >> 4) <slice_type != SI_SLICE && !p_Vid->sp2_frame_indicator) + { + p_Vid->lrec[currMB->pix_y+block_y+j][currMB->pix_x+block_x+i] = + isignab((iabs(currSlice->tblk16x16[j][i]) * q_params_4x4[j][i].ScaleComp + qp_const2) >> q_bits, currSlice->tblk16x16[j][i]);// stores the SP frames coefficients, will be useful to encode SI or switching SP frame + } + } + } + + // inverse transform. + // horizontal + inverse4x4(mb_rres, mb_rres, 0, 0); + + // Decoded block moved to frame memory + for (j=0; j < BLOCK_SIZE; ++j) + { + for (i=0; i < BLOCK_SIZE; ++i) + { + mb_rres[j][i] = iClip1 (p_Vid->max_imgpel_value, rshift_rnd_sf(mb_rres[j][i], DQ_BITS)); + img_enc[currMB->pix_y+block_y+j][currMB->pix_x+block_x+i]=(imgpel) mb_rres[j][i]; + } + } + +} + +/*! + ************************************************************************ + * \brief Eric Setton + * Encoding of a secondary SP / SI frame. + * For an SI frame the predicted block should only come from spatial pred. + * The original image signal is the error coefficients of a primary SP in the raw data stream + * the difference with the primary SP are : + * - the prediction signal is transformed and quantized (qpsp) but not dequantized + * - only one kind of prediction is considered and not two + * - the resulting error coefficients are not quantized before being sent to the VLC + * + * \par Input: + * block_x,block_y: Block position inside a macro block (0,4,8,12). + * + * \par Output: + * nonzero: 0 if no levels are nonzero. 1 if there are nonzero levels. + * coeff_cost: Counter for nonzero coefficients, used to discard expensive levels. + * + * + ************************************************************************ + */ + +int residual_transform_quant_luma_4x4_sp2(Macroblock *currMB, ColorPlane pl, int block_x,int block_y,int *coeff_cost, int intra) +{ + int i,j,ilev,coeff_ctr; + int level,scan_pos = 0,run = -1; + int nonzero = FALSE; + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + imgpel **mb_pred = currSlice->mb_pred[pl]; +// int **mb_ores = currSlice->mb_ores[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + int c_err,qp_const2; + + int pos_x = block_x >> BLOCK_SHIFT; + int pos_y = block_y >> BLOCK_SHIFT; + int b8 = 2*(pos_y >> 1) + (pos_x >> 1); + int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01); + const byte *c_cost = COEFF_COST4x4[currSlice->disthres]; + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + + int level1; + + //int qp = (currMB->qpsp); // should double check spec why these are equal + int qp_sp = (currMB->qpsp); + + //int qp_per = p_Quant->qp_per_matrix[qp]; + //int q_bits = Q_BITS + qp_per; + int qp_per_sp = p_Quant->qp_per_matrix[qp_sp]; + int q_bits_sp = Q_BITS + qp_per_sp; + + //LevelQuantParams **q_params_4x4 = p_Quant->q_params_4x4[pl][intra][qp]; + LevelQuantParams **quant_params_sp = p_Quant->q_params_4x4[pl][intra][qp_sp]; + QuantMethods quant_methods; + + quant_methods.ACLevel = currSlice->cofAC[b8][b4][0]; + quant_methods.ACRun = currSlice->cofAC[b8][b4][1]; + + //qp_const=(1<>1; //sp_pred + + for (j=0; j< BLOCK_SIZE; ++j) + { + for (i=0; i< BLOCK_SIZE; ++i) + { + //Coefficients obtained from the prior encoding of the SP frame + mb_rres[j][i] = p_Vid->lrec[currMB->pix_y+block_y+j][currMB->pix_x+block_x+i]; + //Predicted block + currSlice->tblk16x16[j][i]=mb_pred[j+block_y][i+block_x]; + } + } + // forward transform + forward4x4(currSlice->tblk16x16, currSlice->tblk16x16, 0, 0); + + for (coeff_ctr=0;coeff_ctr < 16;coeff_ctr++) // 8 times if double scan, 16 normal scan + { + + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + run++; + ilev=0; + + //quantization of the predicted block + level1 = (iabs (currSlice->tblk16x16[j][i]) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp; + //substracted from p_Vid->lrec + c_err = mb_rres[j][i]-isignab(level1, currSlice->tblk16x16[j][i]); //substracting the predicted block + + level = iabs(c_err); + if (level != 0) + { + nonzero=TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + quant_methods.ACLevel[scan_pos] = isignab(level,c_err); + quant_methods.ACRun [scan_pos] = run; + ++scan_pos; + run=-1; // reset zero level counter + } + //from now on we are in decoder land + ilev=c_err + isignab(level1,currSlice->tblk16x16[j][i]) ; // adding the quantized predicted block + mb_rres[j][i] = ilev * (quant_params_sp[j][i].InvScaleComp >> 4) << qp_per_sp; + } + quant_methods.ACLevel[scan_pos] = 0; + + // Inverse transform + inverse4x4(mb_rres, mb_rres, 0, 0); + + for (j=0; j < BLOCK_SIZE; ++j) + { + for (i=0; i < BLOCK_SIZE; ++i) + { + img_enc[currMB->pix_y+block_y+j][currMB->pix_x+block_x+i] = (imgpel) iClip3 (0, p_Vid->max_imgpel_value,rshift_rnd_sf(mb_rres[j][i], DQ_BITS)); + } + } + + return nonzero; +} + + +/*! + ************************************************************************ + * \brief Eric Setton + * Encoding of the chroma of a secondary SP / SI frame. + * For an SI frame the predicted block should only come from spatial pred. + * The original image signal is the error coefficients of a primary SP in the raw data stream + * the difference with the primary SP are : + * - the prediction signal is transformed and quantized (qpsp) but not dequantized + * - the resulting error coefficients are not quantized before being sent to the VLC + * + * \par Input: + * uv : Make difference between the U and V chroma component + * cr_cbp: chroma coded block pattern + * + * \par Output: + * cr_cbp: Updated chroma coded block pattern. + * + ************************************************************************ + */ +int residual_transform_quant_chroma_4x4_sp2(Macroblock *currMB, int uv,int cr_cbp) +{ + int i,j,ilev,n2,n1,coeff_ctr,c_err,level ,scan_pos = 0,run = -1; + int m1[BLOCK_SIZE]; + int coeff_cost; + int cr_cbp_tmp; + int mp1[BLOCK_SIZE]; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + QuantMethods quant_methods; + const byte *c_cost = COEFF_COST4x4[currSlice->disthres]; + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN; + + int b4; + int* DCLevel = currSlice->cofDC[uv+1][0]; + int* DCRun = currSlice->cofDC[uv+1][1]; + int level1; + int **mb_rres = currSlice->mb_rres[uv + 1]; + //int **mb_ores = currSlice->mb_ores[uv + 1]; + imgpel **mb_pred = currSlice->mb_pred[uv + 1]; + int intra = IS_INTRA (currMB); + + int qpChroma = currMB->qpc[uv] + currSlice->bitdepth_chroma_qp_scale; + + int qpc_sp = iClip3(-currSlice->bitdepth_chroma_qp_scale, 51, currMB->qpsp + p_Vid->active_pps->chroma_qp_index_offset); + + int qpChromaSP = qpc_sp < 0 ? qpc_sp : QP_SCALE_CR[qpc_sp]; + + int qp_per = p_Quant->qp_per_matrix[qpChroma]; + //int qp_rem = p_Quant->qp_rem_matrix[qpChroma]; + + int qp_per_sp = p_Quant->qp_per_matrix[qpChromaSP]; + int q_bits_sp = Q_BITS + qp_per; + int qp_const2 = (1 << q_bits_sp)>>1; //sp_pred + + //LevelQuantParams **q_params_4x4 = p_Quant->q_params_4x4[uv + 1][intra][qpChroma]; + LevelQuantParams **quant_params_sp = p_Quant->q_params_4x4[uv + 1][intra][qpChromaSP]; + + for (j=0; j < MB_BLOCK_SIZE>>1; ++j) + { + for (i=0; i < MB_BLOCK_SIZE>>1; ++i) + { + currSlice->tblk16x16[j][i]=mb_pred[j][i]; + mb_rres[j][i]=p_Vid->lrec_uv[uv][currMB->pix_c_y + j][currMB->pix_c_x + i]; + } + } + + + for (n2=0; n2 <= BLOCK_SIZE; n2 += BLOCK_SIZE) + { + for (n1=0; n1 <= BLOCK_SIZE; n1 += BLOCK_SIZE) + { + forward4x4(currSlice->tblk16x16, currSlice->tblk16x16, n2, n1); + } + } + + // DC coefficients already transformed and quantized + m1[0]= mb_rres[0][0]; + m1[1]= mb_rres[0][4]; + m1[2]= mb_rres[4][0]; + m1[3]= mb_rres[4][4]; + + // 2X2 transform of predicted DC coeffs. + hadamard2x2(currSlice->tblk16x16, mp1); + + for (coeff_ctr=0; coeff_ctr < 4; coeff_ctr++) + { + run++; + ilev=0; + + //quantization of predicted DC coeff + level1 = (iabs (mp1[coeff_ctr]) * quant_params_sp[0][0].ScaleComp + 2 * qp_const2) >> (q_bits_sp + 1); + //substratcted from lrecUV + c_err = m1[coeff_ctr] - isignab(level1, mp1[coeff_ctr]); + level = iabs(c_err); + + if (level != 0) + { + currMB->cbp_blk |= 0xf0000 << (uv << 2) ; // if one of the 2x2-DC levels is != 0 the coded-bit + cr_cbp=imax(1,cr_cbp); + DCLevel[scan_pos] = isignab(level ,c_err); + DCRun [scan_pos] = run; + scan_pos++; + run=-1; + } + + //from now on decoder world + ilev = c_err + isignab(level1,mp1[coeff_ctr]) ; // we have perfect reconstruction here + + m1[coeff_ctr]= ilev * (quant_params_sp[0][0].InvScaleComp >> 4) << qp_per_sp; + + } + DCLevel[scan_pos] = 0; + + // Inverse transform of 2x2 DC levels + ihadamard2x2(m1, m1); + + mb_rres[0][0]=m1[0]>>1; + mb_rres[0][4]=m1[1]>>1; + mb_rres[4][0]=m1[2]>>1; + mb_rres[4][4]=m1[3]>>1; + + // Quant of chroma AC-coeffs. + coeff_cost=0; + cr_cbp_tmp=0; + + for (n2=0; n2 <= BLOCK_SIZE; n2 += BLOCK_SIZE) + { + for (n1=0; n1 <= BLOCK_SIZE; n1 += BLOCK_SIZE) + { + b4 = 2*(n2 >> 2) + (n1 >> 2); + quant_methods.ACLevel = currSlice->cofAC[uv+4][b4][0]; + quant_methods.ACRun = currSlice->cofAC[uv+4][b4][1]; + + run = -1; + scan_pos = 0; + + for (coeff_ctr=1; coeff_ctr < 16; coeff_ctr++)// start change rd_quant + { + + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + ++run; + ilev=0; + // quantization on prediction + level1 = (iabs(currSlice->tblk16x16[n2+j][n1+i]) * quant_params_sp[j][i].ScaleComp + qp_const2) >> q_bits_sp; + //substracted from p_Vid->lrec + c_err = mb_rres[n2+j][n1+i] - isignab(level1, currSlice->tblk16x16[n2+j][n1+i]); + level = iabs(c_err) ; + + if (level != 0) + { + currMB->cbp_blk |= (int64)1 << (16 + (uv << 2) + ((n2 >> 1) + (n1 >> 2))) ; + + coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + cr_cbp_tmp=2; + quant_methods.ACLevel[scan_pos] = isignab(level,c_err); + quant_methods.ACRun [scan_pos] = run; + ++scan_pos; + run=-1; + } + + //from now on decoder land + ilev=c_err + isignab(level1,currSlice->tblk16x16[n2+j][n1+i]); + mb_rres[n2+j][n1+i] = ilev * (quant_params_sp[j][i].InvScaleComp >> 4) << qp_per_sp; + } + quant_methods.ACLevel[scan_pos] = 0; + } + } + // * reset chroma coeffs + + if(cr_cbp_tmp==2) + cr_cbp=2; + + // inverse transform. + // Horizontal. + for (n2=0; n2 <= BLOCK_SIZE; n2 += BLOCK_SIZE) + { + for (n1=0; n1 <= BLOCK_SIZE; n1 += BLOCK_SIZE) + { + inverse4x4(mb_rres, mb_rres, n2, n1); + + // Vertical. + for (j=0; j < BLOCK_SIZE; ++j) + { + for (i=0; i < BLOCK_SIZE; ++i) + { + p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y + j + n2][currMB->pix_c_x + i + n1 ] = + (imgpel) iClip3 (0, p_Vid->max_imgpel_value,rshift_rnd_sf(mb_rres[n2+j][n1+i], DQ_BITS)); + } + } + } + } + + return cr_cbp; +} + + +void select_transform(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + { + VideoParameters *p_Vid = currMB->p_Vid; + if (p_Vid->active_sps->lossless_qpprime_flag == 1) + { + if (currMB->qp_scaled[(short) p_Vid->colour_plane_id] == 0) + { + currMB->residual_transform_quant_luma_4x4 = residual_transform_quant_luma_4x4_ls; + currMB->residual_transform_quant_luma_16x16 = residual_transform_quant_luma_16x16_ls; + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8_ls; + } + else + { + currMB->residual_transform_quant_luma_4x4 = residual_transform_quant_luma_4x4; + currMB->residual_transform_quant_luma_16x16 = residual_transform_quant_luma_16x16; + if (currSlice->symbol_mode == CAVLC) + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8_cavlc; + else + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8; + currMB->residual_transform_quant_chroma_4x4[0] = residual_transform_quant_chroma_4x4; + currMB->residual_transform_quant_chroma_4x4[1] = residual_transform_quant_chroma_4x4; + } + + if (currMB->qp_scaled[PLANE_U] == 0) + { + currMB->residual_transform_quant_chroma_4x4[0] = residual_transform_quant_chroma_4x4_ls; + } + if (currMB->qp_scaled[PLANE_V] == 0) + { + currMB->residual_transform_quant_chroma_4x4[1] = residual_transform_quant_chroma_4x4_ls; + } + } + else + { + currMB->residual_transform_quant_luma_4x4 = residual_transform_quant_luma_4x4; + currMB->residual_transform_quant_luma_16x16 = residual_transform_quant_luma_16x16; + if (currSlice->symbol_mode == CAVLC) + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8_cavlc; + else + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8; + + currMB->residual_transform_quant_chroma_4x4[0] = residual_transform_quant_chroma_4x4; + currMB->residual_transform_quant_chroma_4x4[1] = residual_transform_quant_chroma_4x4; + } + } + else if(currSlice->slice_type != SI_SLICE && !currSlice->sp2_frame_indicator) + { + currMB->residual_transform_quant_luma_4x4 = residual_transform_quant_luma_4x4_sp; + currMB->residual_transform_quant_luma_16x16 = residual_transform_quant_luma_16x16; + if (currSlice->symbol_mode == CAVLC) + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8_cavlc; + else + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8; + + currMB->residual_transform_quant_chroma_4x4[0] = residual_transform_quant_chroma_4x4_sp; + currMB->residual_transform_quant_chroma_4x4[1] = residual_transform_quant_chroma_4x4_sp; + } + else + { + currMB->residual_transform_quant_luma_4x4 = residual_transform_quant_luma_4x4_sp2; + currMB->residual_transform_quant_luma_16x16 = residual_transform_quant_luma_16x16; + if (currSlice->symbol_mode == CAVLC) + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8_cavlc; + else + currMB->residual_transform_quant_luma_8x8 = residual_transform_quant_luma_8x8; + + currMB->residual_transform_quant_chroma_4x4[0] = residual_transform_quant_chroma_4x4_sp2; + currMB->residual_transform_quant_chroma_4x4[1] = residual_transform_quant_chroma_4x4_sp2; + } +} diff --git a/lencod/src/cabac.c b/lencod/src/cabac.c new file mode 100644 index 0000000..9aa78d9 --- /dev/null +++ b/lencod/src/cabac.c @@ -0,0 +1,1879 @@ +/*! + ************************************************************************************* + * \file cabac.c + * + * \brief + * CABAC entropy coding routines + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + ************************************************************************************** + */ + +#include "global.h" + +#include "cabac.h" +#include "biariencode.h" +#include "image.h" +#include "mb_access.h" + +#if TRACE + #define CABAC_TRACE if (dp->bitstream->trace_enabled) trace2out_cabac (se) +#else + #define CABAC_TRACE +#endif + +/*********************************************************************** + Constant declarations +*********************************************************************** +*/ + + + +//===== position -> ctx for MAP ===== +//--- zig-zag scan ---- +static const byte pos2ctx_map8x8 [] = { + 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 3, 3, 6, 7, 7, 7, 8, 9, 10, 9, 8, 7, + 7, 6, 11, 12, 13, 11, 6, 7, 8, 9, 14, 10, 9, 8, 6, 11, + 12, 13, 11, 6, 9, 14, 10, 9, 11, 12, 13, 11 ,14, 10, 12, 14 +}; // 15 CTX + +static const byte pos2ctx_map8x4 [] = { + 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 9, 8, 6, 7, 8, + 9, 10, 11, 9, 8, 6, 12, 8, 9, 10, 11, 9, 13, 13, 14, 14 +}; // 15 CTX + +static const byte pos2ctx_map4x4 [] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14 +}; // 15 CTX + +static const byte pos2ctx_map2x4c[] = { + 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +}; // 15 CTX + +static const byte pos2ctx_map4x4c[] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 +}; // 15 CTX + +const byte* pos2ctx_map [] = { + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8, pos2ctx_map8x4, + pos2ctx_map8x4, pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map4x4, + pos2ctx_map2x4c, pos2ctx_map4x4c, + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8,pos2ctx_map8x4, + pos2ctx_map8x4, pos2ctx_map4x4, //Cb component + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8,pos2ctx_map8x4, + pos2ctx_map8x4,pos2ctx_map4x4 //Cr component +}; + +//--- interlace scan ---- +//Taken from ABT +static const byte pos2ctx_map8x8i[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 8, 4, 5, + 6, 9, 10, 10, 8, 11, 12, 11, 9, 9, 10, 10, 8, 11, 12, 11, + 9, 9, 10, 10, 8, 11, 12, 11, 9, 9, 10, 10, 8, 13, 13, 9, + 9, 10, 10, 8, 13, 13, 9, 9, 10, 10, 14, 14, 14, 14, 14, 14 +}; // 15 CTX + +static const byte pos2ctx_map8x4i[] = { + 0, 1, 2, 3, 4, 5, 6, 3, 4, 5, 6, 3, 4, 7, 6, 8, + 9, 7, 6, 8, 9, 10, 11, 12, 12, 10, 11, 13, 13, 14, 14, 14 +}; // 15 CTX + +static const byte pos2ctx_map4x8i[] = { + 0, 1, 1, 1, 2, 3, 3, 4, 4, 4, 5, 6, 2, 7, 7, 8, + 8, 8, 5, 6, 9, 10, 10, 11, 11, 11, 12, 13, 13, 14, 14, 14 +}; // 15 CTX + +const byte* pos2ctx_map_int[] = { + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8i,pos2ctx_map8x4i, + pos2ctx_map4x8i,pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map4x4, + pos2ctx_map2x4c, pos2ctx_map4x4c, + //444_TEMP_NOTE: the followings are addded for the 4:4:4 common mode}; + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8i,pos2ctx_map8x4i, + pos2ctx_map8x4i,pos2ctx_map4x4, //Cb component + pos2ctx_map4x4, pos2ctx_map4x4, pos2ctx_map8x8i,pos2ctx_map8x4i, + pos2ctx_map8x4i,pos2ctx_map4x4 //Cr component} +}; + + +//===== position -> ctx for LAST ===== +static const byte pos2ctx_last8x8 [] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8 +}; // 9 CTX + +static const byte pos2ctx_last8x4 [] = { + 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8 +}; // 9 CTX + +static const byte pos2ctx_last4x4 [] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; // 15 CTX + +static const byte pos2ctx_last2x4c[] = { + 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +}; // 15 CTX + +static const byte pos2ctx_last4x4c[] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 +}; // 15 CTX + +const byte* pos2ctx_last [] = { + pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last8x8, pos2ctx_last8x4, + pos2ctx_last8x4, pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last4x4, + pos2ctx_last2x4c, pos2ctx_last4x4c, + pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last8x8,pos2ctx_last8x4, + pos2ctx_last8x4, pos2ctx_last4x4, //Cb component + pos2ctx_last4x4, pos2ctx_last4x4, pos2ctx_last8x8,pos2ctx_last8x4, + pos2ctx_last8x4, pos2ctx_last4x4 //Cr component +}; + +/*********************************************************************** + * L O C A L L Y D E F I N E D F U N C T I O N P R O T O T Y P E S + *********************************************************************** + */ + + +/*! + ************************************************************************ + * \brief + * Exp Golomb binarization and encoding + ************************************************************************ + */ +static void exp_golomb_encode_eq_prob( EncodingEnvironmentPtr eep_dp, + unsigned int symbol, + int k) +{ + for(;;) + { + if (symbol >= (unsigned int)(1<>k)&1)); + break; + } + } +} + +/*! + ************************************************************************ + * \brief + * Unary binarization and encoding of a symbol by using + * one or two distinct models for the first two and all + * remaining bins + * + ************************************************************************/ +static void unary_bin_encode(EncodingEnvironmentPtr eep_dp, + unsigned int symbol, + BiContextTypePtr ctx, + int ctx_offset) +{ + if (symbol==0) + { + biari_encode_symbol(eep_dp, 0, ctx ); + return; + } + else + { + biari_encode_symbol(eep_dp, 1, ctx ); + ctx += ctx_offset; + while ((--symbol) > 0) + biari_encode_symbol(eep_dp, 1, ctx); + biari_encode_symbol(eep_dp, 0, ctx); + } +} + +/*! + ************************************************************************ + * \brief + * Unary binarization and encoding of a symbol by using + * one or two distinct models for the first two and all + * remaining bins; no terminating "0" for max_symbol + * (finite symbol alphabet) + ************************************************************************ + */ +static void unary_bin_max_encode(EncodingEnvironmentPtr eep_dp, + unsigned int symbol, + BiContextTypePtr ctx, + int ctx_offset, + unsigned int max_symbol) +{ + if (symbol==0) + { + biari_encode_symbol(eep_dp, 0, ctx ); + return; + } + else + { + unsigned int l = symbol; + biari_encode_symbol(eep_dp, 1, ctx ); + + ctx += ctx_offset; + while ((--l)>0) + biari_encode_symbol(eep_dp, 1, ctx); + if (symbol < max_symbol) + biari_encode_symbol(eep_dp, 0, ctx); + } +} + +/*! + ************************************************************************ + * \brief + * Exp-Golomb for Level Encoding +* +************************************************************************/ +static void unary_exp_golomb_level_encode( EncodingEnvironmentPtr eep_dp, + unsigned int symbol, + BiContextTypePtr ctx) +{ + if (symbol==0) + { + biari_encode_symbol(eep_dp, 0, ctx ); + return; + } + else + { + unsigned int l=symbol; + unsigned int k = 1; + + biari_encode_symbol(eep_dp, 1, ctx ); + while (((--l)>0) && (++k <= 13)) + biari_encode_symbol(eep_dp, 1, ctx); + if (symbol < 13) + biari_encode_symbol(eep_dp, 0, ctx); + else + exp_golomb_encode_eq_prob(eep_dp,symbol - 13, 0); + } +} + + +/*! + ************************************************************************ + * \brief + * Exp-Golomb for MV Encoding +* +************************************************************************/ +static void unary_exp_golomb_mv_encode(EncodingEnvironmentPtr eep_dp, + unsigned int symbol, + BiContextTypePtr ctx, + unsigned int max_bin) +{ + if (symbol==0) + { + biari_encode_symbol(eep_dp, 0, ctx ); + return; + } + else + { + unsigned int bin = 1; + unsigned int l = symbol, k = 1; + biari_encode_symbol(eep_dp, 1, ctx++ ); + + while (((--l)>0) && (++k <= 8)) + { + biari_encode_symbol(eep_dp, 1, ctx ); + if ((++bin) == 2) + ++ctx; + if (bin == max_bin) + ++ctx; + } + if (symbol < 8) + biari_encode_symbol(eep_dp, 0, ctx); + else + exp_golomb_encode_eq_prob(eep_dp, symbol - 8, 3); + } +} + +/*! + ************************************************************************ + * \brief + * Check for available neighbouring blocks + * and set pointers in current macroblock + ************************************************************************ + */ +void CheckAvailabilityOfNeighborsCABAC(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos up, left; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + p_Vid->getNeighbour(currMB, -1, 0, mb_size, &left); + p_Vid->getNeighbour(currMB, 0, -1, mb_size, &up); + + if (up.available) + currMB->mb_up = &p_Vid->mb_data[up.mb_addr]; + else + currMB->mb_up = NULL; + + if (left.available) + currMB->mb_left = &p_Vid->mb_data[left.mb_addr]; + else + currMB->mb_left = NULL; +} + +/*! + ************************************************************************ + * \brief + * Allocation of contexts models for the motion info + * used for arithmetic encoding + ************************************************************************ + */ +MotionInfoContexts* create_contexts_MotionInfo(void) +{ + MotionInfoContexts* enco_ctx; + + enco_ctx = (MotionInfoContexts*) calloc(1, sizeof(MotionInfoContexts) ); + if( enco_ctx == NULL ) + no_mem_exit("create_contexts_MotionInfo: enco_ctx"); + + return enco_ctx; +} + + +/*! + ************************************************************************ + * \brief + * Allocates of contexts models for the texture info + * used for arithmetic encoding + ************************************************************************ + */ +TextureInfoContexts* create_contexts_TextureInfo(void) +{ + TextureInfoContexts* enco_ctx = (TextureInfoContexts*) calloc(1, sizeof(TextureInfoContexts) ); + if( enco_ctx == NULL ) + no_mem_exit("create_contexts_TextureInfo: enco_ctx"); + + return enco_ctx; +} + +/*! + ************************************************************************ + * \brief + * Frees the memory of the contexts models + * used for arithmetic encoding of the motion info. + ************************************************************************ + */ +void delete_contexts_MotionInfo(MotionInfoContexts *enco_ctx) +{ + free_pointer( enco_ctx ); +} + +/*! + ************************************************************************ + * \brief + * Frees the memory of the contexts models + * used for arithmetic encoding of the texture info. + ************************************************************************ + */ +void delete_contexts_TextureInfo(TextureInfoContexts *enco_ctx) +{ + free_pointer( enco_ctx ); +} + + +/*! + *************************************************************************** + * \brief + * This function is used to arithmetically encode the field + * mode info of a given MB in the case of mb-based frame/field decision + *************************************************************************** + */ +void writeFieldModeInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + VideoParameters *p_Vid = currMB->p_Vid; + Macroblock *mb_data = p_Vid->mb_data; + + int a = currMB->mbAvailA ? mb_data[currMB->mbAddrA].mb_field : 0; + int b = currMB->mbAvailB ? mb_data[currMB->mbAddrB].mb_field : 0; + + int act_ctx = a + b; + +#if ENABLE_FIELD_CTX + TextureInfoContexts *ctx = dp->p_Slice->tex_ctx; + + biari_encode_symbol(eep_dp, (se->value1 != 0), &ctx->mb_aff_contexts[act_ctx]); +#endif + + se->context = act_ctx; + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! +*************************************************************************** +* \brief +* This function is used to arithmetically encode the mb_skip_flag. +*************************************************************************** +*/ +void writeMB_Pskip_flagInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + Slice *currSlice = currMB->p_Slice; + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + MotionInfoContexts *ctx = currSlice->mot_ctx; + int curr_mb_type = se->value1; + int a = (currMB->mb_left != NULL && (currMB->mb_left->skip_flag == 0)) ? 1 : 0; + int b = (currMB->mb_up != NULL && (currMB->mb_up ->skip_flag == 0)) ? 1 : 0; + int act_ctx = a + b; + + if (curr_mb_type==0) // SKIP + biari_encode_symbol(eep_dp, 1, &ctx->mb_type_contexts[1][act_ctx]); + else + biari_encode_symbol(eep_dp, 0, &ctx->mb_type_contexts[1][act_ctx]); + + currMB->skip_flag = (curr_mb_type==0) ? 1 : 0; + + se->context = act_ctx; + se->value1 = 1 - currMB->skip_flag; + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! +*************************************************************************** +* \brief +* This function is used to arithmetically encode the mb_skip_flag for B slices. +*************************************************************************** +*/ +void writeMB_Bskip_flagInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + Slice *currSlice = currMB->p_Slice; + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + MotionInfoContexts *ctx = currSlice->mot_ctx; + int a = (currMB->mb_left != NULL && (currMB->mb_left->skip_flag == 0)) ? 1 : 0; + int b = (currMB->mb_up != NULL && (currMB->mb_up ->skip_flag == 0)) ? 1 : 0; + int act_ctx = a + b; + + act_ctx += 7; + + if (se->value1==0 && se->value2==0) // DIRECT mode, no coefficients + biari_encode_symbol (eep_dp, 1, &ctx->mb_type_contexts[2][act_ctx]); + else + biari_encode_symbol (eep_dp, 0, &ctx->mb_type_contexts[2][act_ctx]); + + currMB->skip_flag = (se->value1==0 && se->value2==0) ? 1 : 0; + + se->context = act_ctx; + se->value1 = 1 - currMB->skip_flag; + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! +*************************************************************************** +* \brief +* This function is used to arithmetically encode the macroblock +* intra_pred_size flag info of a given MB. +*************************************************************************** +*/ + +void writeMB_transform_size_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + TextureInfoContexts *ctx = (dp->p_Slice)->tex_ctx; + + int curr_len = arienco_bits_written(eep_dp); + int act_sym = currMB->luma_transform_size_8x8_flag; + + + int b = (currMB->mb_up == NULL) ? 0 : currMB->mb_up->luma_transform_size_8x8_flag; + int a = (currMB->mb_left == NULL) ? 0 :currMB->mb_left->luma_transform_size_8x8_flag; + int act_ctx = a + b; + + se->context = act_ctx; // store context + biari_encode_symbol(eep_dp, (act_sym != 0), ctx->transform_size_contexts + act_ctx ); + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + *************************************************************************** + * \brief + * This function is used to arithmetically encode the macroblock + * type info of a given MB. + *************************************************************************** + */ + +void writeMB_P_typeInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + + BiContextType *mb_type_contexts = dp->p_Slice->mot_ctx->mb_type_contexts[1]; + + int act_ctx = 0; + int mode_sym = 0; + int act_sym = se->value1; + int mode16x16 = 7; + + if (act_sym >= mode16x16) + { + mode_sym = act_sym - mode16x16; + act_sym = mode16x16; // 16x16 mode info + } + + switch (act_sym) + { + case 0: + break; + case 1: + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[5]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[6]); + break; + case 2: + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[5]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[7]); + break; + case 3: + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[5]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[7]); + break; + case 4: + case 5: + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[5]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[6]); + break; + case 6: + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[7]); + break; + case 7: + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[7]); + break; + default: + printf ("Unsupported MB-MODE in writeMB_I_typeInfo_CABAC!\n"); + exit (1); + } + + if(act_sym == mode16x16) // additional info for 16x16 Intra-mode + { + if( mode_sym == 24 ) + { + biari_encode_symbol_final(eep_dp, 1 ); + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; + return; + } + biari_encode_symbol_final(eep_dp, 0 ); + + act_ctx = 8; + act_sym = mode_sym/12; + biari_encode_symbol(eep_dp, act_sym, mb_type_contexts + act_ctx ); // coding of AC/no AC + mode_sym = mode_sym % 12; + + act_sym = mode_sym >> 2; // coding of cbp: 0,1,2 + act_ctx = 9; + if (act_sym==0) + { + biari_encode_symbol(eep_dp, 0, mb_type_contexts + act_ctx ); + } + else + { + biari_encode_symbol(eep_dp, 1, mb_type_contexts + act_ctx ); + biari_encode_symbol(eep_dp, (act_sym!=1), mb_type_contexts + act_ctx ); + } + + mode_sym = mode_sym & 0x03; // coding of I pred-mode: 0,1,2,3 + act_ctx = 10; + act_sym = mode_sym >> 1; + biari_encode_symbol(eep_dp, act_sym, mb_type_contexts + act_ctx ); + act_sym = (mode_sym & 0x01); + biari_encode_symbol(eep_dp, act_sym, mb_type_contexts + act_ctx ); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + *************************************************************************** + * \brief + * This function is used to arithmetically encode the macroblock + * type info of a given MB in a B slice. + *************************************************************************** + */ + +void writeMB_B_typeInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + + int csym; + int act_sym = se->value1; + + int mode_sym = 0; + int mode16x16 = 24; + + MotionInfoContexts *ctx = dp->p_Slice->mot_ctx; + BiContextType *mb_type_contexts = ctx->mb_type_contexts[2]; + + int a = (currMB->mb_left == NULL) ? 0 : ((currMB->mb_left->mb_type != 0) ? 1 : 0 ); + int b = (currMB->mb_up == NULL) ? 0 : ((currMB->mb_up->mb_type != 0) ? 1 : 0 ); + int act_ctx = a + b; + se->context = act_ctx; // store context + + if (act_sym >= mode16x16) + { + mode_sym = act_sym - mode16x16; + act_sym = mode16x16; // 16x16 mode info + } + + if (act_sym==0) + { + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[act_ctx]); + } + else if (act_sym<=2) + { + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[act_ctx]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[4]); + csym = (act_sym-1 != 0); + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + } + else if (act_sym<=10) + { + int temp_sym = act_sym - 3; + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[act_ctx]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 0, &mb_type_contexts[5]); + csym = ((temp_sym >> 2)&0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + csym = ((temp_sym >> 1)&0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + csym = (temp_sym & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + } + else if (act_sym==11 || act_sym==22) + { + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[act_ctx]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[5]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[6]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[6]); + csym = (act_sym != 11); + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + } + else + { + int temp_sym = (act_sym > 22) ? act_sym - 13 : act_sym - 12; + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[act_ctx]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[4]); + biari_encode_symbol (eep_dp, 1, &mb_type_contexts[5]); + csym = ((temp_sym >> 3)&0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + csym = ((temp_sym >> 2)&0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + csym = ((temp_sym >> 1)&0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + csym = (temp_sym & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &mb_type_contexts[6]); + } + + + if(act_sym == mode16x16) // additional info for 16x16 Intra-mode + { + mb_type_contexts = ctx->mb_type_contexts[1]; + if( mode_sym == 24 ) + { + biari_encode_symbol_final(eep_dp, 1 ); + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; + return; + } + biari_encode_symbol_final(eep_dp, 0 ); + + act_ctx = 8; + act_sym = mode_sym/12; + biari_encode_symbol(eep_dp, act_sym, mb_type_contexts + act_ctx ); // coding of AC/no AC + mode_sym = mode_sym % 12; + + act_sym = mode_sym >> 2; // coding of cbp: 0,1,2 + act_ctx = 9; + if (act_sym==0) + { + biari_encode_symbol(eep_dp, 0, mb_type_contexts + act_ctx ); + } + else + { + biari_encode_symbol(eep_dp, 1, mb_type_contexts + act_ctx ); + biari_encode_symbol(eep_dp, (act_sym!=1), mb_type_contexts + act_ctx ); + } + + mode_sym = mode_sym & 0x03; // coding of I pred-mode: 0,1,2,3 + act_ctx = 10; + act_sym = mode_sym >> 1; + biari_encode_symbol(eep_dp, act_sym, mb_type_contexts + act_ctx ); + act_sym = (mode_sym & 0x01); + biari_encode_symbol(eep_dp, act_sym, mb_type_contexts + act_ctx ); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + *************************************************************************** + * \brief + * This function is used to arithmetically encode the macroblock + * type info of a given MB in an I Slice. + *************************************************************************** + */ +void writeMB_I_typeInfo_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + int a, b; + int act_ctx = 0; + int act_sym; + Slice *currSlice = dp->p_Slice; + int mode_sym = 0; + + MotionInfoContexts *ctx = currSlice->mot_ctx; + + if (currMB->mb_up == NULL) + b = 0; + else + b = ((currMB->mb_up->mb_type != I4MB && currMB->mb_up->mb_type != I8MB) ? 1 : 0 ); + + if (currMB->mb_left == NULL) + a = 0; + else + a = ((currMB->mb_left->mb_type != I4MB && currMB->mb_left->mb_type != I8MB) ? 1 : 0 ); + + act_ctx = a + b; + act_sym = se->value1; + se->context = act_ctx; // store context + + if (act_sym==0) // 4x4 Intra + { + biari_encode_symbol(eep_dp, 0, ctx->mb_type_contexts[0] + act_ctx ); + } + else if( act_sym == 25 ) // PCM-MODE + { + biari_encode_symbol(eep_dp, 1, ctx->mb_type_contexts[0] + act_ctx ); + biari_encode_symbol_final(eep_dp, 1); + } + else // 16x16 Intra + { + biari_encode_symbol(eep_dp, 1, ctx->mb_type_contexts[0] + act_ctx ); + + biari_encode_symbol_final(eep_dp, 0); + + mode_sym = act_sym-1; // Values in the range of 0...23 + act_ctx = 4; + act_sym = mode_sym/12; + biari_encode_symbol(eep_dp, act_sym, ctx->mb_type_contexts[0] + act_ctx ); // coding of AC/no AC + mode_sym = mode_sym % 12; + act_sym = mode_sym / 4; // coding of cbp: 0,1,2 + act_ctx = 5; + if (act_sym==0) + { + biari_encode_symbol(eep_dp, 0, ctx->mb_type_contexts[0] + act_ctx ); + } + else + { + biari_encode_symbol(eep_dp, 1, ctx->mb_type_contexts[0] + act_ctx ); + act_ctx=6; + biari_encode_symbol(eep_dp, (act_sym!=1), ctx->mb_type_contexts[0] + act_ctx ); + } + mode_sym = mode_sym & 0x03; // coding of I pred-mode: 0,1,2,3 + act_sym = mode_sym >> 1; + act_ctx = 7; + biari_encode_symbol(eep_dp, act_sym, ctx->mb_type_contexts[0] + act_ctx ); + act_ctx = 8; + act_sym = mode_sym & 0x01; + biari_encode_symbol(eep_dp, act_sym, ctx->mb_type_contexts[0] + act_ctx ); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + *************************************************************************** + * \brief + * This function is used to arithmetically encode the 8x8 block + * type info + *************************************************************************** + */ +void writeB8_B_typeInfo_CABAC(SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + BiContextType *b8_type_contexts = dp->p_Slice->mot_ctx->b8_type_contexts[1]; + int curr_len = arienco_bits_written(eep_dp); + int act_sym = se->value1; + signed short csym; + + if (act_sym==0) + { + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[0]); + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; + return; + } + else + { + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[0]); + act_sym--; + } + + if (act_sym < 2) + { + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[1]); + biari_encode_symbol (eep_dp, (act_sym!=0), &b8_type_contexts[3]); + } + else if (act_sym < 6) + { + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[1]); + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[2]); + csym = (short) (((act_sym - 2) >> 1) & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &b8_type_contexts[3]); + csym = (short) ((act_sym - 2) & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &b8_type_contexts[3]); + } + else + { + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[1]); + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[2]); + csym = (short) (((act_sym - 6)>> 2) & 0x01); + if (csym) + { + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[3]); + csym = (short) ((act_sym - 6) & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &b8_type_contexts[3]); + } + else + { + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[3]); + csym = (short) (((act_sym - 6) >> 1) & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &b8_type_contexts[3]); + csym = (short) ((act_sym - 6) & 0x01) != 0; + biari_encode_symbol (eep_dp, csym, &b8_type_contexts[3]); + } + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + *************************************************************************** + * \brief + * This function is used to arithmetically encode the 8x8 block + * type info + *************************************************************************** + */ +void writeB8_typeInfo_CABAC(SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + BiContextType (*b8_type_contexts) = dp->p_Slice->mot_ctx->b8_type_contexts[0]; + int curr_len = arienco_bits_written(eep_dp); + + switch (se->value1) + { + case 0: + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[1]); + break; + case 1: + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[1]); + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[3]); + break; + case 2: + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[1]); + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[3]); + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[4]); + break; + case 3: + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[1]); + biari_encode_symbol (eep_dp, 1, &b8_type_contexts[3]); + biari_encode_symbol (eep_dp, 0, &b8_type_contexts[4]); + break; + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode a pair of + * intra prediction modes of a given MB. + **************************************************************************** + */ +void writeIntraPredMode_CABAC(SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + BiContextType *ipr_contexts = (dp->p_Slice)->tex_ctx->ipr_contexts; + + // use_most_probable_mode + if (se->value1 == -1) + biari_encode_symbol(eep_dp, 1, ipr_contexts); + else + { + biari_encode_symbol(eep_dp, 0, ipr_contexts); + + // remaining_mode_selector + biari_encode_symbol(eep_dp, ( se->value1 & 0x1 ), ipr_contexts+1); + biari_encode_symbol(eep_dp, ((se->value1 & 0x2)>>1), ipr_contexts+1); + biari_encode_symbol(eep_dp, ((se->value1 & 0x4)>>2), ipr_contexts+1); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode the reference + * parameter of a given MB. + **************************************************************************** + */ +void writeRefPic_P_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + Slice *currSlice = dp->p_Slice; + VideoParameters *p_Vid = dp->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + MotionInfoContexts *ctx = currSlice->mot_ctx; + + int addctx = 0; + + int a = 0, b = 0; + int act_ctx; + int act_sym; + int list = se->value2; + + PixelPos block_a, block_b; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, currMB->subblock_x - 1, currMB->subblock_y , mb_size, &block_a); + get4x4Neighbour(currMB, currMB->subblock_x, currMB->subblock_y - 1, mb_size, &block_b); + + if (block_b.available) + { + if (p_Vid->mb_aff_frame_flag && (currMB->mb_field == FALSE) && (p_Vid->mb_data[block_b.mb_addr].mb_field == TRUE)) + b = (motion[block_b.pos_y][block_b.pos_x].ref_idx[list] > 1 ? 2 : 0); + else + b = (motion[block_b.pos_y][block_b.pos_x].ref_idx[list] > 0 ? 2 : 0); + } + + if (block_a.available) + { + if (p_Vid->mb_aff_frame_flag && (currMB->mb_field == FALSE) && (p_Vid->mb_data[block_a.mb_addr].mb_field == TRUE)) + a = (motion[block_a.pos_y][block_a.pos_x].ref_idx[list] > 1 ? 1 : 0); + else + a = (motion[block_a.pos_y][block_a.pos_x].ref_idx[list] > 0 ? 1 : 0); + } + + act_ctx = a + b; + se->context = act_ctx; // store context + act_sym = se->value1; + + if (act_sym==0) + { + biari_encode_symbol(eep_dp, 0, ctx->ref_no_contexts[addctx] + act_ctx ); + } + else + { + biari_encode_symbol(eep_dp, 1, ctx->ref_no_contexts[addctx] + act_ctx); + act_sym--; + act_ctx=4; + unary_bin_encode(eep_dp, act_sym, ctx->ref_no_contexts[addctx] + act_ctx, 1); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode the reference + * parameter of a given MB. + **************************************************************************** + */ +void writeRefPic_B_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + Slice *currSlice = dp->p_Slice; + VideoParameters *p_Vid = dp->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + MotionInfoContexts *ctx = currSlice->mot_ctx; + int addctx = 0; + + int a = 0, b = 0; + int act_ctx; + int act_sym; + int list = se->value2; + + int b8a, b8b; + + PixelPos block_a, block_b; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, currMB->subblock_x - 1, currMB->subblock_y , mb_size, &block_a); + get4x4Neighbour(currMB, currMB->subblock_x, currMB->subblock_y - 1, mb_size, &block_b); + + if (block_b.available) + { + b8b=((block_b.x >> 1) & 0x01)+2*((block_b.y >> 1) & 0x01); + + if (((p_Vid->mb_data[block_b.mb_addr].mb_type == 0) && !p_Vid->giRDOpt_B8OnlyFlag) || (p_Vid->mb_data[block_b.mb_addr].b8x8[b8b].mode==0)) + b=0; + else + { + if (p_Vid->mb_aff_frame_flag && (currMB->mb_field == FALSE) && (p_Vid->mb_data[block_b.mb_addr].mb_field == TRUE)) + b = (motion[block_b.pos_y][block_b.pos_x].ref_idx[list] > 1 ? 1 : 0); + else + b = (motion[block_b.pos_y][block_b.pos_x].ref_idx[list] > 0 ? 1 : 0); + } + } + + if (block_a.available) + { + b8a=((block_a.x >> 1) & 0x01)+2*((block_a.y >> 1) & 0x01); + if (((p_Vid->mb_data[block_a.mb_addr].mb_type == 0) && !p_Vid->giRDOpt_B8OnlyFlag) || (p_Vid->mb_data[block_a.mb_addr].b8x8[b8a].mode ==0)) + a=0; + else + { + if (p_Vid->mb_aff_frame_flag && (currMB->mb_field == FALSE) && (p_Vid->mb_data[block_a.mb_addr].mb_field == TRUE)) + a = (motion[block_a.pos_y][block_a.pos_x].ref_idx[list] > 1 ? 1 : 0); + else + a = (motion[block_a.pos_y][block_a.pos_x].ref_idx[list] > 0 ? 1 : 0); + } + } + + act_ctx = a + 2*b; + se->context = act_ctx; // store context + act_sym = se->value1; + + if (act_sym==0) + { + biari_encode_symbol(eep_dp, 0, ctx->ref_no_contexts[addctx] + act_ctx ); + } + else + { + biari_encode_symbol(eep_dp, 1, ctx->ref_no_contexts[addctx] + act_ctx); + act_sym--; + act_ctx=4; + unary_bin_encode(eep_dp, act_sym, ctx->ref_no_contexts[addctx] + act_ctx, 1); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode the coded + * block pattern of a given delta quant. + **************************************************************************** + */ +void writeDquant_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + + TextureInfoContexts *ctx = dp->p_Slice->tex_ctx; + + int dquant = se->value1; + int sign = (dquant <= 0) ? 0 : -1; + int act_sym = (iabs(dquant) << 1) + sign; + int act_ctx = ((currMB->prev_dqp != 0) ? 1 : 0); + + if (act_sym == 0) + { + biari_encode_symbol(eep_dp, 0, ctx->delta_qp_contexts + act_ctx ); + } + else + { + biari_encode_symbol(eep_dp, 1, ctx->delta_qp_contexts + act_ctx); + act_ctx=2; + act_sym--; + unary_bin_encode(eep_dp, act_sym,ctx->delta_qp_contexts+act_ctx,1); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode the motion + * vector data of a B-frame MB. + **************************************************************************** + */ +void writeMVD_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + VideoParameters *p_Vid = currMB->p_Vid; + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + + int curr_len = arienco_bits_written(eep_dp); + MotionInfoContexts *ctx = dp->p_Slice->mot_ctx; + + int i = currMB->subblock_x; + int j = currMB->subblock_y; + int a, b; + int act_ctx; + int act_sym; + int mv_pred_res; + int mv_local_err; + int mv_sign; + int list_idx = se->value2 & 0x01; + int k = (se->value2>>1); // MVD component + + PixelPos block_a, block_b; + + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, i - 1, j , mb_size, &block_a); + get4x4Neighbour(currMB, i , j - 1, mb_size, &block_b); + + if (block_b.available) + { + b = iabs(p_Vid->mb_data[block_b.mb_addr].mvd[list_idx][block_b.y][block_b.x][k]); + if (p_Vid->mb_aff_frame_flag && (k==1)) + { + if ((currMB->mb_field==0) && (p_Vid->mb_data[block_b.mb_addr].mb_field==1)) + b *= 2; + else if ((currMB->mb_field==1) && (p_Vid->mb_data[block_b.mb_addr].mb_field==0)) + b /= 2; + } + } + else + b=0; + + if (block_a.available) + { + a = iabs(p_Vid->mb_data[block_a.mb_addr].mvd[list_idx][block_a.y][block_a.x][k]); + if (p_Vid->mb_aff_frame_flag && (k==1)) + { + if ((currMB->mb_field==0) && (p_Vid->mb_data[block_a.mb_addr].mb_field==1)) + a *= 2; + else if ((currMB->mb_field==1) && (p_Vid->mb_data[block_a.mb_addr].mb_field==0)) + a /= 2; + } + } + else + a = 0; + + if ((mv_local_err = a + b)<3) + act_ctx = 5 * k; + else + { + if (mv_local_err>32) + act_ctx = 5 * k + 3; + else + act_ctx = 5 * k + 2; + } + + mv_pred_res = se->value1; + se->context = act_ctx; + + act_sym = iabs(mv_pred_res); + + if (act_sym == 0) + biari_encode_symbol(eep_dp, 0, &ctx->mv_res_contexts[0][act_ctx] ); + else + { + biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[0][act_ctx] ); + act_sym--; + act_ctx=5*k; + unary_exp_golomb_mv_encode(eep_dp,act_sym,ctx->mv_res_contexts[1]+act_ctx,3); + mv_sign = (mv_pred_res<0) ? 1: 0; + biari_encode_symbol_eq_prob(eep_dp, mv_sign); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode the chroma + * intra prediction mode of an 8x8 block + **************************************************************************** + */ +void writeCIPredMode_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + TextureInfoContexts *ctx = dp->p_Slice->tex_ctx; + + int act_sym = se->value1; + + Macroblock *MbUp = currMB->mb_up; + Macroblock *MbLeft = currMB->mb_left; + + int b = (MbUp != NULL) ? (((MbUp->c_ipred_mode != 0) && (MbUp->mb_type != IPCM)) ? 1 : 0) : 0; + int a = (MbLeft != NULL) ? (((MbLeft->c_ipred_mode != 0) && (MbLeft->mb_type != IPCM)) ? 1 : 0) : 0; + + int act_ctx = a + b; + + if (act_sym==0) + biari_encode_symbol(eep_dp, 0, ctx->cipr_contexts + act_ctx ); + else + { + biari_encode_symbol(eep_dp, 1, ctx->cipr_contexts + act_ctx ); + unary_bin_max_encode(eep_dp,(unsigned int) (act_sym-1),ctx->cipr_contexts + 3,0,2); + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + + +/*! + **************************************************************************** + * \brief + * This function is used to arithmetically encode the coded + * block pattern of an 8x8 block + **************************************************************************** + */ +void writeCBP_BIT_CABAC (Macroblock* currMB, int b8, int bit, int cbp, EncodingEnvironmentPtr eep_dp, TextureInfoContexts *ctx) +{ + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos block_a; + int a = 0, b = 0; + + int mb_x=(b8 & 0x01)<<1; + int mb_y=(b8 >> 1)<<1; + + if (mb_y == 0) + { + if (!((currMB->mb_up == NULL) || ((currMB->mb_up)->mb_type==IPCM))) + { + b = (( ((currMB->mb_up)->cbp & (1<<(2+(mb_x>>1)))) == 0) ? 1 : 0); //VG-ADD + } + + } + else + b = ( ((cbp & (1<<(mb_x >> 1))) == 0) ? 1: 0); + + if (mb_x == 0) + { + get4x4Neighbour(currMB, (mb_x << 2) - 1, (mb_y << 2), p_Vid->mb_size[IS_LUMA], &block_a); + + if (block_a.available && (!(p_Vid->mb_data[block_a.mb_addr].mb_type==IPCM))) + { + a = (( (p_Vid->mb_data[block_a.mb_addr].cbp & (1<<(2*(block_a.y>>1)+1))) == 0) ? 1 : 0); //VG-ADD + } + } + else + a = ( ((cbp & (1<cbp_contexts[0] + a+2*b); +} + +/*! +**************************************************************************** +* \brief +* This function is used to arithmetically encode the coded +* block pattern of a macroblock +**************************************************************************** +*/ +void writeCBP_CABAC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + TextureInfoContexts *ctx = currSlice->tex_ctx; + + int a0 = 0, a1 = 0, b0 = 0, b1 = 0; + int curr_cbp_ctx; + int cbp = se->value1; // symbol to encode + int cbp_bit; + int b8; + + for (b8=0; b8<4; ++b8) + { + writeCBP_BIT_CABAC (currMB, b8, cbp&(1<yuv_format != YUV400) && (p_Vid->yuv_format != YUV444) ) + { + // coding of chroma part + if (currMB->mb_up != NULL) + { + if((currMB->mb_up)->mb_type == IPCM || ((currMB->mb_up)->cbp > 15)) + b0 = 2; + } + + if (currMB->mb_left != NULL) + { + if((currMB->mb_left)->mb_type==IPCM || ((currMB->mb_left)->cbp > 15)) + a0 = 1; + } + + curr_cbp_ctx = a0 + b0; + cbp_bit = (cbp > 15 ) ? 1 : 0; + biari_encode_symbol(eep_dp, cbp_bit, ctx->cbp_contexts[1] + curr_cbp_ctx ); + + if (cbp > 15) + { + if (currMB->mb_up != NULL) + { + if((currMB->mb_up)->mb_type == IPCM || + (((currMB->mb_up)->cbp > 15) && ( ((currMB->mb_up)->cbp >> 4) == 2))) + b1 = 2; + } + + if (currMB->mb_left != NULL) + { + if((currMB->mb_left)->mb_type==IPCM || + (((currMB->mb_left)->cbp > 15) && ( ((currMB->mb_left)->cbp >> 4) == 2))) + a1 = 1; + } + + curr_cbp_ctx = a1 + b1; + cbp_bit = ((cbp>>4) == 2) ? 1 : 0; + biari_encode_symbol(eep_dp, cbp_bit, ctx->cbp_contexts[2] + curr_cbp_ctx ); + } + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + +/*! + **************************************************************************** + * \brief + * Write CBP4-BIT (for 444 formats) + **************************************************************************** + */ +void write_and_store_CBP_block_bit_444 (Macroblock* currMB, EncodingEnvironmentPtr eep_dp, int type, int cbp_bit, TextureInfoContexts* tex_ctx) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Macroblock *mb_data = p_Vid->mb_data; + + int y_ac = (type==LUMA_16AC || type==LUMA_8x8 || type==LUMA_8x4 || type==LUMA_4x8 || type==LUMA_4x4 + || type==CB_16AC || type==CB_8x8 || type==CB_8x4 || type==CB_4x8 || type==CB_4x4 + || type==CR_16AC || type==CR_8x8 || type==CR_8x4 || type==CR_4x8 || type==CR_4x4); + int y_dc = (type==LUMA_16DC || type==CB_16DC || type==CR_16DC); + int u_ac = (type==CHROMA_AC && !p_Vid->is_v_block); + int v_ac = (type==CHROMA_AC && p_Vid->is_v_block); + int chroma_dc = (type==CHROMA_DC || type==CHROMA_DC_2x4 || type==CHROMA_DC_4x4); + int u_dc = (chroma_dc && !p_Vid->is_v_block); + int v_dc = (chroma_dc && p_Vid->is_v_block); + int j = (y_ac || u_ac || v_ac ? currMB->subblock_y : 0); + int i = (y_ac || u_ac || v_ac ? currMB->subblock_x : 0); + int bit = (y_dc ? 0 : y_ac ? 1 : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 : 23); + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + int bit_pos_a = 0; + int bit_pos_b = 0; + + PixelPos block_a, block_b; + + if (y_ac || y_dc) + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4Neighbour(currMB, i, j -1, p_Vid->mb_size[IS_LUMA], &block_b); + if (y_ac) + { + if (block_a.available) + bit_pos_a = (block_a.y << 2) + block_a.x; + if (block_b.available) + bit_pos_b = (block_b.y << 2) + block_b.x; + } + } + else + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4Neighbour(currMB, i, j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + if (u_ac||v_ac) + { + if (block_a.available) + bit_pos_a = (block_a.y << 2) + block_a.x; + if (block_b.available) + bit_pos_b = (block_b.y << 2) + block_b.x; + } + } + + bit = (y_dc ? 0 : y_ac ? 1 + j + (i >> 2) : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 + j + (i >> 2): 35 + j + (i >> 2)); + //--- set bits for current block --- + if (cbp_bit) + { + if (type==LUMA_8x8) + { + currMB->cbp_bits[0] |= ((int64) 0x33 << bit); + + if (p_Vid->enc_picture->chroma_format_idc == YUV444) + { + currMB->cbp_bits_8x8[0] |= ((int64) 0x33 << bit); + } + } + else if (type==CB_8x8) + { + currMB->cbp_bits_8x8[1] |= ((int64) 0x33 << bit); + currMB->cbp_bits[1] |= ((int64) 0x33 << bit); + } + else if (type==CR_8x8) + { + currMB->cbp_bits_8x8[2] |= ((int64) 0x33 << bit); + currMB->cbp_bits[2] |= ((int64) 0x33 << bit); + } + else if (type==LUMA_8x4) + { + currMB->cbp_bits[0] |= ((int64) 0x03 << bit); + } + else if (type==LUMA_4x8) + { + currMB->cbp_bits[0] |= ((int64) 0x11 << bit); + } + else if (type==CB_8x4) + { + currMB->cbp_bits[1] |= ((int64) 0x03 << bit); + } + else if (type==CR_8x4) + { + currMB->cbp_bits[2] |= ((int64) 0x03 << bit); + } + else if (type==CB_4x8) + { + currMB->cbp_bits[1] |= ((int64) 0x11 << bit); + } + else if (type==CR_4x8) + { + currMB->cbp_bits[2] |= ((int64) 0x11 << bit); + } + else if ((type==CB_4x4)||(type==CB_16AC)||(type==CB_16DC)) + { + currMB->cbp_bits[1] |= ((int64) 0x01 << bit); + } + else if ((type == CR_4x4)||(type == CR_16AC)||(type == CR_16DC)) + { + currMB->cbp_bits[2] |= ((int64) 0x01 << bit); + } + else + { + currMB->cbp_bits[0] |= ((int64) 0x01 << bit); + } + } + + bit = (y_dc ? 0 : y_ac ? 1 : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 : 35); + + if (p_Vid->enc_picture->chroma_format_idc!=YUV444) + { + if (type!=LUMA_8x8) + { + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit = 1; + else + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits[0],bit+bit_pos_b); + } + + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type == IPCM) + left_bit = 1; + else + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits[0], bit + bit_pos_a); + } + + ctx = (upper_bit << 1) + left_bit; + + //===== encode symbol ===== + biari_encode_symbol (eep_dp, cbp_bit, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + } + } + else if( (currMB->p_Inp->separate_colour_plane_flag != 0) ) + { + if (type!=LUMA_8x8) + { + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit = 1; + else + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits[0],bit+bit_pos_b); + } + + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type == IPCM) + left_bit = 1; + else + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits[0], bit + bit_pos_a); + } + + ctx = (upper_bit << 1) + left_bit; + + //===== encode symbol ===== + biari_encode_symbol (eep_dp, cbp_bit, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + } + } + else + { + if (block_b.available) + { + if((type==LUMA_8x8 || type==CB_8x8 || type==CR_8x8) && + !mb_data[block_b.mb_addr].luma_transform_size_8x8_flag) + {} + else if(mb_data[block_b.mb_addr].mb_type == IPCM) + upper_bit=1; + else + { + if(type==LUMA_8x8) + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits_8x8[0], bit + bit_pos_b); + else if (type==CB_8x8) + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits_8x8[1], bit + bit_pos_b); + else if (type==CR_8x8) + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits_8x8[2], bit + bit_pos_b); + else if ((type==CB_4x4)||(type==CB_4x8)||(type==CB_8x4)||(type==CB_16AC)||(type==CB_16DC)) + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits[1], bit + bit_pos_b); + else if ((type==CR_4x4)||(type==CR_4x8)||(type==CR_8x4)||(type==CR_16AC)||(type==CR_16DC)) + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits[2], bit + bit_pos_b); + else + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits[0], bit + bit_pos_b); + } + } + + if (block_a.available) + { + if((type==LUMA_8x8 || type==CB_8x8 || type==CR_8x8) && + !mb_data[block_a.mb_addr].luma_transform_size_8x8_flag) + {} + else if(mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit = 1; + else + { + if(type==LUMA_8x8) + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits_8x8[0],bit + bit_pos_a); + else if (type==CB_8x8) + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits_8x8[1],bit + bit_pos_a); + else if (type==CR_8x8) + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits_8x8[2],bit + bit_pos_a); + else if ((type==CB_4x4)||(type==CB_4x8)||(type==CB_8x4)||(type==CB_16AC)||(type==CB_16DC)) + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits[1],bit + bit_pos_a); + else if ((type==CR_4x4)||(type==CR_4x8)||(type==CR_8x4)||(type==CR_16AC)||(type==CR_16DC)) + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits[2],bit + bit_pos_a); + else + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits[0],bit + bit_pos_a); + } + } + + ctx = 2*upper_bit+left_bit; + + //===== encode symbol ===== + biari_encode_symbol (eep_dp, cbp_bit, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]]+ctx); + } +} + + +/*! + **************************************************************************** + * \brief + * Write CBP4-BIT + **************************************************************************** + */ +void write_and_store_CBP_block_bit (Macroblock* currMB, EncodingEnvironmentPtr eep_dp, int type, int cbp_bit, TextureInfoContexts* tex_ctx) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Macroblock *mb_data = p_Vid->mb_data; + int y_ac = (type==LUMA_16AC || type==LUMA_8x8 || type==LUMA_8x4 || type==LUMA_4x8 || type==LUMA_4x4); + int y_dc = (type==LUMA_16DC); + int u_ac = (type==CHROMA_AC && !p_Vid->is_v_block); + int v_ac = (type==CHROMA_AC && p_Vid->is_v_block); + int chroma_dc = (type==CHROMA_DC || type==CHROMA_DC_2x4 || type==CHROMA_DC_4x4); + int u_dc = (chroma_dc && !p_Vid->is_v_block); + int v_dc = (chroma_dc && p_Vid->is_v_block); + int j = (y_ac || u_ac || v_ac ? currMB->subblock_y : 0); + int i = (y_ac || u_ac || v_ac ? currMB->subblock_x : 0); + int bit = (y_dc ? 0 : y_ac ? 1 : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 : 23); + int default_bit = (currMB->is_intra_block ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx; + + int bit_pos_a = 0; + int bit_pos_b = 0; + + PixelPos block_a, block_b; + + if (y_ac || y_dc) + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4Neighbour(currMB, i, j -1, p_Vid->mb_size[IS_LUMA], &block_b); + if (y_ac) + { + if (block_a.available) + bit_pos_a = 4*block_a.y + block_a.x; + if (block_b.available) + bit_pos_b = 4*block_b.y + block_b.x; + } + } + else + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4Neighbour(currMB, i, j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + if (u_ac||v_ac) + { + if (block_a.available) + bit_pos_a = (block_a.y << 2) + block_a.x; + if (block_b.available) + bit_pos_b = (block_b.y << 2) + block_b.x; + } + } + + bit = (y_dc ? 0 : y_ac ? 1 + j + (i >> 2): u_dc ? 17 : v_dc ? 18 : u_ac ? 19 + j + (i >> 2): 35 + j + (i >> 2)); + //--- set bits for current block --- + if (cbp_bit) + { + if (type==LUMA_8x8) + { + currMB->cbp_bits[0] |= ((int64) 0x33 << bit); + } + else if (type==LUMA_8x4) + { + currMB->cbp_bits[0] |= ((int64) 0x03 << bit); + } + else if (type==LUMA_4x8) + { + currMB->cbp_bits[0] |= ((int64) 0x11 << bit); + } + else + { + currMB->cbp_bits[0] |= ((int64) 0x01 << bit); + } + } + + bit = (y_dc ? 0 : y_ac ? 1 : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 : 35); + + if (type!=LUMA_8x8) + { + if (block_b.available) + { + if(mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit = 1; + else + upper_bit = get_bit(mb_data[block_b.mb_addr].cbp_bits[0],bit+bit_pos_b); + } + + + if (block_a.available) + { + if(mb_data[block_a.mb_addr].mb_type == IPCM) + left_bit = 1; + else + left_bit = get_bit(mb_data[block_a.mb_addr].cbp_bits[0], bit + bit_pos_a); + } + + ctx = (upper_bit << 1) + left_bit; + + //===== encode symbol ===== + biari_encode_symbol (eep_dp, cbp_bit, tex_ctx->bcbp_contexts[type2ctx_bcbp[type]] + ctx); + } +} + +/*! +**************************************************************************** +* \brief +* Write Significance MAP +**************************************************************************** +*/ +void write_significance_map (Macroblock* currMB, EncodingEnvironmentPtr eep_dp, int type, int coeff[], int coeff_ctr, TextureInfoContexts* tex_ctx) +{ + int k; + int sig, last; + int k0 = 0; + int k1 = maxpos[type]; + +#if ENABLE_FIELD_CTX + VideoParameters *p_Vid = currMB->p_Vid; + int fld = ( p_Vid->structure!=FRAME || currMB->mb_field ); +#else + int fld = 0; +#endif + BiContextTypePtr map_ctx = tex_ctx->map_contexts [fld][type2ctx_map [type]]; + BiContextTypePtr last_ctx = tex_ctx->last_contexts[fld][type2ctx_last[type]]; + const byte *pos2ctxmap = fld ? pos2ctx_map_int [type] : pos2ctx_map [type]; + const byte *pos2ctxlast = pos2ctx_last[type]; + + if (!c1isdc[type]) + { + ++k0; + ++k1; + --coeff; + } + + for (k=k0; kone_contexts[type2ctx_one[type]]; + BiContextType *abs_contexts = tex_ctx->abs_contexts[type2ctx_abs[type]]; + int absLevel; + int ctx; + short sign; + int greater_one; + int c1 = 1; + int c2 = 0; + int i; + + for (i=maxpos[type]; (i>=0) && (coeff_cnt); i--) + { + if (coeff[i]!=0) + { + coeff_cnt--; + + if (coeff[i] > 0) + { + absLevel = coeff[i]; + sign = 0; + } + else + { + absLevel = -coeff[i]; + sign = 1; + } + + greater_one = (absLevel > 1); + + //--- if coefficient is one --- + ctx = imin(c1, 4); + biari_encode_symbol (eep_dp, greater_one, one_contexts + ctx); + + if (greater_one) + { + ctx = imin(c2++, max_c2[type]); + unary_exp_golomb_level_encode(eep_dp, absLevel - 2, abs_contexts + ctx); + c1 = 0; + } + else if (c1) + { + c1++; + } + biari_encode_symbol_eq_prob (eep_dp, sign); + } + } +} + + + +/*! + **************************************************************************** + * \brief + * Write Block-Transform Coefficients + **************************************************************************** + */ +void writeRunLevel_CABAC (Macroblock* currMB, SyntaxElement *se, DataPartition *dp) +{ + Slice *currSlice = currMB->p_Slice; + EncodingEnvironmentPtr eep_dp = &(dp->ee_cabac); + int curr_len = arienco_bits_written(eep_dp); + + //--- accumulate run-level information --- + if (se->value1 != 0) + { + currSlice->pos += se->value2; + currSlice->coeff[currSlice->pos++] = se->value1; + ++currSlice->coeff_ctr; + } + else + { + TextureInfoContexts *tex_ctx = currSlice->tex_ctx; + //===== encode CBP-BIT ===== + if (currSlice->coeff_ctr > 0) + { + currSlice->write_and_store_CBP_block_bit (currMB, eep_dp, se->context, 1, tex_ctx); + //===== encode significance map ===== + write_significance_map (currMB, eep_dp, se->context, currSlice->coeff, currSlice->coeff_ctr, tex_ctx); + //===== encode significant coefficients ===== + write_significant_coefficients (eep_dp, se->context, currSlice->coeff, tex_ctx, currSlice->coeff_ctr); + + memset(currSlice->coeff, 0 , 64 * sizeof(int)); + } + else + currSlice->write_and_store_CBP_block_bit (currMB, eep_dp, se->context, 0, tex_ctx); + + //--- reset counters --- + currSlice->pos = currSlice->coeff_ctr = 0; + } + + dp->bitstream->write_flag = 1; + se->len = (arienco_bits_written(eep_dp) - curr_len); + CABAC_TRACE; +} + + diff --git a/lencod/src/cconv_yuv2rgb.c b/lencod/src/cconv_yuv2rgb.c new file mode 100644 index 0000000..00f2648 --- /dev/null +++ b/lencod/src/cconv_yuv2rgb.c @@ -0,0 +1,149 @@ + +/*! + ************************************************************************************* + * \file cconv_yuv2rgb.c + * + * \brief + * YUV to RGB color conversion + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + ************************************************************************************* + */ +#include "contributors.h" +#include "global.h" +#include "memalloc.h" +#include "img_distortion.h" + +#define YUV2RGB_YOFFSET + +//YUV to RGB conversion +#ifdef YUV2RGB_YOFFSET +#define OFFSET_Y 16 +static const float K0 = 1.164f; +static const float K1 = 1.596f; +static const float K2 = 0.391f; +static const float K3 = 0.813f; +static const float K4 = 2.018f; +#else +static const float K0 = 1.000f; +static const float K1 = 1.402f; +static const float K2 = 0.34414f; +static const float K3 = 0.71414f; +static const float K4 = 1.772f; +#endif + +int create_RGB_memory(VideoParameters *p_Vid) +{ + int memory_size = 0; + int j; + for( j = 0; j < 3; j++ ) + { + memory_size += get_mem2Dpel (&p_Vid->imgRGB_src.data[j], p_Vid->height, p_Vid->width); + } + for( j = 0; j < 3; j++ ) + { + memory_size += get_mem2Dpel (&p_Vid->imgRGB_ref.data[j], p_Vid->height, p_Vid->width); + } + + return memory_size; +} + +void delete_RGB_memory(VideoParameters *p_Vid) +{ + int i; + for( i = 0; i < 3; i++ ) + { + free_mem2Dpel(p_Vid->imgRGB_src.data[i]); + } + for( i = 0; i < 3; i++ ) + { + free_mem2Dpel(p_Vid->imgRGB_ref.data[i]); + } +} + +void init_YUVtoRGB(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + float conv_scale = (float) (65536.0f); + + p_Vid->wka0 = float2int( conv_scale * K0); + p_Vid->wka1 = float2int( conv_scale * K1); + p_Vid->wka2 = float2int( -conv_scale * K2); + p_Vid->wka3 = float2int( -conv_scale * K3); + p_Vid->wka4 = float2int( conv_scale * K4); + +#ifdef YUV2RGB_YOFFSET + p_Vid->offset_y = OFFSET_Y << (p_Inp->output.bit_depth[0] - 8); + p_Vid->offset_cr = 1 << (p_Inp->output.bit_depth[0] - 1); +#endif +} + +/*! +************************************************************************************* +* \brief +* YUV to RGB conversion +* ITU 601 with and without offset consideration +* Upsampling by repetition of chroma samples in case of 4:2:0 and 4:2:2 +* Method not support for 4:0:0 content +************************************************************************************* +*/ +void YUVtoRGB(VideoParameters *p_Vid, ImageStructure *YUV, ImageStructure *RGB) +{ + int i, j, j_cr, i_cr; + int sy, su, sv; + int wbuv, wguv, wruv; + imgpel *Y, *U, *V, *R, *G, *B; + FrameFormat format = YUV->format; + int width = format.width[0]; + int height = format.height[0]; + int max_value = format.max_value[0]; + + // Color conversion + for (j = 0; j < height; j++) + { + j_cr = j >> p_Vid->shift_cr_y; + Y = YUV->data[0][j]; + U = YUV->data[1][j_cr]; + V = YUV->data[2][j_cr]; + R = RGB->data[0][j]; + G = RGB->data[1][j]; + B = RGB->data[2][j]; + + for (i = 0; i < width; i++) + { + i_cr = i >> p_Vid->shift_cr_x; + + su = U[i_cr] - p_Vid->offset_cr; + sv = V[i_cr] - p_Vid->offset_cr; + + wruv = p_Vid->wka1 * sv; + wguv = p_Vid->wka2 * su + p_Vid->wka3 * sv; + wbuv = p_Vid->wka4 * su; + +#ifdef YUV2RGB_YOFFSET // Y offset value of 16 is considered + sy = p_Vid->wka0 * (Y[i] - p_Vid->offset_y); +#else + sy = p_Vid->wka0 * Y[i]; +#endif + + R[i] = (imgpel) iClip1( max_value, rshift_rnd(sy + wruv, 16)); + G[i] = (imgpel) iClip1( max_value, rshift_rnd(sy + wguv, 16)); + B[i] = (imgpel) iClip1( max_value, rshift_rnd(sy + wbuv, 16)); + } + } + // Setting RGB FrameFormat + RGB->format = format; // copy format information from YUV to RGB + RGB->format.yuv_format = YUV444; + RGB->format.color_model = CM_RGB; + RGB->format.pixel_format = BGR; + RGB->format.height[1] = format.height[0]; + RGB->format.width[1] = format.width[0]; + for (i = 1; i < 3; i++) + { + RGB->format.size_cmp[i] = format.size_cmp[0]; + RGB->format.bit_depth[i] = format.bit_depth[0]; + RGB->format.max_value[i] = max_value; + RGB->format.max_value_sq[i] = format.max_value_sq[0]; + } +} diff --git a/lencod/src/configfile.c b/lencod/src/configfile.c new file mode 100644 index 0000000..8fd28c1 --- /dev/null +++ b/lencod/src/configfile.c @@ -0,0 +1,1529 @@ + +/*! + *********************************************************************** + * \file + * configfile.c + * \brief + * Configuration handling. + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * \note + * In the future this module should hide the Parameters and offer only + * Functions for their access. Modules which make frequent use of some parameters + * (e.g. picture size in macroblocks) are free to buffer them on local variables. + * This will not only avoid global variable and make the code more readable, but also + * speed it up. It will also greatly facilitate future enhancements such as the + * handling of different picture sizes in the same sequence. \n + * \n + * For now, everything is just copied to the inp_par structure (gulp) + * + ************************************************************************************** + * \par Configuration File Format + ************************************************************************************** + * Format is line oriented, maximum of one parameter per line \n + * \n + * Lines have the following format: \n + * \ = \ # Comments \\n \n + * Whitespace is space and \\t + * \par + * \ are the predefined names for Parameters and are case sensitive. + * See configfile.h for the definition of those names and their mapping to + * cfgparams->values. + * \par + * \ are either integers [0..9]* or strings. + * Integers must fit into the wordlengths, signed values are generally assumed. + * Strings containing no whitespace characters can be used directly. Strings containing + * whitespace characters are to be inclosed in double quotes ("string with whitespace") + * The double quote character is forbidden (may want to implement something smarter here). + * \par + * Any Parameters whose ParameterName is undefined lead to the termination of the program + * with an error message. + * + * \par Known bug/Shortcoming: + * zero-length strings (i.e. to signal an non-existing file + * have to be coded as "". + * + * \par Rules for using command files + * \n + * All Parameters are initially taken from DEFAULTCONFIGFILENAME, defined in configfile.h. + * If an -f \ parameter is present in the command line then this file is used to + * update the defaults of DEFAULTCONFIGFILENAME. There can be more than one -f parameters + * present. If -p parameters are present then these + * override the default and the additional config file's settings, and are themselves + * overridden by future -p parameters. There must be whitespace between -f and -p commands + * and their respective parameters + *********************************************************************** + */ + +#define INCLUDED_BY_CONFIGFILE_C + +#include + +#include "global.h" +#include "config_common.h" +#include "configfile.h" +#include "fmo.h" +#include "conformance.h" +#include "mc_prediction.h" +#include "mv_search.h" +#include "img_io.h" +#include "ratectl.h" + +static void PatchInp (VideoParameters *p_Vid, InputParameters *p_Inp); +static int TestEncoderParams (Mapping *Map, int bitdepth_qp_scale[3]); +static int DisplayEncoderParams (Mapping *Map); + +static const int mb_width_cr[4] = {0,8, 8,16}; +static const int mb_height_cr[4]= {0,8,16,16}; + +#define MAX_ITEMS_TO_PARSE 10000 + +#include "sei.h" +static void SetVUIScaleAndTicks(InputParameters *p_Inp, double frame_rate); + +/*! + *********************************************************************** + * \brief + * Set JM VUI parameters + *********************************************************************** + */ + +static void set_jm_vui_params( InputParameters *p_Inp ) +{ + SetVUIScaleAndTicks(p_Inp, 1.25 * p_Inp->output.frame_rate); + + p_Inp->EnableVUISupport = 1; + + p_Inp->VUI.nal_hrd_parameters_present_flag = 0; + p_Inp->VUI.vcl_hrd_parameters_present_flag = 0; + p_Inp->VUI.timing_info_present_flag = 1; + p_Inp->VUI.pic_struct_present_flag = 1; + p_Inp->VUI.fixed_frame_rate_flag = 1; +} + +/*! + *********************************************************************** + * \brief + * print help message and exit + *********************************************************************** + */ +void JMHelpExit (void) +{ + fprintf( stdout, "\n lencod [-h] [-d defenc.cfg] {[-f curenc1.cfg]...[-f curencN.cfg]}" + " {[-p EncParam1=EncValue1]..[-p EncParamM=EncValueM]}\n\n" + "## Parameters\n\n" + + "## Options\n" + " -h : prints function usage\n" + " -d : use as default file for parameter initializations.\n" + " If not used then file defaults to encoder.cfg in local directory.\n" + " -f : read for reseting selected encoder parameters.\n" + " Multiple files could be used that set different parameters\n" + " -p : Set parameter to .\n" + " See default encoder.cfg file for description of all parameters.\n\n" + + "## Supported video file formats\n" + " RAW: .yuv.,rgb -> P444 - Planar, 4:4:4 \n" + " P422 - Planar, 4:2:2 \n" + " P420 - Planar, 4:2:0 \n" + " P400 - Planar, 4:0:0 \n" + " I444 - Packed, 4:4:4 \n" + " I422 - Packed, 4:2:2 \n" + " I420 - Packed, 4:2:0 \n" + " IYUV/YV12 - Planar, 4:2:0 \n" + " IYU1 - Packed, 4:2:0 (UYYVYY) \n" + " IYU2 - Packed, 4:4:4 (UYV) \n" + " YUY2 - Packed, 4:2:2 (YUYV) \n" + " YUV - Packed, 4:4:4 (YUV) \n\n" + + "## Examples of usage:\n" + " lencod\n" + " lencod -h\n" + " lencod -d default.cfg\n" + " lencod -f curenc1.cfg\n" + " lencod -f curenc1.cfg -p InputFile=\"e:\\data\\container_qcif_30.yuv\" -p SourceWidth=176 -p SourceHeight=144\n" + " lencod -f curenc1.cfg -p FramesToBeEncoded=30 -p QPISlice=28 -p QPPSlice=28 -p QPBSlice=30\n"); + + exit(-1); +} + +/*! + ************************************************************************ + * \brief + * Reads Input File Size + * + ************************************************************************ + */ +int64 getVideoFileSize(int video_file) +{ + int64 fsize; + + lseek(video_file, 0, SEEK_END); + fsize = tell((int) video_file); + lseek(video_file, 0, SEEK_SET); + + return fsize; +} + +/*! + ************************************************************************ + * \brief + * Updates the number of frames to encode based on the file size + * + ************************************************************************ + */ +void get_number_of_frames (InputParameters *p_Inp, VideoDataFile *input_file) +{ + int64 fsize = getVideoFileSize(input_file->f_num); + + int64 isize = (int64) p_Inp->source.size; + int maxBitDepth = imax(p_Inp->source.bit_depth[0], p_Inp->source.bit_depth[1]); + + isize <<= (maxBitDepth > 8)? 1: 0; + p_Inp->no_frames = (int) (((fsize - p_Inp->infile_header)/ isize) - p_Inp->start_frame); +} + +/*! + ************************************************************************ + * \brief + * Updates images max values + * + ************************************************************************ + */ +static void updateMaxValue(FrameFormat *format) +{ + format->max_value[0] = (1 << format->bit_depth[0]) - 1; + format->max_value_sq[0] = format->max_value[0] * format->max_value[0]; + format->max_value[1] = (1 << format->bit_depth[1]) - 1; + format->max_value_sq[1] = format->max_value[1] * format->max_value[1]; + format->max_value[2] = (1 << format->bit_depth[2]) - 1; + format->max_value_sq[2] = format->max_value[2] * format->max_value[2]; +} + +/*! + ************************************************************************ + * \brief + * Update output format parameters (resolution & bit-depth) given input + * + ************************************************************************ + */ +static void updateOutFormat(InputParameters *p_Inp) +{ + FrameFormat *output = &p_Inp->output; + FrameFormat *source = &p_Inp->source; + output->yuv_format = (ColorFormat) p_Inp->yuv_format; + source->yuv_format = (ColorFormat) p_Inp->yuv_format; + + if (p_Inp->src_resize == 0) + { + output->width[0] = source->width[0]; + output->height[0] = source->height[0]; + } + + if (p_Inp->yuv_format == YUV400) // reset bitdepth of chroma for 400 content + { + source->bit_depth[1] = 8; + output->bit_depth[1] = 8; + source->width[1] = 0; + source->width[2] = 0; + source->height[1] = 0; + source->height[2] = 0; + output->width[1] = 0; + output->width[2] = 0; + output->height[1] = 0; + output->height[2] = 0; + } + else + { + source->width[1] = (source->width[0] * mb_width_cr [output->yuv_format]) >> 4; + source->width[2] = source->width[1]; + source->height[1] = (source->height[0] * mb_height_cr[output->yuv_format]) >> 4; + source->height[2] = source->height[1]; + output->width[1] = (output->width[0] * mb_width_cr [output->yuv_format]) >> 4; + output->width[2] = output->width[1]; + output->height[1] = (output->height[0] * mb_height_cr[output->yuv_format]) >> 4; + output->height[2] = output->height[1]; + } + + // source size + source->size_cmp[0] = source->width[0] * source->height[0]; + source->size_cmp[1] = source->width[1] * source->height[1]; + source->size_cmp[2] = source->size_cmp[1]; + source->size = source->size_cmp[0] + source->size_cmp[1] + source->size_cmp[2]; + source->mb_width = source->width[0] / MB_BLOCK_SIZE; + source->mb_height = source->height[0] / MB_BLOCK_SIZE; + source->pic_unit_size_on_disk = (imax(source->bit_depth[0], source->bit_depth[1]) > 8) ? 16 : 8; + source->pic_unit_size_shift3 = source->pic_unit_size_on_disk >> 3; + + + // output size (excluding padding) + output->size_cmp[0] = output->width[0] * output->height[0]; + output->size_cmp[1] = output->width[1] * output->height[1]; + output->size_cmp[2] = output->size_cmp[1]; + output->size = output->size_cmp[0] + output->size_cmp[1] + output->size_cmp[2]; + output->mb_width = output->width[0] / MB_BLOCK_SIZE; + output->mb_height = output->height[0] / MB_BLOCK_SIZE; + + + // both chroma components have the same bitdepth + source->bit_depth[2] = source->bit_depth[1]; + output->bit_depth[2] = output->bit_depth[1]; + + // if no bitdepth rescale ensure bitdepth is same + if (p_Inp->src_BitDepthRescale == 0) + { + output->bit_depth[0] = source->bit_depth[0]; + output->bit_depth[1] = source->bit_depth[1]; + output->bit_depth[2] = source->bit_depth[2]; + } + output->pic_unit_size_on_disk = (imax(output->bit_depth[0], output->bit_depth[1]) > 8) ? 16 : 8; + output->pic_unit_size_shift3 = output->pic_unit_size_on_disk >> 3; + + if (p_Inp->enable_32_pulldown) + { + source->frame_rate = source->frame_rate * 5 / 4; + p_Inp->idr_period = p_Inp->idr_period * 5 / 4; + p_Inp->intra_period = p_Inp->intra_period * 5 / 4; + p_Inp->no_frames = p_Inp->no_frames * 5 / 4; + } + + output->frame_rate = source->frame_rate / (p_Inp->frame_skip + 1); + output->color_model = source->color_model; + output->pixel_format = source->pixel_format; + + updateMaxValue(source); + updateMaxValue(output); +} + + +/*! + *********************************************************************** + * \brief + * Parse the command line parameters and read the config files. + * \param p_Vid + * VideoParameters structure for encoding + * \param p_Inp + * InputParameters structure as input configuration + * \param ac + * number of command line parameters + * \param av + * command line parameters + *********************************************************************** + */ +void Configure (VideoParameters *p_Vid, InputParameters *p_Inp, int ac, char *av[]) +{ + char *content = NULL; + int CLcount, ContentLen, NumberParams; + char *filename=DEFAULTCONFIGFILENAME; + + if (ac==2) + { + if (0 == strncmp (av[1], "-v", 2)) + { + printf("JM-" VERSION "\n"); + exit(0); + } + if (0 == strncmp (av[1], "-V", 2)) + { + printf("JM " JM ": compiled " __DATE__ " " __TIME__ "\n"); +#if ( IMGTYPE == 0 ) + printf("support for more than 8 bits/pel disabled\n"); +#endif +#if ( ENABLE_FIELD_CTX == 0 ) + printf("CABAC field coding disabled\n"); +#endif +#if ( ENABLE_HIGH444_CTX == 0 ) + printf("CABAC High 4:4:4 profile coding disabled\n"); +#endif + exit(0); + } + + if (0 == strncmp (av[1], "-h", 2)) + { + JMHelpExit(); + } + } + + memset (&cfgparams, 0, sizeof (InputParameters)); + //Set default parameters. + printf ("Setting Default Parameters...\n"); + InitParams(Map); + + // Process default config file + CLcount = 1; + + if (ac>=3) + { + if (0 == strncmp (av[1], "-d", 2)) + { + filename=av[2]; + CLcount = 3; + } + if (0 == strncmp (av[1], "-h", 2)) + { + JMHelpExit(); + } + } + printf ("Parsing Configfile %s", filename); + content = GetConfigFileContent (filename); + if (NULL==content) + error (errortext, 300); + ParseContent (p_Inp, Map, content, (int) strlen(content)); + printf ("\n"); + free (content); + + // Parse the command line + + while (CLcount < ac) + { + if (0 == strncmp (av[CLcount], "-h", 2)) + { + JMHelpExit(); + } + + if (0 == strncasecmp (av[CLcount], "-f", 2)) // A file parameter? + { + content = GetConfigFileContent (av[CLcount+1]); + if (NULL==content) + error (errortext, 300); + printf ("Parsing Configfile %s", av[CLcount+1]); + ParseContent (p_Inp, Map, content, (int) strlen (content)); + printf ("\n"); + free (content); + CLcount += 2; + } + else + { + if (0 == strncasecmp (av[CLcount], "-p", 2)) // A config change? + { + // Collect all data until next parameter (starting with - (x is any character)), + // put it into content, and parse content. + + ++CLcount; + ContentLen = 0; + NumberParams = CLcount; + + // determine the necessary size for content + while (NumberParams < ac && av[NumberParams][0] != '-') + ContentLen += (int) strlen (av[NumberParams++]); // Space for all the strings + ContentLen += 1000; // Additional 1000 bytes for spaces and \0s + + + if ((content = malloc (ContentLen))==NULL) no_mem_exit("Configure: content");; + content[0] = '\0'; + + // concatenate all parameters identified before + + while (CLcount < NumberParams) + { + char *source = &av[CLcount][0]; + char *destin = &content[(int) strlen (content)]; + + while (*source != '\0') + { + if (*source == '=') // The Parser expects whitespace before and after '=' + { + *destin++=' '; *destin++='='; *destin++=' '; // Hence make sure we add it + } + else + *destin++=*source; + source++; + } + *destin = '\0'; + CLcount++; + } + printf ("Parsing command line string '%s'", content); + ParseContent (p_Inp, Map, content, (int) strlen(content)); + free (content); + printf ("\n"); + } + else + { + snprintf (errortext, ET_SIZE, "Error in command line, ac %d, around string '%s', missing -f or -p parameters?", CLcount, av[CLcount]); + error (errortext, 300); + } + } + } + printf ("\n"); + +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views > 1) + { + printf ("Parsing Second View Configfile %s", p_Inp->View1ConfigName ); + content = GetConfigFileContent ( p_Inp->View1ConfigName ); + if (NULL==content) + error (errortext, 300); + ParseContent (p_Inp, MapView1, content, (int) strlen(content)); + printf ("\n"); + free (content); + } +#endif + + PatchInp(p_Vid, p_Inp); + + cfgparams = *p_Inp; + + if (p_Inp->DisplayEncParams) + DisplayEncoderParams(Map); +} + + + + +/*! + *********************************************************************** + * \brief + * Validates encoding parameters. + * \return + * -1 for error + *********************************************************************** + */ +static int TestEncoderParams(Mapping *Map, int bitdepth_qp_scale[3]) +{ + int i = 0; + + while (Map[i].TokenName != NULL) + { + if (Map[i].param_limits == 1) + { + if (Map[i].Type == 0) + { + if ( * (int *) (Map[i].Place) < (int) Map[i].min_limit || * (int *) (Map[i].Place) > (int) Map[i].max_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should be in [%d, %d] range.", Map[i].TokenName, (int) Map[i].min_limit,(int)Map[i].max_limit ); + error (errortext, 400); + } + + } + else if (Map[i].Type == 2) + { + if ( * (double *) (Map[i].Place) < Map[i].min_limit || * (double *) (Map[i].Place) > Map[i].max_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should be in [%.2f, %.2f] range.", Map[i].TokenName,Map[i].min_limit ,Map[i].max_limit ); + error (errortext, 400); + } + } + } + else if (Map[i].param_limits == 2) + { + if (Map[i].Type == 0) + { + if ( * (int *) (Map[i].Place) < (int) Map[i].min_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should not be smaller than %d.", Map[i].TokenName, (int) Map[i].min_limit); + error (errortext, 400); + } + } + else if (Map[i].Type == 2) + { + if ( * (double *) (Map[i].Place) < Map[i].min_limit ) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should not be smaller than %2.f.", Map[i].TokenName,Map[i].min_limit); + error (errortext, 400); + } + } + } + else if (Map[i].param_limits == 3) // Only used for QPs + { + + if (Map[i].Type == 0) + { + int cur_qp = * (int *) (Map[i].Place); + int min_qp = (int) (Map[i].min_limit - bitdepth_qp_scale[0]); + int max_qp = (int) Map[i].max_limit; + + if (( cur_qp < min_qp ) || ( cur_qp > max_qp )) + { + snprintf(errortext, ET_SIZE, "Error in input parameter %s. Check configuration file. Value should be in [%d, %d] range.", Map[i].TokenName, min_qp, max_qp ); + error (errortext, 400); + } + } + } + + i++; + } + return -1; +} + + + +/*! + *********************************************************************** + * \brief + * Outputs encoding parameters. + * \return + * -1 for error + *********************************************************************** + */ +static int DisplayEncoderParams(Mapping *Map) +{ + int i = 0; + + printf("******************************************************\n"); + printf("* Encoder Parameters *\n"); + printf("******************************************************\n"); + while (Map[i].TokenName != NULL) + { + if (Map[i].Type == 0) + printf("Parameter %s = %d\n",Map[i].TokenName,* (int *) (Map[i].Place)); + else if (Map[i].Type == 1) + printf("Parameter %s = ""%s""\n",Map[i].TokenName,(char *) (Map[i].Place)); + else if (Map[i].Type == 2) + printf("Parameter %s = %.2f\n",Map[i].TokenName,* (double *) (Map[i].Place)); + i++; + } + printf("******************************************************\n"); + return -1; +} + +/*! + ************************************************************************ + * \brief + * read the slice group configuration file. Returns without action + * if type is not 0, 2 or 6 + ************************************************************************ + */ +void read_slice_group_info(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + FILE * sgfile=NULL; + int i; + int ret; + unsigned int PicSizeInMapUnits; + + if ((p_Inp->slice_group_map_type != 0) && (p_Inp->slice_group_map_type != 2) && (p_Inp->slice_group_map_type != 6)) + { + // nothing to do + return; + } + + // do we have a file name (not only NULL character) + if ((int) strlen (p_Inp->SliceGroupConfigFileName) <= 1) + error ("No slice group config file name specified", 500); + + // open file + sgfile = fopen(p_Inp->SliceGroupConfigFileName,"r"); + + if ( NULL==sgfile ) + { + snprintf(errortext, ET_SIZE, "Error opening slice group file %s", p_Inp->SliceGroupConfigFileName); + error (errortext, 500); + } + + switch (p_Inp->slice_group_map_type) + { + case 0: + p_Inp->run_length_minus1=(int *)malloc(sizeof(int)*(p_Inp->num_slice_groups_minus1+1)); + if ( NULL==p_Inp->run_length_minus1 ) + { + fclose(sgfile); + no_mem_exit("read_slice_group_info: p_Inp->run_length_minus1"); + } + + // each line contains one 'run_length_minus1' value + for(i=0; i <= p_Inp->num_slice_groups_minus1;i++) + { + ret = fscanf(sgfile,"%d",(p_Inp->run_length_minus1+i)); + if ( 1!=ret ) + { + fclose(sgfile); + snprintf(errortext, ET_SIZE, "Error while reading slice group config file (line %d)", i+1); + error (errortext, 500); + } + // scan remaining line + ret = fscanf(sgfile,"%*[^\n]"); + } + break; + + case 2: + // determine expected frame size in map units + PicSizeInMapUnits = (p_Inp->output.width[0] >> 4) * (p_Inp->output.height[0] >> 4); + if (p_Inp->MbInterlace||p_Inp->PicInterlace) + PicSizeInMapUnits >>= 1; + + p_Inp->top_left = (unsigned *)malloc(sizeof(unsigned)*p_Inp->num_slice_groups_minus1); + p_Inp->bottom_right = (unsigned *)malloc(sizeof(unsigned)*p_Inp->num_slice_groups_minus1); + + if (NULL==p_Inp->top_left) + { + fclose(sgfile); + no_mem_exit("PatchInp: p_Inp->top_left"); + } + + if (NULL==p_Inp->bottom_right) + { + fclose(sgfile); + no_mem_exit("PatchInp: p_Inp->bottom_right"); + } + + // every two lines contain 'top_left' and 'bottom_right' value + for(i=0;inum_slice_groups_minus1;i++) + { + ret = fscanf(sgfile,"%ud",(p_Inp->top_left+i)); + if ( 1!=ret ) + { + fclose(sgfile); + snprintf(errortext, ET_SIZE, "Error while reading slice group config file (line %d)", 2*i +1); + error (errortext, 500); + } + if (p_Inp->top_left[i] > PicSizeInMapUnits) + { + fprintf(stdout, "Warning: slice group # %d top_left exceeds picture size (will be clipped)\n", i); + } + // scan remaining line + ret = fscanf(sgfile,"%*[^\n]"); + ret = fscanf(sgfile,"%ud",(p_Inp->bottom_right+i)); + if ( 1!=ret ) + { + fclose(sgfile); + snprintf(errortext, ET_SIZE, "Error while reading slice group config file (line %d)", 2*i + 2); + error (errortext, 500); + } + if (p_Inp->bottom_right[i] > PicSizeInMapUnits) + { + fprintf(stdout, "Warning: slice group # %d bottom_right exceeds picture size (will be clipped)\n", i); + } + // scan remaining line + ret = fscanf(sgfile,"%*[^\n]"); + } + break; + case 6: + { + int tmp; + int frame_mb_only; + int mb_width, mb_height, mapunit_height; + + frame_mb_only = !(p_Inp->PicInterlace || p_Inp->MbInterlace); + mb_width = (p_Inp->output.width[0] + p_Vid->auto_crop_right)>>4; + mb_height = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom)>>4; + mapunit_height = mb_height / (2-frame_mb_only); + + p_Inp->slice_group_id=(byte * ) malloc(sizeof(byte)*mapunit_height*mb_width); + if (NULL==p_Inp->slice_group_id) + { + fclose(sgfile); + no_mem_exit("PatchInp: p_Inp->slice_group_id"); + } + + // each line contains slice_group_id for one Macroblock + for (i=0;islice_group_id[i]= (byte) tmp; + if ( 1!=ret ) + { + fclose(sgfile); + snprintf(errortext, ET_SIZE, "Error while reading slice group config file (line %d)", i + 1); + error (errortext, 500); + } + if ( *(p_Inp->slice_group_id+i) > p_Inp->num_slice_groups_minus1 ) + { + fclose(sgfile); + snprintf(errortext, ET_SIZE, "Error while reading slice group config file: slice_group_id not allowed (line %d)", i + 1); + error (errortext, 500); + } + // scan remaining line + ret = fscanf(sgfile,"%*[^\n]"); + } + } + break; + default: + // we should not get here + error ("Wrong slice group type while reading config file", 500); + break; + } + + // close file again + fclose(sgfile); +} + +/*! + *********************************************************************** + * \brief + * Checks the input parameters for consistency. + *********************************************************************** + */ +static void PatchInp (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i; + int bitdepth_qp_scale[3]; + + if (p_Inp->src_BitDepthRescale) + { + bitdepth_qp_scale [0] = 6*(p_Inp->output.bit_depth[0] - 8); + bitdepth_qp_scale [1] = 6*(p_Inp->output.bit_depth[1] - 8); + bitdepth_qp_scale [2] = 6*(p_Inp->output.bit_depth[2] - 8); + } + else + { + bitdepth_qp_scale [0] = 6*(p_Inp->source.bit_depth[0] - 8); + bitdepth_qp_scale [1] = 6*(p_Inp->source.bit_depth[1] - 8); + bitdepth_qp_scale [2] = 6*(p_Inp->source.bit_depth[2] - 8); + } + + TestEncoderParams(Map, bitdepth_qp_scale); + + if (p_Inp->source.frame_rate == 0.0) + p_Inp->source.frame_rate = (double) INIT_FRAME_RATE; + + ParseVideoType(&p_Inp->input_file1); + ParseFrameNoFormatFromString (&p_Inp->input_file1); + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->num_of_views == 2 ) + { + ParseVideoType(&p_Inp->input_file2); + ParseFrameNoFormatFromString (&p_Inp->input_file2); + } +#endif + + if(p_Inp->source.bit_depth[0] >8) + { + if(!IMGTYPE) + { + error("IMGTYPE should be 1 when bitdepth is greater than 8", 600); + } + } + // Read resolution from file name + if (p_Inp->source.width[0] == 0 || p_Inp->source.height[0] == 0) + { + if (ParseSizeFromString (&p_Inp->input_file1, &(p_Inp->source.width[0]), &(p_Inp->source.height[0]), &(p_Inp->source.frame_rate)) == 0) + { + snprintf(errortext, ET_SIZE, "File name does not contain resolution information."); + error (errortext, 500); + } + } + +#if (!ENABLE_FIELD_CTX) + if ( (p_Inp->PicInterlace || p_Inp->MbInterlace) && p_Inp->symbol_mode ) + { + snprintf(errortext, ET_SIZE, "Recompile with ENABLE_FIELD_CTX set to one to enable interlaced coding with CABAC."); + error (errortext, 500); + } +#endif + +#if (!ENABLE_HIGH444_CTX) + if ( p_Inp->ProfileIDC == 244 && p_Inp->symbol_mode ) + { + snprintf(errortext, ET_SIZE, "Recompile with ENABLE_HIGH444_CTX set to one to enable the High 4:4:4 Profile with CABAC."); + error (errortext, 500); + } +#endif + + // Currently to simplify things, lets copy everything (overwrites yuv_format) + p_Inp->input_file1.format = p_Inp->source; + + + if (p_Inp->idr_period && p_Inp->intra_delay && p_Inp->idr_period <= p_Inp->intra_delay) + { + snprintf(errortext, ET_SIZE, " IntraDelay cannot be larger than or equal to IDRPeriod."); + error (errortext, 500); + } + + // some contraints for IntraPeriod, IDRPeriod, EnableIDRGOP, and NumberBFrames + if ( p_Inp->idr_period > 0 && (p_Inp->NumberBFrames + 1 + p_Inp->intra_delay) > p_Inp->idr_period ) + { + snprintf(errortext, ET_SIZE, " Setting NumberBFrames = IDRPeriod - 1 - IntraDelay."); + p_Inp->NumberBFrames = p_Inp->idr_period - 1 - p_Inp->intra_delay; + if ( p_Inp->NumberBFrames < 0 ) + { + p_Inp->NumberBFrames = p_Inp->idr_period - 1; + p_Inp->intra_delay = 0; + } + if ( p_Inp->HierarchicalCoding ) + { + p_Inp->HierarchicalCoding = 2; + } + } + if ( p_Inp->intra_period > 0 && (p_Inp->NumberBFrames + 1 + p_Inp->intra_delay) > p_Inp->intra_period ) + { + snprintf(errortext, ET_SIZE, " Setting NumberBFrames = IntraPeriod - 1 - IntraDelay."); + p_Inp->NumberBFrames = p_Inp->intra_period - 1 - p_Inp->intra_delay; + if ( p_Inp->NumberBFrames < 0 ) + { + p_Inp->NumberBFrames = p_Inp->intra_period - 1; + p_Inp->intra_delay = 0; + } + if ( p_Inp->HierarchicalCoding ) + { + p_Inp->HierarchicalCoding = 2; + } + } + // Added to avoid encoding problems with List 0 being empty + if (p_Inp->intra_delay && p_Inp->NumberBFrames > 0 && p_Inp->EnableOpenGOP) + p_Inp->PocMemoryManagement = 1; + + // Let us set up p_Inp->jumpd from frame_skip and NumberBFrames + p_Inp->jumpd = (p_Inp->NumberBFrames + 1) * (p_Inp->frame_skip + 1) - 1; + + + updateOutFormat(p_Inp); + // SEI/VUI 3:2 pulldown support + if ( p_Inp->SEIVUI32Pulldown && p_Inp->enable_32_pulldown ) + { + snprintf(errortext, ET_SIZE, "SEIVUI32Pulldown and Enable32Pulldown cannot be set at the same time."); + error (errortext, 500); + } + if ( p_Inp->SEIVUI32Pulldown ) + { + set_jm_vui_params( p_Inp ); + } + + if (p_Inp->no_frames == -1) + { + OpenFiles(&p_Inp->input_file1); + get_number_of_frames (p_Inp, &p_Inp->input_file1); + CloseFiles(&p_Inp->input_file1); + } + + if (p_Inp->no_frames < 1) + { + snprintf(errortext, ET_SIZE, "Not enough frames to encode (%d)", p_Inp->no_frames); + error (errortext, 500); + } + + // Check IntraProfile settings + if (p_Inp->IntraProfile) + { + if(p_Inp->NumberBFrames) + { + snprintf(errortext, ET_SIZE, "Use of B slices not supported with Intra Profiles. Set NumberBFrames to 0."); + error (errortext, 400); + } + + if (p_Inp->PocMemoryManagement) + { + printf("Warning: PocMemoryManagement not supported for Intra Profiles. Process Disabled.\n"); + p_Inp->PocMemoryManagement = 0; + } + if (p_Inp->ReferenceReorder) + { + printf("Warning: ReferenceReorder not supported for Intra Profiles. Process Disabled.\n"); + p_Inp->ReferenceReorder = 0; + } + } + + // Direct Mode consistency check + if(p_Inp->NumberBFrames && p_Inp->direct_spatial_mv_pred_flag != DIR_SPATIAL && p_Inp->direct_spatial_mv_pred_flag != DIR_TEMPORAL) + { + snprintf(errortext, ET_SIZE, "Unsupported direct mode=%d, use TEMPORAL=0 or SPATIAL=1", p_Inp->direct_spatial_mv_pred_flag); + error (errortext, 400); + } + + if (p_Inp->PicInterlace>0 || p_Inp->MbInterlace>0) + { + if (p_Inp->directInferenceFlag==0) + printf("\nWarning: DirectInferenceFlag set to 1 due to interlace coding."); + p_Inp->directInferenceFlag = 1; + } + + if(p_Inp->PicInterlace > 0 || p_Inp->MbInterlace > 0) + { + printf("\nWarning: WPMCPredicions is set to 0 due to interlace coding.\n"); + p_Inp->WPMCPrecision = 0; + } +#if TRACE + if ((int) strlen (p_Inp->TraceFile) > 0 && (p_Enc->p_trace = fopen(p_Inp->TraceFile,"w"))==NULL) + { + snprintf(errortext, ET_SIZE, "Error open file %s", p_Inp->TraceFile); + error (errortext, 500); + } +#endif + + + + if ((p_Inp->slice_mode == 1)&&(p_Inp->MbInterlace != 0)) + { + if ((p_Inp->slice_argument & 0x01)!=0) + { + fprintf ( stdout, "Warning: slice border within macroblock pair. "); + if (p_Inp->slice_argument > 1) + { + p_Inp->slice_argument--; + } + else + { + p_Inp->slice_argument++; + } + fprintf ( stdout, "Using %d MBs per slice.\n", p_Inp->slice_argument); + } + } + + if (p_Inp->WPMCPrecision && (p_Inp->RDPictureDecision != 1 || p_Inp->GenerateMultiplePPS != 1) ) + { + snprintf(errortext, ET_SIZE, "WPMCPrecision requires both RDPictureDecision=1 and GenerateMultiplePPS=1.\n"); + error (errortext, 400); + } + p_Inp->num_ref_frames_org = p_Inp->num_ref_frames; + p_Inp->P_List0_refs_org[0] = p_Inp->P_List0_refs[0]; + p_Inp->B_List0_refs_org[0] = p_Inp->B_List0_refs[0]; + p_Inp->B_List1_refs_org[0] = p_Inp->B_List1_refs[0]; + p_Inp->P_List0_refs_org[1] = p_Inp->P_List0_refs[1]; + p_Inp->B_List0_refs_org[1] = p_Inp->B_List0_refs[1]; + p_Inp->B_List1_refs_org[1] = p_Inp->B_List1_refs[1]; + + if (p_Inp->WPMCPrecision && p_Inp->WPMCPrecFullRef && p_Inp->num_ref_frames < 16 ) + { + p_Inp->num_ref_frames++; + if ( p_Inp->P_List0_refs[0] ) + { + p_Inp->P_List0_refs[0]++; + } + else + { + p_Inp->P_List0_refs[0] = p_Inp->num_ref_frames; + } + if ( p_Inp->B_List0_refs[0] ) + { + p_Inp->B_List0_refs[0]++; + } + else + { + p_Inp->B_List0_refs[0] = p_Inp->num_ref_frames; + } + if ( p_Inp->B_List1_refs[0] ) + { + p_Inp->B_List1_refs[0]++; + } + else + { + p_Inp->B_List1_refs[0] = p_Inp->num_ref_frames; + } + if ( p_Inp->SepViewInterSearch ) + { + if ( p_Inp->P_List0_refs[1] ) + { + p_Inp->P_List0_refs[1]++; + } + else + { + p_Inp->P_List0_refs[1] = p_Inp->num_ref_frames; + } + if ( p_Inp->B_List0_refs[1] ) + { + p_Inp->B_List0_refs[1]++; + } + else + { + p_Inp->B_List0_refs[1] = p_Inp->num_ref_frames; + } + if ( p_Inp->B_List1_refs[1] ) + { + p_Inp->B_List1_refs[1]++; + } + else + { + p_Inp->B_List1_refs[1] = p_Inp->num_ref_frames; + } + } + } + else if ( p_Inp->WPMCPrecision && p_Inp->WPMCPrecFullRef ) + { + snprintf(errortext, ET_SIZE, "WPMCPrecFullRef requires NumberReferenceFrames < 16.\n"); + error (errortext, 400); + } + + if (p_Inp->PicInterlace) + { + if (p_Inp->ReferenceReorder == 2) + { + snprintf(errortext, ET_SIZE, "ReferenceReorder = 2 is not supported with field encoding\n"); + error (errortext, 400); + } + if (p_Inp->ReferenceReorder == 2) + { + snprintf(errortext, ET_SIZE, "PocMemoryManagement = 2 is not supported with field encoding\n"); + error (errortext, 400); + } + } + + if (p_Inp->ReferenceReorder && p_Inp->MbInterlace ) + { + snprintf(errortext, ET_SIZE, "ReferenceReorder is not supported with MBAFF\n"); + error (errortext, 400); + } + + if (p_Inp->SetFirstAsLongTerm && (p_Inp->ReferenceReorder == 1 || p_Inp->ReferenceReorder == 2)) + { + printf("SetFirstAsLongTerm is set. ReferenceReorder is not supported and therefore disabled. \n"); + p_Inp->ReferenceReorder = 0; + } + + if ( is_MVC_profile(p_Inp->ProfileIDC) ) + { + if (p_Inp->ReferenceReorder > 1) + { + snprintf(errortext, ET_SIZE, "ReferenceReorder > 1 is not supported with the Multiview (118) or Stereo High (128) profiles and is therefore disabled. \n"); + p_Inp->ReferenceReorder = 0; + } + if ( (p_Inp->PocMemoryManagement) && (p_Inp->PicInterlace > 0) ) + { + snprintf(errortext, ET_SIZE, "PocMemoryManagement>0 is not supported with the Multiview (118) or Stereo High (128) profiles and is therefore disabled. \n"); + p_Inp->PocMemoryManagement = 0; + } + } + + + if (p_Inp->PocMemoryManagement && p_Inp->MbInterlace ) + { + snprintf(errortext, ET_SIZE, "PocMemoryManagement is not supported with MBAFF\n"); + error (errortext, 400); + } + + if(p_Inp->MbInterlace && p_Inp->RDPictureDecision && p_Inp->GenerateMultiplePPS) + { + snprintf(errortext, ET_SIZE, "RDPictureDecision+GenerateMultiplePPS not supported with MBAFF. RDPictureDecision therefore disabled\n"); + p_Inp->RDPictureDecision = 0; + } + + if ((!p_Inp->rdopt)&&(p_Inp->MbInterlace==2)) + { + snprintf(errortext, ET_SIZE, "MB AFF is not compatible with non-rd-optimized coding."); + error (errortext, 500); + } + + // check RDoptimization mode and profile. FMD does not support Frex Profiles. + if (p_Inp->rdopt==2 && ( p_Inp->ProfileIDC>=FREXT_HP || p_Inp->ProfileIDC==FREXT_CAVLC444 )) + { + snprintf(errortext, ET_SIZE, "Fast Mode Decision methods not supported in FREX Profiles"); + error (errortext, 500); + } + + // Tian Dong: May 31, 2002 + // The number of frames in one sub-seq in enhanced layer should not exceed + // the number of reference frame number. + if ( p_Inp->NumFramesInELSubSeq > p_Inp->num_ref_frames || p_Inp->NumFramesInELSubSeq < 0 ) + { + snprintf(errortext, ET_SIZE, "NumFramesInELSubSeq (%d) is out of range [0,%d).", p_Inp->NumFramesInELSubSeq, p_Inp->num_ref_frames); + error (errortext, 500); + } + // Tian Dong: Enhanced GOP is not supported in bitstream mode. September, 2002 + if ( p_Inp->NumFramesInELSubSeq > 0 ) + { + snprintf(errortext, ET_SIZE, "Enhanced GOP is not properly supported yet."); + error (errortext, 500); + } + // Tian Dong (Sept 2002) + // The AFF is not compatible with spare picture for the time being. + if ((p_Inp->PicInterlace || p_Inp->MbInterlace) && p_Inp->SparePictureOption == TRUE) + { + snprintf(errortext, ET_SIZE, "AFF is not compatible with spare picture."); + error (errortext, 500); + } + + // Only the RTP mode is compatible with spare picture for the time being. + if (p_Inp->of_mode != PAR_OF_RTP && p_Inp->SparePictureOption == TRUE) + { + snprintf(errortext, ET_SIZE, "Only RTP output mode is compatible with spare picture features."); + error (errortext, 500); + } + + // RTP is not defined for MVC yet + if (p_Inp->of_mode == PAR_OF_RTP && (( p_Inp->ProfileIDC == STEREO_HIGH ) || (p_Inp->ProfileIDC == MULTIVIEW_HIGH) )) + { + snprintf(errortext, ET_SIZE, "RTP output mode is not compatible with MVC profiles."); + error (errortext, 500); + } + + if( (p_Inp->WeightedPrediction > 0 || p_Inp->WeightedBiprediction > 0) && (p_Inp->MbInterlace)) + { + snprintf(errortext, ET_SIZE, "Weighted prediction coding is not supported for MB AFF currently."); + error (errortext, 500); + } + if( (p_Inp->WeightedPrediction > 0 || p_Inp->WeightedBiprediction > 0) && (p_Inp->yuv_format==3)) + { + snprintf(errortext, ET_SIZE, "Weighted prediction coding is not supported for 4:4:4 encoding."); + error (errortext, 500); + } + if ( p_Inp->NumFramesInELSubSeq > 0 && p_Inp->WeightedPrediction > 0) + { + snprintf(errortext, ET_SIZE, "Enhanced GOP is not supported in weighted prediction coding mode yet."); + error (errortext, 500); + } + + // Rate control + if(p_Inp->RCEnable) + { + if ( p_Inp->RCUpdateMode == RC_MODE_1 && + !( (p_Inp->intra_period == 1 || p_Inp->idr_period == 1 || p_Inp->BRefPictures == 2 ) && !p_Inp->NumberBFrames ) ) + { + snprintf(errortext, ET_SIZE, "Use RCUpdateMode = 1 only for all intra or all B-slice coding."); + error (errortext, 500); + } + if ( (p_Inp->RCUpdateMode == RC_MODE_0 || p_Inp->RCUpdateMode == RC_MODE_2 || p_Inp->RCUpdateMode == RC_MODE_3) && + (p_Inp->PReplaceBSlice && p_Inp->NumberBFrames ) ) + { + snprintf(errortext, ET_SIZE, "PReplaceBSlice is not supported with RCUpdateMode=0,2,3."); + error (errortext, 500); + } + + if ( p_Inp->BRefPictures == 2 && p_Inp->intra_period == 0 && p_Inp->RCUpdateMode != RC_MODE_1 ) + { + snprintf(errortext, ET_SIZE, "Use RCUpdateMode = 1 for all B-slice coding."); + error (errortext, 500); + } + + if ( p_Inp->HierarchicalCoding && p_Inp->RCUpdateMode != RC_MODE_2 && p_Inp->RCUpdateMode != RC_MODE_3 ) + { + snprintf(errortext, ET_SIZE, "Use RCUpdateMode = 2 or 3 for hierarchical B-picture coding."); + error (errortext, 500); + } + if ( (p_Inp->RCUpdateMode != RC_MODE_1) && (p_Inp->intra_period == 1) ) + { + snprintf(errortext, ET_SIZE, "Use RCUpdateMode = 1 for all intra coding."); + error (errortext, 500); + } + } + + if ((p_Inp->NumberBFrames)&&(p_Inp->BRefPictures)&&(p_Inp->idr_period)&&(p_Inp->pic_order_cnt_type!=0)) + { + error("Stored B pictures combined with IDR pictures only supported in Picture Order Count type 0\n",-1000); + } + + if( !p_Inp->direct_spatial_mv_pred_flag && p_Inp->num_ref_frames<2 && p_Inp->NumberBFrames >0) + error("temporal direct needs at least 2 ref frames\n",-1000); + +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->SepViewInterSearch && p_Inp->SearchMode[1] == FAST_FULL_SEARCH && p_Inp->MEErrorMetric[F_PEL] > ERROR_SSE) + { + snprintf(errortext, ET_SIZE, "\nOnly SAD and SSE distortion computation supported with Fast Full Search."); + error (errortext, 500); + } + else +#endif + if (p_Inp->SearchMode[0] == FAST_FULL_SEARCH && p_Inp->MEErrorMetric[F_PEL] > ERROR_SSE) + { + snprintf(errortext, ET_SIZE, "\nOnly SAD and SSE distortion computation supported with Fast Full Search."); + error (errortext, 500); + } + + if (p_Inp->rdopt == 0) + { + if (p_Inp->DisableSubpelME[0] || p_Inp->DisableSubpelME[1]) + { + if (p_Inp->MEErrorMetric[F_PEL] != p_Inp->ModeDecisionMetric) + { + snprintf(errortext, ET_SIZE, "\nLast refinement level (FPel) distortion not the same as Mode decision distortion.\nPlease update MEDistortionFPel (%d) and/or MDDistortion(%d).", p_Inp->MEErrorMetric[F_PEL], p_Inp->ModeDecisionMetric); + error (errortext, 500); + } + } + else if (p_Inp->MEErrorMetric[Q_PEL] != p_Inp->ModeDecisionMetric) + { + snprintf(errortext, ET_SIZE, "\nLast refinement level (QPel) distortion not the same as Mode decision distortion.\nPlease update MEDistortionQPel (%d) and/or MDDistortion(%d).", p_Inp->MEErrorMetric[Q_PEL], p_Inp->ModeDecisionMetric); + error (errortext, 500); + } + } + // frext + if(p_Inp->Transform8x8Mode && p_Inp->sp_periodicity /*SP-frames*/) + { + snprintf(errortext, ET_SIZE, "\nThe new 8x8 mode is not implemented for sp-frames."); + error (errortext, 500); + } + + if(p_Inp->Transform8x8Mode && ( p_Inp->ProfileIDCProfileIDC!=FREXT_CAVLC444 )) + { + snprintf(errortext, ET_SIZE, "\nTransform8x8Mode may be used only with ProfileIDC %d to %d.", FREXT_HP, FREXT_Hi444); + error (errortext, 500); + } + + if (p_Inp->DisableIntra4x4 == 1 && p_Inp->DisableIntra16x16 == 1 && p_Inp->EnableIPCM == 0 && p_Inp->Transform8x8Mode == 0) + { + snprintf(errortext, ET_SIZE, "\nAt least one intra prediction mode needs to be enabled."); + error (errortext, 500); + } + + if(p_Inp->ScalingMatrixPresentFlag && ( p_Inp->ProfileIDCProfileIDC!=FREXT_CAVLC444 )) + { + snprintf(errortext, ET_SIZE, "\nScalingMatrixPresentFlag may be used only with ProfileIDC %d to %d.", FREXT_HP, FREXT_Hi444); + error (errortext, 500); + } + + if(p_Inp->yuv_format==YUV422 && ( p_Inp->ProfileIDC < FREXT_Hi422 && p_Inp->ProfileIDC!=FREXT_CAVLC444 )) + { + snprintf(errortext, ET_SIZE, "\nFRExt Profile(YUV Format) Error!\nYUV422 can be used only with ProfileIDC %d or %d\n",FREXT_Hi422, FREXT_Hi444); + error (errortext, 500); + } + if(p_Inp->yuv_format==YUV444 && ( p_Inp->ProfileIDC < FREXT_Hi444 && p_Inp->ProfileIDC!=FREXT_CAVLC444 )) + { + snprintf(errortext, ET_SIZE, "\nFRExt Profile(YUV Format) Error!\nYUV444 can be used only with ProfileIDC %d.\n",FREXT_Hi444); + error (errortext, 500); + } + + if (p_Inp->NumberBFrames && ((p_Inp->BiPredMotionEstimation) && (p_Inp->search_range[0] < p_Inp->BiPredMESearchRange[0]))) + { + snprintf(errortext, ET_SIZE, "\nBiPredMESearchRange must be smaller or equal SearchRange."); + error (errortext, 500); + } +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->SepViewInterSearch ) + { + if (p_Inp->NumberBFrames && ((p_Inp->BiPredMotionEstimation) && (p_Inp->search_range[1] < p_Inp->BiPredMESearchRange[1]))) + { + snprintf(errortext, ET_SIZE, "\nView1BiPredMESearchRange must be smaller or equal View1SearchRange."); + error (errortext, 500); + } + } +#endif + + if (p_Inp->BiPredMotionEstimation) + { + p_Inp->BiPredMotionEstimation = 0; + for (i = 0 ; i < 4; i++) + p_Inp->BiPredMotionEstimation |= p_Inp->BiPredSearch[i]; + } + else + { + for (i = 0 ; i < 4; i++) + p_Inp->BiPredSearch[i] = 0; + } + + // check consistency + if ( p_Inp->ChromaMEEnable && !(p_Inp->ChromaMCBuffer) ) + { + snprintf(errortext, ET_SIZE, "\nChromaMCBuffer must be set to 1 if ChromaMEEnable is set."); + error (errortext, 500); + } + + if ( p_Inp->ChromaMEEnable && p_Inp->yuv_format == YUV400) + { + fprintf(stdout, "Warning: ChromaMEEnable cannot be used with monochrome color format, disabling ChromaMEEnable.\n"); + p_Inp->ChromaMEEnable = FALSE; + } + + if ( (p_Inp->ChromaMCBuffer == 0) && (( p_Inp->yuv_format == YUV444) && (!p_Inp->separate_colour_plane_flag)) ) + { + fprintf(stdout, "Warning: Enabling ChromaMCBuffer for 4:4:4 combined color coding.\n"); + p_Inp->ChromaMCBuffer = 1; + } + + if (p_Inp->EnableOpenGOP && p_Inp->ReferenceReorder == 2) + { + printf("If OpenGOP is enabled than ReferenceReorder is set to 1. \n"); + } + + if (p_Inp->EnableOpenGOP) + p_Inp->ReferenceReorder = 1; + +#if (MVC_EXTENSION_ENABLE) + if((p_Inp->ProfileIDC==MULTIVIEW_HIGH || p_Inp->ProfileIDC==STEREO_HIGH) && p_Inp->num_of_views != 2) + { + snprintf(errortext, ET_SIZE, "NumberOfViews must be two if ProfileIDC is set to 118 (Multiview High Profile). Otherwise (for a single view) please select a non-multiview profile such as 100."); + error (errortext, 500); + } + +// if (p_Inp->PicInterlace == 2 && p_Inp->MVCInterViewReorder != 0) +// { +// snprintf(errortext, ET_SIZE, "MVCInterViewReorder not supported with Adaptive Frame Field Coding"); +// error (errortext, 500); +// } + + if(p_Inp->MVCInterViewReorder) + { + if ( !is_MVC_profile(p_Inp->ProfileIDC) ) + { + snprintf(errortext, ET_SIZE, "ProfileIDC must be 118, 128, 134, or 135 to use MVCInterViewReorder=1."); + error (errortext, 500); + } + } +#endif + + if (p_Inp->SearchMode[0] != EPZS +#if (MVC_EXTENSION_ENABLE) + && (!p_Inp->SepViewInterSearch || p_Inp->SearchMode[1] != EPZS ) +#endif + ) + p_Inp->EPZSSubPelGrid = 0; + + if (p_Inp->redundant_pic_flag) + { + if (p_Inp->PicInterlace || p_Inp->MbInterlace) + { + snprintf(errortext, ET_SIZE, "Redundant pictures cannot be used with interlaced tools."); + error (errortext, 500); + } + if (p_Inp->RDPictureDecision) + { + snprintf(errortext, ET_SIZE, "Redundant pictures cannot be used with RDPictureDecision."); + error (errortext, 500); + } + if (p_Inp->NumberBFrames) + { + snprintf(errortext, ET_SIZE, "Redundant pictures cannot be used with B frames."); + error (errortext, 500); + } + if (p_Inp->PrimaryGOPLength < (1 << p_Inp->NumRedundantHierarchy)) + { + snprintf(errortext, ET_SIZE, "PrimaryGOPLength must be equal or greater than 2^NumRedundantHierarchy."); + error (errortext, 500); + } + if (p_Inp->num_ref_frames < p_Inp->PrimaryGOPLength) + { + snprintf(errortext, ET_SIZE, "NumberReferenceFrames must be greater than or equal to PrimaryGOPLength."); + error (errortext, 500); + } + } + + if (p_Inp->num_ref_frames == 1 && p_Inp->NumberBFrames) + { + fprintf( stdout, "\nWarning: B slices used but only one reference allocated within reference buffer.\n"); + fprintf( stdout, " Performance may be considerably compromised! \n"); + fprintf( stdout, " 2 or more references recommended for use with B slices.\n"); + } + if ((p_Inp->HierarchicalCoding || p_Inp->BRefPictures) && p_Inp->NumberBFrames) + { + fprintf( stdout, "\nWarning: Hierarchical coding or Referenced B slices used.\n"); + fprintf( stdout, " Make sure that you have allocated enough references\n"); + fprintf( stdout, " in reference buffer to achieve best performance.\n"); + } + + if (p_Inp->FastMDEnable == 0) + { + p_Inp->FastIntraMD = 0; + p_Inp->FastIntra16x16 = 0; + p_Inp->FastIntra4x4 = 0; + p_Inp->FastIntra8x8 = 0; + p_Inp->FastIntraChroma = 0; + } + + // Init RDOQuant + if (p_Inp->UseRDOQuant == 1) + { + if (p_Inp->rdopt == 0) + { + snprintf(errortext, ET_SIZE, "RDO Quantization not supported with low complexity RDO."); + error (errortext, 500); + } + + if (p_Inp->MbInterlace != 0) + { + printf("RDO Quantization currently not supported with MBAFF. Option disabled.\n"); + p_Inp->UseRDOQuant = 0; + p_Inp->RDOQ_QP_Num = 1; + p_Inp->RDOQ_CP_MV = 0; + p_Inp->RDOQ_CP_Mode = 0; + } + else + { + p_Inp->AdaptiveRounding = 0; + printf("AdaptiveRounding is disabled when RDO Quantization is used\n"); + if (p_Inp->RDOQ_QP_Num < 2) + { + p_Inp->RDOQ_CP_MV = 0; + p_Inp->RDOQ_CP_Mode = 0; + } + } + } + else + { + p_Inp->RDOQ_QP_Num = 1; + p_Inp->RDOQ_CP_MV = 0; + p_Inp->RDOQ_CP_Mode = 0; + } + + if(p_Inp->num_slice_groups_minus1 > 0 && (p_Inp->GenerateMultiplePPS ==1 && p_Inp->RDPictureDecision == 1)) + { + printf("Warning: Weighted Prediction may not function correctly for multiple slices\n"); + } + +#if KEEP_B_SAME_LIST + if ( p_Inp->BIdenticalList > 0 && p_Inp->ReferenceReorder != 1 ) + { + snprintf(errortext, ET_SIZE, "Set two lists of B picture identical can only be used when ReferenceReorder is 1"); + error (errortext, 500); + } +#endif + +#if CRA + if ( p_Inp->useCRA == 1 && p_Inp->intra_period == 0 ) + { + printf("Warning: CRA can only be used for IntraPeriod > 0, set CRA to 0\n"); + p_Inp->useCRA = 0; + } + if ( p_Inp->useCRA == 1 && p_Inp->LowDelay == 1 ) + { + snprintf(errortext, ET_SIZE, "CRA cannot be used when LowDelay is 1"); + error (errortext, 500); + } +#endif + +#if HM50_LIKE_MMCO + if ( p_Inp->HM50LikeMMCO == 1 ) + { + printf("Warning: HM50LikeMMCO can only be used for random access case with GOP size equal to 8 and HM-5.0 coding order\n"); + printf(" If it used for other coding structure, the performance may loss\n"); + } + if ( p_Inp->HM50LikeMMCO == 1 && p_Inp->NumberBFrames != 7 ) + { + printf("Warning: HM50LikeMMCO can only be used for random access case with NumberBFrames equal to 7, turn it off\n"); + p_Inp->HM50LikeMMCO = 0; + } + if ( p_Inp->HM50LikeMMCO == 1 && p_Inp->LowDelay == 1 ) + { + printf("Warning: HM50LikeMMCO cannot be used for low delay, turn it off\n"); + p_Inp->HM50LikeMMCO = 0; + } +#endif + +#if LD_REF_SETTING + if ( p_Inp->useF701RefForLD == 1 ) + { + printf("Warning: useF701RefForLD can only be used for low delay case with GOP size equal to 4 and 4 reference frames as HM-5.0 low delay\n"); + printf(" If other GOP size or number of reference frames are used, the performance may be loss with useF701RefForLD\n"); + } + if ( p_Inp->useF701RefForLD == 1 && p_Inp->LowDelay == 0 ) + { + snprintf(errortext, ET_SIZE, "useF701RefForLD can only be used when LowDelay is 1"); + error (errortext, 500); + } +#endif + + profile_check(p_Inp); + + if(!p_Inp->RDPictureDecision) + { + p_Inp->RDPictureMaxPassISlice = 1; + p_Inp->RDPictureMaxPassPSlice = 1; + p_Inp->RDPictureMaxPassBSlice = 1; + p_Inp->RDPictureDeblocking = 0; + p_Inp->RDPictureDirectMode = 0; + p_Inp->RDPictureFrameQPPSlice = 0; + p_Inp->RDPictureFrameQPBSlice = 0; + } +} + +/*! + ************************************************************************ + * \brief + * Set VUI time scale and number of clock ticks given input frame rate + ************************************************************************ +*/ + +static void SetVUIScaleAndTicks(InputParameters *p_Inp, double frame_rate) +{ + double frame_rate_integer = (double)ceil( frame_rate ); + + if ( frame_rate_integer != frame_rate ) + { + // frame rate is a floating-point number + // check whether multiplying it with 1001/1000=1.001 brings it closer to frame_rate_integer + double new_frame_rate = 1.001 * frame_rate; + + if ( dabs( new_frame_rate - frame_rate_integer ) < dabs( frame_rate - frame_rate_integer ) ) + { + p_Inp->VUI.num_units_in_tick = 1001; + p_Inp->VUI.time_scale = (int)floor( frame_rate_integer * (1000 << 1) ); // two ticks per frame + } + else + { + p_Inp->VUI.num_units_in_tick = 1000; + p_Inp->VUI.time_scale = (int)floor( frame_rate * (p_Inp->VUI.num_units_in_tick << 1) + 0.5 ); // two ticks per frame + } + } + else + { + // frame rate is an integer + p_Inp->VUI.num_units_in_tick = 1000; + p_Inp->VUI.time_scale = (int)floor( frame_rate * (p_Inp->VUI.num_units_in_tick << 1) ); // two ticks per frame + } +} + diff --git a/lencod/src/conformance.c b/lencod/src/conformance.c new file mode 100644 index 0000000..52cf1a8 --- /dev/null +++ b/lencod/src/conformance.c @@ -0,0 +1,633 @@ +/*! + ************************************************************************************** + * \file + * conformance.c + * \brief + * Level & Profile related conformance functions + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + * \note + * + ************************************************************************************** + */ + +#include "global.h" +#include "conformance.h" + +// Max Frame Size Limit +// Level Limit - - - - - - - - - 1b 10 11 12 13 - - - - - - 20 21 22 - - - - - - - +static const unsigned int MaxFs [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 396, 396, 396, 0, 0, 0, 0, 0, 0, 396, 792, 1620, 0, 0, 0, 0, 0, 0, 0, +// 30 31 32 - - - - - - - 40 41 42 - - - - - - - 50 51 + 1620, 3600, 5120, 0, 0, 0, 0, 0, 0, 0, 8192, 8192, 8704, 0, 0, 0, 0, 0, 0, 0, 22080, 36864 }; +static const unsigned int MinCR [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2 }; +static const unsigned int MaxBR [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,128, 192, 384, 768, 0, 0, 0, 0, 0, 0,2000,4000,4000, 0, 0, 0, 0, 0, 0, 0, + 10000,14000,20000, 0, 0, 0, 0, 0, 0, 0,20000,50000,50000, 0, 0, 0, 0, 0, 0, 0,135000,240000 }; +static const unsigned int MaxCPB[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0,175,350, 500,1000,2000, 0, 0, 0, 0, 0, 0,2000,4000,4000, 0, 0, 0, 0, 0, 0, 0, + 10000,14000,20000, 0, 0, 0, 0, 0, 0, 0,25000,62500,62500, 0, 0, 0, 0, 0, 0, 0,135000,240000 }; +// Max macroblock processing rate +static const unsigned int MaxMBPS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, 1485, 3000, 6000, 11880, 0, 0, 0, 0, 0, 0, 11880, 19800, 20250, 0, 0, 0, 0, 0, 0, 0, + 40500, 108000, 216000, 0, 0, 0, 0, 0, 0, 0, 245760, 245760, 522240, 0, 0, 0, 0, 0, 0, 0, 589824, 983040 }; +// Vertical MV Limits (integer/halfpel/quarterpel) +// Currently only Integer Pel restrictions are used, +// since the way values are specified +// (i.e. mvlowbound = (levelmvlowbound + 1) and the way +// Subpel ME is performed, subpel will always be within range. +static const int LEVELVMVLIMIT[17][6] = +{ + { -63, 63, -128, 127, -256, 255}, + { -63, 63, -128, 127, -256, 255}, + { -127, 127, -256, 255, -512, 511}, + { -127, 127, -256, 255, -512, 511}, + { -127, 127, -256, 255, -512, 511}, + { -127, 127, -256, 255, -512, 511}, + { -255, 255, -512, 511, -1024, 1023}, + { -255, 255, -512, 511, -1024, 1023}, + { -255, 255, -512, 511, -1024, 1023}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047}, + { -511, 511, -1024, 1023, -2048, 2047} +}; + +const int LEVELHMVLIMIT[6] = { -2047, 2047, -4096, 4095, -8192, 8191}; + +/*! + *********************************************************************** + * \brief + * Get maximum frame size (in MBs) supported given a level + *********************************************************************** + */ +unsigned int getMaxFs (unsigned int levelIdc) +{ + unsigned int ret; + + if ( (levelIdc < 9) || (levelIdc > 51)) + error ("getMaxFs: Unknown LevelIdc", 500); + + // in Baseline, Main and Extended: Level 1b is specified with LevelIdc==11 and constrained_set3_flag == 1 + + ret = MaxFs[levelIdc]; + + if ( 0 == ret ) + error ("getMaxFs: Unknown LevelIdc", 500); + + return ret; +} + +/*! + *********************************************************************** + * \brief + * Get maximum processing rate (in MB/s) supported given a level + *********************************************************************** + */ +unsigned int getMaxMBPS (unsigned int levelIdc) +{ + unsigned int ret; + + if ( (levelIdc < 9) || (levelIdc > 51)) + error ("getMaxMBPS: Unknown LevelIdc", 500); + + // in Baseline, Main and Extended: Level 1b is specified with LevelIdc==11 and constrained_set3_flag == 1 + + ret = MaxMBPS[levelIdc]; + + if ( 0 == ret ) + error ("getMaxMBPS: Unknown LevelIdc", 500); + + return ret; +} + +/*! + *********************************************************************** + * \brief + * Get minimum compression ratio supported given a level + *********************************************************************** + */ +unsigned int getMinCR (unsigned int levelIdc) +{ + unsigned int ret; + + if ( (levelIdc < 9) || (levelIdc > 51)) + error ("getMinCR: Unknown LevelIdc", 500); + + // in Baseline, Main and Extended: Level 1b is specified with LevelIdc==11 and constrained_set3_flag == 1 + + ret = MinCR[levelIdc]; + + if ( 0 == ret ) + error ("getMinCR: Unknown LevelIdc", 500); + + return ret; +} + +/*! + *********************************************************************** + * \brief + * Get maximum bit rate (in bits/s) supported given a level + *********************************************************************** + */ +unsigned int getMaxBR (unsigned int levelIdc) +{ + unsigned int ret; + + if ( (levelIdc < 9) || (levelIdc > 51)) + error ("getMaxBR: Unknown LevelIdc", 500); + + // in Baseline, Main and Extended: Level 1b is specified with LevelIdc==11 and constrained_set3_flag == 1 + + ret = MaxBR[levelIdc]; + + if ( 0 == ret ) + error ("getMaxBR: Unknown LevelIdc", 500); + + return ret; +} + +/*! + *********************************************************************** + * \brief + * Get maximum coded buffer size (in bits) supported given a level + *********************************************************************** + */ +unsigned int getMaxCPB (unsigned int levelIdc) +{ + unsigned int ret; + + if ( (levelIdc < 9) || (levelIdc > 51)) + error ("getMaxCPB: Unknown LevelIdc", 500); + + // in Baseline, Main and Extended: Level 1b is specified with LevelIdc==11 and constrained_set3_flag == 1 + + ret = MaxCPB[levelIdc]; + + if ( 0 == ret ) + error ("getMaxCPB: Unknown LevelIdc", 500); + + return ret; +} + +/*! + *********************************************************************** + * \brief + * Check Profile conformance + *********************************************************************** + */ +void profile_check(InputParameters *p_Inp) +{ + if((p_Inp->ProfileIDC != BASELINE ) && + (p_Inp->ProfileIDC != MAIN ) && + (p_Inp->ProfileIDC != EXTENDED ) && + (p_Inp->ProfileIDC != FREXT_HP ) && + (p_Inp->ProfileIDC != FREXT_Hi10P ) && +#if (MVC_EXTENSION_ENABLE) + (p_Inp->ProfileIDC != MULTIVIEW_HIGH ) && // MVC multiview high profile + (p_Inp->ProfileIDC != STEREO_HIGH ) && // MVC stereo high profile +#endif + (p_Inp->ProfileIDC != FREXT_Hi422 ) && + (p_Inp->ProfileIDC != FREXT_Hi444 ) && + (p_Inp->ProfileIDC != FREXT_CAVLC444 )) + { +#if (MVC_EXTENSION_ENABLE) + snprintf(errortext, ET_SIZE, "Profile must be in\n\n 66 (Baseline),\n 77 (Main),\n 88 (Extended),\n 100 (High),\n 110 (High 10 or High 10 Intra)\n" + " 122 (High 4:2:2 or High 4:2:2 Intra),\n 244 (High 4:4:4 predictive or High 4:4:4 Intra),\n 44 (CAVLC 4:4:4 Intra)\n 118 (MVC profile)\n"); +#else + snprintf(errortext, ET_SIZE, "Profile must be in\n\n 66 (Baseline),\n 77 (Main),\n 88 (Extended),\n 100 (High),\n 110 (High 10 or High 10 Intra)\n" + " 122 (High 4:2:2 or High 4:2:2 Intra),\n 244 (High 4:4:4 predictive or High 4:4:4 Intra),\n 44 (CAVLC 4:4:4 Intra)\n"); +#endif + error (errortext, 500); + } + + if ((p_Inp->partition_mode) && (p_Inp->symbol_mode==CABAC)) + { + snprintf(errortext, ET_SIZE, "Data partitioning and CABAC is not supported in any profile."); + error (errortext, 500); + } + + if (p_Inp->redundant_pic_flag) + { + if (p_Inp->ProfileIDC != BASELINE) + { + snprintf(errortext, ET_SIZE, "Redundant pictures are only allowed in Baseline profile (ProfileIDC = 66)."); + error (errortext, 500); + } + } + + if ((p_Inp->partition_mode) && (p_Inp->ProfileIDC!=EXTENDED)) + { + snprintf(errortext, ET_SIZE, "Data partitioning is only allowed in Extended profile (ProfileIDC = 88)."); + error (errortext, 500); + } + + if (p_Inp->ChromaIntraDisable && p_Inp->FastCrIntraDecision) + { + fprintf( stdout, "\n Warning: ChromaIntraDisable and FastCrIntraDecision cannot be combined together.\n Using only Chroma Intra DC mode.\n"); + p_Inp->FastCrIntraDecision=0; + } + + if ((p_Inp->sp_periodicity) && (p_Inp->ProfileIDC != EXTENDED )) + { + snprintf(errortext, ET_SIZE, "SP pictures are only allowed in Extended profile (ProfileIDC = 88)."); + error (errortext, 500); + } + + // baseline + if (p_Inp->ProfileIDC == BASELINE ) + { + if ((p_Inp->NumberBFrames || p_Inp->BRefPictures==2) && p_Inp->PReplaceBSlice == 0) + { + snprintf(errortext, ET_SIZE, "B slices are not allowed in Baseline profile (ProfileIDC = 66)."); + error (errortext, 500); + } + if (p_Inp->WeightedPrediction) + { + snprintf(errortext, ET_SIZE, "Weighted prediction is not allowed in Baseline profile (ProfileIDC = 66)."); + error (errortext, 500); + } + if (p_Inp->WeightedBiprediction) + { + snprintf(errortext, ET_SIZE, "Weighted prediction is not allowed in Baseline profile (ProfileIDC = 66)."); + error (errortext, 500); + } + if (p_Inp->symbol_mode == CABAC) + { + snprintf(errortext, ET_SIZE, "CABAC is not allowed in Baseline profile (ProfileIDC = 66)."); + error (errortext, 500); + } + if ((p_Inp->PicInterlace) ||(p_Inp->MbInterlace)) + { + snprintf(errortext, ET_SIZE, "Interlace tools are not allowed in Baseline profile (ProfileIDC = 66)."); + error (errortext, 500); + } + if (p_Inp->GenerateMultiplePPS != 0) + { + snprintf(errortext, ET_SIZE, "GenerateMultiplePPS is not supported for Baseline profile because it requires enabling Weighted prediction.\n"); + error (errortext, 400); + } + } + + // main + if (p_Inp->ProfileIDC == MAIN ) + { + if (p_Inp->num_slice_groups_minus1) + { + snprintf(errortext, ET_SIZE, "num_slice_groups_minus1>0 (FMO) is not allowed in Main profile (ProfileIDC = 77)."); + error (errortext, 500); + } + } + + // extended + if (p_Inp->ProfileIDC == EXTENDED ) + { + if (!p_Inp->directInferenceFlag) + { + snprintf(errortext, ET_SIZE, "direct_8x8_inference flag must be equal to 1 in Extended profile (ProfileIDC = 88)."); + error (errortext, 500); + } + + if (p_Inp->symbol_mode == CABAC) + { + snprintf(errortext, ET_SIZE, "CABAC is not allowed in Extended profile (ProfileIDC = 88)."); + error (errortext, 500); + } + } + + //FRExt + if ( p_Inp->separate_colour_plane_flag ) + { + if( p_Inp->yuv_format!=3 ) + { + fprintf( stdout, "\nWarning: SeparateColourPlane has only effect in 4:4:4 chroma mode (YUVFormat=3),\n disabling SeparateColourPlane."); + p_Inp->separate_colour_plane_flag = 0; + } + + if ( p_Inp->ChromaMEEnable ) + { + snprintf(errortext, ET_SIZE, "\nChromaMEEnable is not allowed when SeparateColourPlane is enabled."); + error (errortext, 500); + } + } + + // CAVLC 4:4:4 Intra + if ( p_Inp->ProfileIDC == FREXT_CAVLC444 ) + { + if ( p_Inp->symbol_mode != CAVLC ) + { + snprintf(errortext, ET_SIZE, "\nCABAC is not allowed in CAVLC 4:4:4 Intra profile (ProfileIDC = 44)."); + error (errortext, 500); + } + if ( !p_Inp->IntraProfile ) + { + fprintf (stdout, "\nWarning: ProfileIDC equal to 44 implies an Intra only profile, setting IntraProfile = 1."); + p_Inp->IntraProfile = 1; + } + } + + // Intra only profiles + if (p_Inp->IntraProfile && ( p_Inp->ProfileIDCProfileIDC!=FREXT_CAVLC444 )) + { + snprintf(errortext, ET_SIZE, "\nIntraProfile is allowed only with ProfileIDC %d to %d.", FREXT_HP, FREXT_Hi444); + error (errortext, 500); + } + + if (p_Inp->IntraProfile && !p_Inp->idr_period) + { + snprintf(errortext, ET_SIZE, "\nIntraProfile requires IDRPeriod >= 1."); + error (errortext, 500); + } + + if (p_Inp->IntraProfile && p_Inp->intra_period != 1) + { + snprintf(errortext, ET_SIZE, "\nIntraProfile requires IntraPeriod equal 1."); + error (errortext, 500); + } + + if (p_Inp->IntraProfile && p_Inp->num_ref_frames) + { + fprintf( stdout, "\nWarning: Setting NumberReferenceFrames to 0 in IntraProfile."); + p_Inp->num_ref_frames = 0; + } + + if (p_Inp->IntraProfile == 0 && p_Inp->num_ref_frames == 0) + { + snprintf(errortext, ET_SIZE, "\nProfiles other than IntraProfile require NumberReferenceFrames > 0."); + error (errortext, 500); + } +} + +/*! + *********************************************************************** + * \brief + * Check if Level constraints are satisfied + *********************************************************************** + */ +void level_check(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + unsigned int PicSizeInMbs = ( (p_Inp->output.width[0] + p_Vid->auto_crop_right) * (p_Inp->output.height[0] + p_Vid->auto_crop_bottom) ) >> 8; + unsigned int MBProcessingRate = (unsigned int) (PicSizeInMbs * p_Inp->output.frame_rate + 0.5); + int cpbBrFactor = ( p_Inp->ProfileIDC >= FREXT_HP ) ? 1500 : 1200; + + if ( (p_Inp->LevelIDC>=30) && (p_Inp->directInferenceFlag==0)) + { + fprintf( stdout, "\nWarning: LevelIDC 3.0 and above require direct_8x8_inference to be set to 1. Please check your settings.\n"); + p_Inp->directInferenceFlag=1; + } + if ( ((p_Inp->LevelIDC<21) || (p_Inp->LevelIDC>41)) && (p_Inp->PicInterlace > 0 || p_Inp->MbInterlace > 0) ) + { + snprintf(errortext, ET_SIZE, "\nInterlace modes only supported for LevelIDC in the range of 21 and 41. Please check your settings.\n"); + error (errortext, 500); + } + + if ( PicSizeInMbs > getMaxFs(p_Inp->LevelIDC) ) + { + snprintf(errortext, ET_SIZE, "\nPicSizeInMbs exceeds maximum allowed size at specified LevelIdc %.1f\n", (float) p_Inp->LevelIDC / 10.0); + error (errortext, 500); + } + + if (p_Inp->IntraProfile && (PicSizeInMbs > 1620) && p_Inp->slice_mode != 1) + { + error ("\nIntraProfile with PicSizeInMbs > 1620 requires SliceMode equal 1.", 500); + } + + if (p_Inp->IntraProfile && (PicSizeInMbs > 1620) && ((unsigned int)p_Inp->slice_argument > ( getMaxFs(p_Inp->LevelIDC) >> 2 ) ) ) + { + //when PicSizeInMbs is greater than 1620, the number of macroblocks in any coded slice shall not exceed MaxFS / 4 + snprintf(errortext, ET_SIZE, "\nIntraProfile requires SliceArgument smaller or equal to 1/4 MaxFs at specified LevelIdc %d.", p_Inp->LevelIDC); + error (errortext, 500); + } + + if ( MBProcessingRate > getMaxMBPS(p_Inp->LevelIDC) ) + { + snprintf(errortext, ET_SIZE, "\nMB Processing Rate (%d) exceeds maximum allowed processing rate (%d) at specified LevelIdc %.1f\n", + MBProcessingRate, getMaxMBPS(p_Inp->LevelIDC), (float) p_Inp->LevelIDC / 10.0); + error (errortext, 500); + } + + if ( p_Inp->bit_rate > (int)(cpbBrFactor * getMaxBR(p_Inp->LevelIDC)) ) + { + snprintf(errortext, ET_SIZE, "\nBit Rate (%d) exceeds maximum allowed bit rate (%d) at specified LevelIdc %.1f for NAL HRD\n", + p_Inp->bit_rate, cpbBrFactor * getMaxBR(p_Inp->LevelIDC), (float) p_Inp->LevelIDC / 10.0); + error (errortext, 500); + } +} + +/*! + *********************************************************************** + * \brief + * Update Motion Vector Limits + *********************************************************************** + */ +void update_mv_limits(VideoParameters *p_Vid, byte is_field) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + memcpy(p_Vid->MaxVmvR, LEVELVMVLIMIT[p_Vid->LevelIndex], 6 * sizeof(int)); + memcpy(p_Vid->MaxHmvR, LEVELHMVLIMIT, 6 * sizeof(int)); + if (is_field) + { + int i; + for (i = 0; i < 6; i++) + p_Vid->MaxVmvR[i] = rshift_rnd(p_Vid->MaxVmvR[i], 1); + } + if (p_Inp->UseMVLimits) + { + p_Vid->MaxVmvR[0] = imax(p_Vid->MaxVmvR[0], -(p_Inp->SetMVYLimit)); + p_Vid->MaxVmvR[1] = imin(p_Vid->MaxVmvR[1], (p_Inp->SetMVYLimit)); + p_Vid->MaxVmvR[2] = imax(p_Vid->MaxVmvR[2], -(p_Inp->SetMVYLimit << 1)); + p_Vid->MaxVmvR[3] = imin(p_Vid->MaxVmvR[3], (p_Inp->SetMVYLimit << 1)); + p_Vid->MaxVmvR[4] = imax(p_Vid->MaxVmvR[4], -(p_Inp->SetMVYLimit << 2)); + p_Vid->MaxVmvR[5] = imin(p_Vid->MaxVmvR[5], (p_Inp->SetMVYLimit << 2)); + + p_Vid->MaxHmvR[0] = imax(p_Vid->MaxHmvR[0], -(p_Inp->SetMVXLimit)); + p_Vid->MaxHmvR[1] = imin(p_Vid->MaxHmvR[1], (p_Inp->SetMVXLimit)); + p_Vid->MaxHmvR[2] = imax(p_Vid->MaxHmvR[2], -(p_Inp->SetMVXLimit << 1)); + p_Vid->MaxHmvR[3] = imin(p_Vid->MaxHmvR[3], (p_Inp->SetMVXLimit << 1)); + p_Vid->MaxHmvR[4] = imax(p_Vid->MaxHmvR[4], -(p_Inp->SetMVXLimit << 2)); + p_Vid->MaxHmvR[5] = imin(p_Vid->MaxHmvR[5], (p_Inp->SetMVXLimit << 2)); + } +} + + +/*! + *********************************************************************** + * \brief + * Clip motion vector range given encoding level + *********************************************************************** + */ +void clip_mv_range(VideoParameters *p_Vid, int search_range, MotionVector *mv, int res) +{ + res <<= 1; + + mv->mv_x = (short) iClip3( p_Vid->MaxHmvR[0 + res] + search_range, p_Vid->MaxHmvR[1 + res] - search_range, mv->mv_x); + mv->mv_y = (short) iClip3( p_Vid->MaxVmvR[0 + res] + search_range, p_Vid->MaxVmvR[1 + res] - search_range, mv->mv_y); +} + +/*! + *********************************************************************** + * \brief + * Clip motion vector range given encoding level + *********************************************************************** + */ +void test_clip_mvs(VideoParameters *p_Vid, MotionVector *mv, Boolean write_mb) +{ + if ((mv->mv_x < p_Vid->MaxHmvR[4]) || (mv->mv_x > p_Vid->MaxHmvR[5]) || (mv->mv_y < p_Vid->MaxVmvR[4]) || (mv->mv_y > p_Vid->MaxVmvR[5])) + { + if (write_mb == TRUE) + printf("Warning MVs (%d %d) were out of range x(%d %d) y(%d %d). Clipping mvs before writing\n", mv->mv_x, mv->mv_y, p_Vid->MaxHmvR[4], p_Vid->MaxHmvR[5], p_Vid->MaxVmvR[4], p_Vid->MaxVmvR[5]); + mv->mv_x = (short) iClip3( p_Vid->MaxHmvR[4], p_Vid->MaxHmvR[5], mv->mv_x); + mv->mv_y = (short) iClip3( p_Vid->MaxVmvR[4], p_Vid->MaxVmvR[5], mv->mv_y); + } +} + +/*! + *********************************************************************** + * \brief + * Clip motion vector range given encoding level + *********************************************************************** + */ +int out_of_bounds_mvs(VideoParameters *p_Vid, const MotionVector *mv) +{ + return ((mv->mv_x < p_Vid->MaxHmvR[4]) || (mv->mv_x > p_Vid->MaxHmvR[5]) || (mv->mv_y < p_Vid->MaxVmvR[4]) || (mv->mv_y > p_Vid->MaxVmvR[5])); +} + +int InvalidWeightsForBiPrediction(Slice *currSlice, Block8x8Info* b8x8info, int mode) +{ + seq_parameter_set_rbsp_t *active_sps = currSlice->active_sps; + int cur_blk, cur_comp; + int best8x8l0ref, best8x8l1ref; + int weight_sum = 0; + int invalid_mode = 0; + short *wbp0, *wbp1; + for (cur_blk = 0; cur_blk < 4; cur_blk ++) + { + if (b8x8info->best[mode][cur_blk].pdir == 2) + { + best8x8l0ref = (int) b8x8info->best[mode][cur_blk].ref[LIST_0]; + best8x8l1ref = (int) b8x8info->best[mode][cur_blk].ref[LIST_1]; + wbp0 = &currSlice->wbp_weight[LIST_0][best8x8l0ref][best8x8l1ref][0]; + wbp1 = &currSlice->wbp_weight[LIST_1][best8x8l0ref][best8x8l1ref][0]; + + for (cur_comp = 0; cur_comp < (active_sps->chroma_format_idc == YUV400 ? 1 : 3) ; cur_comp ++) + { + weight_sum = *wbp0++ + *wbp1++; + + if (weight_sum < -128 || weight_sum > 127) + { + invalid_mode = 1; + break; + } + } + if (invalid_mode == 1) + break; + } + } + return invalid_mode; +} + +int InvalidMotionVectors(VideoParameters *p_Vid, Slice *currSlice, Block8x8Info* b8x8info, int mode) +{ + int cur_blk; + int l0ref, l1ref; + int invalid_mode = 0; + int i, j; + + if (mode > P8x8) + return invalid_mode; + + // Brute force method. Note that this ignores currently subpartitions in 8x8 modes + for (cur_blk = 0; cur_blk < 4; cur_blk ++) + { + i = (cur_blk & 0x01) << 1; + j = (cur_blk >> 1) << 1; + switch (b8x8info->best[mode][cur_blk].pdir) + { + case 0: + l0ref = (int) b8x8info->best[mode][cur_blk].ref[LIST_0]; + if (out_of_bounds_mvs(p_Vid, &currSlice->all_mv [LIST_0][l0ref][mode][j][i])) + { + invalid_mode = 1; + return invalid_mode; + } + break; + case 1: + l1ref = (int) b8x8info->best[mode][cur_blk].ref[LIST_1]; + if (out_of_bounds_mvs(p_Vid, &currSlice->all_mv [LIST_1][l1ref][mode][j][i])) + { + invalid_mode = 1; + return invalid_mode; + } + break; + case 2: + l0ref = (int) b8x8info->best[mode][cur_blk].ref[LIST_0]; + l1ref = (int) b8x8info->best[mode][cur_blk].ref[LIST_1]; + if (out_of_bounds_mvs(p_Vid, &currSlice->all_mv [LIST_0][l0ref][mode][j][i])) + { + invalid_mode = 1; + return invalid_mode; + } + if (out_of_bounds_mvs(p_Vid, &currSlice->all_mv [LIST_1][l1ref][mode][j][i])) + { + invalid_mode = 1; + return invalid_mode; + } + break; + default: + break; + } + } + + return invalid_mode; +} + +Boolean CheckPredictionParams(Macroblock *currMB, Block8x8Info *b8x8info, int mode) +{ + Slice *currSlice = currMB->p_Slice; + // check if all sub-macroblock partitions can be used with 8x8 transform + if (mode == P8x8 && currMB->luma_transform_size_8x8_flag == TRUE) + { + int i; + + for (i = 0; i < 4; i++) + { + if (b8x8info->best[P8x8][i].mode != 4 && b8x8info->best[P8x8][i].mode != 0) + { + return FALSE; + } + } + } + + if (InvalidMotionVectors(currSlice->p_Vid, currSlice, b8x8info, mode)) + return FALSE; + + if (currSlice->slice_type == B_SLICE) + { + // check if weights are in valid range for biprediction. + if (currSlice->weighted_prediction == 1 && mode < P8x8) + { + if (InvalidWeightsForBiPrediction(currSlice, b8x8info, mode)) + return FALSE; + } + + // Check if direct mode can be utilized for this partition + if (mode==0) + { + int i, j; + for (j = currMB->block_y; j < currMB->block_y + 4;j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4;i++) + { + if (currSlice->direct_pdir[j][i] < 0) // direct_pdir should be moved and become part of p_Vid parameters + return FALSE; + } + } + } + + } + + return TRUE; +} diff --git a/lencod/src/context_ini.c b/lencod/src/context_ini.c new file mode 100644 index 0000000..7d43e73 --- /dev/null +++ b/lencod/src/context_ini.c @@ -0,0 +1,372 @@ + +/*! + ************************************************************************************* + * \file context_ini.c + * + * \brief + * CABAC context initializations + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Detlev Marpe + * - Heiko Schwarz + ************************************************************************************** + */ + +#define CONTEXT_INI_C + +#include + +#include "global.h" + +#include "ctx_tables.h" +#include "biariencode.h" +#include "memalloc.h" + +#define DEFAULT_CTX_MODEL 0 +#define RELIABLE_COUNT 32.0 +#define FRAME_TYPES 4 +#define FIXED 0 + +// These essentially are constants +static const double probabilities[64] = +{ + 0.500000, 0.474609, 0.450507, 0.427629, 0.405912, 0.385299, 0.365732, 0.347159, + 0.329530, 0.312795, 0.296911, 0.281833, 0.267520, 0.253935, 0.241039, 0.228799, + 0.217180, 0.206151, 0.195682, 0.185744, 0.176312, 0.167358, 0.158859, 0.150792, + 0.143134, 0.135866, 0.128966, 0.122417, 0.116200, 0.110299, 0.104698, 0.099381, + 0.094334, 0.089543, 0.084996, 0.080680, 0.076583, 0.072694, 0.069002, 0.065498, + 0.062172, 0.059014, 0.056018, 0.053173, 0.050473, 0.047909, 0.045476, 0.043167, + 0.040975, 0.038894, 0.036919, 0.035044, 0.033264, 0.031575, 0.029972, 0.028450, + 0.027005, 0.025633, 0.024332, 0.023096, 0.021923, 0.020810, 0.019753, 0.018750 +}; + +void create_context_memory (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int k; + int num_mb = p_Vid->FrameSizeInMbs; // number of macroblocks for frame + double log2 = log(2.0); + + p_Vid->num_mb_per_slice = (p_Inp->slice_mode == 1 ? p_Inp->slice_argument : num_mb); + p_Vid->number_of_slices = (num_mb + p_Vid->num_mb_per_slice - 1) / p_Vid->num_mb_per_slice; + get_mem3Dint(&p_Vid->initialized, 3, FRAME_TYPES, p_Vid->number_of_slices); + //===== set all context sets as "uninitialized" ===== + memset(&p_Vid->initialized[0][0][0], 0, 3 * FRAME_TYPES * p_Vid->number_of_slices * sizeof(int)); + get_mem3Dint(&p_Vid->modelNumber, 3, FRAME_TYPES, p_Vid->number_of_slices); + + //----- init tables ----- + for( k=0; k<64; k++ ) + { + p_Vid->probability[k + 64] = probabilities[k]; + p_Vid->probability[k] = 1.0 - probabilities[63 - k]; + p_Vid->entropy [k] = log( p_Vid->probability[ k] ) / log2; + p_Vid->entropy[127-k] = log( probabilities[63 - k] ) / log2; + p_Vid->enorm [k] = p_Vid->entropy[k] - p_Vid->entropy[127-k]; + p_Vid->enorm[127 - k] = -p_Vid->enorm[k]; + } +} + +void free_context_memory (VideoParameters *p_Vid) +{ + free_mem3Dint(p_Vid->initialized); + free_mem3Dint(p_Vid->modelNumber); +} + +#define BIARI_CTX_INIT2(qp, ii,jj,ctx,tab) \ +{ \ + for (i=0; ip_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + int frame_field = p_Vid->field_picture; + int img_type = currSlice->slice_type; + int ctx_number = currSlice->start_mb_nr / p_Vid->num_mb_per_slice; + + if(img_type == I_SLICE) + { + currSlice->model_number=DEFAULT_CTX_MODEL; + return; + } + + if(p_Inp->context_init_method==FIXED) + { + currSlice->model_number = p_Inp->model_number; + return; + } + + if (p_Vid->initialized [frame_field][img_type][ctx_number]) + { + currSlice->model_number = p_Vid->modelNumber[frame_field][img_type][ctx_number]; + } + else if (ctx_number && p_Vid->initialized[frame_field][img_type][ctx_number-1]) + { + currSlice->model_number = p_Vid->modelNumber[frame_field][img_type][ctx_number-1]; + } + else + { + currSlice->model_number = DEFAULT_CTX_MODEL; + } +} + +void init_contexts (Slice *currSlice) +{ + MotionInfoContexts* mc = currSlice->mot_ctx; + TextureInfoContexts* tc = currSlice->tex_ctx; + int model_number = currSlice->model_number; + int qp = imax(0, currSlice->qp); + int i, j; + + if ((currSlice->slice_type == I_SLICE) || (currSlice->slice_type == SI_SLICE)) + { + //--- motion coding contexts --- + BIARI_CTX_INIT2 (qp, 3, NUM_MB_TYPE_CTX, mc->mb_type_contexts, INIT_MB_TYPE_I[model_number]); + + //--- texture coding contexts --- + binary_context_init1 (qp, NUM_TRANSFORM_SIZE_CTX, tc->transform_size_contexts, INIT_TRANSFORM_SIZE_I[model_number][0]); + binary_context_init1 (qp, NUM_IPR_CTX, tc->ipr_contexts, INIT_IPR_I[model_number][0]); + binary_context_init1 (qp, NUM_CIPR_CTX, tc->cipr_contexts, INIT_CIPR_I[model_number][0]); + BIARI_CTX_INIT2 (qp, 3, NUM_CBP_CTX, tc->cbp_contexts, INIT_CBP_I[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts, INIT_BCBP_I[model_number]); + binary_context_init1 (qp, NUM_DELTA_QP_CTX, tc->delta_qp_contexts,INIT_DELTA_QP_I[model_number][0]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[0], INIT_MAP_I[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[0], INIT_LAST_I[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts, INIT_ONE_I[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts, INIT_ABS_I[model_number]); +#if ENABLE_FIELD_CTX + binary_context_init1 (qp, NUM_MB_AFF_CTX, tc->mb_aff_contexts, INIT_MB_AFF_I[model_number][0]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[1], INIT_FLD_MAP_I[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[1], INIT_FLD_LAST_I[model_number]); +#endif + } + else + { + //--- motion coding contexts --- + BIARI_CTX_INIT2 (qp, 3, NUM_MB_TYPE_CTX, mc->mb_type_contexts, INIT_MB_TYPE_P[model_number]); + BIARI_CTX_INIT2 (qp, 2, NUM_B8_TYPE_CTX, mc->b8_type_contexts, INIT_B8_TYPE_P[model_number]); + BIARI_CTX_INIT2 (qp, 2, NUM_MV_RES_CTX, mc->mv_res_contexts, INIT_MV_RES_P[model_number]); + BIARI_CTX_INIT2 (qp, 2, NUM_REF_NO_CTX, mc->ref_no_contexts, INIT_REF_NO_P[model_number]); + + //--- texture coding contexts --- + binary_context_init1(qp, NUM_TRANSFORM_SIZE_CTX, tc->transform_size_contexts, INIT_TRANSFORM_SIZE_P[model_number][0]); + binary_context_init1(qp, NUM_IPR_CTX, tc->ipr_contexts, INIT_IPR_P[model_number][0]); + binary_context_init1(qp, NUM_CIPR_CTX, tc->cipr_contexts, INIT_CIPR_P[model_number][0]); + BIARI_CTX_INIT2 (qp, 3, NUM_CBP_CTX, tc->cbp_contexts, INIT_CBP_P[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts, INIT_BCBP_P[model_number]); + binary_context_init1 (qp, NUM_DELTA_QP_CTX, tc->delta_qp_contexts,INIT_DELTA_QP_P[model_number][0]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[0], INIT_MAP_P[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[0], INIT_LAST_P[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts, INIT_ONE_P[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts, INIT_ABS_P[model_number]); +#if ENABLE_FIELD_CTX + binary_context_init1 (qp, NUM_MB_AFF_CTX, tc->mb_aff_contexts, INIT_MB_AFF_P[model_number][0]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[1], INIT_FLD_MAP_P[model_number]); + BIARI_CTX_INIT2 (qp, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[1], INIT_FLD_LAST_P[model_number]); +#endif + } +} + + +double XRate (VideoParameters *p_Vid, BiContextTypePtr ctx, const char* model) +{ + int ctx_state, mod_state; + double weight, xr = 0.0; + int qp = imax(0, p_Vid->qp); + + weight = dmin (1.0, (double)ctx->count/(double)RELIABLE_COUNT); + + mod_state = ((model[0]*qp)>>4)+model[1]; + mod_state = iClip3(0, 127, mod_state); + ctx_state = (ctx->MPS ? 64 + ctx->state : 63 - ctx->state); + + xr -= weight * (p_Vid->probability[ctx_state] * p_Vid->enorm[mod_state] + p_Vid->entropy[127 - mod_state]); + + return xr; +} + +/* +static inline void add_xrate2(VideoParameters *p_Vid, int ii, int jj, BiContextType **ctx, const char ***tab, double *xr) +{ + int i, j; + for (i=0; ip_Vid; + int model, j, i; + double xr, min_xr = 1e30; + + if (currSlice->slice_type == I_SLICE) + { + for (model = 0; model < NUM_CTX_MODELS_I; model++) + { + xr = 0.0; + //--- motion coding contexts --- + ADD_XRATE2 (p_Vid, 3, NUM_MB_TYPE_CTX, mc->mb_type_contexts, INIT_MB_TYPE_I [model]); + + //--- texture coding contexts --- + ADD_XRATE1 (p_Vid, NUM_TRANSFORM_SIZE_CTX, tc->transform_size_contexts, INIT_TRANSFORM_SIZE_I[model][0]); + ADD_XRATE1 (p_Vid, NUM_IPR_CTX, tc->ipr_contexts, INIT_IPR_I [model][0]); + ADD_XRATE1 (p_Vid, NUM_CIPR_CTX, tc->cipr_contexts, INIT_CIPR_I[model][0]); + ADD_XRATE2 (p_Vid, 3, NUM_CBP_CTX, tc->cbp_contexts, INIT_CBP_I [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts, INIT_BCBP_I[model]); + ADD_XRATE1 (p_Vid, NUM_DELTA_QP_CTX, tc->delta_qp_contexts, INIT_DELTA_QP_I[model][0]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[0], INIT_MAP_I [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[0], INIT_LAST_I[model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts, INIT_ONE_I [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts, INIT_ABS_I [model]); +#if ENABLE_FIELD_CTX + ADD_XRATE1 (p_Vid, NUM_MB_AFF_CTX, tc->mb_aff_contexts, INIT_MB_AFF_I [model][0]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[1], INIT_FLD_MAP_I [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[1], INIT_FLD_LAST_I[model]); +#endif + + if (xr < min_xr) + { + min_xr = xr; + *mnumber = model; + } + } + } + else + { + for (model=0; modelmb_type_contexts, INIT_MB_TYPE_P [model]); + ADD_XRATE2 (p_Vid, 2, NUM_B8_TYPE_CTX, mc->b8_type_contexts, INIT_B8_TYPE_P [model]); + ADD_XRATE2 (p_Vid, 2, NUM_MV_RES_CTX, mc->mv_res_contexts, INIT_MV_RES_P [model]); + ADD_XRATE2 (p_Vid, 2, NUM_REF_NO_CTX, mc->ref_no_contexts, INIT_REF_NO_P [model]); + + //--- texture coding contexts --- + ADD_XRATE1 (p_Vid, NUM_TRANSFORM_SIZE_CTX, tc->transform_size_contexts, INIT_TRANSFORM_SIZE_P[model][0]); + ADD_XRATE1 (p_Vid, NUM_IPR_CTX, tc->ipr_contexts, INIT_IPR_P [model][0]); + ADD_XRATE1 (p_Vid, NUM_CIPR_CTX, tc->cipr_contexts, INIT_CIPR_P [model][0]); + ADD_XRATE2 (p_Vid, 3, NUM_CBP_CTX, tc->cbp_contexts, INIT_CBP_P [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_BCBP_CTX, tc->bcbp_contexts, INIT_BCBP_P [model]); + ADD_XRATE1 (p_Vid, NUM_DELTA_QP_CTX, tc->delta_qp_contexts, INIT_DELTA_QP_P[model][0]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[0], INIT_MAP_P [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[0], INIT_LAST_P [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_ONE_CTX, tc->one_contexts, INIT_ONE_P [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_ABS_CTX, tc->abs_contexts, INIT_ABS_P [model]); +#if ENABLE_FIELD_CTX + ADD_XRATE1 (p_Vid, NUM_MB_AFF_CTX, tc->mb_aff_contexts, INIT_MB_AFF_P [model][0]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_MAP_CTX, tc->map_contexts[1], INIT_FLD_MAP_P [model]); + ADD_XRATE2 (p_Vid, NUM_BLOCK_TYPES, NUM_LAST_CTX, tc->last_contexts[1], INIT_FLD_LAST_P [model]); +#endif + + if (xr < min_xr) + { + min_xr = xr; + *mnumber = model; + } + } + } +} + +#undef ADD_XRATE2 +#undef ADD_XRATE1 + + +void store_contexts (Slice *currSlice) +{ + if( currSlice->p_Inp->context_init_method ) + { + VideoParameters *p_Vid = currSlice->p_Vid; + int frame_field = p_Vid->field_picture; + int img_type = currSlice->slice_type; + int ctx_number = currSlice->start_mb_nr / p_Vid->num_mb_per_slice; + + p_Vid->initialized [frame_field][img_type][ctx_number] = 1; + GetCtxModelNumber (currSlice, p_Vid->modelNumber[frame_field][img_type] + ctx_number, currSlice->mot_ctx, currSlice->tex_ctx); + } + else + { + // do nothing + } +} + + +void update_field_frame_contexts (VideoParameters *p_Vid, int field) +{ + int i, j; + + if (field) + { + // set frame contexts + for (j=0; jnumber_of_slices; i++) + { + p_Vid->initialized [0][j][i] = p_Vid->initialized [1][j][i>>1]; + p_Vid->modelNumber[0][j][i] = p_Vid->modelNumber[1][j][i>>1]; + } + } + } + else + { + // set field contexts + for (j=0; jnumber_of_slices+1)>>1); i++) + { + p_Vid->initialized [1][j][i] = p_Vid->initialized [0][j][i<<1]; + p_Vid->modelNumber[1][j][i] = p_Vid->modelNumber[0][j][i<<1]; + } + } + } +} + diff --git a/lencod/src/errdo.c b/lencod/src/errdo.c new file mode 100644 index 0000000..6163bb1 --- /dev/null +++ b/lencod/src/errdo.c @@ -0,0 +1,732 @@ + +/*! + ************************************************************************************* + * \file errdo.c + * + * \brief + * Contains functions that estimate the distortion for the + * rate-distortion optimization with losses. + * \date + * October 22nd, 2001 + * + * \author + * Main contributors (see contributors.h for copyright, address and + * affiliation details) + * - Dimitrios Kontopodis + * Code revamped July 2008 by: + * - Peshala Pahalawatta (ppaha@dolby.com) + * - Alexis Tourapis (atour@dolby.com) + * Code modularized to support more distortion estimation algorithms in June 2009 by + * - Zhifeng Chen (zzchen@dolby.com) + ************************************************************************************* + */ + +#include "global.h" +#include "memalloc.h" +#include "refbuf.h" +#include "image.h" +#include "md_common.h" +#include "errdo.h" +#include "errdo_dist_mhyp.h" + +/*! +************************************************************************************** +* \brief +* Allocate memory for error resilient RDO. +************************************************************************************** +*/ +int allocate_errdo_mem(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int memory_size = 0; + + //allocate shared memory for all algorithms + p_Vid->p_decs = (Decoders *) malloc(sizeof(Decoders)); + memory_size += get_mem3Dint(&p_Vid->p_decs->res_img, MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem3Dint(&p_Vid->p_decs->res_mb_best8x8, MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + p_Vid->p_decs->RCD_bestY_mb = NULL; + p_Vid->p_decs->RCD_bestY_b8x8 = NULL; + p_Vid->p_decs->MVCD_bestY_mb = NULL; + p_Vid->p_decs->MVCD_bestY_b8x8 = NULL; + p_Vid->p_decs->flag_bestY_mb = NULL; + p_Vid->p_decs->flag_bestY_b8x8 = NULL; + p_Vid->p_decs->flag_wo_res = NULL; + p_Vid->p_decs->flag_wo_res_bestY_b8x8 = NULL; + p_Vid->p_decs->trans_dist_bestY_mb = NULL; + p_Vid->p_decs->trans_dist_bestY_b8x8 = NULL; + p_Vid->p_decs->trans_dist_wo_res = NULL; //it is used for P8x8, where residual may be set to 0 + p_Vid->p_decs->trans_dist_wo_res_bestY_b8x8 = NULL; //it is used for P8x8, where residual may be set to 0 + p_Vid->p_decs->trans_err_bestY_mb = NULL; + p_Vid->p_decs->trans_err_bestY_b8x8 = NULL; + p_Vid->p_decs->trans_err_wo_res = NULL; //it is used for P8x8, where residual may be set to 0 + p_Vid->p_decs->trans_err_wo_res_bestY_b8x8 = NULL; //it is used for P8x8, where residual may be set to 0 + p_Vid->p_decs->dec_mb_pred = NULL; + p_Vid->p_decs->dec_mbY_best = NULL; + p_Vid->p_decs->dec_mb_pred_best8x8 = NULL; + p_Vid->p_decs->dec_mbY_best8x8 = NULL; + p_Vid->p_decs->first_moment_bestY_mb = NULL; + p_Vid->p_decs->first_moment_bestY_b8x8 = NULL; + p_Vid->p_decs->first_moment_pred_bestY_b8x8 = NULL; + p_Vid->p_decs->first_moment_pred = NULL; + p_Vid->p_decs->second_moment_bestY_mb = NULL; + p_Vid->p_decs->second_moment_bestY_b8x8 = NULL; + p_Vid->p_decs->second_moment_pred_bestY_b8x8 = NULL; + p_Vid->p_decs->second_moment_pred = NULL; + + //Zhifeng 090630 + switch (p_Inp->de) + { + case LLN: + //allocate memory for lln algorithm + memory_size += get_mem3Dpel(&p_Vid->p_decs->dec_mb_pred, p_Inp->NoOfDecoders, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem3Dpel(&p_Vid->p_decs->dec_mbY_best, p_Inp->NoOfDecoders, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem4Dpel(&p_Vid->p_decs->dec_mbY_best8x8, 2, p_Inp->NoOfDecoders, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + memory_size += get_mem4Dpel(&p_Vid->p_decs->dec_mb_pred_best8x8, 2, p_Inp->NoOfDecoders, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + break; + default: + ; + } + return memory_size; +} + +/*! +************************************************************************************** +* \brief +* free memory of error resilient RDO. +************************************************************************************** +*/ +void free_errdo_mem(VideoParameters *p_Vid) +{ + //for shared memory + if (p_Vid->p_decs->res_img) + { + free_mem3Dint(p_Vid->p_decs->res_img); + p_Vid->p_decs->res_img = NULL; + } + if (p_Vid->p_decs->res_mb_best8x8) + { + free_mem3Dint(p_Vid->p_decs->res_mb_best8x8); + p_Vid->p_decs->res_mb_best8x8 = NULL; + } + + //for RMPC + if (p_Vid->p_decs->RCD_bestY_mb) + { + free_mem2Dint(p_Vid->p_decs->RCD_bestY_mb); + p_Vid->p_decs->RCD_bestY_mb = NULL; + } + if (p_Vid->p_decs->RCD_bestY_b8x8) + { + free_mem3Dint(p_Vid->p_decs->RCD_bestY_b8x8); + p_Vid->p_decs->RCD_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->MVCD_bestY_mb) + { + free_mem2Dint(p_Vid->p_decs->MVCD_bestY_mb); + p_Vid->p_decs->MVCD_bestY_mb = NULL; + } + if (p_Vid->p_decs->MVCD_bestY_b8x8) + { + free_mem3Dint(p_Vid->p_decs->MVCD_bestY_b8x8); + p_Vid->p_decs->MVCD_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->flag_bestY_mb) + { + free_mem2D(p_Vid->p_decs->flag_bestY_mb); + p_Vid->p_decs->flag_bestY_mb = NULL; + } + if (p_Vid->p_decs->flag_bestY_b8x8) + { + free_mem3D(p_Vid->p_decs->flag_bestY_b8x8); + p_Vid->p_decs->flag_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->flag_wo_res) + { + free_mem2D(p_Vid->p_decs->flag_wo_res); + p_Vid->p_decs->flag_wo_res = NULL; + } + if (p_Vid->p_decs->flag_wo_res_bestY_b8x8) + { + free_mem3D(p_Vid->p_decs->flag_wo_res_bestY_b8x8); + p_Vid->p_decs->flag_wo_res_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->trans_dist_bestY_mb) + { + free_mem2Dint(p_Vid->p_decs->trans_dist_bestY_mb); + p_Vid->p_decs->trans_dist_bestY_mb = NULL; + } + if (p_Vid->p_decs->trans_dist_bestY_b8x8) + { + free_mem3Dint(p_Vid->p_decs->trans_dist_bestY_b8x8); + p_Vid->p_decs->trans_dist_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->trans_dist_wo_res) + { + free_mem2Dint(p_Vid->p_decs->trans_dist_wo_res); + p_Vid->p_decs->trans_dist_wo_res = NULL; //it is used for P8x8, where residual may be set to 0 + } + if (p_Vid->p_decs->trans_dist_wo_res_bestY_b8x8) + { + free_mem3Dint(p_Vid->p_decs->trans_dist_wo_res_bestY_b8x8); + p_Vid->p_decs->trans_dist_wo_res_bestY_b8x8 = NULL; //it is used for P8x8, where residual may be set to 0 + } + if (p_Vid->p_decs->trans_err_bestY_mb) + { + free_mem2Dint(p_Vid->p_decs->trans_err_bestY_mb); + p_Vid->p_decs->trans_err_bestY_mb = NULL; + } + if (p_Vid->p_decs->trans_err_bestY_b8x8) + { + free_mem3Dint(p_Vid->p_decs->trans_err_bestY_b8x8); + p_Vid->p_decs->trans_err_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->trans_err_wo_res) + { + free_mem2Dint(p_Vid->p_decs->trans_err_wo_res); + p_Vid->p_decs->trans_err_wo_res = NULL; //it is used for P8x8, where residual may be set to 0 + } + if (p_Vid->p_decs->trans_err_wo_res_bestY_b8x8) + { + free_mem3Dint(p_Vid->p_decs->trans_err_wo_res_bestY_b8x8); + p_Vid->p_decs->trans_err_wo_res_bestY_b8x8 = NULL; //it is used for P8x8, where residual may be set to 0 + } + + //for LLN + if (p_Vid->p_decs->dec_mb_pred) + { + free_mem3Dpel(p_Vid->p_decs->dec_mb_pred); + p_Vid->p_decs->dec_mb_pred = NULL; + } + if (p_Vid->p_decs->dec_mbY_best) + { + free_mem3Dpel(p_Vid->p_decs->dec_mbY_best); + p_Vid->p_decs->dec_mbY_best = NULL; + } + if (p_Vid->p_decs->dec_mbY_best8x8) + { + free_mem4Dpel(p_Vid->p_decs->dec_mbY_best8x8); + p_Vid->p_decs->dec_mb_pred_best8x8 = NULL; + } + if (p_Vid->p_decs->dec_mb_pred_best8x8) + { + free_mem4Dpel(p_Vid->p_decs->dec_mb_pred_best8x8); + p_Vid->p_decs->dec_mbY_best8x8 = NULL; + } + + //for ROPE + if (p_Vid->p_decs->first_moment_bestY_mb) + { + free_mem2Dpel(p_Vid->p_decs->first_moment_bestY_mb); + p_Vid->p_decs->first_moment_bestY_mb = NULL; + } + if (p_Vid->p_decs->first_moment_bestY_b8x8) + { + free_mem3Dpel(p_Vid->p_decs->first_moment_bestY_b8x8); + p_Vid->p_decs->first_moment_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->first_moment_pred_bestY_b8x8) + { + free_mem3Dpel(p_Vid->p_decs->first_moment_pred_bestY_b8x8); + p_Vid->p_decs->first_moment_pred_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->first_moment_pred) + { + free_mem2Dpel(p_Vid->p_decs->first_moment_pred); + p_Vid->p_decs->first_moment_pred = NULL; + } + if (p_Vid->p_decs->second_moment_bestY_mb) + { + free_mem2Duint16(p_Vid->p_decs->second_moment_bestY_mb); + p_Vid->p_decs->second_moment_bestY_mb = NULL; + } + if (p_Vid->p_decs->second_moment_bestY_b8x8) + { + free_mem3Duint16(p_Vid->p_decs->second_moment_bestY_b8x8); + p_Vid->p_decs->second_moment_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->second_moment_pred_bestY_b8x8) + { + free_mem3Duint16(p_Vid->p_decs->second_moment_pred_bestY_b8x8); + p_Vid->p_decs->second_moment_pred_bestY_b8x8 = NULL; + } + if (p_Vid->p_decs->second_moment_pred) + { + free_mem2Duint16(p_Vid->p_decs->second_moment_pred); + p_Vid->p_decs->second_moment_pred = NULL; + } + + free_pointer( p_Vid->p_decs ); +} + +/*! + ************************************************************************************* +* \brief + * Initialize error concealment function + * (Currently only copy concealment is implemented. Can extend to other concealment + * types when available.) + * + ************************************************************************************* +*/ +void init_error_conceal(VideoParameters *p_Vid, int concealment_type) +{ + p_Vid->error_conceal_picture = copy_conceal_picture; +} + + +/****************************************************************************************** +* +* Finds reference picture with nearest POC to current picture to use for error concealment +* +******************************************************************************************* +*/ +StorablePicture* find_nearest_ref_picture(DecodedPictureBuffer *p_Dpb, int poc) +{ + unsigned int i; + int min_poc_diff = 1000; + int poc_diff; + StorablePicture* refPic = NULL; + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + poc_diff = iabs(p_Dpb->fs_ref[i]->frame->poc - poc); + if (poc_diff < min_poc_diff) + { + refPic = p_Dpb->fs_ref[i]->frame; + min_poc_diff = poc_diff; + } + } + } + } + return refPic; +} + +/*! + ************************************************************************************* +* \brief + * Gives the prediction residue for a block + ************************************************************************************* +*/ +void errdo_compute_residue (Macroblock *currMB, imgpel **imgY, int **res_img, imgpel **mb_pred, int b8block, int block_size) +{ + int i,j; + int i0 = (b8block & 0x01)<<3, i1 = i0+block_size; + int j0 = (b8block >> 1)<<3, j1 = j0+block_size; + + for (i = i0; i < i1; i++) + { + for (j = j0; j < j1; j++) + { + res_img[j][i] = (int)imgY[j][currMB->pix_x + i] - mb_pred[j][i]; + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Store the best 8x8 block of estimated distortion for errdo. + * + * \param + * + * \note + * For lln algorithm, we need to consider akip and direct? + * + ************************************************************************************* + */ +void errdo_store_best_b8x8(Macroblock *currMB, int transform8x8, int block) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + switch (p_Inp->de) + { + case LLN: + errdo_store_best_block_multihyp(p_Inp, p_Vid->p_decs->dec_mbY_best8x8[transform8x8], p_Vid->enc_picture->de_mem->p_dec_img[0], block, currMB->pix_x, currMB->pix_y, BLOCK_SIZE_8x8); + errdo_store_best_block_multihyp(p_Inp, p_Vid->p_decs->dec_mb_pred_best8x8[transform8x8], p_Vid->p_decs->dec_mb_pred, block, 0, 0, BLOCK_SIZE_8x8); + break; + default: + ; + } +} + + +/*! + ************************************************************************************* + * \brief + * get the best 8x8 block of estimated distortion. Original code seems to have problem. Why not get p_Vid->p_decs->dec_mb_pred_best8x8? + * But since there is errdo_get_best_P8x8() in SetCoeffAndReconstruction8x8(), errdo_get_best_b8x8 seems not necessary. + * + * \param + * + * \note + * For lln algorithm, we need to consider skip and direct? + * This function seems not necessary since we have errdo_get_best_P8x8 + ************************************************************************************* + */ +void errdo_get_best_b8x8(Macroblock *currMB, int transform8x8, int block) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + switch (p_Inp->de) + { + case LLN: + errdo_get_best_block_multihyp(currMB, p_Vid->enc_picture->de_mem->p_dec_img[0], p_Vid->p_decs->dec_mbY_best8x8[transform8x8], block, BLOCK_SIZE_8x8); + break; + default: + ; + } + +} + + + +/*! + ************************************************************************************* +* \brief + * Store the best macroblock of estimated distortion for errdo. +* + * \param + * + ************************************************************************************* +*/ +void errdo_store_best_MB(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + switch (p_Inp->de) + { + case LLN: + errdo_store_best_block_multihyp(p_Inp, p_Vid->p_decs->dec_mbY_best, p_Vid->enc_picture->de_mem->p_dec_img[0], 0, currMB->pix_x, currMB->pix_y, MB_BLOCK_SIZE); + break; + default: + ; + } +} + + + +/*! + ************************************************************************************* + * \brief + * Get the best macroblock of estimated distortion for storable picture. + * + * \param + * + ************************************************************************************* + */ +void errdo_get_best_MB(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + switch (p_Inp->de) + { + case LLN: + errdo_get_best_block_multihyp(currMB, p_Vid->enc_picture->de_mem->p_dec_img[0], p_Vid->p_decs->dec_mbY_best, 0, MB_BLOCK_SIZE); + break; + default: + ; + } + +} + + + +/*! + ************************************************************************************* + * \brief + * Store the best macroblock of estimated distortion for mode P8x8. + * + * \param + * + ************************************************************************************* + */ +void errdo_get_best_P8x8(Macroblock *currMB, int transform8x8) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + switch (p_Inp->de) + { + case LLN: + if (p_Vid->p_decs->rec_type == 0) + { + errdo_get_best_block_multihyp(currMB, p_Vid->enc_picture->de_mem->p_dec_img[0], p_Vid->p_decs->dec_mb_pred_best8x8[transform8x8], 0, MB_BLOCK_SIZE); + } + else + { + errdo_get_best_block_multihyp(currMB, p_Vid->enc_picture->de_mem->p_dec_img[0], p_Vid->p_decs->dec_mbY_best8x8[transform8x8], 0, MB_BLOCK_SIZE); + } + break; + default: + ; + } +} + +/*! + ************************************************************************************* + * \brief + * Initialize distortion estimation algorithm + * (Can extend to support more algorithms when available.) + * + ************************************************************************************* + */ +void init_distortion_estimation(VideoParameters *p_Vid, int de_algorithm) +{ + switch (de_algorithm) + { + case LLN: + p_Vid->estimate_distortion = errdo_distortion_estimation_multihyp; + break; + default: + ; + } +} + + +/*! + ************************************************************************************* + * \brief + * allocate storable picture memory for errdo +* + ************************************************************************************* +*/ +void errdo_alloc_storable_picture(StorablePicture *p, VideoParameters *p_Vid, InputParameters *p_Inp, int size_x, int size_y, int size_x_cr, int size_y_cr) +{ + Dist_Estm *s; + int dec, ndec, nplane; + + p->de_mem = (Dist_Estm *)malloc( sizeof(Dist_Estm) ); + s = p->de_mem; + + s->res_con_diff_Y = NULL; + s->res_con_diff_UV = NULL; + s->MV_con_diff_Y = NULL; + s->MV_con_diff_UV = NULL; + s->error_sign_flag_Y = NULL; + s->error_sign_flag_UV = NULL; + s->transmission_dist_Y = NULL; + s->transmission_dist_UV = NULL; + s->transmission_err_Y = NULL; + s->transmission_err_UV = NULL; + s->dec_imgY = NULL; + s->dec_imgUV = NULL; + s->mb_error_map = NULL; + s->first_moment_Y = NULL; + s->first_moment_UV = NULL; + s->second_moment_Y = NULL; + s->second_moment_UV = NULL; + for (nplane = 0; nplane < 3; nplane++) + { + s->p_res_con_diff[nplane] = NULL; + s->p_MV_con_diff[nplane] = NULL; + s->p_error_sign_flag[nplane] = NULL; + s->p_transmission_dist[nplane] = NULL; + s->p_transmission_err[nplane] = NULL; + s->p_dec_img[nplane] = NULL; + s->p_first_moment[nplane] = NULL; + s->p_second_moment[nplane] = NULL; + } + + switch (p_Inp->de) + { + case LLN: + ndec = p_Inp->NoOfDecoders; + //check the consistent + if (ndec == 0) + { + printf("Number of decoders cannot be zero for LLN and fast LLN algorithms, resetting to 30"); + ndec = 30; + } + get_mem3D(&(s->mb_error_map), ndec, size_y/MB_BLOCK_SIZE, size_x/MB_BLOCK_SIZE); + get_mem3Dpel(&(s->dec_imgY), ndec, size_y, size_x); + + // This seems somewhat inefficient. Why not allocate array as [ndec][x] where x goes from 0 to 2? + if ((s->p_dec_img[0] = (imgpel***)calloc(ndec,sizeof(imgpel**))) == NULL) + { + no_mem_exit("errdo.c: p_dec_img[0]"); + } + + if (p_Vid->yuv_format != YUV400) + { + get_mem4Dpel(&(s->dec_imgUV), ndec, 2, size_y_cr, size_x_cr); + if ((s->p_dec_img[1] = (imgpel***)calloc(ndec,sizeof(imgpel**))) == NULL) + { + no_mem_exit("errdo.c: p_dec_img[1]"); + } + if ((s->p_dec_img[2] = (imgpel***)calloc(ndec,sizeof(imgpel**))) == NULL) + { + no_mem_exit("errdo.c: p_dec_img[2]"); + } + } + + for (dec = 0; dec < ndec; dec++) + { + s->p_dec_img[0][dec] = s->dec_imgY[dec]; + } + + if (p_Vid->yuv_format != YUV400) + { + for (dec = 0; dec < ndec; dec++) + { + s->p_dec_img[1][dec] = s->dec_imgUV[dec][0]; + s->p_dec_img[2][dec] = s->dec_imgUV[dec][1]; + } + } + + break; + default: + ; + } +} + + +/*! + ************************************************************************************* + * \brief + * free storable picture memory for errdo + * + ************************************************************************************* + */ +void errdo_free_storable_picture(StorablePicture* s) +{ + int nplane; + Dist_Estm *p = s->de_mem; + //free memory for RMPC and extended RMPC algorithms + if (p->res_con_diff_Y) + { + free_mem2Dint(p->res_con_diff_Y); + p->res_con_diff_Y = NULL; + } + if (p->res_con_diff_UV) + { + free_mem3Dint(p->res_con_diff_UV); + p->res_con_diff_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_res_con_diff[nplane] = NULL; + } + + if (p->MV_con_diff_Y) + { + free_mem2Dint(p->MV_con_diff_Y); + p->MV_con_diff_Y = NULL; + } + if (p->MV_con_diff_UV) + { + free_mem3Dint(p->MV_con_diff_UV); + p->MV_con_diff_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_MV_con_diff[nplane] = NULL; + } + + if (p->error_sign_flag_Y) + { + free_mem2D(p->error_sign_flag_Y); + p->error_sign_flag_Y = NULL; + } + if (p->error_sign_flag_UV) + { + free_mem3D(p->error_sign_flag_UV); + p->error_sign_flag_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_error_sign_flag[nplane] = NULL; + } + + if (p->transmission_dist_Y) + { + free_mem2Dint(p->transmission_dist_Y); + p->transmission_dist_Y = NULL; + } + if (p->transmission_dist_UV) + { + free_mem3Dint(p->transmission_dist_UV); + p->transmission_dist_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_transmission_dist[nplane] = NULL; + } + + if (p->transmission_err_Y) + { + free_mem2Dint(p->transmission_err_Y); + p->transmission_err_Y = NULL; + } + if (p->transmission_err_UV) + { + free_mem3Dint(p->transmission_err_UV); + p->transmission_err_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_transmission_err[nplane] = NULL; + } + + //free memory for LLN and Faster LLN algorithms + if (p->dec_imgY) + { + free_mem3Dpel(p->dec_imgY); + p->dec_imgY = NULL; + } + if (p->dec_imgUV) + { + free_mem4Dpel(p->dec_imgUV); + p->dec_imgUV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + free_pointer(p->p_dec_img[nplane]); + } + if (p->mb_error_map) + { + free_mem3D(p->mb_error_map); + p->mb_error_map = NULL; + } + + + //free memory for ROPE and extended ROPE algorithms + if (p->first_moment_Y) + { + free_mem2Dpel(p->first_moment_Y); + p->first_moment_Y = NULL; + } + if (p->first_moment_UV) + { + free_mem3Dpel(p->first_moment_UV); + p->first_moment_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_first_moment[nplane] = NULL; + } + if (p->second_moment_Y) + { + free_mem2Duint16(p->second_moment_Y); + p->second_moment_Y = NULL; + } + if (p->second_moment_UV) + { + free_mem3Duint16(p->second_moment_UV); + p->second_moment_UV = NULL; + } + for (nplane = 0; nplane < 3; nplane++) + { + p->p_second_moment[nplane] = NULL; + } + + free_pointer(s->de_mem); +} + diff --git a/lencod/src/errdo_dist_mhyp.c b/lencod/src/errdo_dist_mhyp.c new file mode 100644 index 0000000..eb71269 --- /dev/null +++ b/lencod/src/errdo_dist_mhyp.c @@ -0,0 +1,671 @@ +/*! + ************************************************************************************* + * \file errdo_dist_estimation_multihyp.c + * \brief + * Expected distortion estimation using multiple decoder based method + * refer to the paper "Optimized transmission of H.26L/JVT coded video over packet-lossy networks" + * by T. Stockhammer, T. Wiegand, and S. Wenger in 2002 + * \date + * October 22nd, 2001 + * + * \author + * Main contributors (see contributors.h for copyright, address and + * affiliation details) + * - Dimitrios Kontopodis + * Code revamped July 2008 by: + * - Peshala Pahalawatta (ppaha@dolby.com) + * - Alexis Tourapis (atour@dolby.com) + * Code modularized to support more distortion estimation algorithms in June 2009 by + * - Zhifeng Chen (zzchen@dolby.com) + ************************************************************************************* + */ + +//For distortion estimation +#include "global.h" +#include "mbuffer.h" +#include "errdo.h" +#include "md_distortion.h" +#include "md_common.h" +#include "lln_mc_prediction.h" + +static void add_residue (Macroblock *currMB, StorablePicture *enc_pic, int decoder, int pl, int block8x8, int x_size, int y_size); +static void Build_Status_Map(VideoParameters *p_Vid, InputParameters *p_Inp, byte **s_map); +static void get_predicted_mb(Macroblock *currMB, StorablePicture *enc_pic, int decoder); +static void copy_conceal_mb (Macroblock *currMB, StorablePicture *enc_pic, int decoder, int mb_error, StorablePicture* refPic); +static void decode_one_b8block (Macroblock* currMB, StorablePicture *enc_pic, int decoder, int block8x8, short mv_mode, int pred_dir); +static void decode_one_mb (Macroblock* currMB, StorablePicture *enc, int decoder); + +extern void UpdateDecoders (VideoParameters *p_Vid, InputParameters *p_Inp, StorablePicture *enc_pic); +extern void DeblockFrame(VideoParameters *p_Vid, imgpel **, imgpel ***); + +/*! + ************************************************************************************* + * \brief + * Performs distortion estimation using multiple decoder based algorithm. + * + ************************************************************************************* + */ +distblk errdo_distortion_estimation_multihyp(Macroblock *currMB, int block, int block_size, short mode, short pdir, distblk min_rdcost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int pax = 8*(block & 0x01); + int pay = 8*(block >> 1); + distblk distortion=0; + distblk temp_dist, ddistortion = 0; + int k; + + //Note that in rdcost_for_8x8blocks() no chroma distortion is calculated + //Refer to the function reset_adaptive_rounding(), + //maxplane = (p_Vid->yuv_format == YUV400)? 1 : 3; for p_Vid->ARCofAdj4x4 + //maxplane = (p_Vid->yuv_format == YUV400)? 1 : (p_Vid->P444_joined ? 3 : 1); for p_Vid->ARCofAdj8x8 + if (mode >= 4 && mode <= 7) //to be called by rdcost_for_8x8blocks() + { + //===== get residue ===== + // We need the reconstructed prediction residue for the simulated decoders. + //compute_residue_b8block (p_Vid, &p_Vid->enc_picture->p_img[0][currMB->pix_y], p_Vid->p_decs->res_img[0], block, -1); + errdo_compute_residue (currMB, &p_Vid->enc_picture->p_img[0][currMB->pix_y], p_Vid->p_decs->res_img[0], currSlice->mb_pred[0], block, 8); + + //===== GET DISTORTION + /* + //To keep exactly same as former version, below lines are used + for (k=0; kNoOfDecoders ;k++) + { + decode_one_b8block (currMB, p_Vid->enc_picture, k, block, mode, pdir); + distortion += compute_SSE8x8(&p_Vid->pCurImg[currMB->opix_y + pay], &p_Vid->enc_picture->p_dec_img[0][k][currMB->opix_y + pay], currMB->pix_x + pax, currMB->pix_x + pax); + } + distortion /= p_Inp->NoOfDecoders; + */ + + for (k = 0; k < p_Inp->NoOfDecoders; k++) + { + decode_one_b8block (currMB, p_Vid->enc_picture, k, block, mode, pdir); + ddistortion += compute_SSE8x8(&p_Vid->pCurImg[currMB->opix_y + pay], &p_Vid->enc_picture->de_mem->p_dec_img[0][k][currMB->opix_y + pay], currMB->pix_x + pax, currMB->pix_x + pax); + + { + temp_dist = min_rdcost * p_Inp->NoOfDecoders; + } + if (ddistortion > temp_dist) + { + //distortion = (distblk) ((ddistortion) / (k+1) + 0.5); + return DISTBLK_MAX; + } + } + + distortion = (distblk) (ddistortion / p_Inp->NoOfDecoders); + } + else if (mode != P8x8) //to be called by RDCost_for_macroblocks() + { + errdo_compute_residue (currMB, &p_Vid->enc_picture->p_curr_img[currMB->pix_y], p_Vid->p_decs->res_img[0], mode == I16MB ? currSlice->mpr_16x16[0][ (short) currMB->i16mode] : currSlice->mb_pred[0], 0, 16); + for (k = 0; kNoOfDecoders ;k++) + { + decode_one_mb (currMB, p_Vid->enc_picture, k); + ddistortion += compute_SSE16x16(&p_Vid->pImgOrg[0][currMB->opix_y], &p_Vid->enc_picture->de_mem->p_dec_img[0][k][currMB->pix_y], currMB->pix_x, currMB->pix_x); + + //Use integer calculation + if (min_rdcost < DISTBLK_MAX) + { + { + temp_dist = min_rdcost * p_Inp->NoOfDecoders; + } + } + else + temp_dist = DISTBLK_MAX; + + if (ddistortion > temp_dist) + { + //distortion = (distblk) ((ddistortion) / (k+1) + 0.5); + return DISTBLK_MAX; + } + } + + distortion = (distblk) (ddistortion / p_Inp->NoOfDecoders); + + if ((p_Vid->yuv_format != YUV400) && (active_sps->chroma_format_idc != YUV444)) + { + // CHROMA + distortion += compute_SSE_cr(&p_Vid->pImgOrg[1][currMB->opix_c_y], &p_Vid->enc_picture->imgUV[0][currMB->pix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x); + distortion += compute_SSE_cr(&p_Vid->pImgOrg[2][currMB->opix_c_y], &p_Vid->enc_picture->imgUV[1][currMB->pix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x); + } + } + else //to be called by RDCost_for_macroblocks() + { + for (k = 0; kNoOfDecoders ;k++) + { + ddistortion += compute_SSE16x16(&p_Vid->pImgOrg[0][currMB->opix_y], &p_Vid->enc_picture->de_mem->p_dec_img[0][k][currMB->pix_y], currMB->pix_x, currMB->pix_x); + + //Use integeter calculation + if (min_rdcost < DISTBLK_MAX) + { + { + temp_dist = min_rdcost * p_Inp->NoOfDecoders; + } + } + else + temp_dist = DISTBLK_MAX; + + if (ddistortion > temp_dist) + { + //distortion = (distblk) ((ddistortion) / (k+1) + 0.5); + return DISTBLK_MAX; + } + } + distortion = (distblk) (ddistortion / p_Inp->NoOfDecoders); + + if ((p_Vid->yuv_format != YUV400) && (active_sps->chroma_format_idc != YUV444)) + { + // CHROMA + distortion += compute_SSE_cr(&p_Vid->pImgOrg[1][currMB->opix_c_y], &p_Vid->enc_picture->imgUV[0][currMB->pix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x); + distortion += compute_SSE_cr(&p_Vid->pImgOrg[2][currMB->opix_c_y], &p_Vid->enc_picture->imgUV[1][currMB->pix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x); + } + } + + return distortion; +} + +/*! + ************************************************************************************* + * \brief + * Performs the simulation of the packet losses, calls the error concealment funcs + * and deblocks the error concealed pictures + * + ************************************************************************************* + */ +void UpdateDecoders(VideoParameters *p_Vid, InputParameters *p_Inp, StorablePicture *enc_pic) +{ + int k; + for (k = 0; k < p_Inp->NoOfDecoders; k++) + { + Build_Status_Map(p_Vid, p_Inp, enc_pic->de_mem->mb_error_map[k]); // simulates the packet losses + p_Vid->error_conceal_picture(p_Vid, enc_pic, k); + DeblockFrame (p_Vid, enc_pic->de_mem->p_dec_img[0][k], NULL); + } +} + + + +/*! + ************************************************************************************* + * \brief + * Builds a random status map showing whether each MB is received or lost, based + * on the packet loss rate and the slice structure. + * + * \param s_map + * The status map to be filled + ************************************************************************************* + */ +static void Build_Status_Map(VideoParameters *p_Vid, InputParameters *p_Inp, byte **s_map) +{ + int i,j,slice=-1,mb=0,jj,ii; + byte packet_lost=0; + + jj = p_Vid->height/MB_BLOCK_SIZE; + ii = p_Vid->width/MB_BLOCK_SIZE; + + for (j = 0; j < jj; j++) + { + for (i = 0; i < ii; i++) + { + if (!p_Inp->slice_mode || p_Vid->mb_data[mb].slice_nr != slice) /* new slice */ + { + packet_lost=0; + if ((double)rand()/(double)RAND_MAX*100 < p_Inp->LossRateC) packet_lost += 3; + if ((double)rand()/(double)RAND_MAX*100 < p_Inp->LossRateB) packet_lost += 2; + if ((double)rand()/(double)RAND_MAX*100 < p_Inp->LossRateA) packet_lost = 1; + slice++; + } + if (!packet_lost) + { + s_map[j][i]=0; //! Packet OK + } + else + { + s_map[j][i] = packet_lost; + if(p_Inp->partition_mode == 0) s_map[j][i]=1; + } + mb++; + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Stores the pel values for the current best mode. + ************************************************************************************* + */ +void errdo_store_best_block_multihyp(InputParameters *p_Inp, imgpel*** mbY, imgpel*** dec_img, int block, int img_i, int img_j, int block_size) +{ + int i0 = ((block&0x01)<<3); + int j0 = ((block>>1)<<3); + int j, k; + int j1 = j0 + block_size; + + for (k = 0; k < p_Inp->NoOfDecoders; k++) + { + for (j = j0; j < j1; j++) + { + memcpy(&mbY[k][j][i0], &dec_img[k][img_j+j][img_i+i0], block_size * sizeof(imgpel)); + } + } +} + +/*! + ************************************************************************************* + * \brief + * Restores the pel values from the current best mode. + ************************************************************************************* + */ +void errdo_get_best_block_multihyp(Macroblock *currMB, imgpel*** dec_img, imgpel*** mbY, int block, int block_size) +{ + int i0 = ((block&0x01)<<3); + int j0 = ((block>>1)<<3); + int j, k; + int j1 = j0 + block_size; + + for (k = 0; k < currMB->p_Inp->NoOfDecoders; k++) + { + for (j = j0; j < j1; j++) + { + memcpy(&dec_img[k][currMB->pix_y + j][currMB->pix_x+i0], &mbY[k][j][i0], block_size * sizeof(imgpel)); + } + } +} + +/*! +************************************************************************************** +* \brief +* Decodes one macroblock for error resilient RDO. +* Currently does not support: +* 1) B coded pictures +* 2) Chroma components +* 3) Potential error propagation due to intra prediction +* 4) Field coding +************************************************************************************** +*/ +void decode_one_mb (Macroblock* currMB, StorablePicture *enc_pic, int decoder) +{ + int i0, j; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + imgpel** curComp; + imgpel** oldComp; + + //printf("currMB->mb_type %d\n", currMB->mb_type); + if (currMB->mb_type > P8x8) //Intra MB + { + curComp = &enc_pic->de_mem->p_dec_img[0][decoder][currMB->pix_y]; + oldComp = &enc_pic->p_curr_img[currMB->pix_y]; + i0 = currMB->pix_x; + copy_image_data_16x16(curComp, oldComp, i0, i0); + } + else if ((currMB->mb_type == 0) && (currSlice->slice_type != B_SLICE)) + { + get_predicted_mb(currMB, enc_pic, decoder); + curComp = &enc_pic->de_mem->p_dec_img[0][decoder][currMB->pix_y]; + for(j = 0; j < p_Vid->mb_size[0][1]; j++) + { + memcpy(&(curComp[j][currMB->pix_x]), &(p_Vid->p_decs->dec_mb_pred[decoder][j][0]), p_Vid->mb_size[0][0] * sizeof(imgpel)); + } + } + else + { + get_predicted_mb(currMB, enc_pic, decoder); + add_residue(currMB, enc_pic, decoder, PLANE_Y, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + } +} + +/*! +************************************************************************************** +* \brief +* Finds predicted macroblock values +* and copies them to currSlice->mb_pred[0][][] +************************************************************************************** +*/ +static void get_predicted_mb(Macroblock *currMB, StorablePicture *enc_pic, int decoder) +{ + Slice *currSlice = currMB->p_Slice; + int i,j,k; + int block_size_x, block_size_y; + int mv_mode, pred_dir; + static const byte decode_block_scan[16] = {0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15}; + int block8x8; + int k_start, k_end, k_inc; + + if (currSlice->slice_type == P_SLICE && !currMB->mb_type) + { + block_size_x = MB_BLOCK_SIZE; + block_size_y = MB_BLOCK_SIZE; + perform_mc(currMB, decoder, PLANE_Y, enc_pic, LIST_0, 0, 0, enc_pic->mv_info, 0, 0, block_size_x, block_size_y, 0); + } + else if (currMB->mb_type == 1) + { + block_size_x = MB_BLOCK_SIZE; + block_size_y = MB_BLOCK_SIZE; + pred_dir = currMB->b8x8[0].pdir; + perform_mc(currMB, decoder, PLANE_Y, enc_pic, pred_dir, 1, 1, enc_pic->mv_info, 0, 0, block_size_x, block_size_y, currMB->b8x8[0].bipred); + } + else if (currMB->mb_type == 2) + { + block_size_x = MB_BLOCK_SIZE; + block_size_y = 8; + + for (block8x8 = 0; block8x8 < 4; block8x8 += 2) + { + pred_dir = currMB->b8x8[block8x8].pdir; + perform_mc(currMB, decoder, PLANE_Y, enc_pic, pred_dir, 2, 2, enc_pic->mv_info, 0, block8x8, block_size_x, block_size_y, currMB->b8x8[block8x8].bipred); + } + } + else if (currMB->mb_type == 3) + { + block_size_x = 8; + block_size_y = 16; + + for (block8x8 = 0; block8x8 < 2; block8x8++) + { + i = block8x8<<1; + j = 0; + pred_dir = currMB->b8x8[block8x8].pdir; + perform_mc(currMB, decoder, PLANE_Y, enc_pic, pred_dir, 3, 3, enc_pic->mv_info, i, j, block_size_x, block_size_y, currMB->b8x8[block8x8].bipred); + } + } + else + { + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + mv_mode = currMB->b8x8[block8x8].mode; + pred_dir = currMB->b8x8[block8x8].pdir; + + k_start = (block8x8 << 2); + k_inc = (mv_mode == 5) ? 2 : 1; + + if (mv_mode == 0) + { + k_end = k_start + 1; + block_size_x = 8; + block_size_y = 8; + } + else + { + k_end = (mv_mode == 4) ? k_start + 1 : ((mv_mode == 7) ? k_start + 4 : k_start + k_inc + 1); + block_size_x = ( mv_mode == 5 || mv_mode == 4 ) ? 8 : 4; + block_size_y = ( mv_mode == 6 || mv_mode == 4 ) ? 8 : 4; + } + + for (k = k_start; k < k_end; k += k_inc) + { + i = (decode_block_scan[k] & 3); + j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, decoder, PLANE_Y, enc_pic, pred_dir, mv_mode, mv_mode, enc_pic->mv_info, i, j, block_size_x, block_size_y, currMB->b8x8[block8x8].bipred); + } + } + } +} + + +/*! +************************************************************************************** +* \brief +* Decodes one 8x8 partition for error resilient RDO. +* Currently does not support: +* 1) B coded pictures +* 2) Chroma components +* 3) Potential error propagation due to intra prediction +* 4) Field coding +************************************************************************************** +*/ +void decode_one_b8block (Macroblock* currMB, StorablePicture *enc_pic, int decoder, int block8x8, short mv_mode, int pred_dir) +{ + int i,j,k; + int block_size_x, block_size_y; + int i0 = (block8x8 & 0x01)<<3; + int j0 = (block8x8 >> 1)<<3, j1 = j0+8; + //char*** ref_idx_buf = enc_pic->motion.ref_idx; + imgpel **curComp; + imgpel **oldComp; + int k_start, k_end, k_inc; + static const byte decode_block_scan[16] = {0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15}; + + if (mv_mode > 8) //Intra + { + for(j = j0; j < j1; j++) + { + curComp = &enc_pic->de_mem->p_dec_img[0][decoder][currMB->pix_y]; + oldComp = &enc_pic->p_curr_img[currMB->pix_y]; + memcpy(&(curComp[j][i0]), &(oldComp[j][i0]), sizeof(imgpel)*8); + } + } + else + { + k_start = (block8x8 << 2); + + if (mv_mode == 0) //Direct + { + k_inc = 1; + k_end = k_start+1; + block_size_x = 8; + block_size_y = 8; + //ref_idx_buf = currSlice->direct_ref_idx; + } + else //mv_mode from 4 to 7 + { + k_inc = (mv_mode == 5) ? 2 : 1; + k_end = (mv_mode == 4) ? k_start + 1 : ((mv_mode == 7) ? k_start + 4 : k_start + k_inc + 1); + + block_size_x = ( mv_mode == 5 || mv_mode == 4 ) ? 8 : 4; + block_size_y = ( mv_mode == 6 || mv_mode == 4 ) ? 8 : 4; + } + + for (k = k_start; k < k_end; k += k_inc) + { + i = (decode_block_scan[k] & 3); + j = ((decode_block_scan[k] >> 2) & 3); + perform_mc(currMB, decoder, PLANE_Y, enc_pic, pred_dir, mv_mode, mv_mode, enc_pic->mv_info, i, j, block_size_x, block_size_y, currMB->b8x8[block8x8].bipred); + } + + add_residue(currMB, enc_pic, decoder, PLANE_Y, block8x8, 8, 8); + } +} + +/*! +************************************************************************************** +* \brief +* Add residual to motion predicted block +************************************************************************************** +*/ +static void add_residue (Macroblock *currMB, StorablePicture *enc_pic, int decoder, int pl, int block8x8, int x_size, int y_size) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int max_pel_value = currMB->p_Vid->max_pel_value_comp[pl]; + int i,j; + int i0 = (block8x8 & 0x01)<<3, i1 = i0 + x_size; + int j0 = (block8x8 >> 1)<<3, j1 = j0 + y_size; + + imgpel **p_dec_img = &enc_pic->de_mem->p_dec_img[pl][decoder][currMB->pix_y]; + int **res_img = p_Vid->p_decs->res_img[0]; + imgpel** mpr = p_Vid->p_decs->dec_mb_pred[decoder]; + + for (j = j0; j < j1; j++) + { + for (i = i0; i < i1; i++) + { + p_dec_img[j][currMB->pix_x + i] = (imgpel) iClip3(0, max_pel_value, (mpr[j][i] + res_img[j][i])); + } + } +} + + +/*! +************************************************************************************** +* \brief +* Finds predicted macroblock values for error concealment +* +* Requires enc_pic->motion.mv and enc_pic->motion.ref_idx to be correct for +* current picture. +************************************************************************************** +*/ +static void get_predicted_concealment_mb(Macroblock* currMB, StorablePicture* enc_pic, int decoder) +{ + Slice *currSlice = currMB->p_Slice; + int i,j,k; + int block_size_x, block_size_y; + int mv_mode, pred_dir; + static const byte decode_block_scan[16] = {0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15}; + int block8x8; + int k_start, k_end, k_inc; + + if (currSlice->slice_type == P_SLICE && !currMB->mb_type) + { + block_size_x = MB_BLOCK_SIZE; + block_size_y = MB_BLOCK_SIZE; + perform_mc_concealment(currMB, decoder, PLANE_Y, enc_pic, LIST_0, 0, 0, enc_pic->mv_info, 0, 0, block_size_x, block_size_y); + } + else if (currMB->mb_type == 1) + { + block_size_x = MB_BLOCK_SIZE; + block_size_y = MB_BLOCK_SIZE; + pred_dir = currMB->b8x8[0].pdir; + perform_mc_concealment(currMB, decoder, PLANE_Y, enc_pic, pred_dir, 1, 1, enc_pic->mv_info, 0, 0, block_size_x, block_size_y); + } + else if (currMB->mb_type == 2) + { + block_size_x = MB_BLOCK_SIZE; + block_size_y = 8; + + for (block8x8 = 0; block8x8 < 4; block8x8 += 2) + { + pred_dir = currMB->b8x8[block8x8].pdir; + perform_mc_concealment(currMB, decoder, PLANE_Y, enc_pic, pred_dir, 2, 2, enc_pic->mv_info, 0, block8x8, block_size_x, block_size_y); + } + } + else if (currMB->mb_type == 3) + { + block_size_x = 8; + block_size_y = 16; + + for (block8x8 = 0; block8x8 < 2; block8x8++) + { + i = block8x8<<1; + j = 0; + pred_dir = currMB->b8x8[block8x8].pdir; + perform_mc_concealment(currMB, decoder, PLANE_Y, enc_pic, pred_dir, 3, 3, enc_pic->mv_info, i, j, block_size_x, block_size_y); + } + } + else + { + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + mv_mode = currMB->b8x8[block8x8].mode; + pred_dir = currMB->b8x8[block8x8].pdir; + + k_start = (block8x8 << 2); + k_inc = (mv_mode == 5) ? 2 : 1; + + if (mv_mode == 0) + { + k_end = k_start + 1; + block_size_x = 8; + block_size_y = 8; + } + else + { + k_end = (mv_mode == 4) ? k_start + 1 : ((mv_mode == 7) ? k_start + 4 : k_start + k_inc + 1); + block_size_x = ( mv_mode == 5 || mv_mode == 4 ) ? 8 : 4; + block_size_y = ( mv_mode == 6 || mv_mode == 4 ) ? 8 : 4; + } + + for (k = k_start; k < k_end; k += k_inc) + { + i = (decode_block_scan[k] & 3); + j = ((decode_block_scan[k] >> 2) & 3); + perform_mc_concealment(currMB, decoder, PLANE_Y, enc_pic, pred_dir, mv_mode, mv_mode, enc_pic->mv_info, i, j, block_size_x, block_size_y); + } + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Performs copy error concealment for macroblocks with errors. + * Note: Currently assumes that the reference picture lists remain the same for all + * slices of a picture. + * + ************************************************************************************* + */ +void copy_conceal_picture(VideoParameters *p_Vid, StorablePicture *enc_pic, int decoder) +{ + unsigned int mb; + Macroblock* currMB; + int mb_error; + byte** mb_error_map = enc_pic->de_mem->mb_error_map[decoder]; + StorablePicture* refPic; + BlockPos *PicPos = p_Vid->PicPos; + + refPic = find_nearest_ref_picture(p_Vid->p_Dpb_layer[0], enc_pic->poc); //Used for concealment if actual reference pic is not known. + for (mb = 0; mb < p_Vid->PicSizeInMbs; mb++) + { + currMB = &p_Vid->mb_data[mb]; + currMB->mb_x = PicPos[mb].x; + currMB->mb_y = PicPos[mb].y; + mb_error = mb_error_map[currMB->mb_y][currMB->mb_x]; + if (mb_error) + { + currMB->block_x = currMB ->mb_x << 2; + currMB->block_y = currMB->mb_y << 2; + currMB->pix_x = currMB->block_x << 2; + currMB->pix_y = currMB->block_y << 2; + copy_conceal_mb(currMB, enc_pic, decoder, mb_error, refPic); + } + } +} + +/****************************************************************************************** +* +* Perform copy error concealment for macroblock. +* +******************************************************************************************* +*/ +static void copy_conceal_mb(Macroblock* currMB, StorablePicture *enc_pic, int decoder, int mb_error, StorablePicture* refPic) +{ + Slice *currSlice = currMB->p_Slice; + int j, i, i0 = currMB->pix_x; + imgpel** concealed_img = &(enc_pic->de_mem->p_dec_img[0][decoder][currMB->pix_y]); + imgpel** ref_img; + + if (mb_error == 1 || (mb_error != 3 && currMB->mb_type > P8x8)) //All partitions lost, or intra mb lost + { + if (refPic != NULL) //Use nearest reference picture for concealment + { + ref_img = &(refPic->de_mem->p_dec_img[0][decoder][currMB->pix_y]); + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy(&(concealed_img[j][i0]), &(ref_img[j][i0]), sizeof(imgpel)*MB_BLOCK_SIZE); + } + } + else //No ref picture available + { + for(j=0; jslice_type != I_SLICE && currMB->mb_type < P8x8) //Only partition 3 lost, and P/B macroblock + { + VideoParameters *p_Vid = currMB->p_Vid; + get_predicted_concealment_mb(currMB, enc_pic, decoder); + for(j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy(&(concealed_img[j][i0]), &(p_Vid->p_decs->dec_mb_pred[decoder][j][0]), MB_BLOCK_SIZE * sizeof(imgpel)); + } + } +} diff --git a/lencod/src/explicit_gop.c b/lencod/src/explicit_gop.c new file mode 100644 index 0000000..1fe8c1f --- /dev/null +++ b/lencod/src/explicit_gop.c @@ -0,0 +1,216 @@ +/*! + ************************************************************************************* + * \file explicit_gop.c + * + * \brief + * Code for explicit gop support and hierarchical coding. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include +#include "global.h" + +#include "explicit_gop.h" +#include "image.h" +#include "nalucommon.h" +#include "report.h" + +/*! +************************************************************************ +* \brief +* Initialization of GOP structure. +* +************************************************************************ +*/ +void init_gop_structure(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int max_gopsize = p_Inp->NumberBFrames; + + p_Vid->gop_structure = calloc(imax(10,max_gopsize), sizeof (GOP_DATA)); // +1 for reordering + if (NULL==p_Vid->gop_structure) + no_mem_exit("init_gop_structure: gop_structure"); +} + + +/*! +************************************************************************ +* \brief +* Clear GOP structure +************************************************************************ +*/ +void clear_gop_structure(VideoParameters *p_Vid) +{ + if (p_Vid->gop_structure) + free(p_Vid->gop_structure); +} + + +/*! +************************************************************************ +* \brief +* Interpret GOP struct from input parameters +************************************************************************ +*/ +void interpret_gop_structure(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int nLength = (int) strlen(p_Inp->ExplicitHierarchyFormat); + int i =0, k, dqp, display_no; + int slice_read =0, order_read = 0, stored_read = 0, qp_read =0; + int coded_frame = 0; + int tlyr, temporal_layer_read = 0; + + if (nLength > 0) + { + + for (i = 0; i < nLength ; i++) + { + //! First lets read slice type + if (slice_read == 0) + { + switch (p_Inp->ExplicitHierarchyFormat[i]) + { + case 'P': + case 'p': + p_Vid->gop_structure[coded_frame].slice_type = P_SLICE; + break; + case 'B': + case 'b': + p_Vid->gop_structure[coded_frame].slice_type = B_SLICE; + break; + case 'I': + case 'i': + p_Vid->gop_structure[coded_frame].slice_type = I_SLICE; + break; + default: + snprintf(errortext, ET_SIZE, "Slice Type invalid in ExplicitHierarchyFormat param. Please check configuration file."); + error (errortext, 400); + break; + } + slice_read = 1; + } + else + { + //! Next is Display Order + if (order_read == 0) + { + if (isdigit((int)(*(p_Inp->ExplicitHierarchyFormat+i)))) + { + sscanf(p_Inp->ExplicitHierarchyFormat+i,"%d",&display_no); + p_Vid->gop_structure[coded_frame].display_no = display_no; + order_read = 1; + if (display_no < 0 || display_no >= p_Inp->NumberBFrames) + { + snprintf(errortext, ET_SIZE, "Invalid Frame Order value. Frame position needs to be in [0,%d] range.",p_Inp->NumberBFrames - 1); + error (errortext, 400); + } + for (k=0;kgop_structure[k].display_no == display_no) + { + snprintf(errortext, ET_SIZE, "Frame Order value %d in frame %d already used for enhancement frame %d.",display_no,coded_frame,k); + error (errortext, 400); + } + } + } + else + { + snprintf(errortext, ET_SIZE, "Slice Type needs to be followed by Display Order. Please check configuration file."); + error (errortext, 400); + } + } + else if (order_read == 1) + { + if (stored_read == 0 && !(isdigit((int)(*(p_Inp->ExplicitHierarchyFormat+i))))) + { + switch (p_Inp->ExplicitHierarchyFormat[i]) + { + case 'E': + case 'e': + p_Vid->gop_structure[coded_frame].reference_idc = NALU_PRIORITY_DISPOSABLE; + p_Vid->gop_structure[coded_frame].hierarchy_layer = 0; + break; + case 'R': + case 'r': + p_Vid->gop_structure[coded_frame].reference_idc= NALU_PRIORITY_LOW; + p_Vid->gop_structure[coded_frame].hierarchy_layer = 1; + break; + default: + snprintf(errortext, ET_SIZE, "Reference_IDC invalid in ExplicitHierarchyFormat param. Please check configuration file."); + error (errortext, 400); + break; + } + stored_read = 1; + } + else if (stored_read == 1 && qp_read == 0) + { + if (isdigit((int)(*(p_Inp->ExplicitHierarchyFormat+i)))) + { + sscanf(p_Inp->ExplicitHierarchyFormat+i,"%d",&dqp); + + p_Vid->gop_structure[coded_frame].slice_qp_off = iClip3(-p_Vid->bitdepth_luma_qp_scale, 51, dqp); + qp_read = 1; + } + else + { + snprintf(errortext, ET_SIZE, "Reference_IDC needs to be followed by QP. Please check configuration file."); + error (errortext, 400); + } + } + else if (stored_read == 1 && qp_read == 1 && temporal_layer_read == 0) + { + if (!(isdigit((int)(*(p_Inp->ExplicitHierarchyFormat+i))))) + { + if (p_Inp->ExplicitHierarchyFormat[i] == 't' || p_Inp->ExplicitHierarchyFormat[i] == 'T') + { + p_Vid->gop_structure[coded_frame].temporal_layer = 0; + if (isdigit((int)(*(p_Inp->ExplicitHierarchyFormat+i+1)))) + { + sscanf(p_Inp->ExplicitHierarchyFormat+i+1,"%d",&tlyr); + + p_Vid->gop_structure[coded_frame].temporal_layer = tlyr; + i++; // temporal layer number is specified + } + } + else + { + i--; // temporal layer is optional and it is not specified + } + } + temporal_layer_read = 1; + } + else if (stored_read == 1 && qp_read == 1 && temporal_layer_read == 1 && !(isdigit((int)(*(p_Inp->ExplicitHierarchyFormat+i)))) && (i < nLength - 3)) + + { + stored_read =0; + qp_read=0; + order_read=0; + slice_read=0; + temporal_layer_read=0; + i--; + coded_frame ++; + if (coded_frame >= p_Inp->NumberBFrames ) + { + snprintf(errortext, ET_SIZE, "Total number of frames in Enhancement GOP need to be fewer or equal to NumberBFrames parameter."); + error (errortext, 400); + } + } + } + } + } + } + else + { + snprintf(errortext, ET_SIZE, "ExplicitHierarchyFormat is empty. Please check configuration file."); + error (errortext, 400); + } + + p_Inp->NumberBFrames = coded_frame + 1; +} + diff --git a/lencod/src/explicit_seq.c b/lencod/src/explicit_seq.c new file mode 100644 index 0000000..e8bb69d --- /dev/null +++ b/lencod/src/explicit_seq.c @@ -0,0 +1,329 @@ +/*! + ************************************************************************************* + * \file explicit_seq.c + * + * \brief + * Support for explicit coding order/structure support. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" +#include "global.h" +#include "report.h" +#include "explicit_seq.h" + +/*! +************************************************************************ +* \brief +* Read one Text Field +************************************************************************ +*/ +static int ReadTextField(FILE *expSeqFile, char* keyword) +{ + char readline [100]; + char word[64]; + int err = -1; + int read_line = 0; // read up to 5 lines to detect data + do + { + read_line++; + // let us read a full line of data + if (NULL == fgets(readline, 100, expSeqFile)) + error ("error parsing explicit sequence file", 500); + err = sscanf(readline,"%s",word); + if (err == -1) + break; + if (strcasecmp(word, keyword) != 0) + err = - 1; + + if (feof(expSeqFile)) // move to the end of the line + break; + } + while (err == - 1 && read_line < 6); + // Lets keep err disabled. This allows us to continue encoding even + // when input file is empty or reaches end. + /* + if (err != 1) + { + printf("Error while reading text \"%s\" from input file.\n", keyword); + report_stats_on_error(); + } + */ + return err; +} + +/*! +************************************************************************ +* \brief +* Read one Field of Integer type +************************************************************************ +*/ +void ReadIntField(FILE *expSeqFile, char* format, char* keyword, int* value) +{ + char readline [100]; + char word[64]; + int err = -1; + int read_line = 0; // read up to 5 lines to detect data + + do + { + read_line++; + if (NULL == fgets(readline, 100, expSeqFile)) + error ("error parsing explicit sequence file", 500); + err = sscanf(readline, format, word, value); + if (feof(expSeqFile)) + break; + } + while (strcasecmp(word, keyword) != 0 && read_line < 6); + + if (err != 2 || strcasecmp(word, keyword) != 0) + { + printf("Error while reading %s.\n", keyword); + report_stats_on_error(); + } +} + +/*! +************************************************************************ +* \brief +* Read one Field of String type +************************************************************************ +*/ +void ReadCharField(FILE *expSeqFile, char* format, char* keyword, char* value) +{ + char readline [100]; + char word[64]; + int err = -1; + int read_line = 0; // read up to 5 lines to detect data + + do + { + read_line++; + if (NULL == fgets(readline, 100, expSeqFile)) + error ("error parsing explicit sequence file", 500); + err = sscanf(readline, format, word, value); + + while (!feof(expSeqFile)) // move to the end of the line + break; + } + while (strcasecmp(word, keyword) != 0 && read_line < 6); + + if (err != 2 || strcasecmp(word, keyword) != 0) + { + printf("Error while reading %s.\n", keyword); + report_stats_on_error(); + } +} + + +static void ParseSliceType(char *slice_type, ExpFrameInfo *info, int coding_index) +{ + if ( strcasecmp(slice_type, "P") == 0 ) + { + info->slice_type = P_SLICE; + } + else if ( strcasecmp(slice_type, "B") == 0 ) + { + info->slice_type = B_SLICE; + } + else if ( strcasecmp(slice_type, "I") == 0 ) + { + info->slice_type = I_SLICE; + } + else if ( strcasecmp(slice_type, "SP") == 0 ) + { + info->slice_type = SP_SLICE; + } + else if ( strcasecmp(slice_type, "SI") == 0 ) + { + info->slice_type = SI_SLICE; + } + else + { + printf("ReadExplicitSeqFile : invalid slice type\n"); + report_stats_on_error(); + } + + if (coding_index == 0 && info->slice_type != I_SLICE) + { + printf("ReadExplicitSeqFile : First coded picture needs to be Intra.\n"); + report_stats_on_error(); + } +} + +static void ParseReferenceIDC(int reference_idc, int coding_index) +{ + if ( reference_idc < NALU_PRIORITY_DISPOSABLE || reference_idc > NALU_PRIORITY_HIGHEST) + { + printf("ReadExplicitSeqFile : Invalid reference indicator \n"); + report_stats_on_error(); + } + + if (coding_index == 0 && reference_idc == NALU_PRIORITY_DISPOSABLE) + { + printf("ReadExplicitSeqFile : First coded picture needs to be a reference picture.\n"); + report_stats_on_error(); + } +} + + +static void ParseSeqNumber(int seq_number, ExpSeqInfo *seq_info, int coding_index) +{ + int i; + for (i = 0; i < imin(coding_index, seq_info->no_frames); i++) + { + if (seq_info->info[i].seq_number == seq_number) + { + printf("ReadExplicitSeqFile : SeqNumber used for current frame already used. Terminating\n"); + report_stats_on_error(); + } + } +} + +/*! +************************************************************************ +* \brief +* Read Frame information +************************************************************************ +*/ +void ReadFrameData(FILE *expSeqFile, ExpSeqInfo *seq_info, int coding_index) +{ + Boolean slice_type_present = FALSE; + Boolean seq_number_present = FALSE; + char readline [100]; + char word[64], value[64]; + int err = -1; + ExpFrameInfo *info = &seq_info->info[coding_index % seq_info->no_frames]; + // Set some defaults + info->reference_idc = NALU_PRIORITY_HIGHEST; + + ReadTextField (expSeqFile, "{"); // Start bracket + do + { + // read one line of data + if (NULL == fgets(readline, 100, expSeqFile)) + error ("error parsing explicit sequence file", 500); + // let us check if ending character reached or error + err = sscanf(readline, "%s : %s", word, value); + if (err == 1) // Check ending characters + { + if (strcasecmp(word, "}") == 0) + break; + else if (strcasecmp(word, "{") == 0) + { + printf("Invalid \"{\" character found. Terminating\n"); + report_stats_on_error(); + } + } + else if (err == 2) // parse different parameters. Input method is flexible and does not fix input order. + { + if (strcasecmp(word, "SeqNumber") == 0) + { + info->seq_number = atoi(value); + ParseSeqNumber(info->seq_number, seq_info, coding_index); + seq_number_present = TRUE; + } + else if (strcasecmp(word, "SliceType") == 0) + { + ParseSliceType(value, info, coding_index); + slice_type_present = TRUE; + } + else if (strcasecmp(word, "IDRPicture") == 0) + info->is_idr = atoi(value); + else if (strcasecmp(word, "Reference") == 0) + { + info->reference_idc = atoi(value); + ParseReferenceIDC(info->reference_idc, coding_index); + } + } + } + while (!feof(expSeqFile)); + + if (slice_type_present == FALSE || seq_number_present == FALSE) + { + printf("Sequence info file does not contain all mandatory info (SeqNumber or SliceType). Terminating.\n"); + report_stats_on_error(); + } +} + +/*! + ************************************************************************ + * \brief + * Read one picture from explicit sequence information file + ************************************************************************ + */ +void ReadExplicitSeqFile(ExpSeqInfo *seq_info, FILE *expSFile, int coding_index) +{ + int frm_header = ReadTextField(expSFile, "Frame"); + + if (frm_header != -1) + { + ReadFrameData (expSFile, seq_info, coding_index); + } + else + { + printf("ReadExplicitSeqFile : No more data. \n"); + report_stats_on_error(); + } +} + +/*! + ************************************************************************ + * \brief + * Open explicit sequence information file + ************************************************************************ + */ +void OpenExplicitSeqFile(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int frm_count = 0; + p_Vid->expSFile = fopen(p_Inp->ExplicitSeqFile, "r"); + if (p_Vid->expSFile == NULL) + { + printf("ERROR while opening the explicit sequence information file.\n"); + report_stats_on_error(); + } + + if (ReadTextField(p_Vid->expSFile, "Sequence") == -1) + { + printf("Sequence info file is of invalid format. Terminating\n"); + report_stats_on_error(); + } + else + { + ReadIntField (p_Vid->expSFile, "%s : %d", "FrameCount", &frm_count); + if (frm_count > 0) + { + p_Vid->expSeq = (ExpSeqInfo *) malloc(sizeof(ExpSeqInfo)); + p_Vid->expSeq->no_frames = frm_count; + p_Vid->expSeq->info = (ExpFrameInfo *) calloc(frm_count, sizeof(ExpFrameInfo)); + } + else + { + printf("Invalid FrameCount in Sequence info file. Terminating\n"); + report_stats_on_error(); + } + } +} + +/*! +************************************************************************ +* \brief +* Close explicit sequence information file +************************************************************************ +*/ +void CloseExplicitSeqFile(VideoParameters *p_Vid) +{ + if (p_Vid->expSFile != NULL) + fclose(p_Vid->expSFile); + if (p_Vid->expSeq != NULL) + { + free(p_Vid->expSeq->info); + free(p_Vid->expSeq); + } +} + + diff --git a/lencod/src/filehandle.c b/lencod/src/filehandle.c new file mode 100644 index 0000000..9ac7ab8 --- /dev/null +++ b/lencod/src/filehandle.c @@ -0,0 +1,277 @@ + +/*! +************************************************************************************** +* \file +* filehandle.c +* \brief +* Start and terminate sequences +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Thomas Stockhammer +* - Detlev Marpe +*************************************************************************************** +*/ + +#include "contributors.h" + +#include "global.h" +#include "enc_statistics.h" + +#include "rtp.h" +#include "annexb.h" + +#include "annexb_split.h" + +#include "parset.h" +#include "mbuffer.h" + + +/*! +************************************************************************ +* \brief +* Error handling procedure. Print error message to stdout and exit +* with supplied code. +* \param text +* Error message +* \param code +* Exit code +************************************************************************ +*/ +void error(char *text, int code) +{ + fprintf(stdout, "%s\n", text); + flush_dpb(p_Enc->p_Vid->p_Dpb_layer[0], &p_Enc->p_Inp->output); + flush_dpb(p_Enc->p_Vid->p_Dpb_layer[1], &p_Enc->p_Inp->output); +#if (_DEBUG) +#if( WIN32 ) + system("pause"); +#endif +#endif + exit(code); +} + +/*! +************************************************************************ +* \brief +* This function generates and writes the PPS +* +************************************************************************ +*/ +int write_PPS(VideoParameters *p_Vid, int len, int PPS_id) +{ + NALU_t *nalu; + nalu = NULL; + nalu = GeneratePic_parameter_set_NALU (p_Vid, PPS_id); + len += p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + FreeNALU (nalu); + + return len; +} + +/*! +************************************************************************ +* \brief +* This function opens the output files and generates the +* appropriate sequence header +************************************************************************ +*/ +int start_sequence(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i,len=0, total_pps = (p_Inp->GenerateMultiplePPS) ? 3 : 1; + NALU_t *nalu; + + switch(p_Inp->of_mode) + { + case PAR_OF_ANNEXB: + p_Vid->WriteNALU = WriteAnnexbNALU; + p_Vid->f_out = &p_Vid->f_annexb; + OpenAnnexbFile (p_Inp->outfile, p_Vid->f_out); +#if (MVC_EXTENSION_ENABLE) + OpenAnnexbFileBaseView (p_Vid, p_Inp->outfile_base); + OpenAnnexbFileAuxView (p_Vid, p_Inp->outfile_aux); +#endif + break; + case PAR_OF_RTP: + p_Vid->WriteNALU = WriteRTPNALU; + p_Vid->f_out = &p_Vid->f_rtp; + OpenRTPFile (p_Inp->outfile, p_Vid->f_out); + break; + default: + snprintf(errortext, ET_SIZE, "Output File Mode %d not supported", p_Inp->of_mode); + error(errortext,1); + } + + // Access Unit Delimiter NALU + if ( p_Inp->SendAUD ) + { + len += Write_AUD_NALU(p_Vid); + } + + //! As a sequence header, here we write both sequence and picture + //! parameter sets. As soon as IDR is implemented, this should go to the + //! IDR part, as both parsets have to be transmitted as part of an IDR. + //! An alternative may be to consider this function the IDR start function. + + nalu = NULL; + nalu = GenerateSeq_parameter_set_NALU (p_Vid); + len += p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + FreeNALU (nalu); + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers==2) + { + int bits; + nalu = NULL; + nalu = GenerateSubsetSeq_parameter_set_NALU (p_Vid); + bits = p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + len += bits; + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1] = bits; + FreeNALU (nalu); + } + else + { + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1] = 0; + } +#endif + + //! Lets write now the Picture Parameter sets. Output will be equal to the total number of bits spend here. + for (i=0;iGenerateSEIMessage) + { + nalu = NULL; + nalu = GenerateSEImessage_NALU(p_Inp); + len += p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + FreeNALU (nalu); + } + + p_Vid->p_Stats->bit_ctr_parametersets_n = len; +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + { + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0] = len - p_Vid->p_Stats->bit_ctr_parametersets_n_v[1]; + } +#endif + return 0; +} + +int end_of_stream(VideoParameters *p_Vid) +{ + int bits; + NALU_t *nalu; + + nalu = AllocNALU(MAXNALUSIZE); + nalu->startcodeprefix_len = 4; + nalu->forbidden_bit = 0; + nalu->nal_reference_idc = 0; + nalu->nal_unit_type = NALU_TYPE_EOSTREAM; + nalu->len = 0; + bits = p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + + p_Vid->p_Stats->bit_ctr_parametersets += bits; + FreeNALU (nalu); + return bits; +} + +/*! +************************************************************************ +* \brief +* This function opens the output files and generates the +* appropriate sequence header +************************************************************************ +*/ +int rewrite_paramsets(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i,len=0, total_pps = (p_Inp->GenerateMultiplePPS) ? 3 : 1; + NALU_t *nalu; + + // Access Unit Delimiter NALU + if ( p_Inp->SendAUD ) + { + len += Write_AUD_NALU(p_Vid); + } + + //! As a sequence header, here we write both sequence and picture + //! parameter sets. As soon as IDR is implemented, this should go to the + //! IDR part, as both parsets have to be transmitted as part of an IDR. + //! An alternative may be to consider this function the IDR start function. + + nalu = NULL; + nalu = GenerateSeq_parameter_set_NALU (p_Vid); + len += p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + FreeNALU (nalu); + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers==2) + { + int bits; + nalu = GenerateSubsetSeq_parameter_set_NALU (p_Vid); + bits = p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + len += bits; + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1] = bits; + FreeNALU (nalu); + } +#endif + + //! Lets write now the Picture Parameter sets. Output will be equal to the total number of bits spend here. + for (i=0;iGenerateSEIMessage) + { + nalu = NULL; + nalu = GenerateSEImessage_NALU(p_Inp); + len += p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + FreeNALU (nalu); + } + + p_Vid->p_Stats->bit_ctr_parametersets_n = len; +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + { + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0] = len - p_Vid->p_Stats->bit_ctr_parametersets_n_v[1]; + } +#endif + return 0; +} + +/*! +************************************************************************ +* \brief +* This function terminates the sequence and closes the +* output files +************************************************************************ +*/ +int terminate_sequence(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + // Bitstream *currStream; + + // Mainly flushing of everything + // Add termination symbol, etc. + + switch(p_Inp->of_mode) + { + case PAR_OF_ANNEXB: + CloseAnnexbFile(*p_Vid->f_out); + //! Edited by Joao Carreira +#if (MVC_EXTENSION_ENABLE) + CloseAnnexbFileBaseView(p_Vid); + CloseAnnexbFileAuxView(p_Vid); +#endif + break; + case PAR_OF_RTP: + CloseRTPFile(*p_Vid->f_out); + return 0; + default: + snprintf(errortext, ET_SIZE, "Output File Mode %d not supported", p_Inp->of_mode); + error(errortext,1); + } + return 1; // make lint happy +} + diff --git a/lencod/src/fmo.c b/lencod/src/fmo.c new file mode 100644 index 0000000..ec26877 --- /dev/null +++ b/lencod/src/fmo.c @@ -0,0 +1,717 @@ +/*! + ***************************************************************************** + * + * \file fmo.c + * + * \brief + * Support for Flexible Macroblock Ordering for different Slice Group Modes: MBAmap handling + * + * \date + * 16 June, 2002 Modified April 25, 2004 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + * Dong Wang Dong.Wang@bristol.ac.uk + * + *****************************************************************************/ + +/*! + **************************************************************************** + * Notes by Dong Wang (April 25 2004) + * + * Source codes are modified to support 7 slice group types (fmo modes). + * The functions for generating map are very similar to that in decoder, but have + * a little difference. + * + * The MB map is calculated at the beginning of coding of each picture (frame or field). + * + * 'slice_group_change_cycle' in structure 'VideoParameters' is the syntax in the slice + * header. It's set to be 1 before the initialization of FMO in function code_a_picture(). + * It can be changed every time if needed. + * + **************************************************************************** + */ + +/*! + ***************************************************************************** + * How does a MBAmap look like? + * + * An MBAmap is a one-diemnsional array of ints. Each int + * represents an MB in scan order. A zero or positive value represents + * a slice group ID. Negative values are reserved for future extensions. + * The numbering range for the SliceGroupIDs is 0..7 as per JVT-C167. + * + * This module contains a static variable MBAmap. This is the MBAmap of the + * picture currently coded. It can be accessed only through the access + * functions. + ***************************************************************************** +*/ + +//#define PRINT_FMO_MAPS 1 + + +#include "global.h" + +#include "fmo.h" + + +static void FmoGenerateType0MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static void FmoGenerateType1MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static void FmoGenerateType2MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static void FmoGenerateType3MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static void FmoGenerateType4MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static void FmoGenerateType5MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static void FmoGenerateType6MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); + + +static int FmoGenerateMapUnitToSliceGroupMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps); +static int FmoGenerateMBAmap (VideoParameters * p_Vid, seq_parameter_set_rbsp_t* sps); + + +/*! + ************************************************************************ + * \brief + * Generates p_Vid->MapUnitToSliceGroupMap + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + * + ************************************************************************ + */ +static int FmoGenerateMapUnitToSliceGroupMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps) +{ + p_Vid->PicSizeInMapUnits = p_Vid->PicHeightInMapUnits * p_Vid->PicWidthInMbs; + + + if (pps->slice_group_map_type == 6) + { + if ((pps->pic_size_in_map_units_minus1+1) != p_Vid->PicSizeInMapUnits) + { + error ("wrong pps->pic_size_in_map_units_minus1 for used SPS and FMO type 6", 500); + } + } + + // allocate memory for p_Vid->MapUnitToSliceGroupMap + if (p_Vid->MapUnitToSliceGroupMap) + free (p_Vid->MapUnitToSliceGroupMap); + + if ((p_Vid->MapUnitToSliceGroupMap = malloc ((p_Vid->PicSizeInMapUnits) * sizeof (byte))) == NULL) + { + printf ("cannot allocated %d bytes for p_Vid->MapUnitToSliceGroupMap , exit\n", (int) ( p_Vid->PicSizeInMapUnits * sizeof (byte))); + exit (-1); + } + + if (pps->num_slice_groups_minus1 == 0) // only one slice group + { + memset (p_Vid->MapUnitToSliceGroupMap, 0, p_Vid->PicSizeInMapUnits * sizeof (byte)); + return 0; + } + + switch (pps->slice_group_map_type) + { + case 0: + FmoGenerateType0MapUnitMap (p_Vid, pps); + break; + case 1: + FmoGenerateType1MapUnitMap (p_Vid, pps); + break; + case 2: + FmoGenerateType2MapUnitMap (p_Vid, pps); + break; + case 3: + FmoGenerateType3MapUnitMap (p_Vid, pps); + break; + case 4: + FmoGenerateType4MapUnitMap (p_Vid, pps); + break; + case 5: + FmoGenerateType5MapUnitMap (p_Vid, pps); + break; + case 6: + FmoGenerateType6MapUnitMap (p_Vid, pps); + break; + default: + printf ("Illegal slice_group_map_type %d , exit \n", pps->slice_group_map_type); + exit (-1); + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * Generates MBAmap from p_Vid->MapUnitToSliceGroupMap + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param sps + * Sequence Parameter set to be used for map generation + * + ************************************************************************ + */ +static int FmoGenerateMBAmap (VideoParameters * p_Vid, seq_parameter_set_rbsp_t* sps) +{ + unsigned i; + + // allocate memory for p_Vid->MBAmap + if (p_Vid->MBAmap) + free (p_Vid->MBAmap); + + + if ((p_Vid->MBAmap = malloc ((p_Vid->PicSizeInMbs) * sizeof (byte))) == NULL) + { + printf ("cannot allocated %d bytes for p_Vid->MBAmap, exit\n", (int) ((p_Vid->PicSizeInMbs) * sizeof (byte))); + exit (-1); + } + + if ((sps->frame_mbs_only_flag) || p_Vid->field_picture) + { + for (i=0; iPicSizeInMbs; i++) + { + p_Vid->MBAmap[i] = p_Vid->MapUnitToSliceGroupMap [i]; + } + } + else + if (sps->mb_adaptive_frame_field_flag && (! p_Vid->field_picture)) + { + for (i=0; iPicSizeInMbs; i++) + { + p_Vid->MBAmap[i] = p_Vid->MapUnitToSliceGroupMap [i >> 1]; + } + } + else + { + for (i=0; iPicSizeInMbs; i++) + { + p_Vid->MBAmap[i] = p_Vid->MapUnitToSliceGroupMap [(i/(2*p_Vid->PicWidthInMbs))*p_Vid->PicWidthInMbs+(i%p_Vid->PicWidthInMbs)]; + } + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * FMO initialization: Generates p_Vid->MapUnitToSliceGroupMap and p_Vid->MBAmap. + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + * \param sps + * Sequence Parameter set to be used for map generation + ************************************************************************ + */ +int FmoInit(VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps, seq_parameter_set_rbsp_t * sps) +{ + +#ifdef PRINT_FMO_MAPS + unsigned i,j; + int bottom; +#endif + + int k; + for (k = 0; k < MAXSLICEGROUPIDS; k++) + p_Vid->FirstMBInSlice[k] = -1; + + FmoGenerateMapUnitToSliceGroupMap(p_Vid, pps); + FmoGenerateMBAmap(p_Vid, sps); + +#ifdef PRINT_FMO_MAPS + printf("\n"); + printf("FMO Map (Units):\n"); + + for (j=0; jPicHeightInMapUnits; j++) + { + for (i=0; iPicWidthInMbs; i++) + { + printf("%d ",p_Vid->MapUnitToSliceGroupMap [i+j*p_Vid->PicWidthInMbs]); + } + printf("\n"); + } + printf("\n"); + + if(sps->mb_adaptive_frame_field_flag==0) + { + printf("FMO Map (Mb):\n"); + for (j=0; j<(p_Vid->PicSizeInMbs/p_Vid->PicWidthInMbs); j++) + { + for (i=0; iPicWidthInMbs; i++) + { + printf("%d ",p_Vid->MBAmap[i+j*p_Vid->PicWidthInMbs]); + } + printf("\n"); + } + printf("\n"); + } + else + { + printf("FMO Map (Mb in scan order for MBAFF):\n"); + for (j=0; j<(p_Vid->PicSizeInMbs/p_Vid->PicWidthInMbs); j++) + { + for (i=0; iPicWidthInMbs; i++) + { + bottom=(j & 0x01); + printf("%d ",p_Vid->MBAmap[(j-bottom)*p_Vid->PicWidthInMbs+i*2+bottom]); + } + printf("\n"); + + } + printf("\n"); + + } + +#endif + + return 0; +} + + +/*! + ************************************************************************ + * \brief + * Free memory if allocated by FMO functions + ************************************************************************ + */ +void FmoUninit(VideoParameters *p_Vid) +{ + if (p_Vid->MBAmap) + { + free (p_Vid->MBAmap); + p_Vid->MBAmap = NULL; + } + if (p_Vid->MapUnitToSliceGroupMap ) + { + free (p_Vid->MapUnitToSliceGroupMap ); + p_Vid->MapUnitToSliceGroupMap = NULL; + } + +} + + +/*! + ************************************************************************ + * \brief + * Generate interleaved slice group map type MapUnit map (type 0) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ + */ +static void FmoGenerateType0MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + unsigned iGroup, j; + unsigned i = 0; + + do + { + for( iGroup = 0; + (iGroup <= pps->num_slice_groups_minus1) && (i < p_Vid->PicSizeInMapUnits); + i += pps->run_length_minus1[iGroup++] + 1) + { + for( j = 0; j <= pps->run_length_minus1[ iGroup ] && i + j < p_Vid->PicSizeInMapUnits; j++ ) + p_Vid->MapUnitToSliceGroupMap [i+j] = (byte) iGroup; + } + } + while( i < p_Vid->PicSizeInMapUnits ); +} + + +/*! + ************************************************************************ + * \brief + * Generate dispersed slice group map type MapUnit map (type 1) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ + */ +static void FmoGenerateType1MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + unsigned i; + for( i = 0; i < p_Vid->PicSizeInMapUnits; i++ ) + { + p_Vid->MapUnitToSliceGroupMap [i] = (byte) (((i%p_Vid->PicWidthInMbs)+(((i/p_Vid->PicWidthInMbs)*(pps->num_slice_groups_minus1+1))>>1)) + %(pps->num_slice_groups_minus1+1)); + } +} + +/*! + ************************************************************************ + * \brief + * Generate foreground with left-over slice group map type MapUnit map (type 2) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ + */ +static void FmoGenerateType2MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + int iGroup; + unsigned i, x, y; + unsigned yTopLeft, xTopLeft, yBottomRight, xBottomRight; + + for( i = 0; i < p_Vid->PicSizeInMapUnits; i++ ) + p_Vid->MapUnitToSliceGroupMap [ i ] = (byte) pps->num_slice_groups_minus1; + + for( iGroup = pps->num_slice_groups_minus1 - 1 ; iGroup >= 0; iGroup-- ) + { + yTopLeft = pps->top_left[ iGroup ] / p_Vid->PicWidthInMbs; + xTopLeft = pps->top_left[ iGroup ] % p_Vid->PicWidthInMbs; + yBottomRight = pps->bottom_right[ iGroup ] / p_Vid->PicWidthInMbs; + xBottomRight = pps->bottom_right[ iGroup ] % p_Vid->PicWidthInMbs; + for( y = yTopLeft; y <= yBottomRight; y++ ) + for( x = xTopLeft; x <= xBottomRight; x++ ) + p_Vid->MapUnitToSliceGroupMap [ y * p_Vid->PicWidthInMbs + x ] = (byte) iGroup; + } +} + + +/*! + ************************************************************************ + * \brief + * Generate box-out slice group map type MapUnit map (type 3) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ + */ +static void FmoGenerateType3MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + unsigned i, k; + int leftBound, topBound, rightBound, bottomBound; + int x, y, xDir, yDir; + int mapUnitVacant; + + unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * p_Vid->slice_group_change_cycle, p_Vid->PicSizeInMapUnits); + + for( i = 0; i < p_Vid->PicSizeInMapUnits; i++ ) + p_Vid->MapUnitToSliceGroupMap [ i ] = 2; + + x = ( p_Vid->PicWidthInMbs - pps->slice_group_change_direction_flag ) / 2; + y = ( p_Vid->PicHeightInMapUnits - pps->slice_group_change_direction_flag ) / 2; + + leftBound = x; + topBound = y; + rightBound = x; + bottomBound = y; + + xDir = pps->slice_group_change_direction_flag - 1; + yDir = pps->slice_group_change_direction_flag; + + for( k = 0; k < p_Vid->PicSizeInMapUnits; k += mapUnitVacant ) + { + mapUnitVacant = ( p_Vid->MapUnitToSliceGroupMap [ y * p_Vid->PicWidthInMbs + x ] == 2 ); + if( mapUnitVacant ) + p_Vid->MapUnitToSliceGroupMap [ y * p_Vid->PicWidthInMbs + x ] = (byte) ( k >= mapUnitsInSliceGroup0 ); + + if( xDir == -1 && x == leftBound ) + { + leftBound = imax( leftBound - 1, 0 ); + x = leftBound; + xDir = 0; + yDir = 2 * pps->slice_group_change_direction_flag - 1; + } + else + if( xDir == 1 && x == rightBound ) + { + rightBound = imin( rightBound + 1, (int)p_Vid->PicWidthInMbs - 1 ); + x = rightBound; + xDir = 0; + yDir = 1 - 2 * pps->slice_group_change_direction_flag; + } + else + if( yDir == -1 && y == topBound ) + { + topBound = imax( topBound - 1, 0 ); + y = topBound; + xDir = 1 - 2 * pps->slice_group_change_direction_flag; + yDir = 0; + } + else + if( yDir == 1 && y == bottomBound ) + { + bottomBound = imin( bottomBound + 1, (int)p_Vid->PicHeightInMapUnits - 1 ); + y = bottomBound; + xDir = 2 * pps->slice_group_change_direction_flag - 1; + yDir = 0; + } + else + { + x = x + xDir; + y = y + yDir; + } + } + +} + +/*! + ************************************************************************ + * \brief + * Generate raster scan slice group map type MapUnit map (type 4) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ + */ +static void FmoGenerateType4MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + + unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * p_Vid->slice_group_change_cycle, p_Vid->PicSizeInMapUnits); + unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( p_Vid->PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0; + + unsigned i; + + for( i = 0; i < p_Vid->PicSizeInMapUnits; i++ ) + if( i < sizeOfUpperLeftGroup ) + p_Vid->MapUnitToSliceGroupMap [ i ] = (byte) pps->slice_group_change_direction_flag; + else + p_Vid->MapUnitToSliceGroupMap [ i ] = (byte) (1 - pps->slice_group_change_direction_flag); + +} + +/*! + ************************************************************************ + * \brief + * Generate wipe slice group map type MapUnit map (type 5) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ +*/ +static void FmoGenerateType5MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + + unsigned mapUnitsInSliceGroup0 = imin((pps->slice_group_change_rate_minus1 + 1) * p_Vid->slice_group_change_cycle, p_Vid->PicSizeInMapUnits); + unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( p_Vid->PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0; + + unsigned i,j, k = 0; + + for( j = 0; j < p_Vid->PicWidthInMbs; j++ ) + for( i = 0; i < p_Vid->PicHeightInMapUnits; i++ ) + if( k++ < sizeOfUpperLeftGroup ) + p_Vid->MapUnitToSliceGroupMap [ i * p_Vid->PicWidthInMbs + j ] = (byte) pps->slice_group_change_direction_flag; + else + p_Vid->MapUnitToSliceGroupMap [ i * p_Vid->PicWidthInMbs + j ] = (byte) (1 - pps->slice_group_change_direction_flag); + +} + +/*! + ************************************************************************ + * \brief + * Generate explicit slice group map type MapUnit map (type 6) + * + * \param p_Vid + * Image Parameter to be used for map generation + * \param pps + * Picture Parameter set to be used for map generation + ************************************************************************ + */ +static void FmoGenerateType6MapUnitMap (VideoParameters * p_Vid, pic_parameter_set_rbsp_t * pps ) +{ + unsigned i; + for (i=0; iPicSizeInMapUnits; i++) + { + p_Vid->MapUnitToSliceGroupMap [i] = (byte) pps->slice_group_id[i]; + } +} + +/*! + ************************************************************************ + * \brief + * FmoStartPicture: initializes FMO at the begin of each new picture + * + * \par Input: + * None + ************************************************************************ + */ +int FmoStartPicture (VideoParameters *p_Vid) +{ + int i; + + assert (p_Vid->MBAmap != NULL); + + for (i=0; iFirstMBInSlice[i] = FmoGetFirstMBOfSliceGroup (p_Vid, i); + return 0; +} + + + +/*! + ************************************************************************ + * \brief + * FmoEndPicture: Ends the Scattered Slices Module (called once + * per picture). + * + * \par Input: + * None + ************************************************************************ + */ +int FmoEndPicture () +{ + // Do nothing + return 0; +} + + +/*! + ************************************************************************ + * \brief + * FmoMB2Slice: Returns SliceID for a given MB + * + * \par Input: + * Macroblock Nr (in scan order) + ************************************************************************ + */ +int FmoMB2SliceGroup (VideoParameters *p_Vid, int mb) +{ + assert (mb < (int)p_Vid->PicSizeInMbs); + assert (p_Vid->MBAmap != NULL); + return p_Vid->MBAmap[mb]; +} + +/*! + ************************************************************************ + * \brief + * FmoGetNextMBBr: Returns the MB-Nr (in scan order) of the next + * MB in the (FMO) Slice, -1 if the SliceGroup is finished + * + * \par Input: + * CurrentMbNr + ************************************************************************ + */ +int FmoGetNextMBNr (VideoParameters *p_Vid, int CurrentMbNr) +{ + + int SliceGroupID = FmoMB2SliceGroup (p_Vid, CurrentMbNr); + + while (++CurrentMbNr<(int)p_Vid->PicSizeInMbs && p_Vid->MBAmap[CurrentMbNr] != SliceGroupID) + ; + + if (CurrentMbNr >= (int)p_Vid->PicSizeInMbs) + return -1; // No further MB in this slice (could be end of picture) + else + return CurrentMbNr; +} + + +/*! + ************************************************************************ + * \brief + * FmoGetNextMBBr: Returns the MB-Nr (in scan order) of the next + * MB in the (FMO) Slice, -1 if the SliceGroup is finished + * + * \par Input: + * CurrentMbNr + ************************************************************************ + */ +int FmoGetPreviousMBNr (VideoParameters *p_Vid, int CurrentMbNr) +{ + + int SliceGroupID = FmoMB2SliceGroup (p_Vid, CurrentMbNr); + CurrentMbNr--; + while (CurrentMbNr>=0 && p_Vid->MBAmap[CurrentMbNr] != SliceGroupID) + CurrentMbNr--; + + if (CurrentMbNr < 0) + return -1; // No previous MB in this slice + else + return CurrentMbNr; +} + + +/*! + ************************************************************************ + * \brief + * FmoGetFirstMBOfSliceGroup: Returns the MB-Nr (in scan order) of the + * next first MB of the Slice group, -1 if no such MB exists + * + * \par Input: + * SliceGroupID: Id of SliceGroup + ************************************************************************ + */ +int FmoGetFirstMBOfSliceGroup (VideoParameters *p_Vid, int SliceGroupID) +{ + int i = 0; + while ((i<(int)p_Vid->PicSizeInMbs) && (FmoMB2SliceGroup (p_Vid, i) != SliceGroupID)) + i++; + + if (i < (int)p_Vid->PicSizeInMbs) + return i; + else + return -1; +} + + +/*! + ************************************************************************ + * \brief + * FmoGetLastCodedMBOfSlice: Returns the MB-Nr (in scan order) of + * the last MB of the slice group + * + * \par Input: + * SliceGroupID + * \par Return + * MB Nr in case of success (is always >= 0) + * -1 if the SliceGroup doesn't exist + ************************************************************************ + */ +int FmoGetLastCodedMBOfSliceGroup (VideoParameters *p_Vid, int SliceGroupID) +{ + int i; + int LastMB = -1; + + for (i=0; i<(int)p_Vid->PicSizeInMbs; i++) + if (FmoMB2SliceGroup (p_Vid, i) == SliceGroupID) + LastMB = i; + return LastMB; +} + + +void FmoSetLastMacroblockInSlice ( VideoParameters *p_Vid, int mb) +{ + // called by terminate_slice(), writes the last processed MB into the + // FirstMBInSlice[MAXSLICEGROUPIDS] array. FmoGetFirstMacroblockInSlice() + // uses this info to identify the first uncoded MB in each slice group + + int currSliceGroup = FmoMB2SliceGroup (p_Vid, mb); + assert (mb >= 0); + mb = FmoGetNextMBNr (p_Vid, mb); // The next (still uncoded) MB, or -1 if SG is finished + p_Vid->FirstMBInSlice[currSliceGroup] = mb; +} + +int FmoGetFirstMacroblockInSlice ( VideoParameters *p_Vid, int SliceGroup) +{ + return p_Vid->FirstMBInSlice[SliceGroup]; + // returns the first uncoded MB in each slice group, -1 if there is no + // more to do in this slice group +} + + +int FmoSliceGroupCompletelyCoded( VideoParameters *p_Vid, int SliceGroupID) +{ + if (FmoGetFirstMacroblockInSlice (p_Vid, SliceGroupID) < 0) // slice group completelty coded or not present + return TRUE; + else + return FALSE; +} + + + diff --git a/lencod/src/get_block_otf.c b/lencod/src/get_block_otf.c new file mode 100644 index 0000000..e86161c --- /dev/null +++ b/lencod/src/get_block_otf.c @@ -0,0 +1,1083 @@ +/*! + ************************************************************************************* + * \file get_block_otf.c + * + * \brief + * get predicted (chroma|luma) block with subpel interpolation computes on-the-fly + * + * + ************************************************************************************* + */ + +#include "global.h" +#include "block.h" + +#include "macroblock.h" +#include "image.h" +#include "mb_access.h" +#include "get_block_otf.h" +#include "refbuf_otf.h" + + +/*! + ************************************************************************ + * \brief + * Integer positions + ************************************************************************ + */ + +static void get_block_00(imgpel *block, imgpel *cur_img, int block_size_y, int block_size_x, int shift_x) +{ + int j; + + for (j = 0; j < block_size_y; j += 1) + { + memcpy(block, cur_img, block_size_x * sizeof(imgpel)); + block += block_size_x ; + cur_img += shift_x; + } +} + +/*! + ************************************************************************ + * \brief + * Qpel (1,0) horizontal + ************************************************************************ + */ +static void get_luma_10(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos , int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + + for (j = 0; j < block_size_y; j++) + { + cur_line = &(cur_imgY[j][x_pos]); + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block+j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + } +} + +/*! + ************************************************************************ + * \brief + * Half horizontal + ************************************************************************ + */ +static void get_luma_20(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos , int max_imgpel_value) + { + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int i, j; + int result; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } +} + +/*! + ************************************************************************ + * \brief + * Qpel (3,0) horizontal + ************************************************************************ + */ +static void get_luma_30(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos , int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + + for (j = 0; j < block_size_y; j++) + { + cur_line = &(cur_imgY[j][x_pos + 1]); + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block + j*block_size_x ; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + } +} + + +/*! + ************************************************************************ + * \brief + * Qpel vertical (0, 1) + ************************************************************************ + */ +static void get_luma_01(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + int jj = 0; + p0 = &(cur_imgY[ - 2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x ; + cur_line = &(cur_imgY[jj++][x_pos]); + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + p0 = p1 - block_size_x; + } +} + +/*! + ************************************************************************ + * \brief + * Half vertical + ************************************************************************ + */ +static void get_luma_02(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int i, j; + int result; + p0 = &(cur_imgY[ - 2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x ; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + p0 = p1 - block_size_x; + } +} + + +/*! + ************************************************************************ + * \brief + * Qpel vertical (0, 3) + ************************************************************************ + */ +static void get_luma_03(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line, *cur_line; + int i, j; + int result; + int jj = 1; + + p0 = &(cur_imgY[ -2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x ; + cur_line = &(cur_imgY[jj++][x_pos]); + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + *orig_line = (imgpel) ((*orig_line + *(cur_line++) + 1 ) >> 1); + orig_line++; + } + p0 = p1 - block_size_x; + } +} + +/*! + ************************************************************************ + * \brief + * Hpel horizontal, Qpel vertical (2, 1) + ************************************************************************ + */ +static void get_luma_21(imgpel *block, imgpel **cur_imgY, int *tmp_res, int block_size_y, int block_size_x, int x_pos, int max_imgpel_value) +{ + int i, j; + /* Vertical & horizontal interpolation */ + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + int jj = -2; + + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + tmp_line = tmp_res + j*block_size_x ; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + } + + jj = 2; + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res+ jj*block_size_x; jj++; + x0 = tmp_res + j*block_size_x ; + x1 = tmp_res + (j + 1)*block_size_x; + x2 = tmp_res + (j + 2)*block_size_x; + x3 = tmp_res + (j + 3)*block_size_x; + x4 = tmp_res + (j + 4)*block_size_x; + x5 = tmp_res + (j + 5)*block_size_x; + orig_line = block + j*block_size_x ; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) - 5 * (*x1++ + *x4++) + 20 * (*x2++ + *x3++); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16) >> 5)) + 1 )>> 1); + orig_line++; + } + } +} + +/*! + ************************************************************************ + * \brief + * Hpel horizontal, Hpel vertical (2, 2) + ************************************************************************ + */ +static void get_luma_22(imgpel *block, imgpel **cur_imgY, int *tmp_res, int block_size_y, int block_size_x, int x_pos, int max_imgpel_value) +{ + int i, j; + /* Vertical & horizontal interpolation */ + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + int jj = - 2; + + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + tmp_line = tmp_res + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + } + + for (j = 0; j < block_size_y; j++) + { + x0 = tmp_res + j*block_size_x ; + x1 = tmp_res + (j + 1)*block_size_x; + x2 = tmp_res + (j + 2)*block_size_x; + x3 = tmp_res + (j + 3)*block_size_x; + x4 = tmp_res + (j + 4)*block_size_x; + x5 = tmp_res + (j + 5)*block_size_x; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) - 5 * (*x1++ + *x4++) + 20 * (*x2++ + *x3++); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + } + } +} + +/*! + ************************************************************************ + * \brief + * Hpel horizontal, Qpel vertical (2, 3) + ************************************************************************ + */ +static void get_luma_23(imgpel *block, imgpel **cur_imgY, int *tmp_res, int block_size_y, int block_size_x, int x_pos, int max_imgpel_value) +{ + int i, j; + /* Vertical & horizontal interpolation */ + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + int jj = -2; + + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + tmp_line = tmp_res + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + } + + jj = 3; + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res+ jj*block_size_x; jj++; + x0 = tmp_res + j*block_size_x ; + x1 = tmp_res + (j + 1)*block_size_x; + x2 = tmp_res + (j + 2)*block_size_x; + x3 = tmp_res + (j + 3)*block_size_x; + x4 = tmp_res + (j + 4)*block_size_x; + x5 = tmp_res + (j + 5)*block_size_x; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) - 5 * (*x1++ + *x4++) + 20 * (*x2++ + *x3++); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16) >> 5)) + 1 )>> 1); + orig_line++; + } + } +} + +/*! + ************************************************************************ + * \brief + * Qpel horizontal, Hpel vertical (1, 2) + ************************************************************************ + */ +static void get_luma_12(imgpel *block, imgpel **cur_imgY, int *tmp_res, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + p0 = &(cur_imgY[ -2][x_pos - 2]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + tmp_line = tmp_res + j*(block_size_x+5); + + for (i = 0; i < block_size_x + 5; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + p0 = p1 - (block_size_x + 5); + } + + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res + j*(block_size_x+5) + 2 ; + orig_line = block + j*block_size_x ; + x0 = tmp_res + j*(block_size_x+5) ; + x1 = x0 + 1; + x2 = x1 + 1; + x3 = x2 + 1; + x4 = x3 + 1; + x5 = x4 + 1; + + for (i = 0; i < block_size_x; i++) + { + result = (*(x0++) + *(x5++)) - 5 * (*(x1++) + *(x4++)) + 20 * (*(x2++) + *(x3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16)>>5))+1)>>1); + orig_line ++; + } + } +} + +/*! + ************************************************************************ + * \brief + * Qpel horizontal, Hpel vertical (3, 2) + ************************************************************************ + */ +static void get_luma_32(imgpel *block, imgpel **cur_imgY, int *tmp_res, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + imgpel *orig_line; + int result; + + p0 = &(cur_imgY[ -2][x_pos - 2]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + tmp_line = tmp_res + j*(block_size_x+5); + + for (i = 0; i < block_size_x + 5; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + } + p0 = p1 - (block_size_x + 5); + } + + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res + j*(block_size_x+5) + 3; + orig_line = block + j*block_size_x; + x0 = tmp_res + j*(block_size_x+5); + x1 = x0 + 1; + x2 = x1 + 1; + x3 = x2 + 1; + x4 = x3 + 1; + x5 = x4 + 1; + + for (i = 0; i < block_size_x; i++) + { + result = (*(x0++) + *(x5++)) - 5 * (*(x1++) + *(x4++)) + 20 * (*(x2++) + *(x3++)); + + *orig_line = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16)>>5))+1)>>1); + orig_line ++; + } + } +} + +/*! + ************************************************************************ + * \brief + * Qpel horizontal, Qpel vertical (3, 3) + ************************************************************************ + */ +static void get_luma_33(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 1; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos + 1]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + + +/*! + ************************************************************************ + * \brief + * Qpel horizontal, Qpel vertical (1, 1) + ************************************************************************ + */ +static void get_luma_11(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 0; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + +/*! + ************************************************************************ + * \brief + * Qpel horizontal, Qpel vertical (1, 3) + ************************************************************************ + */ +static void get_luma_13(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + /* Diagonal interpolation */ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 1; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + +/*! + ************************************************************************ + * \brief + * Qpel horizontal, Qpel vertical (3, 1) + ************************************************************************ + */ +static void get_luma_31(imgpel *block, imgpel **cur_imgY, int block_size_y, int block_size_x, int x_pos, int shift_x, int max_imgpel_value) +{ + /* Diagonal interpolation */ + int i, j; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + imgpel *orig_line; + int result; + + int jj = 0; + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][x_pos + 1]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block + j*block_size_x; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) - 5 * (*(p1++) + *(p4++)) + 20 * (*(p2++) + *(p3++)); + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } +} + +/*! + ************************************************************************ + * \brief + * Interpolation on-the-fly of 1/4 subpixel + ************************************************************************ + */ + +static inline void get_block_luma_otf( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array of prediction values (row by row) + int* tmp_pred, //!< array of temporary prediction values (row by row), used for some hal-pel interpolations + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical coordinate of block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int pl //!< plane + ) +{ + imgpel **ref_block = (p_Vid->P444_joined && pl>PLANE_Y)? ref->imgUV[pl-1] : ref->imgY; + int dx = (pic_pix_x & 0x03); + int dy = (pic_pix_y & 0x03); + int x_pos = iClip3(-IMG_PAD_SIZE_X+2, ref->size_x_pad-2, pic_pix_x>>2); + int y_pos = iClip3(-IMG_PAD_SIZE_Y+2, ref->size_y_pad-2, pic_pix_y>>2); + + if (dx == 0 && dy == 0) + get_block_00(mpred, &(ref_block[y_pos][x_pos]), block_size_y, block_size_x, p_Vid->padded_size_x); + else + { /* other positions */ + if (dy == 0) /* No vertical interpolation */ + { + if (dx == 1) + get_luma_10(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->max_imgpel_value); + else if (dx == 2) + get_luma_20(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->max_imgpel_value); + else + get_luma_30(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->max_imgpel_value); + } + else if (dx == 0) /* No horizontal interpolation */ + { + if (dy == 1) + get_luma_01(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + else if (dy == 2) + get_luma_02(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + else + get_luma_03(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + } + else if (dx == 2) /* Vertical & horizontal interpolation */ + { + if (dy == 1) + get_luma_21(mpred, &ref_block[y_pos], tmp_pred, block_size_y, block_size_x, x_pos, p_Vid->max_imgpel_value); + else if (dy == 2) + get_luma_22(mpred, &ref_block[y_pos], tmp_pred, block_size_y, block_size_x, x_pos, p_Vid->max_imgpel_value); + else + get_luma_23(mpred, &ref_block[y_pos], tmp_pred, block_size_y, block_size_x, x_pos, p_Vid->max_imgpel_value); + } + else if (dy == 2) + { + if (dx == 1) + get_luma_12(mpred, &ref_block[y_pos], tmp_pred, block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + else + get_luma_32(mpred, &ref_block[y_pos], tmp_pred, block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + } + else + { + if (dx == 1) + { + if (dy == 1) + get_luma_11(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + else + get_luma_13(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + } + else + { + if (dy == 1) + get_luma_31(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + else + get_luma_33(mpred, &ref_block[y_pos], block_size_y, block_size_x, x_pos, p_Vid->padded_size_x, p_Vid->max_imgpel_value); + } + } + } +} + +void get_block_luma_otf_L2( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array of prediction values (row by row) + int* tmp_pred, //!< array of temporary prediction values (row by row), used for some hal-pel interpolations + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical coordinate of block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int pl //!< plane + ) +{ + get_block_luma_otf( p_Vid, mpred, tmp_pred, pic_pix_x, pic_pix_y, block_size_x, block_size_y, ref, pl ) ; +} + +void get_block_luma_otf_L1( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array of prediction values (row by row) + int* tmp_pred, //!< array of temporary prediction values (row by row), used for some hal-pel interpolations + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical coordinate of block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int pl //!< plane + ) +{ + if( is_qpel( pic_pix_x, pic_pix_y, 0x03, 0x03 ) ) + { + get_block_luma_otf( p_Vid, mpred, tmp_pred, pic_pix_x, pic_pix_y, block_size_x, block_size_y, ref, pl ) ; + } + else + { + int j; + imgpel *ref_line ; + ref->p_curr_img_sub = (p_Vid->P444_joined && pl>PLANE_Y) ? (ref->imgUV_sub[pl-1]):(ref->imgY_sub); // select plane for 4:4:4 compatibility + ref_line = UMVLine4X_otf ( ref, pic_pix_y, pic_pix_x ) ; + for (j = 0; j < block_size_y; j++) + { + memcpy(mpred, ref_line, block_size_x * sizeof(imgpel)); + ref_line += p_Vid->padded_size_x; + mpred += block_size_x; + } + } +} + +/*! + ************************************************************************ + * \brief + * Chroma (0,X) + ************************************************************************ + */ +static void get_chroma_0X(imgpel *block, imgpel *cur_img, int span, int block_size_y, int block_size_x, int w00, int w01, int total_scale) +{ + imgpel *cur_row = cur_img; + imgpel *nxt_row = cur_img + span; + + + imgpel *cur_line, *cur_line_p1; + imgpel *blk_line; + int result; + int i, j; + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_row; + cur_line_p1 = nxt_row; + blk_line = block; + block += block_size_x ; + cur_row = nxt_row; + nxt_row += span; + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *cur_line++ + w01 * *cur_line_p1++); + *(blk_line++) = (imgpel) rshift_rnd_sf(result, total_scale); + } + } +} + +/*! + ************************************************************************ + * \brief + * Chroma (X,0) + ************************************************************************ + */ +static void get_chroma_X0(imgpel *block, imgpel *cur_img, int span, int block_size_y, int block_size_x, int w00, int w10, int total_scale) +{ + imgpel *cur_row = cur_img; + imgpel *cur_line, *cur_line_p1; + imgpel *blk_line; + int result; + int i, j; + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_row; + cur_line_p1 = cur_line + 1; + blk_line = block; + block += block_size_x ; + cur_row += span; + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *cur_line++ + w10 * *cur_line_p1++); + //*(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + *(blk_line++) = (imgpel) rshift_rnd_sf(result, total_scale); + } + } +} + + +/*! + ************************************************************************ + * \brief + * Chroma (X,X) + ************************************************************************ + */ +static void get_chroma_XX(imgpel *block, imgpel *cur_img, int span, int block_size_y, int block_size_x, int w00, int w01, int w10, int w11, int total_scale) +{ + imgpel *cur_row = cur_img; + imgpel *nxt_row = cur_img + span; + imgpel *cur_line, *cur_line_p1; + imgpel *blk_line; + int result; + int i, j; + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_row; + cur_line_p1 = nxt_row; + blk_line = block; + block += block_size_x ; + cur_row = nxt_row; + nxt_row += span; + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *(cur_line++) + w01 * *(cur_line_p1++)); + result += (w10 * *(cur_line ) + w11 * *(cur_line_p1 )); + *(blk_line++) = (imgpel) rshift_rnd_sf(result, total_scale); + } + } + +} + +static inline void get_block_chroma_otf ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv ) //!< chroma component +{ + int dx = (pic_pix_x & p_Vid->chroma_mask_mv_x) ; + int dy = (pic_pix_y & p_Vid->chroma_mask_mv_y) ; + int x_pos = iClip3(-ref->pad_size_uv_x+1, ref->size_x_cr_pad-1, pic_pix_x >> p_Vid->chroma_shift_x) ; + int y_pos = iClip3(-ref->pad_size_uv_y+1, ref->size_y_cr_pad-1, pic_pix_y >> p_Vid->chroma_shift_y) ; + int total_scale = p_Vid->chroma_shift_x + p_Vid->chroma_shift_y ; + + + imgpel *ref_line = &(ref->imgUV[ uv-1 ][y_pos][x_pos]) ; + + if (dx == 0 && dy == 0) + { + get_block_00(mpred, ref_line, block_size_y, block_size_x, p_Vid->cr_padded_size_x); + } + else + { + short dxcur = (short) (p_Vid->chroma_mask_mv_x + 1 - dx); + short dycur = (short) (p_Vid->chroma_mask_mv_y + 1 - dy); + short w00 = dxcur * dycur; + if (dx == 0) + { + short w01 = dxcur * dy; + get_chroma_0X(mpred, ref_line, p_Vid->cr_padded_size_x, block_size_y, block_size_x, w00, w01, total_scale); + } + else if (dy == 0) + { + short w10 = dx * dycur; + get_chroma_X0(mpred, ref_line, p_Vid->cr_padded_size_x, block_size_y, block_size_x, w00, w10, total_scale); + } + else + { + short w01 = dxcur * dy; + short w10 = dx * dycur; + short w11 = dx * dy; + get_chroma_XX(mpred, ref_line, p_Vid->cr_padded_size_x, block_size_y, block_size_x, w00, w01, w10, w11, total_scale); + } + } +} + + +void get_block_chroma_otf_L2 ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv ) //!< chroma component +{ + get_block_chroma_otf ( p_Vid, mpred, tmp_pred, pic_pix_x, pic_pix_y, block_size_x, block_size_y, ref, uv ); +} + + +void me_get_block_chroma_otf_L1 ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv ) //!< chroma component +{ + if( is_qpel( pic_pix_x, pic_pix_y, ref->chroma_mask_mv_x, ref->chroma_mask_mv_y) ) + { + get_block_chroma_otf ( p_Vid, mpred, tmp_pred, pic_pix_x, pic_pix_y, block_size_x, block_size_y, ref, uv ); + } + else + { + int j; + imgpel *ref_line = UMVLine8X_chroma_otf (ref, uv, pic_pix_y, pic_pix_x); + for (j = 0; j < block_size_y; j++) + { + memcpy(mpred, ref_line, block_size_x * sizeof(imgpel)); + ref_line += p_Vid->cr_padded_size_x; + mpred += block_size_x; + } + } +} + +void mc_get_block_chroma_otf_L1 ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int* tmp_pred, + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *ref, //!< reference picture list + int uv ) //!< chroma component +{ + if( is_qpel( pic_pix_x, pic_pix_y, ref->chroma_mask_mv_x, ref->chroma_mask_mv_y ) ) + { + get_block_chroma_otf ( p_Vid, mpred, tmp_pred, pic_pix_x, pic_pix_y, block_size_x, block_size_y, ref, uv ); + } + else + { + int j; + imgpel *ref_line = UMVLine4Xcr_otf (ref, uv, pic_pix_y, pic_pix_x); + for (j = 0; j < block_size_y; j++) + { + memcpy(mpred, ref_line, block_size_x * sizeof(imgpel)); + ref_line += p_Vid->cr_padded_size_x; + mpred += block_size_x; + } + } +} \ No newline at end of file diff --git a/lencod/src/header.c b/lencod/src/header.c new file mode 100644 index 0000000..685fd67 --- /dev/null +++ b/lencod/src/header.c @@ -0,0 +1,614 @@ +/*! + ************************************************************************************* + * \file header.c + * + * \brief + * H.264 Slice and Sequence headers + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * - Karsten Suehring + ************************************************************************************* + */ + +#include + +#include "global.h" + +#include "elements.h" +#include "header.h" +#include "rtp.h" +#include "mbuffer.h" +#include "vlc.h" +#include "parset.h" +#if (MVC_EXTENSION_ENABLE) +#include "list_reorder.h" +#endif + +// A little trick to avoid those horrible #if TRACE all over the source code +#if TRACE +#define SYMTRACESTRING(s) strncpy(sym.tracestring,s,TRACESTRING_SIZE) +#else +#define SYMTRACESTRING(s) // do nothing +#endif + +const int * assignSE2partition[2] ; +const int assignSE2partition_NoDP[SE_MAX_ELEMENTS] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +const int assignSE2partition_DP[SE_MAX_ELEMENTS] = + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0 } ; + +#if (MVC_EXTENSION_ENABLE) +static int mvc_ref_pic_list_reordering(Slice *currSlice, Bitstream *bitstream); +#endif +static int ref_pic_list_reordering(Slice *currSlice, Bitstream *bitstream); +static int pred_weight_table (Slice *currSlice, Bitstream *bitstream); +static int get_picture_type (Slice *currSlice); +/*! + ******************************************************************************************** + * \brief + * Write a slice header + * + * \return + * number of bits used + ******************************************************************************************** +*/ +int SliceHeader(Slice* currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + seq_parameter_set_rbsp_t *active_sps = currSlice->active_sps; + pic_parameter_set_rbsp_t *active_pps = currSlice->active_pps; + + int dP_nr = assignSE2partition[currSlice->partition_mode][SE_HEADER]; + Bitstream *bitstream = currSlice->partArr[dP_nr].bitstream; + int len = 0; + unsigned int field_pic_flag = 0; + byte bottom_field_flag = 0; + + int num_bits_slice_group_change_cycle; + float numtmp; + + if (currSlice->mb_aff_frame_flag) + len = write_ue_v("SH: first_mb_in_slice", p_Vid->current_mb_nr >> 1, bitstream); + else + len = write_ue_v("SH: first_mb_in_slice", p_Vid->current_mb_nr, bitstream); + + len += write_ue_v("SH: slice_type", get_picture_type (currSlice), bitstream); + + len += write_ue_v("SH: pic_parameter_set_id" , active_pps->pic_parameter_set_id ,bitstream); + + if( active_sps->separate_colour_plane_flag == 1 ) + len += write_u_v( 2, "SH: colour_plane_id", p_Vid->colour_plane_id, bitstream ); + +#if (MVC_EXTENSION_ENABLE) + //if(p_Vid->num_of_layers==2) + // len += write_u_v (p_Vid->log2_max_frame_num_minus4 + 4,"SH: frame_num", p_Vid->frame_num/2, bitstream); + //else + len += write_u_v (p_Vid->log2_max_frame_num_minus4 + 4,"SH: frame_num", p_Vid->frame_num, bitstream); +#else + len += write_u_v (p_Vid->log2_max_frame_num_minus4 + 4,"SH: frame_num", p_Vid->frame_num, bitstream); +#endif + + if (!currSlice->active_sps->frame_mbs_only_flag) + { + // field_pic_flag u(1) + field_pic_flag = (currSlice->structure == TOP_FIELD || currSlice->structure ==BOTTOM_FIELD)?1:0; + assert( field_pic_flag == p_Vid->fld_flag ); + len += write_u_1("SH: field_pic_flag", field_pic_flag, bitstream); + + if (field_pic_flag) + { + //bottom_field_flag u(1) + bottom_field_flag = (byte) (currSlice->structure == BOTTOM_FIELD); + len += write_u_1("SH: bottom_field_flag" , bottom_field_flag ,bitstream); + } + } + +#if (MVC_EXTENSION_ENABLE) + if (currSlice->idr_flag || (p_Vid->view_id && !p_Vid->non_idr_flag[currSlice->structure == BOTTOM_FIELD ? 1 : 0]) ) +#else + if (currSlice->idr_flag) +#endif + { + // idr_pic_id + len += write_ue_v ("SH: idr_pic_id", (p_Vid->number & 0x01), bitstream); + } + + if (p_Vid->pic_order_cnt_type == 0) + { + if (active_sps->frame_mbs_only_flag) + { + p_Vid->pic_order_cnt_lsb = (p_Vid->toppoc & ~((((unsigned int)(-1)) << (p_Vid->log2_max_pic_order_cnt_lsb_minus4+4))) ); + } + else + { + if (!field_pic_flag || currSlice->structure == TOP_FIELD) + p_Vid->pic_order_cnt_lsb = (p_Vid->toppoc & ~((((unsigned int)(-1)) << (p_Vid->log2_max_pic_order_cnt_lsb_minus4+4))) ); + else if ( currSlice->structure == BOTTOM_FIELD ) + p_Vid->pic_order_cnt_lsb = (p_Vid->bottompoc & ~((((unsigned int)(-1)) << (p_Vid->log2_max_pic_order_cnt_lsb_minus4+4))) ); + } + + len += write_u_v (p_Vid->log2_max_pic_order_cnt_lsb_minus4+4, "SH: pic_order_cnt_lsb", p_Vid->pic_order_cnt_lsb, bitstream); + + if (p_Vid->bottom_field_pic_order_in_frame_present_flag && !field_pic_flag) + { + len += write_se_v ("SH: delta_pic_order_cnt_bottom", p_Vid->delta_pic_order_cnt_bottom, bitstream); + } + } + if (p_Vid->pic_order_cnt_type == 1 && !p_Vid->delta_pic_order_always_zero_flag) + { + len += write_se_v ("SH: delta_pic_order_cnt[0]", p_Vid->delta_pic_order_cnt[0], bitstream); + + if (p_Vid->bottom_field_pic_order_in_frame_present_flag && !field_pic_flag) + { + len += write_se_v ("SH: delta_pic_order_cnt[1]", p_Vid->delta_pic_order_cnt[1], bitstream); + } + } + + if (active_pps->redundant_pic_cnt_present_flag) + { + len += write_ue_v ("SH: redundant_pic_cnt", p_Vid->redundant_pic_cnt, bitstream); + } + + // Direct Mode Type selection for B pictures + if (currSlice->slice_type == B_SLICE) + { + len += write_u_1 ("SH: direct_spatial_mv_pred_flag", p_Vid->direct_spatial_mv_pred_flag, bitstream); + } + + if ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == B_SLICE) || currSlice->slice_type==SP_SLICE) + { + int override_flag; + if ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == SP_SLICE)) + { + override_flag = (currSlice->num_ref_idx_active[LIST_0] != (active_pps->num_ref_idx_l0_default_active_minus1 +1)) ? 1 : 0; + } + else + { + override_flag = ((currSlice->num_ref_idx_active[LIST_0] != (active_pps->num_ref_idx_l0_default_active_minus1 +1)) + || (currSlice->num_ref_idx_active[LIST_1] != (active_pps->num_ref_idx_l1_default_active_minus1 +1))) ? 1 : 0; + } + + len += write_u_1 ("SH: num_ref_idx_active_override_flag", override_flag, bitstream); + + if (override_flag) + { + len += write_ue_v ("SH: num_ref_idx_l0_active_minus1", currSlice->num_ref_idx_active[LIST_0]-1, bitstream); + if (currSlice->slice_type == B_SLICE) + { + len += write_ue_v ("SH: num_ref_idx_l1_active_minus1", currSlice->num_ref_idx_active[LIST_1]-1, bitstream); + } + } + + } + + // add reference list modification info if needed +#if (MVC_EXTENSION_ENABLE) + if(currSlice->layer_id > 0) + len += mvc_ref_pic_list_reordering(currSlice, bitstream); + else +#endif + len += ref_pic_list_reordering(currSlice, bitstream); + + if (((currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE) && active_pps->weighted_pred_flag) || + ((currSlice->slice_type == B_SLICE) && currSlice->weighted_prediction == 1)) + { + len += pred_weight_table(currSlice, bitstream); + } + + if (p_Vid->nal_reference_idc) + { + p_Vid->adaptive_ref_pic_buffering_flag = (p_Vid->dec_ref_pic_marking_buffer != NULL); + len += dec_ref_pic_marking(bitstream, + p_Vid->dec_ref_pic_marking_buffer, +#if (MVC_EXTENSION_ENABLE) + (currSlice->idr_flag || (p_Vid->view_id && !p_Vid->non_idr_flag[currSlice->structure == BOTTOM_FIELD ? 1 : 0]) ) ? 1 : 0, +#else + currSlice->idr_flag, +#endif + p_Vid->no_output_of_prior_pics_flag, + p_Vid->long_term_reference_flag ); + } + + if(currSlice->symbol_mode==CABAC && currSlice->slice_type!=I_SLICE /*&& currSlice->slice_type!=SI_IMG*/) + { + len += write_ue_v("SH: cabac_init_idc", currSlice->model_number, bitstream); + } + + len += write_se_v("SH: slice_qp_delta", (currSlice->qp - 26 - active_pps->pic_init_qp_minus26), bitstream); + + if (currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) // SP or SI + { + if (currSlice->slice_type == SP_SLICE) // Switch Flag only for SP pictures + { + len += write_u_1 ("SH: sp_for_switch_flag", currSlice->sp2_frame_indicator, bitstream); // 1 for switching SP, 0 for normal SP + } + len += write_se_v ("SH: slice_qs_delta", (p_Vid->qpsp - 26), bitstream ); + } + + if (active_pps->deblocking_filter_control_present_flag) + { + len += write_ue_v("SH: disable_deblocking_filter_idc",currSlice->DFDisableIdc, bitstream); // Turn deblocking filter on/off on slice basis + + if (currSlice->DFDisableIdc!=1) + { + len += write_se_v ("SH: slice_alpha_c0_offset_div2", currSlice->DFAlphaC0Offset / 2, bitstream); + len += write_se_v ("SH: slice_beta_offset_div2 ", currSlice->DFBetaOffset / 2, bitstream); + } + } + + if ( active_pps->num_slice_groups_minus1 > 0 && + active_pps->slice_group_map_type >= 3 && active_pps->slice_group_map_type <= 5) + { + numtmp=p_Vid->PicHeightInMapUnits*p_Vid->PicWidthInMbs/(float)(active_pps->slice_group_change_rate_minus1+1)+1; + num_bits_slice_group_change_cycle = (int)ceil(log(numtmp)/log(2)); + + //! p_Vid->slice_group_change_cycle can be changed before calling FmoInit() + len += write_u_v (num_bits_slice_group_change_cycle, "SH: slice_group_change_cycle", p_Vid->slice_group_change_cycle, bitstream); + } + + // NOTE: The following syntax element is actually part + // Slice data bitstream A RBSP syntax + + if(currSlice->partition_mode && !currSlice->idr_flag) + { + len += write_ue_v("DPA: slice_id", currSlice->slice_nr, bitstream); + } + + return len; +} + +/*! + ******************************************************************************************** + * \brief + * writes the ref_pic_list_reordering syntax + * based on content of according fields in p_Vid structure + * + * \return + * number of bits used + ******************************************************************************************** +*/ +int ref_pic_list_reordering(Slice *currSlice, Bitstream *bitstream) +{ + int list; + int i, len=0; + + for(list = LIST_0; list <= LIST_1; list++) + { + if(currSlice->num_ref_idx_active[list]==0) + continue; + + reorder_against_default_ref_pic_lists(currSlice, list); + + if (currSlice->slice_type!=I_SLICE && currSlice->slice_type!=SI_SLICE) + { + len += write_u_1 ("SH: ref_pic_list_reordering_flag", currSlice->ref_pic_list_reordering_flag[list], bitstream); + if (currSlice->ref_pic_list_reordering_flag[list]) + { + i=-1; + do + { + i++; + len += write_ue_v ("SH: modification_of_pic_nums_idc", currSlice->modification_of_pic_nums_idc[list][i], bitstream); + if (currSlice->modification_of_pic_nums_idc[list][i] == 0 || currSlice->modification_of_pic_nums_idc[list][i] == 1) + { + len += write_ue_v ("SH: abs_diff_pic_num_minus1", currSlice->abs_diff_pic_num_minus1[list][i], bitstream); + } + else if (currSlice->modification_of_pic_nums_idc[list][i] == 2) + { + len += write_ue_v ("SH: long_term_pic_idx", currSlice->long_term_pic_idx[list][i], bitstream); + } + } while (currSlice->modification_of_pic_nums_idc[list][i] != 3); + } + } + } + + return len; +} + +#if (MVC_EXTENSION_ENABLE) +/*! +******************************************************************************************** +* \brief +* writes the mvc_ref_pic_list_reordering syntax +* for both LIST_0 and LIST_1 +* +* \return +* number of bits used +******************************************************************************************** +*/ + +static int mvc_ref_pic_list_reordering(Slice *currSlice, Bitstream *bitstream) +{ + int list; + int i, len=0; + + for(list = LIST_0; list <= LIST_1; list++) + { + if(currSlice->num_ref_idx_active[list]==0) + continue; + + reorder_against_default_ref_pic_lists(currSlice, list); + + if (currSlice->slice_type!=I_SLICE && currSlice->slice_type!=SI_SLICE) + { + len += write_u_1 ("SH: ref_pic_list_reordering_flag", currSlice->ref_pic_list_reordering_flag[list], bitstream); + if (currSlice->ref_pic_list_reordering_flag[list]) + { + i=-1; + do + { + i++; + len += write_ue_v ("SH: modification_of_pic_nums_idc", currSlice->modification_of_pic_nums_idc[list][i], bitstream); + if (currSlice->modification_of_pic_nums_idc[list][i] == 0 || currSlice->modification_of_pic_nums_idc[list][i] == 1) + { + len += write_ue_v ("SH: abs_diff_pic_num_minus1", currSlice->abs_diff_pic_num_minus1[list][i], bitstream); + } + else if (currSlice->modification_of_pic_nums_idc[list][i] == 2) + { + len += write_ue_v ("SH: long_term_pic_idx", currSlice->long_term_pic_idx[list][i], bitstream); + } + else if (currSlice->modification_of_pic_nums_idc[list][i] == 4 || currSlice->modification_of_pic_nums_idc[list][i] == 5) + { + len += write_ue_v ("SH: abs_diff_view_idx_minus1", currSlice->abs_diff_view_idx_minus1[list][i], bitstream); + } + } while (currSlice->modification_of_pic_nums_idc[list][i] != 3); + } + } + } + + return len; +} +#endif + +/*! + ************************************************************************ + * \brief + * write the memory management control operations + * + * \return + * number of bits used + ************************************************************************ + */ +int dec_ref_pic_marking(Bitstream *bitstream, DecRefPicMarking_t *p_drpm, int idr_flag, int no_output_of_prior_pics_flag, int long_term_reference_flag ) +{ + DecRefPicMarking_t *tmp_drpm; + + int val, len=0; + int adaptive_ref_pic_buffering_flag; + + if (idr_flag) + { + len += write_u_1("SH: no_output_of_prior_pics_flag", no_output_of_prior_pics_flag, bitstream); + len += write_u_1("SH: long_term_reference_flag", long_term_reference_flag, bitstream); + } + else + { + adaptive_ref_pic_buffering_flag = (p_drpm != NULL); + + len += write_u_1("SH: adaptive_ref_pic_buffering_flag", adaptive_ref_pic_buffering_flag, bitstream); + + if (adaptive_ref_pic_buffering_flag) + { + tmp_drpm = p_drpm; + // write Memory Management Control Operation + do + { + if (tmp_drpm==NULL) error ("Error encoding MMCO commands", 500); + + val = tmp_drpm->memory_management_control_operation; + len += write_ue_v("SH: memory_management_control_operation", val, bitstream); + + if ((val==1)||(val==3)) + { + len += 1 + write_ue_v("SH: difference_of_pic_nums_minus1", tmp_drpm->difference_of_pic_nums_minus1, bitstream); + } + if (val==2) + { + len+= write_ue_v("SH: long_term_pic_num", tmp_drpm->long_term_pic_num, bitstream); + } + if ((val==3)||(val==6)) + { + len+= write_ue_v("SH: long_term_frame_idx", tmp_drpm->long_term_frame_idx, bitstream); + } + if (val==4) + { + len += write_ue_v("SH: max_long_term_pic_idx_plus1", tmp_drpm->max_long_term_frame_idx_plus1, bitstream); + } + + tmp_drpm=tmp_drpm->Next; + + } while (val != 0); + + } + } + return len; +} + + +/*! + ************************************************************************ + * \brief + * write prediction weight table + * + * \return + * number of bits used + ************************************************************************ + */ +static int pred_weight_table(Slice *currSlice, Bitstream *bitstream) +{ + int len = 0; + int i,j; + + len += write_ue_v("SH: luma_log_weight_denom", currSlice->luma_log_weight_denom, bitstream); + + if ( 0 != currSlice->active_sps->chroma_format_idc) + { + len += write_ue_v("SH: chroma_log_weight_denom", currSlice->chroma_log_weight_denom, bitstream); + } + + for (i=0; i< currSlice->num_ref_idx_active[LIST_0]; i++) + { + if ( (currSlice->wp_weight[0][i][0] != 1<luma_log_weight_denom) || (currSlice->wp_offset[0][i][0] != 0) ) + { + len += write_u_1 ("SH: luma_weight_flag_l0", 1, bitstream); + len += write_se_v ("SH: luma_weight_l0", currSlice->wp_weight[0][i][0], bitstream); + len += write_se_v ("SH: luma_offset_l0", (currSlice->wp_offset[0][i][0]>>(currSlice->bitdepth_luma - 8)), bitstream); + } + else + { + len += write_u_1 ("SH: luma_weight_flag_l0", 0, bitstream); + } + + if (currSlice->active_sps->chroma_format_idc!=0) + { + if ( (currSlice->wp_weight[0][i][1] != 1<chroma_log_weight_denom) || (currSlice->wp_offset[0][i][1] != 0) || + (currSlice->wp_weight[0][i][2] != 1<chroma_log_weight_denom) || (currSlice->wp_offset[0][i][2] != 0) ) + { + len += write_u_1 ("chroma_weight_flag_l0", 1, bitstream); + for (j=1; j<3; j++) + { + len += write_se_v ("chroma_weight_l0", currSlice->wp_weight[0][i][j] ,bitstream); + len += write_se_v ("chroma_offset_l0", (currSlice->wp_offset[0][i][j]>>(currSlice->bitdepth_chroma-8)) ,bitstream); + } + } + else + { + len += write_u_1 ("chroma_weight_flag_l0", 0, bitstream); + } + } + } + + if (currSlice->slice_type == B_SLICE) + { + for (i=0; i< currSlice->num_ref_idx_active[LIST_1]; i++) + { + if ( (currSlice->wp_weight[1][i][0] != 1<luma_log_weight_denom) || (currSlice->wp_offset[1][i][0] != 0) ) + { + len += write_u_1 ("SH: luma_weight_flag_l1", 1, bitstream); + len += write_se_v ("SH: luma_weight_l1", currSlice->wp_weight[1][i][0], bitstream); + len += write_se_v ("SH: luma_offset_l1", (currSlice->wp_offset[1][i][0]>>(currSlice->bitdepth_luma-8)), bitstream); + } + else + { + len += write_u_1 ("SH: luma_weight_flag_l1", 0, bitstream); + } + + if (currSlice->active_sps->chroma_format_idc!=0) + { + if ( (currSlice->wp_weight[1][i][1] != 1<chroma_log_weight_denom) || (currSlice->wp_offset[1][i][1] != 0) || + (currSlice->wp_weight[1][i][2] != 1<chroma_log_weight_denom) || (currSlice->wp_offset[1][i][2] != 0) ) + { + len += write_u_1 ("chroma_weight_flag_l1", 1, bitstream); + for (j=1; j<3; j++) + { + len += write_se_v ("chroma_weight_l1", currSlice->wp_weight[1][i][j] ,bitstream); + len += write_se_v ("chroma_offset_l1", (currSlice->wp_offset[1][i][j]>>(currSlice->bitdepth_chroma-8)) ,bitstream); + } + } + else + { + len += write_u_1 ("chroma_weight_flag_l1", 0, bitstream); + } + } + } + } + return len; +} + + +/*! + ************************************************************************ + * \brief + * Selects picture type and codes it to symbol + * + * \return + * symbol value for picture type + ************************************************************************ + */ +static int get_picture_type(Slice *currSlice) +{ + // set this value to zero for transmission without signaling + // that the whole picture has the same slice type + int same_slicetype_for_whole_frame = 5; + +#if (MVC_EXTENSION_ENABLE) + if(currSlice->p_Inp->num_of_views==2) + { + same_slicetype_for_whole_frame = 0; + } +#endif + + switch (currSlice->slice_type) + { + case I_SLICE: + return 2 + same_slicetype_for_whole_frame; + break; + case P_SLICE: + return 0 + same_slicetype_for_whole_frame; + break; + case B_SLICE: + return 1 + same_slicetype_for_whole_frame; + break; + case SP_SLICE: + return 3 + same_slicetype_for_whole_frame; + break; + case SI_SLICE: + return 4 + same_slicetype_for_whole_frame; + break; + default: + error("Picture Type not supported!",1); + break; + } + + return 0; +} + + + +/*! + ***************************************************************************** + * + * \brief + * int Partition_BC_Header () write the Partition type B, C header + * + * \return + * Number of bits used by the partition header + * + * \par Parameters + * PartNo: Partition Number to which the header should be written + * + * \par Side effects + * Partition header as per VCEG-N72r2 is written into the appropriate + * partition bit buffer + * + * \par Limitations/Shortcomings/Tweaks + * The current code does not support the change of picture parameters within + * one coded sequence, hence there is only one parameter set necessary. This + * is hard coded to zero. + * + * \date + * October 24, 2001 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ +int Partition_BC_Header(Slice *currSlice, int PartNo) +{ + DataPartition *partition = &((currSlice)->partArr[PartNo]); + SyntaxElement sym; + + assert (PartNo > 0 && PartNo < currSlice->max_part_nr); + + sym.type = SE_HEADER; // This will be true for all symbols generated here + sym.value2 = 0; + + SYMTRACESTRING("RTP-PH: Slice ID"); + sym.value1 = currSlice->slice_nr; + writeSE_UVLC (&sym, partition); + + return sym.len; +} + diff --git a/lencod/src/image.c b/lencod/src/image.c new file mode 100644 index 0000000..5627aa2 --- /dev/null +++ b/lencod/src/image.c @@ -0,0 +1,3374 @@ + +/*! + ************************************************************************************* + * \file image.c + * + * \brief + * Code one image/slice + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langoy + * - Rickard Sjoberg + * - Jani Lainema + * - Sebastian Purreiter + * - Byeong-Moon Jeon + * - Yoon-Seong Soh + * - Thomas Stockhammer + * - Detlev Marpe + * - Guido Heising + * - Thomas Wedi + * - Ragip Kurceren + * - Antti Hallapuro + * - Alexis Michael Tourapis + * - Athanasios Leontaris + * - Yan Ye + ************************************************************************************* + */ +#include "contributors.h" + +#include +#include + +#include "global.h" + +#include "filehandle.h" +#include "mbuffer.h" +#include "img_luma.h" +#include "img_chroma.h" +#include "img_distortion.h" +#include "intrarefresh.h" +#include "slice.h" +#include "fmo.h" +#include "sei.h" +#include "memalloc.h" +#include "fast_memory.h" +#include "nalu.h" +#include "ratectl.h" +#include "mb_access.h" +#include "context_ini.h" +#include "biariencode.h" +#include "enc_statistics.h" +#include "conformance.h" +#include "report.h" + +#include "q_matrix.h" +#include "q_offsets.h" +#include "wp.h" +#include "input.h" +#include "image.h" +#include "errdo.h" +#include "img_process.h" +#include "rdopt.h" +#include "sei.h" +#include "configfile.h" +#include "mbuffer.h" + +//#include "resize.h" +#include "md_common.h" +#include "me_epzs_common.h" + +//! Edited by Joao Carreira +#include "transcode_enc.h" + +extern void UpdateDecoders (VideoParameters *p_Vid, InputParameters *p_Inp, StorablePicture *enc_pic); + +extern void DeblockFrame (VideoParameters *p_Vid, imgpel **, imgpel ***); + +static void code_a_picture (VideoParameters *p_Vid, Picture *pic); +static void field_picture (VideoParameters *p_Vid, Picture *top, Picture *bottom); +static void prepare_enc_frame_picture (VideoParameters *p_Vid, StorablePicture **stored_pic); +#if (MVC_EXTENSION_ENABLE) +static void writeout_picture (VideoParameters *p_Vid, Picture *pic, int is_bottom); +#else +static void writeout_picture (VideoParameters *p_Vid, Picture *pic); +#endif +static byte picture_structure_decision(VideoParameters *p_Vid, Picture *frame, Picture *top, Picture *bot); +static void distortion_fld (VideoParameters *p_Vid, InputParameters *p_Inp, Picture *field_pic, ImageData *imgData); + +static void field_mode_buffer (VideoParameters *p_Vid); +static void frame_mode_buffer (VideoParameters *p_Vid); +static void init_frame (VideoParameters *p_Vid, InputParameters *p_Inp); +static void init_field (VideoParameters *p_Vid, InputParameters *p_Inp); +static void put_buffer_frame (VideoParameters *p_Vid); +static void put_buffer_top (VideoParameters *p_Vid); +static void put_buffer_bot (VideoParameters *p_Vid); + +static void ReportFirstframe (VideoParameters *p_Vid, int64 tmp_time); +static void ReportI (VideoParameters *p_Vid, int64 tmp_time); +static void ReportP (VideoParameters *p_Vid, int64 tmp_time); +static void ReportB (VideoParameters *p_Vid, int64 tmp_time); +static void ReportNALNonVLCBits(VideoParameters *p_Vid, int64 tmp_time); + +extern void rd_picture_coding(VideoParameters *p_Vid, InputParameters *p_Inp); + +void MbAffPostProc(VideoParameters *p_Vid) +{ + imgpel temp[32][16]; + + StorablePicture *p_Enc_Pic = p_Vid->enc_picture; + imgpel ** imgY = p_Enc_Pic->imgY; + imgpel ***imgUV = p_Enc_Pic->imgUV; + short i, y, x0, y0, uv; + + if (p_Vid->yuv_format != YUV400) + { + for (i=0; i<(int)p_Vid->PicSizeInMbs; i+=2) + { + if (p_Enc_Pic->motion.mb_field[i]) + { + get_mb_pos(p_Vid, i, p_Vid->mb_size[IS_LUMA], &x0, &y0); + for (y=0; y<(2*MB_BLOCK_SIZE);y++) + memcpy(&temp[y],&imgY[y0+y][x0], MB_BLOCK_SIZE * sizeof(imgpel)); + + for (y=0; ymb_cr_size_x); + y0 = y0 / (16/p_Vid->mb_cr_size_y); + + for (uv=0; uv<2; uv++) + { + for (y=0; y < (2 * p_Vid->mb_cr_size_y); y++) + memcpy(&temp[y],&imgUV[uv][y0+y][x0], p_Vid->mb_cr_size_x * sizeof(imgpel)); + + for (y=0; ymb_cr_size_y;y++) + { + memcpy(&imgUV[uv][y0+(2*y)][x0],temp[y], p_Vid->mb_cr_size_x * sizeof(imgpel)); + memcpy(&imgUV[uv][y0+(2*y + 1)][x0],temp[y+ p_Vid->mb_cr_size_y], p_Vid->mb_cr_size_x * sizeof(imgpel)); + } + } + } + } + } + else + { + for (i=0; i<(int)p_Vid->PicSizeInMbs; i+=2) + { + if (p_Enc_Pic->motion.mb_field[i]) + { + get_mb_pos(p_Vid, i, p_Vid->mb_size[IS_LUMA], &x0, &y0); + for (y=0; y<(2*MB_BLOCK_SIZE);y++) + memcpy(&temp[y],&imgY[y0+y][x0], MB_BLOCK_SIZE * sizeof(imgpel)); + + for (y=0; ytype = (short) slice_type; // set slice type + p_Vid->RCMinQP = p_Inp->RCMinQP[p_Vid->type]; + p_Vid->RCMaxQP = p_Inp->RCMaxQP[p_Vid->type]; +} + +static void code_a_plane(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + unsigned int NumberOfCodedMBs = 0; + int SliceGroup = 0; + DistMetric distortion; + + // The slice_group_change_cycle can be changed here. + // FmoInit() is called before coding each picture, frame or field + p_Vid->slice_group_change_cycle=1; + FmoInit(p_Vid, p_Vid->active_pps, p_Vid->active_sps); + FmoStartPicture (p_Vid); //! picture level initialization of FMO + + CalculateQuant4x4Param (p_Vid); + CalculateOffset4x4Param(p_Vid); + + if(p_Inp->Transform8x8Mode) + { + CalculateQuant8x8Param (p_Vid); + CalculateOffset8x8Param(p_Vid); + } + + reset_pic_bin_count(p_Vid); + p_Vid->bytes_in_picture = 0; + + while (NumberOfCodedMBs < p_Vid->PicSizeInMbs) // loop over slices + { + // Encode one SLice Group + while (!FmoSliceGroupCompletelyCoded (p_Vid, SliceGroup)) + { + // Encode the current slice + if (!p_Vid->mb_aff_frame_flag) + NumberOfCodedMBs += encode_one_slice (p_Vid, SliceGroup, NumberOfCodedMBs); + else + NumberOfCodedMBs += encode_one_slice_MBAFF (p_Vid, SliceGroup, NumberOfCodedMBs); + + FmoSetLastMacroblockInSlice (p_Vid, p_Vid->current_mb_nr); + // Proceed to next slice + p_Vid->current_slice_nr++; + p_Vid->p_Stats->bit_slice = 0; + } + // Proceed to next SliceGroup + SliceGroup++; + } + FmoEndPicture (); + + if ((p_Inp->SkipDeBlockNonRef == 0) || (p_Vid->nal_reference_idc != 0)) + { + if(p_Inp->RDPictureDeblocking && !p_Vid->TurnDBOff) + { + find_distortion(p_Vid, &p_Vid->imgData); + distortion.value[0] = p_Vid->p_Dist->metric[SSE].value[0]; + distortion.value[1] = p_Vid->p_Dist->metric[SSE].value[1]; + distortion.value[2] = p_Vid->p_Dist->metric[SSE].value[2]; + } + else + distortion.value[0] = distortion.value[1] = distortion.value[2] = 0; + + DeblockFrame (p_Vid, p_Vid->enc_picture->imgY, p_Vid->enc_picture->imgUV); //comment out to disable deblocking filter + + if(p_Inp->RDPictureDeblocking && !p_Vid->TurnDBOff) + { + find_distortion(p_Vid, &p_Vid->imgData); + if(distortion.value[0]+distortion.value[1]+distortion.value[2] < + p_Vid->p_Dist->metric[SSE].value[0]+ + p_Vid->p_Dist->metric[SSE].value[1]+ + p_Vid->p_Dist->metric[SSE].value[2]) + { + p_Vid->EvaluateDBOff = 1; + } + } + } + +} +/*! + ************************************************************************ + * \brief + * Encodes a picture + * + * This is the main picture coding loop.. It is called by all this + * frame and field coding stuff after the p_Vid-> elements have been + * set up. Not sure whether it is useful for MB-adaptive frame/field + * coding + ************************************************************************ + */ +static void code_a_picture(VideoParameters *p_Vid, Picture *pic) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int pl; + + p_Vid->currentPicture = pic; + p_Vid->currentPicture->idr_flag = get_idr_flag(p_Vid); + + pic->no_slices = 0; + + RandomIntraNewPicture (p_Vid); //! Allocates forced INTRA MBs (even for fields!) + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( pl=0; plcurrent_mb_nr = 0; + p_Vid->current_slice_nr = 0; + p_Vid->SumFrameQP = 0; + p_Vid->num_ref_idx_l0_active = 0; + p_Vid->num_ref_idx_l1_active = 0; + + p_Vid->colour_plane_id = (char) pl; + + code_a_plane(p_Vid, p_Inp); + } + } + else + { + code_a_plane(p_Vid, p_Inp); + } + + if (p_Vid->mb_aff_frame_flag) + MbAffPostProc(p_Vid); + +} + +/*! + ************************************************************************ + * \brief + * Determine whether picture is coded as IDR + ************************************************************************ + */ +byte get_idr_flag( VideoParameters *p_Vid ) +{ + int idr_flag; + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + + switch( p_Vid->structure ) + { + default: + case FRAME: + idr_flag = p_cur_frm->p_frame_pic->idr_flag; + break; + case TOP_FIELD: + idr_flag = p_cur_frm->p_top_fld_pic->idr_flag; + break; + case BOTTOM_FIELD: + idr_flag = p_cur_frm->p_bot_fld_pic->idr_flag; + break; + } + + return (byte) idr_flag; +} + +/*! + ************************************************************************ + * \brief + * Determine whether picture is coded as IDR or Openg GOP Intra + ************************************************************************ + */ +byte get_random_access_flag( VideoParameters *p_Vid ) +{ + int random_access; + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + + switch( p_Vid->structure ) + { + default: + case FRAME: + random_access = p_cur_frm->p_frame_pic->random_access; + break; + case TOP_FIELD: + random_access = p_cur_frm->p_top_fld_pic->random_access; + break; + case BOTTOM_FIELD: + random_access = p_cur_frm->p_bot_fld_pic->random_access; + break; + } + + return (byte) random_access; +} + +/*! + ************************************************************************ + * \brief + * Update global stats + ************************************************************************ + */ +void update_global_stats(InputParameters *p_Inp, StatParameters *gl_stats, StatParameters *cur_stats) +{ + int i, j, k; + + if (p_Inp->skip_gl_stats == 0) + { + for (i = 0; i < 4; i++) + { + gl_stats->intra_chroma_mode[i] += cur_stats->intra_chroma_mode[i]; + } + + for (i = 0; i < 5; i++) + { + gl_stats->quant[i] += cur_stats->quant[i]; + gl_stats->num_macroblocks[i] += cur_stats->num_macroblocks[i]; + gl_stats->bit_use_mb_type [i] += cur_stats->bit_use_mb_type[i]; + gl_stats->bit_use_header [i] += cur_stats->bit_use_header[i]; + gl_stats->tmp_bit_use_cbp [i] += cur_stats->tmp_bit_use_cbp[i]; + gl_stats->bit_use_coeffC [i] += cur_stats->bit_use_coeffC[i]; + gl_stats->bit_use_coeff[0][i] += cur_stats->bit_use_coeff[0][i]; + gl_stats->bit_use_coeff[1][i] += cur_stats->bit_use_coeff[1][i]; + gl_stats->bit_use_coeff[2][i] += cur_stats->bit_use_coeff[2][i]; + gl_stats->bit_use_delta_quant[i] += cur_stats->bit_use_delta_quant[i]; + gl_stats->bit_use_stuffing_bits[i] += cur_stats->bit_use_stuffing_bits[i]; + + for (k = 0; k < 2; k++) + gl_stats->b8_mode_0_use[i][k] += cur_stats->b8_mode_0_use[i][k]; + + for (j = 0; j < 15; j++) + { + gl_stats->mode_use[i][j] += cur_stats->mode_use[i][j]; + gl_stats->bit_use_mode[i][j] += cur_stats->bit_use_mode[i][j]; + for (k = 0; k < 2; k++) + gl_stats->mode_use_transform[i][j][k] += cur_stats->mode_use_transform[i][j][k]; + } + } + } +} + +static void storeRedundantFrame(VideoParameters *p_Vid) +{ + int j, k; + if(p_Vid->key_frame) + { + for(j=0; jheight; j++) + { + memcpy(p_Vid->imgY_tmp[j], p_Vid->enc_frame_picture[0]->imgY[j], p_Vid->width * sizeof(imgpel)); + } + + for (k = 0; k < 2; k++) + { + for(j=0; jheight_cr; j++) + { + memcpy(p_Vid->imgUV_tmp[k][j], p_Vid->enc_frame_picture[0]->imgUV[k][j], p_Vid->width_cr * sizeof(imgpel)); + } + } + } + + if(p_Vid->redundant_coding) + { + for(j=0; jheight; j++) + { + memcpy(p_Vid->enc_frame_picture[0]->imgY[j], p_Vid->imgY_tmp[j], p_Vid->width * sizeof(imgpel)); + } + for (k = 0; k < 2; k++) + { + for(j=0; jheight_cr; j++) + { + memcpy(p_Vid->enc_frame_picture[0]->imgUV[k][j], p_Vid->imgUV_tmp[k][j], p_Vid->width_cr * sizeof(imgpel)); + } + } + } +} +/*! + ************************************************************************ + * \brief + * Free storable pictures + ************************************************************************ + */ +void free_pictures(VideoParameters *p_Vid, int dummy) +{ + int i; + for (i = 0; i < 6; i++) + { + if(p_Vid->enc_picture != p_Vid->enc_frame_picture[i]) + free_storable_picture(p_Vid, p_Vid->enc_frame_picture[i]); + } +} + +#if (MVC_EXTENSION_ENABLE) +/*! + ************************************************************************ + * \brief + * Write EL NALUs for field coded pictures + ************************************************************************ + */ +void write_el_field_vcl_nalu(VideoParameters *p_Vid) +{ + int temp1_nal_reference_idc; + int temp1_non_idr_flag[2]; + int temp1_priority_id; + int temp1_view_id; + int temp1_temporal_id; + int temp1_anchor_pic_flag[2]; + int temp1_inter_view_flag[2]; + + if(p_Vid->view_id == 1) + { + int temp_view_id = p_Vid->view_id; + + p_Vid->view_id = 0; + p_Vid->structure = TOP_FIELD; + write_non_vcl_nalu_mvc(p_Vid); + + //backup view_id 1 + temp1_nal_reference_idc = p_Vid->nal_reference_idc; + temp1_non_idr_flag[0] = p_Vid->non_idr_flag[0]; + temp1_non_idr_flag[1] = p_Vid->non_idr_flag[1]; + temp1_priority_id = p_Vid->priority_id; + temp1_view_id = temp_view_id; + temp1_temporal_id = p_Vid->temporal_id; + temp1_anchor_pic_flag[0] = p_Vid->anchor_pic_flag[0]; + temp1_anchor_pic_flag[1] = p_Vid->anchor_pic_flag[1]; + temp1_inter_view_flag[0] = p_Vid->inter_view_flag[0]; + temp1_inter_view_flag[1] = p_Vid->inter_view_flag[1]; + + //restore view_id 0 + p_Vid->nal_reference_idc = p_Vid->temp0_nal_reference_idc; + p_Vid->non_idr_flag[0] = p_Vid->temp0_non_idr_flag[0]; + p_Vid->non_idr_flag[1] = p_Vid->temp0_non_idr_flag[1]; + p_Vid->priority_id = p_Vid->temp0_priority_id; + p_Vid->view_id = p_Vid->temp0_view_id; + p_Vid->temporal_id = p_Vid->temp0_temporal_id; + p_Vid->anchor_pic_flag[0] = p_Vid->temp0_anchor_pic_flag[0]; + p_Vid->anchor_pic_flag[1] = p_Vid->temp0_anchor_pic_flag[1]; + p_Vid->inter_view_flag[0] = p_Vid->temp0_inter_view_flag[0]; + p_Vid->inter_view_flag[1] = p_Vid->temp0_inter_view_flag[1]; + writeout_picture (p_Vid, p_Vid->field_pic1[0], 0); //top + + //restore view_id 1 + p_Vid->nal_reference_idc = temp1_nal_reference_idc; + p_Vid->non_idr_flag[0] = temp1_non_idr_flag[0]; + p_Vid->non_idr_flag[1] = temp1_non_idr_flag[1]; + p_Vid->priority_id = temp1_priority_id; + p_Vid->view_id = temp1_view_id; + p_Vid->temporal_id = temp1_temporal_id; + p_Vid->anchor_pic_flag[0] = temp1_anchor_pic_flag[0]; + p_Vid->anchor_pic_flag[1] = temp1_anchor_pic_flag[1]; + p_Vid->inter_view_flag[0] = temp1_inter_view_flag[0]; + p_Vid->inter_view_flag[1] = temp1_inter_view_flag[1]; + write_non_vcl_nalu_mvc( p_Vid ); + writeout_picture (p_Vid, p_Vid->field_pic2[0], 0); //top + + //restore view_id 0 + p_Vid->nal_reference_idc = p_Vid->temp0_nal_reference_idc; + p_Vid->non_idr_flag[0] = p_Vid->temp0_non_idr_flag[0]; + p_Vid->non_idr_flag[1] = p_Vid->temp0_non_idr_flag[1]; + p_Vid->priority_id = p_Vid->temp0_priority_id; + p_Vid->view_id = p_Vid->temp0_view_id; + p_Vid->temporal_id = p_Vid->temp0_temporal_id; + p_Vid->anchor_pic_flag[0] = p_Vid->temp0_anchor_pic_flag[0]; + p_Vid->anchor_pic_flag[1] = p_Vid->temp0_anchor_pic_flag[1]; + p_Vid->inter_view_flag[0] = p_Vid->temp0_inter_view_flag[0]; + p_Vid->inter_view_flag[1] = p_Vid->temp0_inter_view_flag[1]; + p_Vid->structure = BOTTOM_FIELD; + write_non_vcl_nalu_mvc( p_Vid ); + writeout_picture (p_Vid, p_Vid->field_pic1[1], 1); //bot + + //restore view_id 1 + p_Vid->nal_reference_idc = temp1_nal_reference_idc; + p_Vid->non_idr_flag[0] = temp1_non_idr_flag[0]; + p_Vid->non_idr_flag[1] = temp1_non_idr_flag[1]; + p_Vid->priority_id = temp1_priority_id; + p_Vid->view_id = temp1_view_id; + p_Vid->temporal_id = temp1_temporal_id; + p_Vid->anchor_pic_flag[0] = temp1_anchor_pic_flag[0]; + p_Vid->anchor_pic_flag[1] = temp1_anchor_pic_flag[1]; + p_Vid->inter_view_flag[0] = temp1_inter_view_flag[0]; + p_Vid->inter_view_flag[1] = temp1_inter_view_flag[1]; + write_non_vcl_nalu_mvc( p_Vid ); + writeout_picture (p_Vid, p_Vid->field_pic2[1], 1); //bot + } + else // store the first view nal unit + { + p_Vid->temp0_nal_reference_idc = p_Vid->nal_reference_idc; + p_Vid->temp0_non_idr_flag[0] = p_Vid->non_idr_flag[0]; + p_Vid->temp0_non_idr_flag[1] = p_Vid->non_idr_flag[1]; + p_Vid->temp0_priority_id = p_Vid->priority_id; + p_Vid->temp0_view_id = p_Vid->view_id; + p_Vid->temp0_temporal_id = p_Vid->temporal_id; + p_Vid->temp0_anchor_pic_flag[0] = p_Vid->anchor_pic_flag[0]; + p_Vid->temp0_anchor_pic_flag[1] = p_Vid->anchor_pic_flag[1]; + p_Vid->temp0_inter_view_flag[0] = p_Vid->inter_view_flag[0]; + p_Vid->temp0_inter_view_flag[1] = p_Vid->inter_view_flag[1]; + } +} + +/*! + ************************************************************************ + * \brief + * Write coded frame (one frame picture or two field pictures) + ************************************************************************ + */ +void write_frame_picture(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + if (p_Vid->fld_flag) // field mode (use field when fld_flag=1 only) + { + field_mode_buffer (p_Vid); + + if(p_Inp->num_of_views==1) + { + p_Vid->structure = TOP_FIELD; + write_non_vcl_nalu(p_Vid); + writeout_picture (p_Vid, p_Vid->field_pic1[0], 0); + p_Vid->structure = BOTTOM_FIELD; + write_non_vcl_nalu_bot_fld(p_Vid); + writeout_picture (p_Vid, p_Vid->field_pic1[1], 1); + } + else + { + write_el_field_vcl_nalu(p_Vid); + } + } + else //frame mode + { + frame_mode_buffer (p_Vid); + p_Vid->structure = FRAME; + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->num_of_views == 2 ) + { + write_non_vcl_nalu_mvc(p_Vid); + } + else +#endif + write_non_vcl_nalu(p_Vid); + if (p_Vid->type==SI_SLICE) + { + writeout_picture (p_Vid, p_Vid->frame_pic_si, 0); + } + else + { + writeout_picture (p_Vid, p_Vid->p_frame_pic, 0); + } + } +} +#else +void write_frame_picture(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + if (p_Vid->fld_flag) // field mode (use field when fld_flag=1 only) + { + p_Vid->structure = TOP_FIELD; + field_mode_buffer (p_Vid); + write_non_vcl_nalu(p_Vid); + writeout_picture (p_Vid, p_Vid->field_pic[0]); + p_Vid->structure = BOTTOM_FIELD; + write_non_vcl_nalu_bot_fld(p_Vid); + writeout_picture (p_Vid, p_Vid->field_pic[1]); + } + else //frame mode + { + frame_mode_buffer (p_Vid); + + write_non_vcl_nalu(p_Vid); + if (p_Vid->type==SI_SLICE) + { + writeout_picture (p_Vid, p_Vid->frame_pic_si); + } + else + { + writeout_picture (p_Vid, p_Vid->p_frame_pic); + } + } +} +#endif + +/*! + ************************************************************************ + * \brief + * Read input data while considering and performing a 3:2 pulldown + * process. + ************************************************************************ + */ +static int read_input_data_32pulldown(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int file_read = 0; + int frm_no_in_file_first = 0; + int frm_no_in_file_second = 0; + int pull_down_offset = p_Inp->enable_32_pulldown == 1 ? 1 : 2; + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2 && p_Vid->view_id == 1) + { + frm_no_in_file_first = ((p_Vid->frm_no_in_file * 4 + pull_down_offset)/ 5); + frm_no_in_file_second = ((p_Vid->frm_no_in_file * 4 + 3)/ 5); + + // Read frame data (first frame) + file_read = read_one_frame (p_Vid, &p_Inp->input_file2, frm_no_in_file_first, p_Inp->infile_header, &p_Inp->source, &p_Inp->output, p_Vid->imgData0.frm_data); + if ( !file_read ) + { + // end of file or stream found: trigger error handling + get_number_of_frames (p_Inp, &p_Inp->input_file2); + fprintf(stdout, "\nIncorrect FramesToBeEncoded: actual number is %6d frames!\n", p_Inp->no_frames ); + return 0; + } + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData0.frm_data); + + // Read frame data (second frame) + file_read = read_one_frame (p_Vid, &p_Inp->input_file2, frm_no_in_file_second, p_Inp->infile_header, &p_Inp->source, &p_Inp->output, p_Vid->imgData4.frm_data); + if ( !file_read ) + { + // end of file or stream found: trigger error handling + get_number_of_frames (p_Inp, &p_Inp->input_file2); + fprintf(stdout, "\nIncorrect FramesToBeEncoded: actual number is %6d frames!\n", p_Inp->no_frames ); + return 0; + } + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData4.frm_data); + } + else +#endif + { + frm_no_in_file_first = ((p_Vid->frm_no_in_file * 4 + pull_down_offset)/ 5); + frm_no_in_file_second = ((p_Vid->frm_no_in_file * 4 + 3)/ 5); + + // Read frame data (first frame) + file_read = read_one_frame (p_Vid, &p_Inp->input_file1, frm_no_in_file_first, p_Inp->infile_header, &p_Inp->source, &p_Inp->output, p_Vid->imgData0.frm_data); + if ( !file_read ) + { + // end of file or stream found: trigger error handling + get_number_of_frames (p_Inp, &p_Inp->input_file1); + fprintf(stdout, "\nIncorrect FramesToBeEncoded: actual number is %6d frames!\n", p_Inp->no_frames ); + return 0; + } + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData0.frm_data); + + // Read frame data (second frame) + file_read = read_one_frame (p_Vid, &p_Inp->input_file1, frm_no_in_file_second, p_Inp->infile_header, &p_Inp->source, &p_Inp->output, p_Vid->imgData4.frm_data); + if ( !file_read ) + { + // end of file or stream found: trigger error handling + get_number_of_frames (p_Inp, &p_Inp->input_file1); + fprintf(stdout, "\nIncorrect FramesToBeEncoded: actual number is %6d frames!\n", p_Inp->no_frames ); + return 0; + } + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData4.frm_data); + } + + + return 1; +} + +static int read_input_data(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int file_read = 0; + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2 && p_Vid->view_id == 1) + { + file_read = read_one_frame (p_Vid, &p_Inp->input_file2, p_Vid->frm_no_in_file, p_Inp->infile_header, &p_Inp->source, &p_Inp->output, p_Vid->imgData0.frm_data); + if ( !file_read ) + { + // end of file or stream found: trigger error handling + get_number_of_frames (p_Inp, &p_Inp->input_file2); + fprintf(stdout, "\nIncorrect FramesToBeEncoded: actual number is %6d frames!\n", p_Inp->no_frames ); + return 0; + } + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData0.frm_data); + } + else +#endif + { + file_read = read_one_frame (p_Vid, &p_Inp->input_file1, p_Vid->frm_no_in_file, p_Inp->infile_header, &p_Inp->source, &p_Inp->output, p_Vid->imgData0.frm_data); + if ( !file_read ) + { + // end of file or stream found: trigger error handling + get_number_of_frames (p_Inp, &p_Inp->input_file1); + fprintf(stdout, "\nIncorrect FramesToBeEncoded: actual number is %6d frames!\n", p_Inp->no_frames ); + return 0; + } + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData0.frm_data); + } + + return 1; +} + +void perform_encode_field(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + //Rate control + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + p_Vid->p_rc_gen->FieldControl = 1; + + p_Vid->field_picture = 1; // we encode fields + +#if (MVC_EXTENSION_ENABLE) + field_picture (p_Vid, p_Vid->field_pic_ptr[0], p_Vid->field_pic_ptr[1]); +#else + field_picture (p_Vid, p_Vid->field_pic[0], p_Vid->field_pic[1]); +#endif + p_Vid->fld_flag = TRUE; +} + +void perform_encode_frame(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int tmpFrameQP = 0; + int num_ref_idx_l0 = 0; + int num_ref_idx_l1 = 0; + + int frame_type; + + //if( p_Vid->type != I_SLICE ) + // readTranscodingInfo( p_Vid ); + + //Rate control + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + p_Vid->p_rc_gen->FieldControl = 0; + + p_Vid->field_picture = 0; // we encode a frame + + //Rate control + if(p_Inp->RCEnable) + rc_init_frame(p_Vid, p_Inp); + // Ensure that p_Vid->p_curr_frm_struct->qp is properly set + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + + p_Vid->active_pps = p_Vid->PicParSet[0]; + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->view_id!=1 || !p_Vid->sec_view_force_fld) + { +#endif + if ((p_Vid->type == B_SLICE || p_Vid->type == P_SLICE || p_Vid->type==I_SLICE) && p_Inp->RDPictureDecision) + { + frame_picture_mp (p_Vid, p_Inp); + } + else + { + frame_picture (p_Vid, p_Vid->frame_pic[0], &p_Vid->imgData, 0); + p_Vid->p_frame_pic = p_Vid->frame_pic[0]; + } + + tmpFrameQP = p_Vid->SumFrameQP; // call it here since rd_picture_coding buffers it and may modify it + num_ref_idx_l0 = p_Vid->num_ref_idx_l0_active; + num_ref_idx_l1 = p_Vid->num_ref_idx_l1_active; + + if (p_Vid->p_curr_frm_struct->type == SI_SLICE) + { + // once the picture has been encoded as a primary SP frame encode as an SI frame + set_slice_type( p_Vid, p_Inp, SI_SLICE ); + frame_picture (p_Vid, p_Vid->frame_pic_si, &p_Vid->imgData, 0); + } + + if ((p_Vid->type == SP_SLICE) && (p_Inp->sp_output_indicator)) + { + // output the transformed and quantized coefficients (useful for switching SP frames) + output_SP_coefficients(p_Vid, p_Inp); + } +#if (MVC_EXTENSION_ENABLE) + } +#endif + +#if (MVC_EXTENSION_ENABLE) + if ((p_Inp->PicInterlace == ADAPTIVE_CODING) && (!is_MVC_profile(p_Vid->active_sps->profile_idc) || + (/*(p_Vid->active_sps->profile_idc == SBSPLUS_HIGH) &&*/ ((p_Vid->view_id == 0) || (p_Vid->view_id == 1 && p_Vid->sec_view_force_fld))))) +#else + if (p_Inp->PicInterlace == ADAPTIVE_CODING) +#endif + { + DecRefPicMarking_t *tmp_drpm; + + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + p_Vid->p_rc_gen->FieldControl=1; + p_Vid->write_macroblock = FALSE; + p_Vid->bot_MB = FALSE; + + frame_type = p_Vid->type; + + p_Vid->field_picture = 1; // we encode fields + + //Free frame based dec_ref_pic_marking_buffer + while (p_Vid->dec_ref_pic_marking_buffer) + { + tmp_drpm = p_Vid->dec_ref_pic_marking_buffer; + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm->Next; + free(tmp_drpm); + } + +#if (MVC_EXTENSION_ENABLE) + field_picture (p_Vid, p_Vid->field_pic_ptr[0], p_Vid->field_pic_ptr[1]); + + if(p_Inp->num_of_views==1 || p_Vid->view_id==0) // first view will make the decision + { + if(p_Vid->rd_pass == 0) + p_Vid->fld_flag = picture_structure_decision (p_Vid, p_Vid->frame_pic[0], p_Vid->field_pic_ptr[0], p_Vid->field_pic_ptr[1]); + else if(p_Vid->rd_pass == 1) + p_Vid->fld_flag = picture_structure_decision (p_Vid, p_Vid->frame_pic[1], p_Vid->field_pic_ptr[0], p_Vid->field_pic_ptr[1]); + else + p_Vid->fld_flag = picture_structure_decision (p_Vid, p_Vid->frame_pic[2], p_Vid->field_pic_ptr[0], p_Vid->field_pic_ptr[1]); + + p_Vid->sec_view_force_fld = p_Vid->fld_flag; // store 1st view decision, same coding structure to be used for second view + } + else + { + p_Vid->fld_flag = (byte) p_Vid->sec_view_force_fld; + } +#else + field_picture (p_Vid, p_Vid->field_pic[0], p_Vid->field_pic[1]); + + if(p_Vid->rd_pass == 0) + p_Vid->fld_flag = picture_structure_decision (p_Vid, p_Vid->frame_pic[0], p_Vid->field_pic[0], p_Vid->field_pic[1]); + else if(p_Vid->rd_pass == 1) + p_Vid->fld_flag = picture_structure_decision (p_Vid, p_Vid->frame_pic[1], p_Vid->field_pic[0], p_Vid->field_pic[1]); + else + p_Vid->fld_flag = picture_structure_decision (p_Vid, p_Vid->frame_pic[2], p_Vid->field_pic[0], p_Vid->field_pic[1]); +#endif + + if ( p_Vid->fld_flag ) + { + tmpFrameQP = p_Vid->SumFrameQP; + num_ref_idx_l0 = p_Vid->num_ref_idx_l0_active; + num_ref_idx_l1 = p_Vid->num_ref_idx_l1_active; + } + + if ( p_Vid->fld_flag==0 ) + { + p_Vid->type = (short) frame_type; + } + + update_field_frame_contexts (p_Vid, p_Vid->fld_flag); + + //Rate control + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + p_Vid->p_rc_gen->FieldFrame = !(p_Vid->fld_flag) ? 1 : 0; + } + else + p_Vid->fld_flag = FALSE; + + p_Vid->SumFrameQP = tmpFrameQP; + p_Vid->num_ref_idx_l0_active = num_ref_idx_l0; + p_Vid->num_ref_idx_l1_active = num_ref_idx_l1; +} + +void free_slice_data(VideoParameters *p_Vid) +{ + int i; + + if (p_Vid->frame_pic_si) + { + free_slice_list(p_Vid->frame_pic_si); + } + + for (i = 0; i < p_Vid->frm_iter; i++) + { + if (p_Vid->frame_pic[i]) + { + free_slice_list(p_Vid->frame_pic[i]); + } + } + +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->field_pic_ptr && (p_Vid->p_Inp->num_of_views==1 || p_Vid->view_id==1) ) + { + for (i = 0; i < 2; i++) + { + if (p_Vid->field_pic1[i]) + free_slice_list(p_Vid->field_pic1[i]); + if (p_Vid->p_Inp->num_of_views==2 && p_Vid->field_pic2) + { + if (p_Vid->field_pic2[i]) + free_slice_list(p_Vid->field_pic2[i]); + } + } + } +#else + if (p_Vid->field_pic) + { + for (i = 0; i < 2; i++) + { + if (p_Vid->field_pic[i]) + free_slice_list(p_Vid->field_pic[i]); + } + } +#endif +} + +void store_coded_picture(DecodedPictureBuffer *p_Dpb) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + unsigned int profile_idc = p_Vid->active_sps->profile_idc; + +#if (MVC_EXTENSION_ENABLE) + if ( (p_Inp->PicInterlace == ADAPTIVE_CODING) && ((p_Dpb->layer_id == 0 ) || !is_MVC_profile(profile_idc))) +#else + if ( p_Inp->PicInterlace == ADAPTIVE_CODING ) +#endif + { + if (p_Vid->fld_flag) + { + update_global_stats(p_Inp, p_Vid->p_Stats, &p_Vid->enc_field_picture[0]->stats); + update_global_stats(p_Inp, p_Vid->p_Stats, &p_Vid->enc_field_picture[1]->stats); + // store bottom field + store_picture_in_dpb (p_Dpb, p_Vid->enc_field_picture[1], &p_Inp->output); +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->proc_picture && is_MVC_profile(profile_idc) ) + { + store_proc_picture_in_dpb (p_Vid->p_Dpb_layer[1], p_Vid->proc_picture, &p_Inp->output); + p_Vid->proc_picture = NULL; + } +#endif + free_storable_picture(p_Vid, p_Vid->enc_frame_picture[0]); + free_storable_picture(p_Vid, p_Vid->enc_frame_picture[1]); + free_storable_picture(p_Vid, p_Vid->enc_frame_picture[2]); + } + else + { + update_global_stats(p_Inp, p_Vid->p_Stats, &p_Vid->enc_frame_picture[p_Vid->rd_pass]->stats); + // replace top with frame + if (p_Vid->rd_pass==2) + { + replace_top_pic_with_frame(p_Dpb, p_Vid->enc_frame_picture[2], &p_Inp->output); + free_storable_picture (p_Vid, p_Vid->enc_frame_picture[0]); + free_storable_picture (p_Vid, p_Vid->enc_frame_picture[1]); + } + else if (p_Vid->rd_pass==1) + { + replace_top_pic_with_frame(p_Dpb, p_Vid->enc_frame_picture[1], &p_Inp->output); + free_storable_picture (p_Vid, p_Vid->enc_frame_picture[0]); + free_storable_picture (p_Vid, p_Vid->enc_frame_picture[2]); + } + else + { + if(p_Inp->redundant_pic_flag==0 || (p_Vid->key_frame==0)) + { + replace_top_pic_with_frame(p_Dpb, p_Vid->enc_frame_picture[0], &p_Inp->output); + free_storable_picture (p_Vid, p_Vid->enc_frame_picture[1]); + free_storable_picture (p_Vid, p_Vid->enc_frame_picture[2]); + } + } + free_storable_picture(p_Vid, p_Vid->enc_field_picture[1]); + } + } + else + { + if (p_Vid->fld_flag) + { + update_global_stats(p_Inp, p_Vid->p_Stats, &p_Vid->enc_field_picture[0]->stats); + update_global_stats(p_Inp, p_Vid->p_Stats, &p_Vid->enc_field_picture[1]->stats); + store_picture_in_dpb(p_Dpb, p_Vid->enc_field_picture[1], &p_Inp->output); +#if (MVC_EXTENSION_ENABLE) + if ( is_MVC_profile(profile_idc) && p_Vid->proc_picture) + { + store_proc_picture_in_dpb (p_Vid->p_Dpb_layer[1], p_Vid->proc_picture, &p_Inp->output); + p_Vid->proc_picture = NULL; + } +#endif + } + else + { + if ((p_Inp->redundant_pic_flag != 1) || (p_Vid->key_frame == 0)) + { + update_global_stats(p_Inp, p_Vid->p_Stats, &p_Vid->enc_picture->stats); + store_picture_in_dpb (p_Dpb, p_Vid->enc_picture, &p_Inp->output); + +#if (MVC_EXTENSION_ENABLE) + if ( is_MVC_profile(profile_idc) && p_Vid->proc_picture) + { + store_proc_picture_in_dpb (p_Vid->p_Dpb_layer[1], p_Vid->proc_picture, &p_Inp->output); + p_Vid->proc_picture = NULL; + } +#endif + free_pictures(p_Vid, -1); + } + } + } +} + +void update_bitcounter_stats(VideoParameters *p_Vid) +{ + p_Vid->p_Stats->bit_ctr_n = p_Vid->p_Stats->bit_ctr; + p_Vid->p_Stats->bit_ctr_parametersets_n = 0; + p_Vid->p_Stats->bit_ctr_filler_data_n = p_Vid->p_Stats->bit_ctr_filler_data; + +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + if ( p_Vid->fld_flag ) + { + if ( p_Vid->view_id == 1 ) + { + p_Vid->p_Stats->bit_ctr_parametersets_v[0] += p_Vid->p_Stats->bit_ctr_parametersets_n_v[0]; + p_Vid->p_Stats->bit_ctr_parametersets_v[1] += p_Vid->p_Stats->bit_ctr_parametersets_n_v[1]; + p_Vid->p_Stats->bit_ctr_n_v[0] = p_Vid->p_Stats->bit_ctr_v[0]; + p_Vid->p_Stats->bit_ctr_n_v[1] = p_Vid->p_Stats->bit_ctr_v[1]; + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0] = 0; + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1] = 0; + p_Vid->p_Stats->bit_ctr_filler_data_n_v[0] = p_Vid->p_Stats->bit_ctr_filler_data_v[0]; + p_Vid->p_Stats->bit_ctr_filler_data_n_v[1] = p_Vid->p_Stats->bit_ctr_filler_data_v[1]; + } + } + else // this seems to be enough and the check above seems redundant...check later... + { + p_Vid->p_Stats->bit_ctr_parametersets_v[p_Vid->view_id] += p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id]; + p_Vid->p_Stats->bit_ctr_n_v[p_Vid->view_id] = p_Vid->p_Stats->bit_ctr_v[p_Vid->view_id]; + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] = 0; + p_Vid->p_Stats->bit_ctr_filler_data_n_v[p_Vid->view_id] = p_Vid->p_Stats->bit_ctr_filler_data_v[p_Vid->view_id]; + } + } +#endif +} + +void update_idr_order_stats(VideoParameters *p_Vid) +{ + if ( p_Vid->fld_flag ) // need to check both fields here + { + // top field picture + if ( p_Vid->p_curr_frm_struct->p_top_fld_pic->p_Slice[0].type == I_SLICE && p_Vid->p_curr_frm_struct->p_top_fld_pic->nal_ref_idc) + { + p_Vid->lastINTRA = imax(p_Vid->lastINTRA, p_Vid->frame_no); + p_Vid->lastIntraNumber = p_Vid->curr_frm_idx; + if ( p_Vid->p_curr_frm_struct->p_top_fld_pic->idr_flag ) + { + p_Vid->last_idr_disp_order = imax( p_Vid->frame_no, p_Vid->last_idr_disp_order ); + p_Vid->last_idr_code_order = p_Vid->curr_frm_idx; + } + } + // bottom field picture + if ( p_Vid->p_curr_frm_struct->p_bot_fld_pic->p_Slice[0].type == I_SLICE && p_Vid->p_curr_frm_struct->p_bot_fld_pic->nal_ref_idc) + { + p_Vid->lastINTRA = imax(p_Vid->lastINTRA, p_Vid->frame_no); + p_Vid->lastIntraNumber = p_Vid->curr_frm_idx; + if ( p_Vid->p_curr_frm_struct->p_bot_fld_pic->idr_flag ) + { + p_Vid->last_idr_disp_order = imax( p_Vid->frame_no, p_Vid->last_idr_disp_order ); + p_Vid->last_idr_code_order = p_Vid->curr_frm_idx; + } + } + } + else + { + // frame picture + if ( p_Vid->p_curr_frm_struct->p_frame_pic->p_Slice[0].type == I_SLICE && p_Vid->p_curr_frm_struct->p_frame_pic->nal_ref_idc) + { + p_Vid->lastINTRA = imax(p_Vid->lastINTRA, p_Vid->frame_no); + p_Vid->lastIntraNumber = p_Vid->curr_frm_idx; + if ( p_Vid->p_curr_frm_struct->p_frame_pic->idr_flag ) + { + p_Vid->last_idr_disp_order = imax( p_Vid->frame_no, p_Vid->last_idr_disp_order ); + p_Vid->last_idr_code_order = p_Vid->curr_frm_idx; + } + } + } +} + +int update_video_stats(VideoParameters *p_Vid) +{ + int bits = 0; + InputParameters *p_Inp = p_Vid->p_Inp; + + //Rate control + if(p_Inp->RCEnable) + { + if ((!p_Inp->PicInterlace) && (!p_Inp->MbInterlace)) + { + bits = (int) (p_Vid->p_Stats->bit_ctr - p_Vid->p_Stats->bit_ctr_n) + + (int)( p_Vid->p_Stats->bit_ctr_filler_data - p_Vid->p_Stats->bit_ctr_filler_data_n ); + } + else if ( p_Inp->RCUpdateMode <= MAX_RC_MODE ) + { + bits = (int)(p_Vid->p_Stats->bit_ctr - (p_Vid->p_rc_quad->Pprev_bits)) + + (int)( p_Vid->p_Stats->bit_ctr_filler_data - p_Vid->p_Stats->bit_ctr_filler_data_n ); // used for rate control update + p_Vid->p_rc_quad->Pprev_bits = p_Vid->p_Stats->bit_ctr + p_Vid->p_Stats->bit_ctr_filler_data; + } + else + { + bits = (int) (p_Vid->p_Stats->bit_ctr - p_Vid->p_Stats->bit_ctr_n) + + (int)( p_Vid->p_Stats->bit_ctr_filler_data - p_Vid->p_Stats->bit_ctr_filler_data_n ); + } + } + + p_Vid->p_Stats->bit_counter[p_Vid->type] += p_Vid->p_Stats->bit_ctr - p_Vid->p_Stats->bit_ctr_n; + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->num_of_views == 2 ) + { + if ( p_Vid->fld_flag ) + { + if ( p_Vid->view_id == 1 ) + { + int prev_type = (p_Vid->p_pred->p_frm_mvc + ( (p_Vid->curr_frm_idx << 1) % p_Vid->p_pred->num_frames_mvc ))->type; + + p_Vid->p_Stats->bit_counter_v[0][prev_type] += p_Vid->p_Stats->bit_ctr_v[0] - p_Vid->p_Stats->bit_ctr_n_v[0]; + p_Vid->p_Stats->bit_counter_v[1][p_Vid->type] += p_Vid->p_Stats->bit_ctr_v[1] - p_Vid->p_Stats->bit_ctr_n_v[1]; + } + } + else + { + p_Vid->p_Stats->bit_counter_v[p_Vid->view_id][p_Vid->type] += p_Vid->p_Stats->bit_ctr_v[p_Vid->view_id] - p_Vid->p_Stats->bit_ctr_n_v[p_Vid->view_id]; + } + } +#endif + + return bits; +} + +/*! + ************************************************************************ + * \brief + * Encodes one frame + ************************************************************************ + */ +int encode_one_frame (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i; + int nplane; + + //Rate control + int bits = 0; + + TIME_T start_time; + TIME_T end_time; + int64 tmp_time; + + p_Vid->me_time = 0; + p_Vid->rd_pass = 0; + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplaneenc_frame_picture_JV[nplane] = NULL; + } + } + + for (i = 0; i < 6; i++) + p_Vid->enc_frame_picture[i] = NULL; + + gettime(&start_time); // start time in ms + + //Rate control + p_Vid->write_macroblock = FALSE; + /* + //Shankar Regunathan (Oct 2002) + //Prepare Panscanrect SEI payload + UpdatePanScanRectInfo (p_SEI); + //Prepare Arbitrarydata SEI Payload + UpdateUser_data_unregistered (p_SEI); + //Prepare Registered data SEI Payload + UpdateUser_data_registered_itu_t_t35 (p_SEI); + //Prepare RandomAccess SEI Payload + UpdateRandomAccess (p_Vid); + */ + + put_buffer_frame (p_Vid); // sets the pointers to the frame structures + // (and not to one of the field structures) + init_frame (p_Vid, p_Inp); + + if (p_Inp->enable_32_pulldown) + { + if ( !read_input_data_32pulldown (p_Vid) ) + { + return 0; + } + } + else + { + if ( !read_input_data (p_Vid) ) + { + return 0; + } + } + + process_image(p_Vid, p_Inp); + pad_borders (p_Inp->output, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr, p_Vid->imgData.frm_data); + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==1 || p_Vid->view_id==0) + { + p_Vid->field_pic_ptr = p_Vid->field_pic1; + } + else + { + p_Vid->field_pic_ptr = p_Vid->field_pic2; + } +#endif + + + // Following code should consider optimal coding mode. Currently also does not support + // multiple slices per frame. + p_Vid->p_Dist->frame_ctr++; +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + p_Vid->p_Dist->frame_ctr_v[p_Vid->view_id]++; + } +#endif + + if(p_Vid->type == SP_SLICE) + { + if(p_Inp->sp2_frame_indicator) + { // switching SP frame encoding + p_Vid->sp2_frame_indicator = TRUE; + read_SP_coefficients(p_Vid, p_Inp); + } + } + else + { + p_Vid->sp2_frame_indicator = FALSE; + } + + if ( p_Inp->WPMCPrecision ) + { + wpxInitWPXPasses(p_Vid, p_Inp); + p_Vid->pWPX->curr_wp_rd_pass = p_Vid->pWPX->wp_rd_passes; + p_Vid->pWPX->curr_wp_rd_pass->algorithm = WP_REGULAR; + } + + if (p_Inp->PicInterlace == FIELD_CODING) + perform_encode_field(p_Vid); + else + perform_encode_frame(p_Vid); + + p_Vid->p_Stats->frame_counter++; + p_Vid->p_Stats->frame_ctr[p_Vid->type]++; + + // Here, p_Vid->structure may be either FRAME or BOTTOM FIELD depending on whether AFF coding is used + // The picture structure decision changes really only the fld_flag + write_frame_picture(p_Vid); + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + { + // view_id 1 will follow view_id 0 anchor_pic_flag value + if((p_Vid->anchor_pic_flag[0]==1) && (p_Vid->view_id&1)==0) + { + p_Vid->prev_view_is_anchor = 1; + } + else + { + p_Vid->prev_view_is_anchor = 0; + } + } +#endif + + //Need slice data for deblocking in UpdateDecoders + if (p_Inp->PicInterlace == FRAME_CODING) + { + if ((p_Inp->rdopt == 3) && (p_Inp->de == LLN) && (p_Vid->nal_reference_idc != 0)) + { + UpdateDecoders (p_Vid, p_Inp, p_Vid->enc_picture); // simulate packet losses and move decoded image to reference buffers + } + + if (p_Inp->RestrictRef) + UpdatePixelMap (p_Vid, p_Inp); + } + +#if OUTPUT_REF_LIST + { + int i; + printf( " [L0]: " ); + for ( i = 0; icurrentSlice->listXsize[0]; i++ ) + { + printf( "%d ", p_Vid->currentSlice->listX[0][i]->poc / 2 ); // may not work with field + } + printf( " [L1]: " ); + for ( i = 0; icurrentSlice->listXsize[1]; i++ ) + { + printf( "%d ", p_Vid->currentSlice->listX[1][i]->poc / 2 ); // may not work with field + } + printf("\n"); + } +#endif + + free_slice_data(p_Vid); + + //Rate control + if ( p_Inp->RCEnable ) + { + // we could add here a function pointer! + bits = (int)( p_Vid->p_Stats->bit_ctr - p_Vid->p_Stats->bit_ctr_n ) + + (int)( p_Vid->p_Stats->bit_ctr_filler_data - p_Vid->p_Stats->bit_ctr_filler_data_n ); + + if ( p_Inp->RCUpdateMode <= MAX_RC_MODE ) + p_Vid->rc_update_pict_frame_ptr(p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_gen, bits); + + } + + compute_distortion(p_Vid, &p_Vid->imgData); + + // redundant pictures: save reconstruction to calculate SNR and replace reference picture + if(p_Inp->redundant_pic_flag) + { + storeRedundantFrame(p_Vid); + } + + //printf("view_id:%d, frame_num:%d, poc:%d\n", p_Vid->view_id, (int)p_Vid->enc_picture->frame_num, p_Vid->enc_picture->poc); + store_coded_picture(p_Vid->p_Dpb_layer[p_Vid->view_id]); + + + p_Vid->AverageFrameQP = isign(p_Vid->SumFrameQP) * ((iabs(p_Vid->SumFrameQP) + (int) (p_Vid->FrameSizeInMbs >> 1))/ (int) p_Vid->FrameSizeInMbs); + + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE && p_Vid->type != B_SLICE && p_Inp->basicunit < p_Vid->FrameSizeInMbs ) + p_Vid->p_rc_quad->CurrLastQP = p_Vid->AverageFrameQP + p_Vid->p_rc_quad->bitdepth_qp_scale; + +#ifdef _LEAKYBUCKET_ + // Store bits used for this frame and increment counter of no. of coded frames + if (!p_Vid->redundant_coding) + { + p_Vid->Bit_Buffer[p_Vid->total_frame_buffer++] = (long) (p_Vid->p_Stats->bit_ctr - p_Vid->p_Stats->bit_ctr_n) + + (long)( p_Vid->p_Stats->bit_ctr_filler_data - p_Vid->p_Stats->bit_ctr_filler_data_n ); + } +#endif + + // POC200301: Verify that POC coding type 2 is not used if more than one consecutive + // non-reference frame is requested or if decoding order is different from output order + if (p_Vid->pic_order_cnt_type == 2) + { + if (!p_Vid->nal_reference_idc) + p_Vid->consecutive_non_reference_pictures++; + else + p_Vid->consecutive_non_reference_pictures = 0; + + if (p_Vid->frame_no < p_Vid->prev_frame_no || p_Vid->consecutive_non_reference_pictures>1) + error("POC type 2 cannot be applied for the coding pattern where the encoding /decoding order of pictures are different from the output order.\n", -1); + p_Vid->prev_frame_no = p_Vid->frame_no; + } + + gettime(&end_time); // end time in ms + tmp_time = timediff(&start_time, &end_time); + p_Vid->tot_time += tmp_time; + tmp_time = timenorm(tmp_time); + p_Vid->me_time = timenorm(p_Vid->me_time); + if (p_Vid->p_Stats->bit_ctr_parametersets_n!=0 && p_Inp->Verbose != 3) + ReportNALNonVLCBits(p_Vid, tmp_time); + +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->curr_frm_idx == 0 && !p_Vid->view_id) +#else + if (p_Vid->curr_frm_idx == 0) +#endif + ReportFirstframe(p_Vid, tmp_time); + else + { + bits = update_video_stats(p_Vid); + + switch (p_Vid->type) + { + case I_SLICE: + case SI_SLICE: + ReportI(p_Vid, tmp_time); + break; + case B_SLICE: + ReportB(p_Vid, tmp_time); + break; + case SP_SLICE: + ReportP(p_Vid, tmp_time); + break; + case P_SLICE: + default: + ReportP(p_Vid, tmp_time); + } + } + + if (p_Inp->Verbose == 0) + { + //for (i = 0; i <= (p_Vid->number & 0x0F); i++) + //printf("."); + //printf(" \r"); + printf("Completed Encoding Frame %05d.\r", p_Vid->frame_no); + } + // Flush output statistics + fflush(stdout); + + //Rate control + if(p_Inp->RCEnable) + p_Vid->rc_update_picture_ptr( p_Vid, p_Inp, bits ); + + // update bit counters + update_bitcounter_stats(p_Vid); + + update_idr_order_stats(p_Vid); + + return 1; +} + + +/*! + ************************************************************************ + * \brief + * This function write out a picture + * \return + * 0 if OK, \n + * 1 in case of error + * + ************************************************************************ + */ +#if (MVC_EXTENSION_ENABLE) +static void writeout_picture(VideoParameters *p_Vid, Picture *pic, int is_bottom) +{ + int partition, slice, bits; + Slice *currSlice; + NALU_t *nalu = NULL; + + p_Vid->currentPicture = pic; + + // loop over all slices of the picture + for (slice=0; slice < pic->no_slices; slice++) + { + currSlice = pic->slices[slice]; + + // loop over the partitions + for (partition=0; partition < currSlice->max_part_nr; partition++) + { + // write only if the partition has content + if ( currSlice->partArr[partition].bitstream->write_flag ) + { + if(p_Vid->p_Inp->num_of_views==2 && p_Vid->view_id==0) + { + nalu = AllocNALU(64000); + nalu->startcodeprefix_len = 4; + nalu->nal_unit_type = NALU_TYPE_PREFIX; + nalu->nal_reference_idc = NALU_PRIORITY_HIGHEST; + nalu->svc_extension_flag = 0; + nalu->non_idr_flag = p_Vid->non_idr_flag[is_bottom]; + nalu->priority_id = p_Vid->priority_id; + nalu->view_id = p_Vid->view_id; + nalu->temporal_id = p_Vid->temporal_id; + nalu->anchor_pic_flag = p_Vid->anchor_pic_flag[is_bottom]; + nalu->inter_view_flag = p_Vid->inter_view_flag[is_bottom]; + nalu->reserved_one_bit = 1; + + bits = p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + p_Vid->p_Stats->bit_ctr += bits; + p_Vid->p_Stats->bit_ctr_v[0] += bits; + FreeNALU(nalu); + } + + bits = p_Vid->WriteNALU (p_Vid, currSlice->partArr[partition].nal_unit, p_Vid->f_out); + p_Vid->p_Stats->bit_ctr += bits; + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + p_Vid->p_Stats->bit_ctr_v[p_Vid->view_id] += bits; + } + } + } + } +} +#else +static void writeout_picture(VideoParameters *p_Vid, Picture *pic) +{ + int partition, slice, bits; + Slice *currSlice; + + p_Vid->currentPicture = pic; + + // loop over all slices of the picture + for (slice=0; slice < pic->no_slices; slice++) + { + currSlice = pic->slices[slice]; + + // loop over the partitions + for (partition=0; partition < currSlice->max_part_nr; partition++) + { + // write only if the partition has content + if (currSlice->partArr[partition].bitstream->write_flag ) + { + bits = p_Vid->WriteNALU (p_Vid, currSlice->partArr[partition].nal_unit, p_Vid->f_out); + p_Vid->p_Stats->bit_ctr += bits; + + } + } + } +} +#endif + +void copy_params(VideoParameters *p_Vid, StorablePicture *enc_picture, seq_parameter_set_rbsp_t *active_sps) +{ + enc_picture->frame_mbs_only_flag = active_sps->frame_mbs_only_flag; + enc_picture->frame_cropping_flag = active_sps->frame_cropping_flag; + enc_picture->chroma_format_idc = active_sps->chroma_format_idc; + enc_picture->chroma_mask_mv_x = p_Vid->chroma_mask_mv_x; + enc_picture->chroma_mask_mv_y = p_Vid->chroma_mask_mv_y; + enc_picture->chroma_shift_y = p_Vid->chroma_shift_y; + enc_picture->chroma_shift_x = p_Vid->chroma_shift_x; + enc_picture->otf_flag = p_Vid->p_Inp->OnTheFlyFractMCP; + + if (active_sps->frame_cropping_flag) + { + enc_picture->frame_crop_left_offset = active_sps->frame_crop_left_offset; + enc_picture->frame_crop_right_offset = active_sps->frame_crop_right_offset; + enc_picture->frame_crop_top_offset = active_sps->frame_crop_top_offset; + enc_picture->frame_crop_bottom_offset = active_sps->frame_crop_bottom_offset; + } + else + { + enc_picture->frame_crop_left_offset = 0; + enc_picture->frame_crop_right_offset = 0; + enc_picture->frame_crop_top_offset = 0; + enc_picture->frame_crop_bottom_offset = 0; + } +} + +/*! + ************************************************************************ + * \brief + * Prepare and allocate an encoded frame picture structure + ************************************************************************ + */ +static void prepare_enc_frame_picture (VideoParameters *p_Vid, StorablePicture **stored_pic) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + (*stored_pic) = alloc_storable_picture (p_Vid, (PictureStructure) p_Vid->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr); + + p_Vid->ThisPOC = p_Vid->framepoc; + (*stored_pic)->poc = p_Vid->framepoc; + (*stored_pic)->top_poc = p_Vid->toppoc; + (*stored_pic)->bottom_poc = p_Vid->bottompoc; + (*stored_pic)->frame_poc = p_Vid->framepoc; + (*stored_pic)->pic_num = p_Vid->frame_num; + (*stored_pic)->frame_num = p_Vid->frame_num; + (*stored_pic)->coded_frame = 1; + (*stored_pic)->mb_aff_frame_flag = p_Vid->mb_aff_frame_flag = (Boolean) (p_Inp->MbInterlace != FRAME_CODING); + + p_Vid->get_mb_block_pos = p_Vid->mb_aff_frame_flag ? get_mb_block_pos_mbaff : get_mb_block_pos_normal; + p_Vid->getNeighbour = p_Vid->mb_aff_frame_flag ? getAffNeighbour : getNonAffNeighbour; + p_Vid->enc_picture = *stored_pic; + + copy_params(p_Vid, p_Vid->enc_picture, p_Vid->active_sps); +} + +static void calc_picture_bits(Picture *frame) +{ + int i, j; + Slice *thisSlice = NULL; + + frame->bits_per_picture = 0; + + for ( i = 0; i < frame->no_slices; i++ ) + { + thisSlice = frame->slices[i]; + + for ( j = 0; j < thisSlice->max_part_nr; j++ ) + frame->bits_per_picture += 8 * ((thisSlice->partArr[j]).bitstream)->byte_pos; + } +} + +/*! + ************************************************************************ + * \brief + * Encodes a frame picture + ************************************************************************ + */ +void frame_picture (VideoParameters *p_Vid, Picture *frame, ImageData *imgData, int rd_pass) +{ + int nplane; + InputParameters *p_Inp = p_Vid->p_Inp; + p_Vid->rd_pass = rd_pass; + p_Vid->SumFrameQP = 0; + p_Vid->num_ref_idx_l0_active = 0; + p_Vid->num_ref_idx_l1_active = 0; + p_Vid->p_curr_pic = p_Vid->p_curr_frm_struct->p_frame_pic; + p_Vid->structure = FRAME; + p_Vid->PicSizeInMbs = p_Vid->FrameSizeInMbs; + //set mv limits to frame type + update_mv_limits(p_Vid, FALSE); + + InitWP(p_Vid, p_Inp, 0); + if(rd_pass == 0 && p_Vid->wp_parameters_set == 0) + ResetWP(p_Vid, p_Inp); + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplaneenc_frame_picture_JV[nplane] ); + } + } + else + { + prepare_enc_frame_picture( p_Vid, &p_Vid->enc_frame_picture[rd_pass] ); + } + + p_Vid->fld_flag = FALSE; + code_a_picture(p_Vid, frame); + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + make_frame_picture_JV(p_Vid); + } + + calc_picture_bits(frame); + + if (p_Vid->structure==FRAME) + { + find_distortion (p_Vid, imgData); + frame->distortion = p_Vid->p_Dist->metric[SSE]; + } +} + + +/*! + ************************************************************************ + * \brief + * Encodes a field picture, consisting of top and bottom field + ************************************************************************ + */ +static void field_picture (VideoParameters *p_Vid, Picture *top, Picture *bottom) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + //Rate control + int TopFieldBits; + + p_Vid->SumFrameQP = 0; + p_Vid->num_ref_idx_l0_active = 0; + p_Vid->num_ref_idx_l1_active = 0; + + //set mv limits to field type + update_mv_limits(p_Vid, TRUE); + + p_Vid->height = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom) >> 1; + p_Vid->height_cr = p_Vid->height_cr_frame >> 1; + p_Vid->fld_flag = TRUE; + p_Vid->PicSizeInMbs = p_Vid->FrameSizeInMbs >> 1; + // Top field + + p_Vid->enc_field_picture[0] = alloc_storable_picture (p_Vid, (PictureStructure) p_Vid->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr); + p_Vid->enc_field_picture[0]->poc = p_Vid->toppoc; + p_Vid->enc_field_picture[0]->frame_poc = p_Vid->toppoc; + /*Potentially buggy to not divide by num_of_layers */ + p_Vid->enc_field_picture[0]->pic_num = p_Vid->frame_num; + p_Vid->enc_field_picture[0]->frame_num = p_Vid->frame_num; + p_Vid->enc_field_picture[0]->coded_frame = 0; + p_Vid->enc_field_picture[0]->mb_aff_frame_flag = p_Vid->mb_aff_frame_flag = FALSE; + p_Vid->get_mb_block_pos = get_mb_block_pos_normal; + p_Vid->getNeighbour = getNonAffNeighbour; + p_Vid->ThisPOC = p_Vid->toppoc; + + p_Vid->p_curr_pic = p_Vid->p_curr_frm_struct->p_top_fld_pic; + p_Vid->structure = TOP_FIELD; + p_Vid->enc_picture = p_Vid->enc_field_picture[0]; + copy_params(p_Vid, p_Vid->enc_picture, p_Vid->active_sps); + + put_buffer_top (p_Vid); + init_field (p_Vid, p_Inp); + set_slice_type(p_Vid, p_Inp, p_Vid->p_curr_pic->p_Slice[0].type); + + p_Vid->fld_flag = TRUE; + + //Rate control + if(p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE) + rc_init_top_field(p_Vid, p_Inp); + + code_a_picture(p_Vid, top); + p_Vid->enc_picture->structure = TOP_FIELD; + store_picture_in_dpb(p_Vid->p_Dpb_layer[p_Vid->view_id], p_Vid->enc_field_picture[0], &p_Inp->output); + +#if (MVC_EXTENSION_ENABLE) + if ( is_MVC_profile(p_Vid->active_sps->profile_idc) && p_Vid->proc_picture) + { + store_proc_picture_in_dpb (p_Vid->p_Dpb_layer[1], p_Vid->proc_picture, &p_Inp->output); + p_Vid->proc_picture = NULL; + } +#endif + calc_picture_bits(top); + + //Rate control + TopFieldBits=top->bits_per_picture; + + // Bottom field + p_Vid->enc_field_picture[1] = alloc_storable_picture (p_Vid, (PictureStructure) p_Vid->structure, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr); + p_Vid->enc_field_picture[1]->poc=p_Vid->bottompoc; + p_Vid->enc_field_picture[1]->frame_poc = p_Vid->bottompoc; + p_Vid->enc_field_picture[1]->pic_num = p_Vid->frame_num; + p_Vid->enc_field_picture[1]->frame_num = p_Vid->frame_num; + p_Vid->enc_field_picture[1]->coded_frame = 0; + p_Vid->enc_field_picture[1]->mb_aff_frame_flag = p_Vid->mb_aff_frame_flag = FALSE; + p_Vid->get_mb_block_pos = get_mb_block_pos_normal; + p_Vid->getNeighbour = getNonAffNeighbour; + + p_Vid->ThisPOC = p_Vid->bottompoc; + p_Vid->p_curr_pic = p_Vid->p_curr_frm_struct->p_bot_fld_pic; + p_Vid->structure = BOTTOM_FIELD; + p_Vid->enc_picture = p_Vid->enc_field_picture[1]; + copy_params(p_Vid, p_Vid->enc_picture, p_Vid->active_sps); + put_buffer_bot (p_Vid); + + init_field (p_Vid, p_Inp); + set_slice_type(p_Vid, p_Inp, p_Vid->p_curr_pic->p_Slice[0].type); + + p_Vid->fld_flag = TRUE; + + //Rate control + if(p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE) + rc_init_bottom_field( p_Vid, p_Inp, TopFieldBits ); + + p_Vid->enc_picture->structure = BOTTOM_FIELD; + code_a_picture(p_Vid, bottom); + + calc_picture_bits(bottom); + + // the distortion for a field coded frame (consisting of top and bottom field) + // lives in the top->distortion variables, the bottom-> are dummies + distortion_fld (p_Vid, p_Inp, top, &p_Vid->imgData); +} + +/*! + ************************************************************************ + * \brief + * form frame picture from two field pictures + ************************************************************************ + */ +static void combine_field(VideoParameters *p_Vid) +{ + int i, k; + + for (i = 0; i < (p_Vid->height >> 1); i++) + { + memcpy(p_Vid->imgY_com[i*2], p_Vid->enc_field_picture[0]->imgY[i], p_Vid->width*sizeof(imgpel)); // top field + memcpy(p_Vid->imgY_com[i*2 + 1], p_Vid->enc_field_picture[1]->imgY[i], p_Vid->width*sizeof(imgpel)); // bottom field + } + + if (p_Vid->yuv_format != YUV400) + { + for (k = 0; k < 2; k++) + { + for (i = 0; i < (p_Vid->height_cr >> 1); i++) + { + memcpy(p_Vid->imgUV_com[k][i * 2], p_Vid->enc_field_picture[0]->imgUV[k][i], p_Vid->width_cr*sizeof(imgpel)); + memcpy(p_Vid->imgUV_com[k][i * 2 + 1], p_Vid->enc_field_picture[1]->imgUV[k][i], p_Vid->width_cr*sizeof(imgpel)); + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Distortion Field + ************************************************************************ + */ +static void distortion_fld (VideoParameters *p_Vid, InputParameters *p_Inp, Picture *field_pic, ImageData *imgData) +{ + p_Vid->height = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom); + p_Vid->height_cr = p_Vid->height_cr_frame; + + combine_field (p_Vid); + + p_Vid->pCurImg = imgData->frm_data[0]; + p_Vid->pImgOrg[0] = imgData->frm_data[0]; + + if (p_Inp->output.yuv_format != YUV400) + { + p_Vid->pImgOrg[1] = imgData->frm_data[1]; + p_Vid->pImgOrg[2] = imgData->frm_data[2]; + } + + find_distortion (p_Vid, imgData); // find snr from original frame picture + field_pic->distortion = p_Vid->p_Dist->metric[SSE]; +} + + +/*! + ************************************************************************ + * \brief + * RD decision of frame and field coding + ************************************************************************ + */ +static byte decide_fld_frame(float snr_frame_Y, float snr_field_Y, int bit_field, int bit_frame, double lambda_picture) +{ + double cost_frame, cost_field; + + cost_frame = bit_frame * lambda_picture + snr_frame_Y; + cost_field = bit_field * lambda_picture + snr_field_Y; + + if (cost_field > cost_frame) + return FALSE; + else + return TRUE; +} + +/*! + ************************************************************************ + * \brief + * Picture Structure Decision + ************************************************************************ + */ +static byte picture_structure_decision (VideoParameters *p_Vid, Picture *frame, Picture *top, Picture *bot) +{ + double lambda_picture; + float sse_frame, sse_field; + int bit_frame, bit_field; + + lambda_picture = 0.68 * pow (2, p_Vid->bitdepth_lambda_scale + ((p_Vid->qp - SHIFT_QP) / 3.0)) * ((p_Vid->type == B_SLICE) ? 1 : 1); + + sse_frame = frame->distortion.value[0] + frame->distortion.value[1] + frame->distortion.value[2]; + //! all distrortions of a field picture are accumulated in the top field + sse_field = top->distortion.value[0] + top->distortion.value[1] + top->distortion.value[2]; + + bit_field = top->bits_per_picture + bot->bits_per_picture; + bit_frame = frame->bits_per_picture; + return decide_fld_frame (sse_frame, sse_field, bit_field, bit_frame, lambda_picture); +} + + +/*! + ************************************************************************ + * \brief + * Field Mode Buffer + ************************************************************************ + */ +static void field_mode_buffer (VideoParameters *p_Vid) +{ + put_buffer_frame (p_Vid); +} + + +/*! + ************************************************************************ + * \brief + * Frame Mode Buffer + ************************************************************************ + */ +static void frame_mode_buffer (VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + put_buffer_frame (p_Vid); + + if ((p_Inp->PicInterlace != FRAME_CODING)||(p_Inp->MbInterlace != FRAME_CODING)) + { + p_Vid->height = p_Vid->height / 2; + p_Vid->height_cr = p_Vid->height_cr / 2; + + put_buffer_top (p_Vid); + + put_buffer_bot (p_Vid); + + p_Vid->height = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom); + p_Vid->height_cr = p_Vid->height_cr_frame; + + put_buffer_frame (p_Vid); + } +} + + +/*! + ************************************************************************ + * \brief + * mmco initializations should go here + ************************************************************************ + */ +static void init_dec_ref_pic_marking_buffer(VideoParameters *p_Vid) +{ + p_Vid->dec_ref_pic_marking_buffer=NULL; +} + +/*! +************************************************************************ +* \brief +* Init fixed QP I_SLICE +************************************************************************ +*/ + +static inline void init_fixed_qp_i_slice(VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_cur_frm ) +{ + //QP oscillation for secondary SP frames + p_Vid->qp = p_cur_frm->qp; // set quant. parameter for I-frame + + if (p_Vid->redundant_coding) + { + //!KS: hard code qp increment + p_Vid->qp = imin(p_Vid->qp + 5, 51); + } +} + +/*! +************************************************************************ +* \brief +* Init fixed QP P_SLICE or B_SLICE +************************************************************************ +*/ + +static inline void init_fixed_qp_pb_slice(VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_cur_frm, int type ) +{ + //QP oscillation for secondary SP frames + p_Vid->qp = p_cur_frm->qp; + +} + +/*! +************************************************************************ +* \brief +* Init fixed QP SP_SLICE +************************************************************************ +*/ + +static inline void init_fixed_qp_sp_slice(VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_cur_frm ) +{ + p_Vid->qp = p_cur_frm->qp; + p_Vid->qpsp = p_Inp->qpsp; +} + +/*! +************************************************************************ +* \brief +* Initializes the quantization parameters for a new frame (no RC) +* ***Much of what happens in this function have to be moved elsewhere...*** +************************************************************************ +*/ + +static void init_fixed_qp(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + + if (p_cur_frm->layer == 0) + { + switch( p_cur_frm->type ) + { + default: + case I_SLICE: + init_fixed_qp_i_slice( p_Vid, p_Inp, p_cur_frm ); + break; + case P_SLICE: + case B_SLICE: + init_fixed_qp_pb_slice( p_Vid, p_Inp, p_cur_frm, p_cur_frm->type ); + break; + case SP_SLICE: + case SI_SLICE: + init_fixed_qp_sp_slice( p_Vid, p_Inp, p_cur_frm ); + break; + } + + p_Vid->mb_y_intra = p_Vid->mb_y_upd; // p_Vid->mb_y_intra indicates which GOB to intra code for this frame + + if (p_Inp->intra_upd > 0) // if error robustness, find next GOB to update + { + p_Vid->mb_y_upd = (p_Vid->curr_frm_idx / p_Inp->intra_upd) % (p_Vid->height / MB_BLOCK_SIZE); + } + } + else + { + p_Vid->qp = p_cur_frm->qp; + } + + // Change QP + if ( p_Inp->qp2frame && p_Inp->qp2frame < p_Vid->frame_no ) + { + p_Vid->p_curr_frm_struct->qp = p_Vid->qp = iClip3( -p_Vid->bitdepth_luma_qp_scale, MAX_QP, p_Vid->qp + p_Inp->qp2off[p_cur_frm->type] ); + } +} + +/*! + ************************************************************************ + * \brief + * Initializes the quantization parameters for a new frame (no RC) + ************************************************************************ + */ + +static void init_mb_line_intra_up(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + + if (p_cur_frm->layer == 0) + { + p_Vid->mb_y_intra = p_Vid->mb_y_upd; // p_Vid->mb_y_intra indicates which GOB to intra code for this frame + + if (p_Inp->intra_upd > 0) // if error robustness, find next GOB to update + { + p_Vid->mb_y_upd = (p_Vid->curr_frm_idx / p_Inp->intra_upd) % (p_Vid->width / MB_BLOCK_SIZE); + } + } +} + +/*! + ************************************************************************ + * \brief + * Initializes the parameters for a new frame + ************************************************************************ + */ +static void init_frame (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i, j; + + p_Vid->current_mb_nr = 0; + p_Vid->current_slice_nr = 0; + p_Vid->p_Stats->bit_slice = 0; + + // The 'slice_nr' of each macroblock is set to -1 here, to guarantee the correct encoding + // with FMO (if no FMO, encoding is correct without following assignment), + // for which MBs may not be encoded with scan order + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( j = 0; j < MAX_PLANE; j++ ){ + for(i = 0; i < ((int) (p_Vid->FrameSizeInMbs));i++) + p_Vid->mb_data_JV[j][i].slice_nr = -1; + } + } + else + { + for(i = 0; i < ((int) (p_Vid->FrameSizeInMbs)); i++) + p_Vid->mb_data[i].slice_nr = -1; + } + + if ( !(p_Inp->RCEnable) ) + { + init_fixed_qp(p_Vid, p_Inp); + } + init_mb_line_intra_up(p_Vid, p_Inp); + + p_Vid->no_output_of_prior_pics_flag = 0; + p_Vid->long_term_reference_flag = FALSE; + + init_dec_ref_pic_marking_buffer(p_Vid); + + if(p_Inp->WPIterMC) + p_Vid->frameOffsetAvail = 0; + + // set parameters for direct mode and deblocking filter + // currently selection is done at the frame level instead of slice level. This needs to be changed. + p_Vid->direct_spatial_mv_pred_flag = (char) p_Inp->direct_spatial_mv_pred_flag; +#if (MVC_EXTENSION_ENABLE) + if ( (p_Inp->num_of_views == 1) || (p_Vid->view_id == 0) ) +#endif + { + p_Vid->DFDisableIdc = (char) p_Inp->DFDisableIdc[p_Vid->nal_reference_idc > 0][p_Vid->type]; + p_Vid->DFAlphaC0Offset = (char) p_Inp->DFAlpha [p_Vid->nal_reference_idc > 0][p_Vid->type]; + p_Vid->DFBetaOffset = (char) p_Inp->DFBeta [p_Vid->nal_reference_idc > 0][p_Vid->type]; + } +#if (MVC_EXTENSION_ENABLE) + else + { + p_Vid->DFDisableIdc = (char) p_Inp->EnhLayerDFDisableIdc[p_Vid->nal_reference_idc > 0][p_Vid->type]; + p_Vid->DFAlphaC0Offset = (char) p_Inp->EnhLayerDFAlpha [p_Vid->nal_reference_idc > 0][p_Vid->type]; + p_Vid->DFBetaOffset = (char) p_Inp->EnhLayerDFBeta [p_Vid->nal_reference_idc > 0][p_Vid->type]; + } +#endif + p_Vid->AdaptiveRounding = p_Inp->AdaptiveRounding; +} + +/*! + ************************************************************************ + * \brief + * Initializes the parameters for a new field + ************************************************************************ + */ +static void init_field (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + + p_Vid->current_mb_nr = 0; + p_Vid->current_slice_nr = 0; + p_Vid->p_Stats->bit_slice = 0; + + if (!p_cur_frm->layer) + { + if(!p_Inp->RCEnable) // without using rate control + { + p_Vid->qp = p_cur_frm->qp; + if (p_Vid->type == SP_SLICE || p_Vid->type == SI_SLICE) + { + p_Vid->qpsp = p_Inp->qpsp; + } + } + init_mb_line_intra_up( p_Vid, p_Inp ); + } + else + { + if(!p_Inp->RCEnable) + { + p_Vid->qp = p_cur_frm->qp; + } + } +} + +/*! + ************************************************************************ + * \brief + * Upsample 4 times, store them in out4x. Color is simply copied + * + * \par Input: + * srcy, srcu, srcv, out4y, out4u, out4v + * + * \par Side Effects_ + * Uses (writes) img4Y_tmp. This should be moved to a static variable + * in this module + ************************************************************************/ +void UnifiedOneForthPix ( VideoParameters *p_Vid, StorablePicture *s) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + if(s->bInterpolated) + return; + s->bInterpolated = 1; + // Y component + s->p_img_sub[0] = s->imgY_sub; + s->p_curr_img_sub = s->imgY_sub; + s->p_curr_img = s->imgY; + + // derive the subpixel images for first component + // No need to interpolate if intra only encoding + //if (p_Inp->intra_period != 1) + if ( (!p_Inp->OnTheFlyFractMCP) || (p_Inp->OnTheFlyFractMCP==OTF_L1) ) // JLT : on-the-fly + { + getSubImagesLuma ( p_Vid, s ); + // and the sub-images for U and V + if ( ((p_Vid->yuv_format != YUV400) && (p_Inp->ChromaMCBuffer)) || p_Vid->P444_joined ) + { + if (p_Vid->P444_joined) + { + imgpel **** p_curr_img_sub = s->p_curr_img_sub; + imgpel ** p_curr_img = s->p_curr_img; + //U + select_plane(p_Vid, PLANE_U); + s->p_curr_img_sub = s->imgUV_sub[0]; + s->p_curr_img = s->imgUV[0]; + getSubImagesLuma (p_Vid, s); + //V + select_plane(p_Vid, PLANE_V); + s->p_curr_img_sub = s->imgUV_sub[1]; + s->p_curr_img = s->imgUV[1]; + getSubImagesLuma (p_Vid, s); + //Y + select_plane(p_Vid, PLANE_Y); + s->p_curr_img_sub = p_curr_img_sub; + s->p_curr_img = p_curr_img; + } + else + { + getSubImagesChroma( p_Vid, s ); + } + } + } + else + { + // perform padding ( copying borders) that is implicitly done above if p_Inp->OnTheFlyFractMCP=0 + OtfCompatibility_copyWithPadding( s->imgY, s->imgY, s->size_x, s->size_y, IMG_PAD_SIZE_X, IMG_PAD_SIZE_Y ) ; + OtfCompatibility_copyWithPadding( s->imgUV[0], s->imgUV[0], s->size_x_cr, s->size_y_cr, p_Vid->pad_size_uv_x,p_Vid->pad_size_uv_y ) ; + OtfCompatibility_copyWithPadding( s->imgUV[1], s->imgUV[1], s->size_x_cr, s->size_y_cr, p_Vid->pad_size_uv_x, p_Vid->pad_size_uv_y ) ; + } +} + +/*! + ************************************************************************ + * \brief + * Upsample 4 times, store them in out4x. Color is simply copied + * for 4:4:4 Independent mode + * + * \par Input: + * nplane + * + ************************************************************************/ +void UnifiedOneForthPix_JV (VideoParameters *p_Vid, int nplane, StorablePicture *s) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + if( nplane == 0 ) + { + if(s->bInterpolated) + return; + s->bInterpolated = 1; + s->p_img[0] = s->imgY; + s->p_img[1] = s->imgUV[0]; + s->p_img[2] = s->imgUV[1]; + + if ( (!p_Inp->OnTheFlyFractMCP) || (p_Inp->OnTheFlyFractMCP==OTF_L1) ) // JLT : on-the-fly + { + s->p_img_sub[0] = s->imgY_sub; + s->p_img_sub[1] = s->imgUV_sub[0]; + s->p_img_sub[2] = s->imgUV_sub[1]; + } + } + + // derive the subpixel images for first component + s->colour_plane_id = nplane; + s->p_curr_img = s->p_img[nplane]; + s->p_curr_img_sub = s->p_img_sub[nplane]; + + if( (!p_Inp->OnTheFlyFractMCP) || (p_Inp->OnTheFlyFractMCP==OTF_L1) ) + { + getSubImagesLuma ( p_Vid, s ); + } + else + { + // perform padding ( copying borders) that is implicitly done above if p_Inp->OnTheFlyFractMCP=0 + OtfCompatibility_copyWithPadding( s->p_img[nplane], s->p_img[nplane], s->size_x, s->size_y, IMG_PAD_SIZE_X, IMG_PAD_SIZE_Y ) ; + } +} + + /*! + ************************************************************************ + * \brief + * Just a placebo + ************************************************************************ + */ +Boolean dummy_slice_too_big (int bits_slice) +{ + return FALSE; +} + +static void ReportSimple(VideoParameters *p_Vid, char *pic_type, int cur_bits, DistMetric *metric, int tmp_time) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + if ( p_Vid->fld_flag && p_Vid->view_id == 0 ) + { + p_Vid->prev_cs.frm_no_in_file = p_Vid->frm_no_in_file; + p_Vid->prev_cs.view_id = p_Vid->view_id; + p_Vid->prev_cs.cur_bits = cur_bits; + strcpy( p_Vid->prev_cs.pic_type, pic_type ); + p_Vid->prev_cs.AverageFrameQP = p_Vid->AverageFrameQP; + p_Vid->prev_cs.lambda = 0; + p_Vid->prev_cs.psnr_value[0] = metric->value[0]; + p_Vid->prev_cs.psnr_value[1] = metric->value[1]; + p_Vid->prev_cs.psnr_value[2] = metric->value[2]; + p_Vid->prev_cs.ssim_value[0] = 0; + p_Vid->prev_cs.ssim_value[1] = 0; + p_Vid->prev_cs.ssim_value[2] = 0; + p_Vid->prev_cs.tmp_time = tmp_time; + p_Vid->prev_cs.me_time = (int)p_Vid->me_time; + p_Vid->prev_cs.fld_flag = p_Vid->fld_flag; + p_Vid->prev_cs.intras = p_Vid->intras; + p_Vid->prev_cs.direct_mode = 0; + p_Vid->prev_cs.num_ref_idx_l0_active = p_Vid->num_ref_idx_l0_active; + p_Vid->prev_cs.num_ref_idx_l1_active = p_Vid->num_ref_idx_l1_active; + p_Vid->prev_cs.rd_pass = p_Vid->rd_pass; + p_Vid->prev_cs.nal_reference_idc = p_Vid->nal_reference_idc; + } + else if ( p_Vid->fld_flag && p_Vid->view_id == 1 ) + { + printf ("%05d(%3s) %1d %8d %2d %7.3f %7.3f %7.3f %9d %7d %3s %d\n", + p_Vid->prev_cs.frm_no_in_file, p_Vid->prev_cs.pic_type, p_Vid->prev_cs.view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[0] - p_Vid->p_Stats->bit_ctr_n_v[0]) + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[0] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[0]), + p_Vid->prev_cs.AverageFrameQP, + p_Vid->prev_cs.psnr_value[0], p_Vid->prev_cs.psnr_value[1], p_Vid->prev_cs.psnr_value[2], + p_Vid->prev_cs.tmp_time, (int) p_Vid->prev_cs.me_time, + p_Vid->prev_cs.fld_flag ? "FLD" : "FRM", + p_Vid->prev_cs.nal_reference_idc); + printf ("%05d(%3s) %1d %8d %2d %7.3f %7.3f %7.3f %9d %7d %3s %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[1] - p_Vid->p_Stats->bit_ctr_n_v[1]) + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[1] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[1]), + p_Vid->AverageFrameQP, + metric->value[0], metric->value[1], metric->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", + p_Vid->nal_reference_idc); + } + else + { + printf ("%05d(%3s) %1d %8d %2d %7.3f %7.3f %7.3f %9d %7d %3s %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, + p_Vid->AverageFrameQP, + metric->value[0], metric->value[1], metric->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", + p_Vid->nal_reference_idc); + } + } + else +#endif + printf ("%05d(%3s)%8d %2d %7.3f %7.3f %7.3f %9d %7d %3s %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, + p_Vid->AverageFrameQP, + metric->value[0], metric->value[1], metric->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", + p_Vid->nal_reference_idc); +} + +static void ReportVerbose(VideoParameters *p_Vid, char *pic_type, int cur_bits, int wp_method, int lambda, DistMetric *mPSNR, int tmp_time, int direct_mode) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + if ( p_Vid->fld_flag && p_Vid->view_id == 0 ) + { + p_Vid->prev_cs.frm_no_in_file = p_Vid->frm_no_in_file; + p_Vid->prev_cs.view_id = p_Vid->view_id; + p_Vid->prev_cs.cur_bits = cur_bits; + strcpy( p_Vid->prev_cs.pic_type, pic_type ); + p_Vid->prev_cs.AverageFrameQP = p_Vid->AverageFrameQP; + p_Vid->prev_cs.lambda = 0; + p_Vid->prev_cs.psnr_value[0] = mPSNR->value[0]; + p_Vid->prev_cs.psnr_value[1] = mPSNR->value[1]; + p_Vid->prev_cs.psnr_value[2] = mPSNR->value[2]; + p_Vid->prev_cs.ssim_value[0] = 0; + p_Vid->prev_cs.ssim_value[1] = 0; + p_Vid->prev_cs.ssim_value[2] = 0; + p_Vid->prev_cs.tmp_time = tmp_time; + p_Vid->prev_cs.me_time = (int)p_Vid->me_time; + p_Vid->prev_cs.fld_flag = p_Vid->fld_flag; + p_Vid->prev_cs.intras = p_Vid->intras; + p_Vid->prev_cs.direct_mode = direct_mode; + p_Vid->prev_cs.num_ref_idx_l0_active = p_Vid->num_ref_idx_l0_active; + p_Vid->prev_cs.num_ref_idx_l1_active = p_Vid->num_ref_idx_l1_active; + p_Vid->prev_cs.rd_pass = p_Vid->rd_pass; + p_Vid->prev_cs.nal_reference_idc = p_Vid->nal_reference_idc; + } + else if ( p_Vid->fld_flag && p_Vid->view_id == 1 ) + { + printf ("%05d(%3s) %1d %8d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->prev_cs.frm_no_in_file, p_Vid->prev_cs.pic_type, p_Vid->prev_cs.view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[0] - p_Vid->p_Stats->bit_ctr_n_v[0]) + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[0] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[0]), + p_Vid->prev_cs.wp_method, p_Vid->prev_cs.AverageFrameQP, p_Vid->prev_cs.lambda, + p_Vid->prev_cs.psnr_value[0], p_Vid->prev_cs.psnr_value[1], p_Vid->prev_cs.psnr_value[2], + p_Vid->prev_cs.tmp_time, (int) p_Vid->prev_cs.me_time, + p_Vid->prev_cs.fld_flag ? "FLD" : "FRM", p_Vid->prev_cs.intras, p_Vid->prev_cs.direct_mode, + p_Vid->prev_cs.num_ref_idx_l0_active, p_Vid->prev_cs.num_ref_idx_l1_active, p_Vid->prev_cs.rd_pass, p_Vid->prev_cs.nal_reference_idc); + printf ("%05d(%3s) %1d %8d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[1] - p_Vid->p_Stats->bit_ctr_n_v[1]) + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[1] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[1]), wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + else + { + printf ("%05d(%3s) %1d %8d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + } + else +#endif + { + printf ("%05d(%3s)%8d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } +} + +static void ReportVerboseNVB(VideoParameters *p_Vid, char *pic_type, int cur_bits, int nvb_bits, int wp_method, int lambda, DistMetric *mPSNR, int tmp_time, int direct_mode) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->num_of_layers == 2 ) + { + if ( p_Vid->fld_flag && p_Vid->view_id == 0 ) + { + p_Vid->prev_cs.frm_no_in_file = p_Vid->frm_no_in_file; + p_Vid->prev_cs.view_id = p_Vid->view_id; + p_Vid->prev_cs.cur_bits = cur_bits; + strcpy( p_Vid->prev_cs.pic_type, pic_type ); + p_Vid->prev_cs.AverageFrameQP = p_Vid->AverageFrameQP; + p_Vid->prev_cs.lambda = 0; + p_Vid->prev_cs.psnr_value[0] = mPSNR->value[0]; + p_Vid->prev_cs.psnr_value[1] = mPSNR->value[1]; + p_Vid->prev_cs.psnr_value[2] = mPSNR->value[2]; + p_Vid->prev_cs.ssim_value[0] = 0; + p_Vid->prev_cs.ssim_value[1] = 0; + p_Vid->prev_cs.ssim_value[2] = 0; + p_Vid->prev_cs.tmp_time = tmp_time; + p_Vid->prev_cs.me_time = (int)p_Vid->me_time; + p_Vid->prev_cs.fld_flag = p_Vid->fld_flag; + p_Vid->prev_cs.intras = p_Vid->intras; + p_Vid->prev_cs.direct_mode = direct_mode; + p_Vid->prev_cs.num_ref_idx_l0_active = p_Vid->num_ref_idx_l0_active; + p_Vid->prev_cs.num_ref_idx_l1_active = p_Vid->num_ref_idx_l1_active; + p_Vid->prev_cs.rd_pass = p_Vid->rd_pass; + p_Vid->prev_cs.nal_reference_idc = p_Vid->nal_reference_idc; + } + else if ( p_Vid->fld_flag && p_Vid->view_id == 1 ) + { + printf ("%05d(%3s) %1d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->prev_cs.frm_no_in_file, p_Vid->prev_cs.pic_type, p_Vid->prev_cs.view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[0] - p_Vid->p_Stats->bit_ctr_n_v[0]) + + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[0] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[0]) + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0], + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0], p_Vid->prev_cs.wp_method, p_Vid->prev_cs.AverageFrameQP, p_Vid->prev_cs.lambda, + p_Vid->prev_cs.psnr_value[0], p_Vid->prev_cs.psnr_value[1], p_Vid->prev_cs.psnr_value[2], + p_Vid->prev_cs.tmp_time, (int) p_Vid->prev_cs.me_time, + p_Vid->prev_cs.fld_flag ? "FLD" : "FRM", p_Vid->prev_cs.intras, p_Vid->prev_cs.direct_mode, + p_Vid->prev_cs.num_ref_idx_l0_active, p_Vid->prev_cs.num_ref_idx_l1_active, p_Vid->prev_cs.rd_pass, p_Vid->prev_cs.nal_reference_idc); + printf ("%05d(%3s) %1d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[1] - p_Vid->p_Stats->bit_ctr_n_v[1]) + + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[1] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[1]) + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1], + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1], wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + else + { + printf ("%05d(%3s) %1d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc, p_Vid->iInterViewMBs); + } + } + else +#endif + { + printf ("%05d(%3s)%8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + + } +} + +static void ReportVerboseFDN(VideoParameters *p_Vid, char *pic_type, int cur_bits, int fdn_bits, int nvb_bits, int wp_method, int lambda, DistMetric *mPSNR, int tmp_time, int direct_mode) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + if ( p_Vid->fld_flag && p_Vid->view_id == 0 ) + { + p_Vid->prev_cs.frm_no_in_file = p_Vid->frm_no_in_file; + p_Vid->prev_cs.view_id = p_Vid->view_id; + p_Vid->prev_cs.cur_bits = cur_bits; + strcpy( p_Vid->prev_cs.pic_type, pic_type ); + p_Vid->prev_cs.AverageFrameQP = p_Vid->AverageFrameQP; + p_Vid->prev_cs.lambda = 0; + p_Vid->prev_cs.psnr_value[0] = mPSNR->value[0]; + p_Vid->prev_cs.psnr_value[1] = mPSNR->value[1]; + p_Vid->prev_cs.psnr_value[2] = mPSNR->value[2]; + p_Vid->prev_cs.ssim_value[0] = 0; + p_Vid->prev_cs.ssim_value[1] = 0; + p_Vid->prev_cs.ssim_value[2] = 0; + p_Vid->prev_cs.tmp_time = tmp_time; + p_Vid->prev_cs.me_time = (int)p_Vid->me_time; + p_Vid->prev_cs.fld_flag = p_Vid->fld_flag; + p_Vid->prev_cs.intras = p_Vid->intras; + p_Vid->prev_cs.direct_mode = direct_mode; + p_Vid->prev_cs.num_ref_idx_l0_active = p_Vid->num_ref_idx_l0_active; + p_Vid->prev_cs.num_ref_idx_l1_active = p_Vid->num_ref_idx_l1_active; + p_Vid->prev_cs.rd_pass = p_Vid->rd_pass; + p_Vid->prev_cs.nal_reference_idc = p_Vid->nal_reference_idc; + } + else if ( p_Vid->fld_flag && p_Vid->view_id == 1 ) + { + printf ("%05d(%3s) %1d %8d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->prev_cs.frm_no_in_file, p_Vid->prev_cs.pic_type, p_Vid->prev_cs.view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[0] - p_Vid->p_Stats->bit_ctr_n_v[0]) + + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[0] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[0]) + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0], + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[0] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[0]), + p_Vid->p_Stats->bit_ctr_parametersets_n_v[0], + p_Vid->prev_cs.wp_method, p_Vid->prev_cs.AverageFrameQP, p_Vid->prev_cs.lambda, + p_Vid->prev_cs.psnr_value[0], p_Vid->prev_cs.psnr_value[1], p_Vid->prev_cs.psnr_value[2], + p_Vid->prev_cs.tmp_time, (int) p_Vid->prev_cs.me_time, + p_Vid->prev_cs.fld_flag ? "FLD" : "FRM", p_Vid->prev_cs.intras, p_Vid->prev_cs.direct_mode, + p_Vid->prev_cs.num_ref_idx_l0_active, p_Vid->prev_cs.num_ref_idx_l1_active, p_Vid->prev_cs.rd_pass, p_Vid->prev_cs.nal_reference_idc); + printf ("%05d(%3s) %1d %8d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, + (int)(p_Vid->p_Stats->bit_ctr_v[1] - p_Vid->p_Stats->bit_ctr_n_v[1]) + + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[1] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[1]) + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1], + (int)(p_Vid->p_Stats->bit_ctr_filler_data_v[1] - p_Vid->p_Stats->bit_ctr_filler_data_n_v[1]), + p_Vid->p_Stats->bit_ctr_parametersets_n_v[1], + wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + else + { + printf ("%05d(%3s) %1d %8d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, fdn_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + } + else +#endif + { + printf ("%05d(%3s)%8d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, fdn_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } +} + +static void ReportVerboseSSIM(VideoParameters *p_Vid, char *pic_type, int cur_bits, int wp_method, int lambda, DistMetric *mPSNR, DistMetric *mSSIM,int tmp_time, int direct_mode) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + printf ("%05d(%3s) %1d %8d %1d %2d %4d %7.3f %7.3f %7.3f %7.4f %7.4f %7.4f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + mSSIM->value[0], mSSIM->value[1], mSSIM->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active,p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + else +#endif + { + printf ("%05d(%3s)%8d %1d %2d %4d %7.3f %7.3f %7.3f %7.4f %7.4f %7.4f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + mSSIM->value[0], mSSIM->value[1], mSSIM->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active,p_Vid->rd_pass, p_Vid->nal_reference_idc); + } +} + +static void ReportVerboseNVBSSIM(VideoParameters *p_Vid, char *pic_type, int cur_bits, int nvb_bits, int wp_method, int lambda, DistMetric *mPSNR, DistMetric *mSSIM,int tmp_time, int direct_mode) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + printf ("%05d(%3s) %1d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %7.4f %7.4f %7.4f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + mSSIM->value[0], mSSIM->value[1], mSSIM->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + else +#endif + { + printf ("%05d(%3s)%8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %7.4f %7.4f %7.4f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + mSSIM->value[0], mSSIM->value[1], mSSIM->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } +} + +static void ReportVerboseFDNSSIM(VideoParameters *p_Vid, char *pic_type, int cur_bits, int fdn_bits, int nvb_bits, int wp_method, int lambda, DistMetric *mPSNR, DistMetric *mSSIM,int tmp_time, int direct_mode) +{ +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->p_Inp->num_of_views == 2 ) + { + printf ("%05d(%3s) %1d %8d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %7.4f %7.4f %7.4f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, p_Vid->view_id, cur_bits, fdn_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + mSSIM->value[0], mSSIM->value[1], mSSIM->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } + else +#endif + { + printf ("%05d(%3s)%8d %8d %3d %1d %2d %4d %7.3f %7.3f %7.3f %7.4f %7.4f %7.4f %9d %7d %3s %5d %1d %2d %2d %d %d\n", + p_Vid->frm_no_in_file, pic_type, cur_bits, fdn_bits, nvb_bits, wp_method, + p_Vid->AverageFrameQP, lambda, + mPSNR->value[0], mPSNR->value[1], mPSNR->value[2], + mSSIM->value[0], mSSIM->value[1], mSSIM->value[2], + tmp_time, (int) p_Vid->me_time, + p_Vid->fld_flag ? "FLD" : "FRM", p_Vid->intras, direct_mode, + p_Vid->num_ref_idx_l0_active, p_Vid->num_ref_idx_l1_active, p_Vid->rd_pass, p_Vid->nal_reference_idc); + } +} + + +static void ReportNALNonVLCBits(VideoParameters *p_Vid, int64 tmp_time) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + StatParameters *p_Stats = p_Vid->p_Stats; + + //! Need to add type (i.e. SPS, PPS, SEI etc). +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + if (p_Inp->Verbose != 0) + printf ("%05d(NVB) %8d \n", p_Vid->frame_no, p_Stats->bit_ctr_parametersets_n); + } + else +#endif + { + if (p_Inp->Verbose != 0) + printf ("%05d(NVB)%8d \n", p_Vid->frame_no, p_Stats->bit_ctr_parametersets_n); + } +} + +static void ReportFirstframe(VideoParameters *p_Vid, int64 tmp_time) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + StatParameters *stats = p_Vid->p_Stats; + + int cur_bits = (int)(stats->bit_ctr - stats->bit_ctr_n) + + (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n); + + if (p_Inp->Verbose == 1) + { + ReportSimple(p_Vid, "IDR", cur_bits, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time); + } + else if (p_Inp->Verbose == 2) + { + int lambda = (int) p_Vid->lambda_me[I_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseSSIM(p_Vid, "IDR", cur_bits, 0, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + else + ReportVerbose(p_Vid, "IDR", cur_bits, 0, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + else if (p_Inp->Verbose == 3) + { + int lambda = (int) p_Vid->lambda_me[I_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseNVBSSIM(p_Vid, "IDR", cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + else + ReportVerboseNVB(p_Vid, "IDR", cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + else if (p_Inp->Verbose == 4) + { + int lambda = (int) p_Vid->lambda_me[I_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseFDNSSIM(p_Vid, "IDR", cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + else + ReportVerboseFDN(p_Vid, "IDR", cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + + stats->bit_counter[I_SLICE] = stats->bit_ctr; +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->num_of_views == 2 ) + { + if ( !p_Vid->fld_flag ) + { + stats->bit_counter_v[p_Vid->view_id][I_SLICE] = stats->bit_ctr; + } + stats->bit_ctr_v[0] = 0; + stats->bit_ctr_v[1] = 0; + } +#endif + stats->bit_ctr = 0; +} + +static void ReportI(VideoParameters *p_Vid, int64 tmp_time) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + StatParameters *stats = p_Vid->p_Stats; + char pic_type[4]; + int cur_bits = (int)(stats->bit_ctr - stats->bit_ctr_n) + + (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n); + + if ((p_Inp->redundant_pic_flag == 0) || !p_Vid->redundant_coding ) + { + if (p_Vid->currentPicture->idr_flag == TRUE) + strcpy(pic_type,"IDR"); + else if ( p_Vid->type == SI_SLICE ) + strcpy(pic_type,"SI "); + else + strcpy(pic_type," I "); + } + else + strcpy(pic_type,"R"); + + if (p_Inp->Verbose == 1) + { + ReportSimple(p_Vid, pic_type, cur_bits, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time); + } + else if (p_Inp->Verbose == 2) + { + int lambda = (int) p_Vid->lambda_me[I_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + { + ReportVerboseSSIM(p_Vid, pic_type, cur_bits, 0, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + } + else + { + ReportVerbose(p_Vid, pic_type, cur_bits, 0, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + } + else if (p_Inp->Verbose == 3) + { + int lambda = (int) p_Vid->lambda_me[I_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + { + ReportVerboseNVBSSIM(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + } + else + { + ReportVerboseNVB(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + } + else if (p_Inp->Verbose == 4) + { + int lambda = (int) p_Vid->lambda_me[I_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + { + ReportVerboseFDNSSIM(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + } + else + { + ReportVerboseFDN(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, 0, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + } +} + +static void ReportB(VideoParameters *p_Vid, int64 tmp_time) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + StatParameters *stats = p_Vid->p_Stats; + + int cur_bits = (int)(stats->bit_ctr - stats->bit_ctr_n) + + (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n); + + if (p_Inp->Verbose == 1) + { + ReportSimple(p_Vid, " B ", cur_bits, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time); + } + else if (p_Inp->Verbose == 2) + { + int lambda = (int) p_Vid->lambda_me[B_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseSSIM(p_Vid, " B ", cur_bits, p_Vid->active_pps->weighted_bipred_idc, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, p_Vid->direct_spatial_mv_pred_flag); + else + ReportVerbose(p_Vid, " B ", cur_bits, p_Vid->active_pps->weighted_bipred_idc, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, p_Vid->direct_spatial_mv_pred_flag); + } + else if (p_Inp->Verbose == 3) + { + int lambda = (int) p_Vid->lambda_me[B_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseNVBSSIM(p_Vid, " B ", cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_bipred_idc, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, p_Vid->direct_spatial_mv_pred_flag); + else + ReportVerboseNVB(p_Vid, " B ", cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_bipred_idc, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, p_Vid->direct_spatial_mv_pred_flag); + } + else if (p_Inp->Verbose == 4) + { + int lambda = (int) p_Vid->lambda_me[B_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseFDNSSIM(p_Vid, " B ", cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_bipred_idc, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, p_Vid->direct_spatial_mv_pred_flag); + else + ReportVerboseFDN(p_Vid, " B ", cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_bipred_idc, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, p_Vid->direct_spatial_mv_pred_flag); + } +} + +static void ReportP(VideoParameters *p_Vid, int64 tmp_time) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + StatParameters *stats = p_Vid->p_Stats; + + char pic_type[4]; + int cur_bits = (int)(stats->bit_ctr - stats->bit_ctr_n) + + (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n); + + if (p_Vid->type == SP_SLICE) + strcpy(pic_type,"SP "); + else if ((p_Inp->redundant_pic_flag == 0) || !p_Vid->redundant_coding ) + strcpy(pic_type," P "); + else + strcpy(pic_type," R "); + + if (p_Inp->Verbose == 1) + { + ReportSimple(p_Vid, pic_type, cur_bits, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time); + } + else if (p_Inp->Verbose == 2) + { + int lambda = (int) p_Vid->lambda_me[P_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseSSIM(p_Vid, pic_type, cur_bits, p_Vid->active_pps->weighted_pred_flag, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + else + ReportVerbose(p_Vid, pic_type, cur_bits, p_Vid->active_pps->weighted_pred_flag, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + else if (p_Inp->Verbose == 3) + { + int lambda = (int) p_Vid->lambda_me[P_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseNVBSSIM(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_pred_flag, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + else + ReportVerboseNVB(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_pred_flag, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } + else if (p_Inp->Verbose == 4) + { + int lambda = (int) p_Vid->lambda_me[P_SLICE][p_Vid->masterQP][F_PEL]; + if (p_Inp->Distortion[SSIM] == 1) + ReportVerboseFDNSSIM(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_pred_flag, lambda, &p_Vid->p_Dist->metric[PSNR], &p_Vid->p_Dist->metric[SSIM], (int) tmp_time, 0); + else + ReportVerboseFDN(p_Vid, pic_type, cur_bits + stats->bit_ctr_parametersets_n, (int)(stats->bit_ctr_filler_data - stats->bit_ctr_filler_data_n), stats->bit_ctr_parametersets_n, p_Vid->active_pps->weighted_pred_flag, lambda, &p_Vid->p_Dist->metric[PSNR], (int) tmp_time, 0); + } +} + +/*! + ************************************************************************ + * \brief + * point to frame coding variables + ************************************************************************ + */ +static void put_buffer_frame(VideoParameters *p_Vid) +{ + p_Vid->pCurImg = p_Vid->imgData.frm_data[0]; + p_Vid->pImgOrg[0] = p_Vid->imgData.frm_data[0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrg[1] = p_Vid->imgData.frm_data[1]; + p_Vid->pImgOrg[2] = p_Vid->imgData.frm_data[2]; + } + + if (p_Vid->p_Inp->MDReference[0] || p_Vid->p_Inp->MDReference[1]) + { + p_Vid->pCurImgRef = p_Vid->imgRefData.frm_data[0]; + p_Vid->pImgOrgRef[0] = p_Vid->imgRefData.frm_data[0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrgRef[1] = p_Vid->imgRefData.frm_data[1]; + p_Vid->pImgOrgRef[2] = p_Vid->imgRefData.frm_data[2]; + } + } +} + +/*! + ************************************************************************ + * \brief + * point to top field coding variables + ************************************************************************ + */ +static void put_buffer_top(VideoParameters *p_Vid) +{ + p_Vid->fld_type = 0; + + p_Vid->pCurImg = p_Vid->imgData.top_data[0]; + p_Vid->pImgOrg[0] = p_Vid->imgData.top_data[0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrg[1] = p_Vid->imgData.top_data[1]; + p_Vid->pImgOrg[2] = p_Vid->imgData.top_data[2]; + } + + if ( p_Vid->p_Inp->MDReference[0] || p_Vid->p_Inp->MDReference[1] ) + { + p_Vid->pCurImgRef = p_Vid->imgRefData.top_data[0]; + p_Vid->pImgOrgRef[0] = p_Vid->imgRefData.top_data[0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrgRef[1] = p_Vid->imgRefData.top_data[1]; + p_Vid->pImgOrgRef[2] = p_Vid->imgRefData.top_data[2]; + } + } +} + +/*! + ************************************************************************ + * \brief + * point to bottom field coding variables + ************************************************************************ + */ +static void put_buffer_bot(VideoParameters *p_Vid) +{ + p_Vid->fld_type = 1; + + p_Vid->pCurImg = p_Vid->imgData.bot_data[0]; + p_Vid->pImgOrg[0] = p_Vid->imgData.bot_data[0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrg[1] = p_Vid->imgData.bot_data[1]; + p_Vid->pImgOrg[2] = p_Vid->imgData.bot_data[2]; + } + + if ( p_Vid->p_Inp->MDReference[0] || p_Vid->p_Inp->MDReference[1] ) + { + p_Vid->pCurImgRef = p_Vid->imgRefData.bot_data[0]; + p_Vid->pImgOrgRef[0] = p_Vid->imgRefData.bot_data[0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrgRef[1] = p_Vid->imgRefData.bot_data[1]; + p_Vid->pImgOrgRef[2] = p_Vid->imgRefData.bot_data[2]; + } + } +} + +/*! +************************************************************************************* +* Brief +* Output SP frames coefficients +************************************************************************************* +*/ +void output_SP_coefficients(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i,k; + FILE *SP_coeff_file; + int ret; + if(p_Vid->number_sp2_frames==0) + { + if ((SP_coeff_file = fopen(p_Inp->sp_output_filename,"wb")) == NULL) + { + printf ("Fatal: cannot open SP output file '%s', exit (-1)\n", p_Inp->sp_output_filename); + exit (-1); + } + p_Vid->number_sp2_frames++; + } + else + { + if ((SP_coeff_file = fopen(p_Inp->sp_output_filename,"ab")) == NULL) + { + printf ("Fatal: cannot open SP output file '%s', exit (-1)\n", p_Inp->sp_output_filename); + exit (-1); + } + } + + for(i=0;iheight;i++) + { + ret = (int) fwrite(p_Vid->lrec[i], sizeof(int), p_Vid->width, SP_coeff_file); + if (ret != p_Vid->width) + { + error ("cannot write to SP output file", -1); + } + } + + for(k=0;k<2;k++) + { + for(i=0;iheight_cr;i++) + { + ret = (int) fwrite(p_Vid->lrec_uv[k][i], sizeof(int), p_Vid->width_cr, SP_coeff_file); + if (ret != p_Vid->width_cr) + { + error ("cannot write to SP output file", -1); + } + } + } + fclose(SP_coeff_file); +} + +/*! +************************************************************************************* +* Brief +* Read SP frames coefficients +************************************************************************************* +*/ +void read_SP_coefficients(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i,k; + FILE *SP_coeff_file; + + if ( p_Inp->sp_switch_period > 0 && ( p_Vid->number_sp2_frames % (p_Inp->sp_switch_period << 1) ) >= p_Inp->sp_switch_period ) + { + if ((SP_coeff_file = fopen(p_Inp->sp2_input_filename1,"rb")) == NULL) + { + printf ("Fatal: cannot open SP input file '%s', exit (-1)\n", p_Inp->sp2_input_filename2); + exit (-1); + } + } + else + { + if ((SP_coeff_file = fopen(p_Inp->sp2_input_filename2,"rb")) == NULL) + { + printf ("Fatal: cannot open SP input file '%s', exit (-1)\n", p_Inp->sp2_input_filename1); + exit (-1); + } + } + + if (0 != fseek (SP_coeff_file, p_Vid->size * 3/2*p_Vid->number_sp2_frames*sizeof(int), SEEK_SET)) + { + printf ("Fatal: cannot seek in SP input file, exit (-1)\n"); + exit (-1); + } + p_Vid->number_sp2_frames++; + + for(i=0;iheight;i++) + { + if(p_Vid->width!=(int)fread(p_Vid->lrec[i],sizeof(int),p_Vid->width,SP_coeff_file)) + { + printf ("Fatal: cannot read in SP input file, exit (-1)\n"); + exit (-1); + } + } + + for(k=0;k<2;k++) + { + for(i=0;iheight_cr;i++) + { + if(p_Vid->width_cr!=(int)fread(p_Vid->lrec_uv[k][i],sizeof(int),p_Vid->width_cr,SP_coeff_file)) + { + printf ("Fatal: cannot read in SP input file, exit (-1)\n"); + exit (-1); + } + } + } + fclose(SP_coeff_file); +} + + +/*! +************************************************************************************* +* Brief +* Select appropriate image plane (for 444 coding) +************************************************************************************* +*/ +void select_plane(VideoParameters *p_Vid, ColorPlane color_plane) +{ + p_Vid->pCurImg = p_Vid->pImgOrg[color_plane]; + p_Vid->enc_picture->p_curr_img = p_Vid->enc_picture->p_img[color_plane]; + p_Vid->enc_picture->p_curr_img_sub = p_Vid->enc_picture->p_img_sub[color_plane]; + p_Vid->max_imgpel_value = (short) p_Vid->max_pel_value_comp[color_plane]; + p_Vid->dc_pred_value = p_Vid->dc_pred_value_comp[color_plane]; +} + +/*! +************************************************************************************* +* Brief +* Is this picture the first access unit in this GOP? +************************************************************************************* +*/ +static int is_gop_first_unit(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + return ( get_idr_flag(p_Vid) || ( p_Vid->type == I_SLICE && p_Inp->EnableOpenGOP && get_random_access_flag(p_Vid) ) ); +} + +/*! +************************************************************************************* +* Brief +* AUD, SPS, PPS, and SEI messages +************************************************************************************* +*/ +void write_non_vcl_nalu( VideoParameters *p_Vid ) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + // SPS + PPS + AUD + if (p_Inp->ResendSPS == 3 && is_gop_first_unit(p_Vid, p_Inp) && p_Vid->number) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + else if (p_Inp->ResendSPS == 2 && get_idr_flag(p_Vid) && p_Vid->number) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + else if (p_Inp->ResendSPS == 1 && p_Vid->type == I_SLICE && p_Vid->curr_frm_idx != 0) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + // PPS + AUD + else if ( p_Inp->ResendPPS && p_Vid->curr_frm_idx != 0 ) + { + int i, total_pps = p_Inp->GenerateMultiplePPS ? 3 : 1; + + p_Vid->p_Stats->bit_ctr_parametersets_n = 0; + // Access Unit Delimiter NALU + if ( p_Inp->SendAUD ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n = Write_AUD_NALU(p_Vid); + } + for ( i = 0; i < total_pps; i++ ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += write_PPS(p_Vid, 0, i); + } + } + // Access Unit Delimiter NALU + else if ( p_Inp->SendAUD && p_Vid->curr_frm_idx != 0 ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += Write_AUD_NALU(p_Vid); + } + + UpdateSubseqInfo (p_Vid, p_Inp, p_Vid->layer); // Tian Dong (Sept 2002) + UpdateSceneInformation (p_Vid->p_SEI, FALSE, 0, 0, -1); // JVT-D099, scene information SEI, nothing included by default + + //! Commented out by StW, needs fixing in SEI.h to keep the trace file clean + // PrepareAggregationSEIMessage (p_Vid); + + // write tone mapping SEI message + if (p_Inp->ToneMappingSEIPresentFlag) + { + UpdateToneMapping(p_Vid->p_SEI); + } + + // pic timing + ClearPicTiming(p_Vid->p_SEI); + if ( p_Inp->SEIVUI32Pulldown ) + { + UpdatePicTiming(p_Vid, p_Inp); + PrepareAggregationSEIMessage(p_Vid); + p_Vid->p_Stats->bit_ctr_parametersets_n += Write_SEI_NALU(p_Vid, 0); + ClearPicTiming(p_Vid->p_SEI); + // clear message + clear_sei_message(p_Vid->p_SEI, AGGREGATION_SEI); + } + else + { + PrepareAggregationSEIMessage(p_Vid); + } + + p_Vid->p_Stats->bit_ctr_parametersets_n += Write_SEI_NALU(p_Vid, 0); + + // update seq NVB counter + p_Vid->p_Stats->bit_ctr_parametersets += p_Vid->p_Stats->bit_ctr_parametersets_n; +} + +/*! +************************************************************************************* +* Brief +* AUD, SPS, PPS, and SEI messages for the bottom field picture +************************************************************************************* +*/ +void write_non_vcl_nalu_bot_fld( VideoParameters *p_Vid ) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int init_param_set_bits = p_Vid->p_Stats->bit_ctr_parametersets_n; + + // SPS + PPS + AUD + if (p_Inp->ResendSPS == 1 && p_Vid->type == I_SLICE) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + // PPS + AUD + else if ( p_Inp->ResendPPS ) + { + int i, total_pps = p_Inp->GenerateMultiplePPS ? 3 : 1; + + p_Vid->p_Stats->bit_ctr_parametersets_n = 0; + // Access Unit Delimiter NALU + if ( p_Inp->SendAUD ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n = Write_AUD_NALU(p_Vid); + } + for ( i = 0; i < total_pps; i++ ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += write_PPS(p_Vid, 0, i); + } + } + // Access Unit Delimiter NALU + else if ( p_Inp->SendAUD ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += Write_AUD_NALU(p_Vid); + } + + UpdateSubseqInfo (p_Vid, p_Inp, p_Vid->layer); // Tian Dong (Sept 2002) + UpdateSceneInformation (p_Vid->p_SEI, FALSE, 0, 0, -1); // JVT-D099, scene information SEI, nothing included by default + + //! Commented out by StW, needs fixing in SEI.h to keep the trace file clean + // PrepareAggregationSEIMessage (p_Vid); + + // write tone mapping SEI message + if (p_Inp->ToneMappingSEIPresentFlag) + { + UpdateToneMapping(p_Vid->p_SEI); + } + + PrepareAggregationSEIMessage(p_Vid); + + p_Vid->p_Stats->bit_ctr_parametersets_n += Write_SEI_NALU(p_Vid, 0); + + // update seq NVB counter + p_Vid->p_Stats->bit_ctr_parametersets += (p_Vid->p_Stats->bit_ctr_parametersets_n - init_param_set_bits); +} + +void OtfCompatibility_copyWithPadding ( imgpel **dstImg, imgpel **srcImg, int size_x, int size_y, int padding_x, int padding_y ) +{ + int i, j; + int size_x_minus1 = size_x - 1; + + imgpel *wBufSrc, *wBufDst; + + // Copy top line + wBufDst = &( dstImg[-padding_y][-padding_x] ); + wBufSrc = srcImg[0]; + // left IMG_PAD_SIZE + for (i = 0; i < padding_x; ++i) + *(wBufDst++) = wBufSrc[0]; + // center 0-(size_x) + memcpy(wBufDst, wBufSrc, size_x * sizeof(imgpel)); + wBufDst += size_x; + // right IMG_PAD_SIZE + for (i = 0; i < padding_x; ++i) + *(wBufDst++) = wBufSrc[size_x_minus1]; + + // Now copy remaining pad lines + for (j = -padding_y+1; j < 0; ++j) + { + memcpy(dstImg[j]-padding_x, dstImg[j - 1]-padding_x, (size_x+2*padding_x) * sizeof(imgpel)); + } + + for (j = 0; j < size_y; ++j) + { + wBufDst = &( dstImg[j][-padding_x] ); // 4:4:4 independent mode + wBufSrc = srcImg[j]; + // left IMG_PAD_SIZE + for (i = 0; i < padding_x; ++i) + *(wBufDst++) = wBufSrc[0]; + // center 0-(size_x) + //memcpy(wBufDst, wBufSrc, size_x * sizeof(imgpel)); + wBufDst += size_x; + // right IMG_PAD_SIZE + for (i = 0; i < padding_x; ++i) + *(wBufDst++) = wBufSrc[size_x_minus1]; + } + + // Replicate bottom pad lines + for (j = size_y; j < size_y+padding_y; ++j) + { + memcpy(dstImg[j]-padding_x, dstImg[j - 1]-padding_x, (size_x+2*padding_x) * sizeof(imgpel)); + } + +} + +#if (MVC_EXTENSION_ENABLE) +/*! +************************************************************************************* +* Brief +* MVC AUD, SPS, PPS, and SEI messages +************************************************************************************* +*/ +void write_non_vcl_nalu_mvc( VideoParameters *p_Vid ) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int bits; + + if ( p_Vid->view_id ) + { + if ( p_Inp->SendAUD == 2 ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += bits = Write_AUD_NALU(p_Vid); + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] += bits; + } + } + else // view_id == 0 + { + // SPS + PPS + AUD + if (p_Inp->ResendSPS == 3 && is_gop_first_unit(p_Vid, p_Inp) && p_Vid->number && p_Vid->structure != BOTTOM_FIELD) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + else if (p_Inp->ResendSPS == 2 && get_idr_flag(p_Vid) && p_Vid->number && p_Vid->structure != BOTTOM_FIELD) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + else if (p_Inp->ResendSPS == 1 && p_Vid->type == I_SLICE && p_Vid->curr_frm_idx != 0 && p_Vid->structure != BOTTOM_FIELD) + { + p_Vid->p_Stats->bit_slice = rewrite_paramsets(p_Vid); + } + // PPS + AUD + else if ( p_Inp->ResendPPS && p_Vid->curr_frm_idx != 0 ) + { + int i, total_pps = p_Inp->GenerateMultiplePPS ? 3 : 1; + + p_Vid->p_Stats->bit_ctr_parametersets_n = 0; + // Access Unit Delimiter NALU + if ( p_Inp->SendAUD ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n = bits = Write_AUD_NALU(p_Vid); + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] += bits; + for ( i = 0; i < total_pps; i++ ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += bits = write_PPS(p_Vid, 0, i); + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] += bits; + } + } + else + { + for ( i = 0; i < total_pps; i++ ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += bits = write_PPS(p_Vid, 0, i); + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] += bits; + } + } + } + // Access Unit Delimiter NALU + else if ( p_Inp->SendAUD && (p_Vid->curr_frm_idx != 0 || p_Vid->structure == BOTTOM_FIELD) ) + { + p_Vid->p_Stats->bit_ctr_parametersets_n += bits = Write_AUD_NALU(p_Vid); + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] += bits; + } + } + + UpdateSubseqInfo (p_Vid, p_Inp, p_Vid->layer); // Tian Dong (Sept 2002) + UpdateSceneInformation (p_Vid->p_SEI, FALSE, 0, 0, -1); // JVT-D099, scene information SEI, nothing included by default + + //! Commented out by StW, needs fixing in SEI.h to keep the trace file clean + // PrepareAggregationSEIMessage (p_Vid); + + // write tone mapping SEI message + if (p_Inp->ToneMappingSEIPresentFlag) + { + UpdateToneMapping(p_Vid->p_SEI); + } + + PrepareAggregationSEIMessage(p_Vid); + + p_Vid->p_Stats->bit_ctr_parametersets_n += bits = Write_SEI_NALU(p_Vid, 0); + p_Vid->p_Stats->bit_ctr_parametersets_n_v[p_Vid->view_id] += bits; + + // update seq NVB counter + p_Vid->p_Stats->bit_ctr_parametersets += p_Vid->p_Stats->bit_ctr_parametersets_n; +} +#endif + + diff --git a/lencod/src/image_mp.c b/lencod/src/image_mp.c new file mode 100644 index 0000000..b9b5899 --- /dev/null +++ b/lencod/src/image_mp.c @@ -0,0 +1,691 @@ + +/*! + ************************************************************************************* + * \file image.c + * + * \brief + * multiple-pass encoding of one frame + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Yan Ye + ************************************************************************************* + */ +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "rc_quadratic.h" +#include "wp.h" +#include "pred_struct.h" +#include "slice.h" + +#define DBG_IMAGE_MP 0 + +typedef enum +{ + REGULAR = 0, + EXP_WP = 1, + IMP_WP = 2, // only applicable to B + FRAME_TYPE = 2, // only applicable to P + FRAME_QP = 3, + ALT_DIRECT = 4, + ALT_ENTROPY = 5, + DB_OFF = 6, +} FrameCodingMethod; + +void frame_picture_mp_i_slice(VideoParameters *p_Vid, InputParameters *p_Inp); +void frame_picture_mp_p_slice(VideoParameters *p_Vid, InputParameters *p_Inp); +void frame_picture_mp_b_slice(VideoParameters *p_Vid, InputParameters *p_Inp); + +void store_coding_info(VideoParameters *p_Vid, CodingInfo *coding_info) +{ + coding_info->type = p_Vid->type; + coding_info->intras = p_Vid->intras; + coding_info->sumFrameQP = p_Vid->SumFrameQP; + coding_info->num_ref_idx_l0 = p_Vid->num_ref_idx_l0_active; + coding_info->num_ref_idx_l1 = p_Vid->num_ref_idx_l1_active; + coding_info->active_pps = p_Vid->active_pps; +} + +void store_coding_and_rc_info(VideoParameters *p_Vid, CodingInfo *coding_info) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + store_coding_info( p_Vid, coding_info ); + + if ( p_Inp->RCEnable ) + { + rc_save_state( p_Vid, p_Inp ); + } +} + +void restore_coding_info(VideoParameters *p_Vid, CodingInfo *coding_info) +{ + p_Vid->type = coding_info->type; + p_Vid->intras = coding_info->intras; + p_Vid->SumFrameQP = coding_info->sumFrameQP; + p_Vid->num_ref_idx_l0_active = coding_info->num_ref_idx_l0; + p_Vid->num_ref_idx_l1_active = coding_info->num_ref_idx_l1; + p_Vid->active_pps = coding_info->active_pps; +} + +void swap_frame_buffer(VideoParameters *p_Vid, int a, int b) +{ + StorablePicture *s; + Picture *p; + + p = p_Vid->frame_pic[a]; + p_Vid->frame_pic[a] = p_Vid->frame_pic[b]; + p_Vid->frame_pic[b] = p; + + s = p_Vid->enc_frame_picture[a]; + p_Vid->enc_frame_picture[a] = p_Vid->enc_frame_picture[b]; + p_Vid->enc_frame_picture[b] = s; +} + + +void frame_picture_mp_exit(VideoParameters *p_Vid, CodingInfo *coding_info) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + p_Vid->enc_picture=p_Vid->enc_frame_picture[0]; + p_Vid->p_frame_pic = p_Vid->frame_pic[0]; + restore_coding_info(p_Vid, coding_info); + + if ( p_Inp->RCEnable ) + { + rc_restore_state(p_Vid, p_Inp); + } +} + + +void frame_picture_mp_p_slice(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int rd_pass = 0; + int rd_qp = p_Vid->p_curr_frm_struct->qp; + float rateRatio = 1.0F; + int wp_pass=0; + int frame_type_pass = 0; + CodingInfo coding_info; + FrameCodingMethod best_method = REGULAR; + int frame_type = P_SLICE; + int apply_wp = 0; + int selection; + + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + + if(p_Inp->WPIterMC) + p_Vid->frameOffsetAvail = 1; + +#if (DBG_IMAGE_MP) + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[0]->bits_per_picture, + p_Vid->frame_pic[0]->distortion.value[0], p_Vid->frame_pic[0]->distortion.value[1], p_Vid->frame_pic[0]->distortion.value[2]); +#endif + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassPSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + + // for P_Slice, consider WP + wp_pass = 0; + if (p_Inp->GenerateMultiplePPS) + { + Slice *dummy_slice = NULL; + + InitWP(p_Vid, p_Inp, 0); + if ( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass = p_Vid->pWPX->wp_rd_passes + 1; + init_slice_lite(p_Vid, &dummy_slice, 0); + + if (p_Vid->TestWPPSlice(dummy_slice, 0) == 1) + { + // regular WP pass + p_Vid->active_pps = p_Vid->PicParSet[1]; + if ( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass->algorithm = WP_REGULAR; + wp_pass = 1; + } + else if ( p_Inp->WPMCPrecision ) + { + // WPMC pass + p_Vid->active_pps = p_Vid->PicParSet[1]; + wp_pass = 1; + } + + // The way it is, the code would only reach here if prior conditional using + // generatemultiplepps is satisfied + if(wp_pass) + { + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("rd_pass = %d, selection = %d\n", rd_pass, selection); +#endif +#if (DBG_IMAGE_MP) + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[rd_pass]->bits_per_picture, + p_Vid->frame_pic[rd_pass]->distortion.value[0], p_Vid->frame_pic[rd_pass]->distortion.value[1], p_Vid->frame_pic[rd_pass]->distortion.value[2]); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = EXP_WP; + apply_wp = 1; + } + + if(p_Inp->WPMethod == 0 || p_Inp->WPMCPrecision) + { + wp_pass = 0; + if ( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass = p_Vid->pWPX->wp_rd_passes + 2; + if (p_Inp->WPMethod == 0 && p_Vid->TestWPPSlice(dummy_slice, 1) == 1) + { + // regular WP pass + p_Vid->active_pps = p_Vid->PicParSet[1]; + if ( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass->algorithm = WP_REGULAR; + wp_pass = 1; + } + else if ( p_Inp->WPMCPrecision ) + { + // WPMC pass + p_Vid->active_pps = p_Vid->PicParSet[1]; + wp_pass = 1; + } + + if(wp_pass) + { + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + free_slice_list(p_Vid->frame_pic[rd_pass]); + free_storable_picture(p_Vid, p_Vid->enc_frame_picture[rd_pass]); + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("rd_pass = %d, selection = %d\n", rd_pass, selection); +#endif +#if (DBG_IMAGE_MP) + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[rd_pass]->bits_per_picture, + p_Vid->frame_pic[rd_pass]->distortion.value[0], p_Vid->frame_pic[rd_pass]->distortion.value[1], p_Vid->frame_pic[rd_pass]->distortion.value[2]); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = EXP_WP; + apply_wp = 1; + } + } + } + + rd_pass++; + //free_slice(dummy_slice); + + if(rd_pass >= p_Inp->RDPictureMaxPassPSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + free_slice(dummy_slice); + return; + } + } + free_slice(dummy_slice); + } + + + // code as I? or maybe as B? + frame_type_pass = 0; + if(p_Inp->RDPSliceITest && (coding_info.intras * 100/p_Vid->FrameSizeInMbs) >= 75) + { + frame_type = I_SLICE; + set_slice_type(p_Vid, p_Inp, I_SLICE); + populate_frame_slice_type( p_Inp, p_Vid->p_curr_frm_struct, I_SLICE, p_Vid->p_pred->max_num_slices ); + p_Vid->active_pps = p_Vid->PicParSet[0]; + frame_type_pass = 1; + } + else if (p_Inp->RDPSliceBTest && p_Vid->active_sps->profile_idc != BASELINE) + // later need to add some automatic criterion to see if this (coding P as B) may be beneficial + { + frame_type = B_SLICE; + set_slice_type(p_Vid, p_Inp, B_SLICE ); + populate_frame_slice_type( p_Inp, p_Vid->p_curr_frm_struct, B_SLICE, p_Vid->p_pred->max_num_slices ); + p_Vid->active_pps = p_Vid->PicParSet[0]; + frame_type_pass = 1; + } + + if(frame_type_pass) + { + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("rd_pass = %d, selection = %d\n", rd_pass, selection); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = FRAME_TYPE; + } + // reset frame_type + else + frame_type = P_SLICE; + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassPSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + } + + if(p_Vid->EvaluateDBOff) + { + // Perform DB off coding pass + p_Vid->active_pps = (best_method == EXP_WP?p_Vid->PicParSet[1]:p_Vid->PicParSet[0]); + if(frame_type != P_SLICE) + { + set_slice_type(p_Vid, p_Inp, frame_type); + populate_frame_slice_type( p_Inp, p_Vid->p_curr_frm_struct, frame_type, p_Vid->p_pred->max_num_slices ); + } + p_Vid->TurnDBOff = 1; + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("DB OFF, rd_pass = %d, selection = %d\n", rd_pass, selection); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = DB_OFF; + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassPSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + } + + if(p_Inp->RDPictureFrameQPPSlice) + { + // frame QP pass + p_Vid->active_pps = (apply_wp?p_Vid->PicParSet[1]:p_Vid->PicParSet[0]); + if(frame_type != P_SLICE) + { + set_slice_type(p_Vid, p_Inp, frame_type); + populate_frame_slice_type( p_Inp, p_Vid->p_curr_frm_struct, I_SLICE, p_Vid->p_pred->max_num_slices ); + } + p_Vid->qp = (p_Vid->nal_reference_idc==0 ? rd_qp+1:rd_qp-1); + p_Vid->qp = iClip3( p_Vid->RCMinQP, p_Vid->RCMaxQP, p_Vid->qp ); + if ( p_Inp->RCEnable ) + { + rateRatio = p_Vid->nal_reference_idc ? 1.15F : 0.85F; + rc_init_frame_rdpic( p_Vid, p_Inp, rateRatio ); + } + p_Vid->TurnDBOff = 0; + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("rd_pass = %d, selection = %d\n", rd_pass, selection); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = FRAME_QP; + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassPSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + } + + frame_picture_mp_exit(p_Vid, &coding_info); +} + +void frame_picture_mp_i_slice(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int rd_pass = 0; + int qp = p_Vid->qp; + float rateRatio = 1.0F; + CodingInfo coding_info; + int selection; + + // initial pass encoding + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassISlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + + { + // try QP-1 + qp = p_Vid->qp; + p_Vid->qp = qp - 1; + p_Vid->qp = iClip3( p_Vid->RCMinQP, p_Vid->RCMaxQP, p_Vid->qp ); + if ( p_Inp->RCEnable ) + { + rateRatio = 1.15F; + rc_init_frame_rdpic( p_Vid, p_Inp, rateRatio ); + } + + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], qp); + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassISlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + + // try QP+1 + p_Vid->qp = (qp + 1); + p_Vid->qp = iClip3( p_Vid->RCMinQP, p_Vid->RCMaxQP, p_Vid->qp ); + p_Vid->write_macroblock = FALSE; + + if ( p_Inp->RCEnable ) + { + rateRatio = 1.0F; + rc_init_frame_rdpic( p_Vid, p_Inp, rateRatio ); + } + + p_Vid->qp = iClip3( p_Vid->RCMinQP, p_Vid->RCMaxQP, p_Vid->qp ); + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], qp); + + if ( selection ) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassISlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + } + + frame_picture_mp_exit(p_Vid, &coding_info); +} + +void frame_picture_mp_b_slice(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int rd_pass = 0; + int rd_qp = p_Vid->p_curr_frm_struct->qp; + float rateRatio = 1.0F; + int wp_pass = 0; + CodingInfo coding_info; + FrameCodingMethod best_method = REGULAR; + int apply_wp = 0; + int selection; + Slice *dummy_slice = NULL; + +#if (DBG_IMAGE_MP) + printf("pass0_wp = %d\n", p_Vid->pass0_wp); +#endif + + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + + if(p_Inp->WPIterMC) + p_Vid->frameOffsetAvail = 1; + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassBSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + return; + } + + init_slice_lite(p_Vid, &dummy_slice, 0); + +#if (DBG_IMAGE_MP) + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[0]->bits_per_picture, + p_Vid->frame_pic[0]->distortion.value[0], p_Vid->frame_pic[0]->distortion.value[1], p_Vid->frame_pic[0]->distortion.value[2]); +#endif + + // for B_Slice, consider implicit WP + wp_pass = 0; + { + if (p_Inp->GenerateMultiplePPS) + { + InitWP(p_Vid, p_Inp, 0); + if ( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass = p_Vid->pWPX->wp_rd_passes + 1; + + if (p_Vid->TestWPBSlice(dummy_slice, 1) == 1) + { + // regular WP pass + p_Vid->active_pps = p_Vid->PicParSet[2]; + if(p_Inp->WPMCPrecision) + p_Vid->pWPX->curr_wp_rd_pass->algorithm = WP_REGULAR; + wp_pass = 1; + } + } + + if(wp_pass) + { + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("IMP WP, rd_pass = %d, selection = %d\n", rd_pass, selection); + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[rd_pass]->bits_per_picture, + p_Vid->frame_pic[rd_pass]->distortion.value[0], p_Vid->frame_pic[rd_pass]->distortion.value[1], p_Vid->frame_pic[rd_pass]->distortion.value[2]); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = IMP_WP; + apply_wp = IMP_WP; + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassBSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + free_slice(dummy_slice); + return; + } + } + + // for B_Slice, consider explicit WP + wp_pass = 0; + if (p_Inp->GenerateMultiplePPS) + { + InitWP(p_Vid, p_Inp, 0); + if( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass = p_Vid->pWPX->wp_rd_passes + 1; + + if (p_Vid->TestWPBSlice(dummy_slice, 0) == 1) + { + // regular WP pass + p_Vid->active_pps = p_Vid->PicParSet[1]; + if( p_Inp->WPMCPrecision ) + p_Vid->pWPX->curr_wp_rd_pass->algorithm = WP_REGULAR; + wp_pass = 1; + } + else if ( p_Inp->WPMCPrecision == 2 && (p_Inp->WPMCPrecBSlice == 2 || (p_Inp->WPMCPrecBSlice == 1 && p_Vid->nal_reference_idc) ) ) + { + p_Vid->active_pps = p_Vid->PicParSet[1]; + wp_pass = 1; + } + } + + if(wp_pass) + { + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("EXP WP, rd_pass = %d, selection = %d\n", rd_pass, selection); + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[rd_pass]->bits_per_picture, + p_Vid->frame_pic[rd_pass]->distortion.value[0], p_Vid->frame_pic[rd_pass]->distortion.value[1], p_Vid->frame_pic[rd_pass]->distortion.value[2]); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = EXP_WP; + apply_wp = EXP_WP; + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassBSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + free_slice(dummy_slice); + return; + } + } + } + + if(p_Inp->RDPictureFrameQPBSlice) + { + // frame QP pass + p_Vid->active_pps = best_method == EXP_WP ? p_Vid->PicParSet[1]:best_method==IMP_WP?p_Vid->PicParSet[2]:p_Vid->PicParSet[0]; + //p_Vid->qp = (p_Vid->nal_reference_idc==0 ? rd_qp + 1 : rd_qp - 1); + p_Vid->qp = (p_Vid->nal_reference_idc==0 ? rd_qp + 1 : rd_qp ); + p_Vid->qp = iClip3( p_Vid->RCMinQP, p_Vid->RCMaxQP, p_Vid->qp ); + if ( p_Inp->RCEnable ) + { + rateRatio = p_Vid->nal_reference_idc ? 1.15F : 0.85F; + rc_init_frame_rdpic( p_Vid, p_Inp, rateRatio ); + } + + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("frame QP, rd_pass = %d, selection = %d \n", rd_pass, selection); + printf("rd_pass = %d: %d (%.0f, %.0f, %.0f)\n", rd_pass, + p_Vid->frame_pic[rd_pass]->bits_per_picture, + p_Vid->frame_pic[rd_pass]->distortion.value[0], p_Vid->frame_pic[rd_pass]->distortion.value[1], p_Vid->frame_pic[rd_pass]->distortion.value[2]); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = FRAME_QP; + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassBSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + free_slice(dummy_slice); + return; + } + } + + // alternative direct mode pass + if(p_Inp->RDPictureDirectMode) + { + // consider using the best coding "method" found so far + p_Vid->active_pps = apply_wp == IMP_WP ? p_Vid->PicParSet[1]:apply_wp==EXP_WP?p_Vid->PicParSet[2]:p_Vid->PicParSet[0]; + if(best_method == FRAME_QP) + p_Vid->qp = (p_Vid->nal_reference_idc==0 ? rd_qp+1:rd_qp-1); + else + p_Vid->qp = rd_qp; + p_Vid->qp = iClip3( p_Vid->RCMinQP, p_Vid->RCMaxQP, p_Vid->qp ); + // flip direct mode type + p_Vid->direct_spatial_mv_pred_flag = 1-p_Vid->direct_spatial_mv_pred_flag; + p_Vid->write_macroblock = FALSE; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp; + frame_picture (p_Vid, p_Vid->frame_pic[rd_pass], &p_Vid->imgData, rd_pass); + selection = picture_coding_decision(p_Vid, p_Vid->frame_pic[0], p_Vid->frame_pic[rd_pass], rd_qp); +#if (DBG_IMAGE_MP) + printf("alternate direct mode, rd_pass = %d, selection = %d\n", rd_pass, selection); +#endif + + if (selection) + { + swap_frame_buffer(p_Vid, 0, rd_pass); + store_coding_and_rc_info(p_Vid, &coding_info); + best_method = ALT_DIRECT; + } + + rd_pass++; + if(rd_pass >= p_Inp->RDPictureMaxPassBSlice) + { + frame_picture_mp_exit(p_Vid, &coding_info); + free_slice(dummy_slice); + return; + } + } + frame_picture_mp_exit(p_Vid, &coding_info); + free_slice(dummy_slice); + return; +} + +void frame_picture_mp(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + p_Vid->EvaluateDBOff = 0; + p_Vid->TurnDBOff = 0; + if(p_Vid->type == I_SLICE) + { + frame_picture_mp_i_slice(p_Vid, p_Inp); + } + else if(p_Vid->type == P_SLICE) + { + frame_picture_mp_p_slice(p_Vid, p_Inp); + } + else if(p_Vid->type == B_SLICE) + { + frame_picture_mp_b_slice(p_Vid, p_Inp); + } + p_Vid->rd_pass = 0; +} + diff --git a/lencod/src/img_chroma.c b/lencod/src/img_chroma.c new file mode 100644 index 0000000..497347c --- /dev/null +++ b/lencod/src/img_chroma.c @@ -0,0 +1,437 @@ + +/*! +************************************************************************************* +* \file img_chroma.c +* +* \brief +* Chroma interpolation functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Athanasios Leontaris +* - Alexis Michael Tourapis +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "img_chroma.h" + + +static void generateChroma00( VideoParameters *p_Vid, int size_x_minus1, int size_y_minus1, imgpel **wImgDst, imgpel **imgUV) +{ + int i;//, j; + int jpad = -p_Vid->pad_size_uv_y; + imgpel *wBufDst; + imgpel *wBufSrc0; + + wBufDst = wImgDst[jpad++]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[0]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *wBufDst++ = *wBufSrc0; + } + + memcpy(wBufDst, wBufSrc0, size_x_minus1 * sizeof(imgpel)); + wBufDst += size_x_minus1; + wBufSrc0 += size_x_minus1; + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *wBufDst++ = *wBufSrc0; + } + + for(; jpad < 0; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } + + for (jpad = 0; jpad < size_y_minus1+1; jpad++) + { + wBufDst = wImgDst[jpad]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[jpad]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *wBufDst++ = *wBufSrc0; + } + + //memcpy(wBufDst, wBufSrc0, size_x_minus1 * sizeof(imgpel)); + wBufDst += size_x_minus1+1; + wBufSrc0 += size_x_minus1; + + for (i = 0; i < p_Vid->pad_size_uv_x; i++) + { + *wBufDst++ = *wBufSrc0; + } + } + + for (jpad = size_y_minus1+1; jpad < size_y_minus1+1+p_Vid->pad_size_uv_y; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Horizontal chroma interpolation image generation routine + ************************************************************************ + */ +static void generateChroma01( VideoParameters *p_Vid, int size_x_minus1, int size_y_minus1, int weight00, int weight01, imgpel **wImgDst, imgpel **imgUV) +{ + int i;//, j; + int jpad = -p_Vid->pad_size_uv_y; + int cur_value; + imgpel *wBufDst; + imgpel *wBufSrc0; + + wBufDst = wImgDst[jpad++]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[0]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (i = 0; i < size_x_minus1; i++) + { + cur_value = weight00 * (*wBufSrc0++); + cur_value += weight01 * (*wBufSrc0 ); + *(wBufDst++) = (imgpel) rshift_rnd_sf(cur_value, 6); + } + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (; jpad < 1; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } + + for (jpad = 1; jpad < size_y_minus1+1; jpad++) + { + wBufDst = wImgDst[jpad]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[jpad]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (i = 0; i < size_x_minus1; i++) + { + cur_value = weight00 * (*wBufSrc0++); + cur_value += weight01 * (*wBufSrc0 ); + *(wBufDst++) = (imgpel) rshift_rnd_sf(cur_value, 6); + } + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = *wBufSrc0; + } + } + + for (jpad = size_y_minus1+1; jpad < size_y_minus1+1+p_Vid->pad_size_uv_y; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Vertical chroma interpolation image generation routine + ************************************************************************ + */ +static void generateChroma10(VideoParameters *p_Vid, int size_x_minus1, int size_y_minus1, int weight00, int weight10, imgpel **wImgDst, imgpel **imgUV) +{ + int i;//, j; + int jpad = -p_Vid->pad_size_uv_y; + int cur_value; + imgpel *wBufDst; + imgpel *wBufSrc0, *wBufSrc1; + + wBufDst = wImgDst[jpad++]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[0]; + + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + memcpy(wBufDst, wBufSrc0, size_x_minus1 * sizeof(imgpel)); + wBufDst += size_x_minus1; + wBufSrc0 += size_x_minus1; + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for(;jpad < 0; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } + + for (jpad = 0; jpad < size_y_minus1; jpad++) + { + wBufDst = wImgDst[jpad]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[jpad]; + wBufSrc1 = imgUV[jpad+1]; + + cur_value = rshift_rnd_sf(weight00 * (*wBufSrc0) + weight10 * (*wBufSrc1), 6 ); + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = (imgpel) cur_value; + } + + for (i = 0; i < size_x_minus1; i++) + { + cur_value = weight00 * (*wBufSrc0++) + weight10 * (*wBufSrc1++); + *(wBufDst++) = (imgpel) rshift_rnd_sf(cur_value, 6); + } + + cur_value = rshift_rnd_sf(weight00 * (*wBufSrc0) + weight10 * (*wBufSrc1), 6 ); + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = (imgpel) cur_value; + } + } + + wBufDst = wImgDst[jpad]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[size_y_minus1]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + memcpy(wBufDst, wBufSrc0, size_x_minus1 * sizeof(imgpel)); + wBufDst += size_x_minus1; + wBufSrc0 += size_x_minus1; + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (jpad = size_y_minus1+1; jpad < size_y_minus1+1+p_Vid->pad_size_uv_y; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Generic/Diagonal chroma interpolation image generation routine + ************************************************************************ + */ +static void generateChromaXX( VideoParameters *p_Vid, int size_x_minus1, int size_y_minus1, int weight00, int weight01, int weight10, int weight11, imgpel **wImgDst, imgpel **imgUV) +{ + int i;//, j; + int jpad = -p_Vid->pad_size_uv_y; + int cur_value; + imgpel *wBufDst; + imgpel *wBufSrc0, *wBufSrc1; + int weight0001 = weight00 + weight01; + int weight1011 = weight10 + weight11; + int weight0010 = weight00 + weight10; + int weight0111 = weight01 + weight11; + + wBufDst = wImgDst[jpad++]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[0]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (i = 0; i < size_x_minus1; i++) + { + cur_value = weight0010 * (*wBufSrc0++); + cur_value += weight0111 * (*wBufSrc0 ); + *(wBufDst++) = (imgpel) rshift_rnd_sf(cur_value, 6); + } + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (; jpad < 0; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } + + for (jpad = 0; jpad < size_y_minus1; jpad++) + { + wBufDst = wImgDst[jpad]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[jpad]; + wBufSrc1 = imgUV[jpad + 1]; + + cur_value = rshift_rnd_sf(weight0001 * (*wBufSrc0) + weight1011 * (*wBufSrc1), 6 ); + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = (imgpel) cur_value; + } + + for (i = 0; i < size_x_minus1; i++) + { + cur_value = weight00 * (*wBufSrc0++) + weight10 * (*wBufSrc1++); + cur_value += weight01 * (*wBufSrc0 ) + weight11 * (*wBufSrc1 ); + *(wBufDst++) = (imgpel) rshift_rnd_sf(cur_value, 6); + } + + cur_value = rshift_rnd_sf(weight0001 * (*wBufSrc0) + weight1011 * (*wBufSrc1), 6 ); + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = (imgpel) cur_value; + } + } + + wBufDst = wImgDst[jpad]-p_Vid->pad_size_uv_x; + wBufSrc0 = imgUV[size_y_minus1]; + + for (i = -p_Vid->pad_size_uv_x; i < 0; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (i = 0; i < size_x_minus1; i++) + { + cur_value = weight0010 * (*wBufSrc0++); + cur_value += weight0111 * (*wBufSrc0 ); + *(wBufDst++) = (imgpel) rshift_rnd_sf(cur_value, 6); + } + + for (i = -1; i < p_Vid->pad_size_uv_x; i++) + { + *(wBufDst++) = *wBufSrc0; + } + + for (jpad = size_y_minus1+1; jpad < size_y_minus1+1+p_Vid->pad_size_uv_y; jpad++) + { + memcpy(wImgDst[jpad]-p_Vid->pad_size_uv_x, wImgDst[jpad - 1]-p_Vid->pad_size_uv_x, (2 * p_Vid->pad_size_uv_x + size_x_minus1+1) * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Creates the 16 (YUV444), 32 (YUV422), or 64 (YUV420) sub-images that + * contain quarter-pel samples sub-sampled at different + * spatial orientationss; + * enables more efficient implementation + ************************************************************************* + */ +void getSubImagesChroma( VideoParameters *p_Vid, StorablePicture *s ) +{ + int uv, k, l, m; + int weight00, weight01, weight10, weight11; + int subimages_y, subimages_x, subx, suby; + int size_x_minus1, size_y_minus1; + imgpel ****curr_img_sub; + imgpel **curr_img; + + // multiplier factor for index to account for UV sampling ratios + int mul_x, mul_y; + int mm, kk; + + size_x_minus1 = s->size_x_cr - 1; + size_y_minus1 = s->size_y_cr - 1; + + if( p_Vid->p_Inp->OnTheFlyFractMCP == OTF_L1 ) // JLT : on-the-fly mode + { + if ( p_Vid->yuv_format == YUV420 ) + { + subimages_x = 4; + subimages_y = 4; + mul_x = mul_y = 2; + } + else if ( p_Vid->yuv_format == YUV422 ) + { + subimages_x = 4; + subimages_y = 2; + mul_y = 4; + mul_x = 2; + } + else + { // YUV444 + subimages_x = 2; + subimages_y = 2; + mul_x = mul_y = 4; + } + } + else + { + if ( p_Vid->yuv_format == YUV420 ) + { + subimages_x = 8; + subimages_y = 8; + mul_x = mul_y = 1; + } + else if ( p_Vid->yuv_format == YUV422 ) + { + subimages_x = 8; + subimages_y = 4; + mul_y = 2; + mul_x = 1; + } + else + { // YUV444 + subimages_x = 4; + subimages_y = 4; + mul_x = mul_y = 2; + } + } + + // U or V + for ( uv = 0; uv < 2; uv++ ) + { + curr_img = s->imgUV[uv]; + curr_img_sub = s->p_img_sub[uv + 1]; + + for ( suby = 0, k = 0; suby < subimages_y; suby++, k += mul_y ) + { + m = (8 - k); + mm = m << 3; + kk = k << 3; + for ( subx = 0, l = 0; subx < subimages_x; subx++, l += mul_x ) + { + weight01 = m * l; + weight00 = mm - weight01; + weight11 = k * l; + weight10 = kk - weight11; + + // Lets break things into cases + if (weight01 == 0 && weight10 == 0 && weight11 == 0) // integer + { + generateChroma00( p_Vid, size_x_minus1, size_y_minus1, curr_img_sub[suby][subx], curr_img); + } + else if (weight10 == 0 && weight11 == 0) // horizontal + { + generateChroma01( p_Vid, size_x_minus1, size_y_minus1, weight00, weight01, curr_img_sub[suby][subx], curr_img); + } + else if (weight01 == 0 && weight11 == 0) // vertical + { + generateChroma10( p_Vid, size_x_minus1, size_y_minus1, weight00, weight10, curr_img_sub[suby][subx], curr_img); + } + else //diagonal + { + generateChromaXX( p_Vid, size_x_minus1, size_y_minus1, weight00, weight01, weight10, weight11, curr_img_sub[suby][subx], curr_img); + } + } + } + } +} diff --git a/lencod/src/img_dist_ms_ssim.c b/lencod/src/img_dist_ms_ssim.c new file mode 100644 index 0000000..d6c9f10 --- /dev/null +++ b/lencod/src/img_dist_ms_ssim.c @@ -0,0 +1,349 @@ + +/*! + ************************************************************************************* + * \file img_dist_ms_ssim.c + * + * \brief + * Compute structural similarity (SSIM) index using the encoded image and the reference image + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + * - Peshala Pahalawatta + * - Zhen Li + * - Alexis Michael Tourapis + ************************************************************************************* + */ +#include "contributors.h" +#include "global.h" +#include "img_distortion.h" +#include "enc_statistics.h" +#include "memalloc.h" +#include "math.h" + +#ifndef UNBIASED_VARIANCE + #define UNBIASED_VARIANCE // unbiased estimation of the variance +#endif + +#define MS_SSIM_PAD 6 +#define MS_SSIM_PAD2 3 + +#define MS_SSIM_BETA0 0.0448 +#define MS_SSIM_BETA1 0.2856 +#define MS_SSIM_BETA2 0.3001 +#define MS_SSIM_BETA3 0.2363 +#define MS_SSIM_BETA4 0.1333 + +#define MAX_SSIM_LEVELS 5 + +//Computes the product of the contrast and structure componenents of the structural similarity metric. +float compute_structural_components (VideoParameters *p_Vid, InputParameters *p_Inp, imgpel **refImg, imgpel **encImg, int height, int width, int win_height, int win_width, int comp) +{ + static const float K2 = 0.03f; + float max_pix_value_sqd; + float C2; + float win_pixels = (float) (win_width * win_height); +#ifdef UNBIASED_VARIANCE + float win_pixels_bias = win_pixels - 1; +#else + float win_pixels_bias = win_pixels; +#endif + float mb_ssim, meanOrg, meanEnc; + float varOrg, varEnc, covOrgEnc; + int imeanOrg, imeanEnc, ivarOrg, ivarEnc, icovOrgEnc; + float cur_distortion = 0.0; + int i, j, n, m, win_cnt = 0; + int overlapSize = p_Inp->SSIMOverlapSize; + + max_pix_value_sqd = (float) (p_Vid->max_pel_value_comp[comp] * p_Vid->max_pel_value_comp[comp]); + C2 = K2 * K2 * max_pix_value_sqd; + + for (j = 0; j <= height - win_height; j += overlapSize) + { + for (i = 0; i <= width - win_width; i += overlapSize) + { + imeanOrg = 0; + imeanEnc = 0; + ivarOrg = 0; + ivarEnc = 0; + icovOrgEnc = 0; + + for ( n = j;n < j + win_height;n ++) + { + for (m = i;m < i + win_width;m ++) + { + imeanOrg += refImg[n][m]; + imeanEnc += encImg[n][m]; + ivarOrg += refImg[n][m] * refImg[n][m]; + ivarEnc += encImg[n][m] * encImg[n][m]; + icovOrgEnc += refImg[n][m] * encImg[n][m]; + } + } + + meanOrg = (float) imeanOrg / win_pixels; + meanEnc = (float) imeanEnc / win_pixels; + + varOrg = ((float) ivarOrg - ((float) imeanOrg) * meanOrg) / win_pixels_bias; + varEnc = ((float) ivarEnc - ((float) imeanEnc) * meanEnc) / win_pixels_bias; + covOrgEnc = ((float) icovOrgEnc - ((float) imeanOrg) * meanEnc) / win_pixels_bias; + + mb_ssim = (float) (2.0 * covOrgEnc + C2); + mb_ssim /= (float) (varOrg + varEnc + C2); + + cur_distortion += mb_ssim; + win_cnt++; + } + } + + cur_distortion /= (float) win_cnt; + + if (cur_distortion >= 1.0 && cur_distortion < 1.01) // avoid float accuracy problem at very low QP(e.g.2) + cur_distortion = 1.0; + + return cur_distortion; +} + +float compute_luminance_component (VideoParameters *p_Vid, InputParameters *p_Inp, imgpel **refImg, imgpel **encImg, int height, int width, int win_height, int win_width, int comp) +{ + static const float K1 = 0.01f; + float max_pix_value_sqd; + float C1; + float win_pixels = (float) (win_width * win_height); + float mb_ssim, meanOrg, meanEnc; + int imeanOrg, imeanEnc; + float cur_distortion = 0.0; + int i, j, n, m, win_cnt = 0; + int overlapSize = p_Inp->SSIMOverlapSize; + + max_pix_value_sqd = (float) (p_Vid->max_pel_value_comp[comp] * p_Vid->max_pel_value_comp[comp]); + C1 = K1 * K1 * max_pix_value_sqd; + + for (j = 0; j <= height - win_height; j += overlapSize) + { + for (i = 0; i <= width - win_width; i += overlapSize) + { + imeanOrg = 0; + imeanEnc = 0; + + for ( n = j;n < j + win_height;n ++) + { + for (m = i;m < i + win_width;m ++) + { + imeanOrg += refImg[n][m]; + imeanEnc += encImg[n][m]; + } + } + + meanOrg = (float) imeanOrg / win_pixels; + meanEnc = (float) imeanEnc / win_pixels; + + mb_ssim = (float) (2.0 * meanOrg * meanEnc + C1); + mb_ssim /= (float) (meanOrg * meanOrg + meanEnc * meanEnc + C1); + + cur_distortion += mb_ssim; + win_cnt++; + } + } + + cur_distortion /= (float) win_cnt; + + if (cur_distortion >= 1.0 && cur_distortion < 1.01) // avoid float accuracy problem at very low QP(e.g.2) + cur_distortion = 1.0; + + return cur_distortion; +} + +void horizontal_symmetric_extension(int **buffer, int width, int height ) +{ + int j; + int* buf; + + int height_plus_pad2 = height + MS_SSIM_PAD2; + int width_plus_pad2_minus_one = width + MS_SSIM_PAD2 - 1; + + // horizontal PSE + for (j = MS_SSIM_PAD2; j < height_plus_pad2; j++ ) { + // left column + buf = &buffer[j][MS_SSIM_PAD2]; + buf[-1] = buf[1]; + buf[-2] = buf[2]; + + // right column + buf = &buffer[j][width_plus_pad2_minus_one]; + buf[1] = buf[-1]; + buf[2] = buf[-2]; + buf[3] = buf[-3]; + } +} + +void vertical_symmetric_extension(int **buffer, int width, int height) +{ + int i; + + int *bufminus1 = &buffer[MS_SSIM_PAD2-1][MS_SSIM_PAD2]; + int *bufminus2 = &buffer[MS_SSIM_PAD2-2][MS_SSIM_PAD2]; + int *bufplus1 = &buffer[MS_SSIM_PAD2+1][MS_SSIM_PAD2]; + int *bufplus2 = &buffer[MS_SSIM_PAD2+2][MS_SSIM_PAD2]; + + int *bufhminus1 = &buffer[height + MS_SSIM_PAD2-2][MS_SSIM_PAD2]; + int *bufhminus2 = &buffer[height + MS_SSIM_PAD2-3][MS_SSIM_PAD2]; + int *bufhminus3 = &buffer[height + MS_SSIM_PAD2-4][MS_SSIM_PAD2]; + int *bufhplus1 = &buffer[height + MS_SSIM_PAD2][MS_SSIM_PAD2]; + int *bufhplus2 = &buffer[height + MS_SSIM_PAD2+1][MS_SSIM_PAD2]; + int *bufhplus3 = &buffer[height + MS_SSIM_PAD2+2][MS_SSIM_PAD2]; + + for (i = 0; i < width; i++) + { + //Top Rows + bufminus1[i] = bufplus1[i]; + bufminus2[i] = bufplus2[i]; + //Bottom Rows + bufhplus1[i] = bufhminus1[i]; + bufhplus2[i] = bufhminus2[i]; + bufhplus3[i] = bufhminus3[i]; + } +} + +static void imgpel_to_padded_int(imgpel** src, int **buffer, int width, int height) +{ + int i, j; + int* tmpDst; + imgpel* tmpSrc; + + tmpDst = buffer[MS_SSIM_PAD2]; + for (j = 0; j < height; j++) + { + tmpSrc = src[j]; + tmpDst = &buffer[j + MS_SSIM_PAD2][MS_SSIM_PAD2]; + for (i = 0; i < width; i++) + { + tmpDst[i] = (int)tmpSrc[i]; + } + } +} + +void downsample(imgpel** src, imgpel** out, int height, int width) +{ + int height2 = height >> 1; + int width2 = width >> 1; + int i, j; + int ii, jj; + int iDst; + int tmp, tmp1, tmp2; + int* tmpDst; + int* tmpSrc; + + int** itemp; + int** dest; + + get_mem2Dint(&itemp, height + MS_SSIM_PAD, width + MS_SSIM_PAD); + get_mem2Dint(&dest, height + MS_SSIM_PAD, width2 + MS_SSIM_PAD); + + imgpel_to_padded_int(src, itemp, width, height); + horizontal_symmetric_extension(itemp, width, height); + + for (j = 0; j < height; j++) + { + tmpDst = dest[j+MS_SSIM_PAD2]; + tmpSrc = itemp[j+MS_SSIM_PAD2]; + iDst = MS_SSIM_PAD2; + for (i = 0; i < width2; i++, iDst++) + { + ii = (i << 1) + MS_SSIM_PAD2; + tmp1 = tmpSrc[ii-1] + tmpSrc[ii+2]; + tmp2 = tmpSrc[ii] + tmpSrc[ii+1]; + tmpDst[iDst] = tmpSrc[ii-2] + tmpSrc[ii+3] + (tmp1 << 1) + tmp1 + (tmp2 << 5) - (tmp2 << 2); + tmpDst[iDst] >>= 6; + } + } + + //Periodic extension + vertical_symmetric_extension(dest, width2, height); + + for (i = 0; i < width2; i++) + { + ii = i + MS_SSIM_PAD2; + for (j = 0; j < height2; j++) + { + jj = (j << 1) + MS_SSIM_PAD2; + tmp1 = dest[jj-1][ii] + dest[jj+2][ii]; + tmp2 = dest[jj][ii] + dest[jj+1][ii]; + tmp = dest[jj-2][ii] + dest[jj+3][ii] + (tmp1 << 1) + tmp1 + (tmp2 << 5) - (tmp2 << 2); + out[j][i] = (unsigned char) (tmp >> 6); //Note: Should change for different bit depths + } + } + free_mem2Dint(itemp); + free_mem2Dint(dest); +} + +float compute_ms_ssim(VideoParameters *p_Vid, InputParameters *p_Inp, imgpel **refImg, imgpel **encImg, int height, int width, int win_height, int win_width, int comp) +{ + float structural[MAX_SSIM_LEVELS]; + float cur_distortion; + float luminance; + imgpel** dsRef; + imgpel** dsEnc; + int m; + static const int max_ssim_levels_minus_one = MAX_SSIM_LEVELS - 1; + static const float exponent[5] = {(float)MS_SSIM_BETA0, (float)MS_SSIM_BETA1, (float)MS_SSIM_BETA2, (float)MS_SSIM_BETA3, (float)MS_SSIM_BETA4}; + + dsRef = NULL; + dsEnc = NULL; + get_mem2Dpel(&dsRef, height>>1, width>>1); + get_mem2Dpel(&dsEnc, height>>1, width>>1); + + structural[0] = compute_structural_components(p_Vid, p_Inp, refImg, encImg, height, width, win_height, win_width, comp); + cur_distortion = (float)pow(structural[0], exponent[0]); + + downsample(refImg, dsRef, height, width); + downsample(encImg, dsEnc, height, width); + + for (m = 1; m < MAX_SSIM_LEVELS; m++) + { + height >>= 1; + width >>= 1; + structural[m] = compute_structural_components(p_Vid, p_Inp, dsRef, dsEnc, height, width, imin(win_height,height), imin(win_width,width), comp); + cur_distortion *= (float)pow(structural[m], exponent[m]); + if (m < max_ssim_levels_minus_one) + { + downsample(dsRef, dsRef, height, width); + downsample(dsEnc, dsEnc, height, width); + } + else + { + luminance = compute_luminance_component(p_Vid, p_Inp, dsRef, dsEnc, height, width, imin(win_height,height), imin(win_width,width), comp); + cur_distortion *= (float)pow(luminance, exponent[m]); + } + } + free_mem2Dpel(dsRef); + free_mem2Dpel(dsEnc); + dsRef = NULL; + dsEnc = NULL; + + return cur_distortion; +} + +/*! + ************************************************************************ + * \brief + * Find MS-SSIM for all three components + ************************************************************************ + */ +void find_ms_ssim (VideoParameters *p_Vid, InputParameters *p_Inp, ImageStructure *ref, ImageStructure *src, DistMetric *metricSSIM) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + FrameFormat *format = &ref->format; + + metricSSIM->value[0] = compute_ms_ssim (p_Vid, p_Inp, ref->data[0], src->data[0], format->height[0], format->width[0], BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, 0); + // Chroma. + if (format->yuv_format != YUV400) + { + metricSSIM->value[1] = compute_ms_ssim (p_Vid, p_Inp, ref->data[1], src->data[1], format->height[1], format->width[1], p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, 1); + metricSSIM->value[2] = compute_ms_ssim (p_Vid, p_Inp, ref->data[2], src->data[2], format->height[1], format->width[1], p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, 2); + } + + { + accumulate_average(metricSSIM, p_Dist->frame_ctr); + accumulate_avslice(metricSSIM, p_Vid->type, p_Vid->p_Stats->frame_ctr[p_Vid->type]); + } +} diff --git a/lencod/src/img_dist_snr.c b/lencod/src/img_dist_snr.c new file mode 100644 index 0000000..c5292fc --- /dev/null +++ b/lencod/src/img_dist_snr.c @@ -0,0 +1,76 @@ + +/*! + ************************************************************************************* + * \file img_dist_snr.c + * + * \brief + * Compute signal to noise ratio (SNR) between the encoded image and the reference image + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + * - Alexis Michael Tourapis + ************************************************************************************* + */ +#include "contributors.h" + +#include + +#include "enc_statistics.h" +#include "global.h" +#include "img_distortion.h" +#include "md_distortion.h" + +/*! + ************************************************************************ + * \brief + * Find SNR for all three components + ************************************************************************ + */ +void find_snr(VideoParameters *p_Vid, ImageStructure *imgREF, ImageStructure *imgSRC, DistMetric *metricSSE, DistMetric *metricPSNR) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + FrameFormat *format = &imgREF->format; + // Luma. + metricSSE ->value[0] = (float) compute_SSE(imgREF->data[0], imgSRC->data[0], 0, 0, format->height[0], format->width[0]); + metricPSNR->value[0] = psnr(format->max_value_sq[0], format->size_cmp[0], metricSSE->value[0]); + // Chroma. + if (format->yuv_format != YUV400) + { + metricSSE ->value[1] = (float) compute_SSE(imgREF->data[1], imgSRC->data[1], 0, 0, format->height[1], format->width[1]); + metricPSNR->value[1] = psnr(format->max_value_sq[1], format->size_cmp[1], metricSSE->value[1]); + metricSSE ->value[2] = (float) compute_SSE(imgREF->data[2], imgSRC->data[2], 0, 0, format->height[1], format->width[1]); + metricPSNR->value[2] = psnr(format->max_value_sq[2], format->size_cmp[2], metricSSE->value[2]); + } +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->p_Inp->num_of_views == 2) + { + // Luma + p_Vid->p_Dist->metric_v[p_Vid->view_id][SSE].value[0] = metricSSE ->value[0]; + p_Vid->p_Dist->metric_v[p_Vid->view_id][PSNR].value[0] = metricPSNR->value[0]; + // Chroma + if (format->yuv_format != YUV400) + { + p_Vid->p_Dist->metric_v[p_Vid->view_id][SSE].value[1] = metricSSE ->value[1]; + p_Vid->p_Dist->metric_v[p_Vid->view_id][PSNR].value[1] = metricPSNR->value[1]; + p_Vid->p_Dist->metric_v[p_Vid->view_id][SSE].value[2] = metricSSE ->value[2]; + p_Vid->p_Dist->metric_v[p_Vid->view_id][PSNR].value[2] = metricPSNR->value[2]; + } + } +#endif + + { + accumulate_average(metricSSE, p_Dist->frame_ctr); + accumulate_average(metricPSNR, p_Dist->frame_ctr); + + accumulate_avslice(metricSSE, p_Vid->type, p_Vid->p_Stats->frame_ctr[p_Vid->type]); + accumulate_avslice(metricPSNR, p_Vid->type, p_Vid->p_Stats->frame_ctr[p_Vid->type]); +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->p_Inp->num_of_views == 2) + { + accumulate_average(&p_Dist->metric_v[p_Vid->view_id][SSE], p_Dist->frame_ctr_v[p_Vid->view_id]); + accumulate_average(&p_Dist->metric_v[p_Vid->view_id][PSNR], p_Dist->frame_ctr_v[p_Vid->view_id]); + } +#endif + } +} diff --git a/lencod/src/img_dist_ssim.c b/lencod/src/img_dist_ssim.c new file mode 100644 index 0000000..f2477f2 --- /dev/null +++ b/lencod/src/img_dist_ssim.c @@ -0,0 +1,115 @@ + +/*! + ************************************************************************************* + * \file img_dist_ssim.c + * + * \brief + * Compute structural similarity (SSIM) index using the encoded image and the reference image + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + * - Zhen Li + * - Alexis Michael Tourapis + ************************************************************************************* + */ +#include "contributors.h" +#include "global.h" +#include "img_distortion.h" +#include "enc_statistics.h" + +//#define UNBIASED_VARIANCE // unbiased estimation of the variance + +float compute_ssim (VideoParameters *p_Vid, InputParameters *p_Inp, imgpel **refImg, imgpel **encImg, int height, int width, int win_height, int win_width, int comp) +{ + + static const float K1 = 0.01f, K2 = 0.03f; + float max_pix_value_sqd; + float C1, C2; + float win_pixels = (float) (win_width * win_height); +#ifdef UNBIASED_VARIANCE + float win_pixels_bias = win_pixels - 1; +#else + float win_pixels_bias = win_pixels; +#endif + float mb_ssim, meanOrg, meanEnc; + float varOrg, varEnc, covOrgEnc; + int imeanOrg, imeanEnc, ivarOrg, ivarEnc, icovOrgEnc; + float cur_distortion = 0.0; + int i, j, n, m, win_cnt = 0; + int overlapSize = p_Inp->SSIMOverlapSize; + + max_pix_value_sqd = (float) (p_Vid->max_pel_value_comp[comp] * p_Vid->max_pel_value_comp[comp]); + C1 = K1 * K1 * max_pix_value_sqd; + C2 = K2 * K2 * max_pix_value_sqd; + + for (j = 0; j <= height - win_height; j += overlapSize) + { + for (i = 0; i <= width - win_width; i += overlapSize) + { + imeanOrg = 0; + imeanEnc = 0; + ivarOrg = 0; + ivarEnc = 0; + icovOrgEnc = 0; + + for ( n = j;n < j + win_height;n ++) + { + for (m = i;m < i + win_width;m ++) + { + imeanOrg += refImg[n][m]; + imeanEnc += encImg[n][m]; + ivarOrg += refImg[n][m] * refImg[n][m]; + ivarEnc += encImg[n][m] * encImg[n][m]; + icovOrgEnc += refImg[n][m] * encImg[n][m]; + } + } + + meanOrg = (float) imeanOrg / win_pixels; + meanEnc = (float) imeanEnc / win_pixels; + + varOrg = ((float) ivarOrg - ((float) imeanOrg) * meanOrg) / win_pixels_bias; + varEnc = ((float) ivarEnc - ((float) imeanEnc) * meanEnc) / win_pixels_bias; + covOrgEnc = ((float) icovOrgEnc - ((float) imeanOrg) * meanEnc) / win_pixels_bias; + + mb_ssim = (float) ((2.0 * meanOrg * meanEnc + C1) * (2.0 * covOrgEnc + C2)); + mb_ssim /= (float) (meanOrg * meanOrg + meanEnc * meanEnc + C1) * (varOrg + varEnc + C2); + + cur_distortion += mb_ssim; + win_cnt++; + } + } + + cur_distortion /= (float) win_cnt; + + if (cur_distortion >= 1.0 && cur_distortion < 1.01) // avoid float accuracy problem at very low QP(e.g.2) + cur_distortion = 1.0; + + return cur_distortion; +} + +/*! + ************************************************************************ + * \brief + * Find SSIM for all three components + ************************************************************************ + */ +void find_ssim (VideoParameters *p_Vid, InputParameters *p_Inp, ImageStructure *ref, ImageStructure *src, DistMetric *metricSSIM) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + FrameFormat *format = &ref->format; + + metricSSIM->value[0] = compute_ssim (p_Vid, p_Inp, ref->data[0], src->data[0], format->height[0], format->width[0], BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, 0); + // Chroma. + if (format->yuv_format != YUV400) + { + metricSSIM->value[1] = compute_ssim (p_Vid, p_Inp, ref->data[1], src->data[1], format->height[1], format->width[1], p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, 1); + metricSSIM->value[2] = compute_ssim (p_Vid, p_Inp, ref->data[2], src->data[2], format->height[1], format->width[1], p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, 2); + } + + { + accumulate_average(metricSSIM, p_Dist->frame_ctr); + accumulate_avslice(metricSSIM, p_Vid->type, p_Vid->p_Stats->frame_ctr[p_Vid->type]); + } +} + diff --git a/lencod/src/img_distortion.c b/lencod/src/img_distortion.c new file mode 100644 index 0000000..138eeed --- /dev/null +++ b/lencod/src/img_distortion.c @@ -0,0 +1,211 @@ + +/*! + ************************************************************************************* + * \file img_distortion.c + * + * \brief + * Compute distortion for encoded image + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Woo-Shik Kim + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include +#include + +#include "global.h" + +#include "refbuf.h" +#include "mbuffer.h" +#include "img_luma.h" +#include "img_chroma.h" +#include "intrarefresh.h" +#include "fmo.h" +#include "sei.h" +#include "memalloc.h" +#include "nalu.h" +#include "ratectl.h" +#include "mb_access.h" +#include "md_distortion.h" +#include "output.h" +#include "context_ini.h" +#include "conformance.h" +#include "enc_statistics.h" + +#include "q_matrix.h" +#include "q_offsets.h" +#include "quant4x4.h" +#include "quant8x8.h" +#include "wp.h" +#include "input.h" +#include "image.h" +#include "img_distortion.h" +#include "img_dist_snr.h" +#include "img_dist_ssim.h" +#include "img_dist_ms_ssim.h" +#include "cconv_yuv2rgb.h" + + +/*! + ************************************************************************ + * \brief + * Metric accumulator + ************************************************************************ + */ +void accumulate_metric(float *ave_metric, float cur_metric, int frames) +{ + *ave_metric = (float) (*ave_metric * (frames - 1) + cur_metric) / frames; +} + +/*! + ************************************************************************ + * \brief + * Accumulate distortion for all components + ************************************************************************ + */ +void accumulate_average(DistMetric *metric, int frames) +{ + accumulate_metric(&metric->average[0], metric->value[0], frames); + accumulate_metric(&metric->average[1], metric->value[1], frames); + accumulate_metric(&metric->average[2], metric->value[2], frames); +} + +/*! + ************************************************************************ + * \brief + * Accumulate distortion for all components for slice_type + ************************************************************************ + */ +void accumulate_avslice(DistMetric *metric, int slice_type, int frames) +{ + accumulate_metric(&metric->avslice[slice_type][0], metric->value[0], frames); + accumulate_metric(&metric->avslice[slice_type][1], metric->value[1], frames); + accumulate_metric(&metric->avslice[slice_type][2], metric->value[2], frames); +} + +/*! + ************************************************************************ + * \brief + * Find distortion for all three components + ************************************************************************ + */ +void find_distortion (VideoParameters *p_Vid, ImageData *imgData) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + DistortionParams *p_Dist = p_Vid->p_Dist; + int64 diff_cmp[3] = {0}; + + // Calculate SSE for Y, U and V. + if (p_Vid->structure!=FRAME) + { + // Luma. + diff_cmp[0] += compute_SSE(p_Vid->pCurImg, p_Vid->imgY_com, 0, 0, p_Inp->output.height[0], p_Inp->output.width[0]); + + // Chroma. + if (p_Vid->yuv_format != YUV400) + { + diff_cmp[1] += compute_SSE(p_Vid->pImgOrg[1], p_Vid->imgUV_com[0], 0, 0, p_Inp->output.height[1], p_Inp->output.width[1]); + diff_cmp[2] += compute_SSE(p_Vid->pImgOrg[2], p_Vid->imgUV_com[1], 0, 0, p_Inp->output.height[1], p_Inp->output.width[1]); + } + } + else + { + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + p_Vid->enc_picture = p_Vid->enc_frame_picture[0]; + } + p_Vid->pCurImg = imgData->frm_data[0]; + p_Vid->pImgOrg[0] = imgData->frm_data[0]; + + // Luma. + diff_cmp[0] += compute_SSE(p_Vid->pImgOrg[0], p_Vid->enc_picture->imgY, 0, 0, p_Inp->output.height[0], p_Inp->output.width[0]); + + // Chroma. + if (p_Vid->yuv_format != YUV400) + { + p_Vid->pImgOrg[1] = imgData->frm_data[1]; + p_Vid->pImgOrg[2] = imgData->frm_data[2]; + + diff_cmp[1] += compute_SSE(p_Vid->pImgOrg[1], p_Vid->enc_picture->imgUV[0], 0, 0, p_Inp->output.height[1], p_Inp->output.width[1]); + diff_cmp[2] += compute_SSE(p_Vid->pImgOrg[2], p_Vid->enc_picture->imgUV[1], 0, 0, p_Inp->output.height[1], p_Inp->output.width[1]); + } + } + + // This should be assigned to the SSE structure. Should double check code. + p_Dist->metric[SSE].value[0] = (float) diff_cmp[0]; + p_Dist->metric[SSE].value[1] = (float) diff_cmp[1]; + p_Dist->metric[SSE].value[2] = (float) diff_cmp[2]; +} + +void select_img(VideoParameters *p_Vid, ImageStructure *imgSRC, ImageStructure *imgREF, ImageData *imgData) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + if (p_Vid->fld_flag != FALSE) + { + imgSRC->format = p_Inp->output; + imgREF->format = p_Inp->output; + + imgREF->data[0] = p_Vid->pCurImg; + imgSRC->data[0] = p_Vid->imgY_com; + + if (p_Vid->yuv_format != YUV400) + { + imgREF->data[1] = p_Vid->pImgOrg[1]; + imgREF->data[2] = p_Vid->pImgOrg[2]; + imgSRC->data[1] = p_Vid->imgUV_com[0]; + imgSRC->data[2] = p_Vid->imgUV_com[1]; + } + } + else + { + imgSRC->format = p_Inp->output; + imgREF->format = p_Inp->output; + + imgREF->data[0] = imgData->frm_data[0]; + + if ((p_Inp->PicInterlace == ADAPTIVE_CODING) || (p_Inp->separate_colour_plane_flag != 0)) + { + p_Vid->enc_picture = p_Vid->enc_frame_picture[0]; + } + imgSRC->data[0] = p_Vid->enc_picture->imgY; + + if (p_Vid->yuv_format != YUV400) + { + imgREF->data[1] = imgData->frm_data[1]; + imgREF->data[2] = imgData->frm_data[2]; + + imgSRC->data[1] = p_Vid->enc_picture->imgUV[0]; + imgSRC->data[2] = p_Vid->enc_picture->imgUV[1]; + } + } +} + +void compute_distortion(VideoParameters *p_Vid, ImageData *imgData) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + DistortionParams *p_Dist = p_Vid->p_Dist; + if (p_Inp->Verbose != 0) + { + select_img(p_Vid, &p_Vid->imgSRC, &p_Vid->imgREF, imgData); + + find_snr (p_Vid, &p_Vid->imgREF, &p_Vid->imgSRC, &p_Dist->metric[SSE], &p_Dist->metric[PSNR]); + if (p_Inp->Distortion[SSIM] == 1) + find_ssim (p_Vid, p_Inp, &p_Vid->imgREF, &p_Vid->imgSRC, &p_Dist->metric[SSIM]); + if (p_Inp->Distortion[MS_SSIM] == 1) + find_ms_ssim(p_Vid, p_Inp, &p_Vid->imgREF, &p_Vid->imgSRC, &p_Dist->metric[MS_SSIM]); + // RGB Distortion + if(p_Inp->DistortionYUVtoRGB == 1) + { + YUVtoRGB(p_Vid, &p_Vid->imgREF, &p_Vid->imgRGB_ref); + YUVtoRGB(p_Vid, &p_Vid->imgSRC, &p_Vid->imgRGB_src); + find_snr (p_Vid, &p_Vid->imgRGB_ref, &p_Vid->imgRGB_src, &p_Dist->metric[SSE_RGB], &p_Dist->metric[PSNR_RGB]); + if (p_Inp->Distortion[SSIM] == 1) + find_ssim (p_Vid, p_Inp, &p_Vid->imgRGB_ref, &p_Vid->imgRGB_src, &p_Dist->metric[SSIM_RGB]); + if (p_Inp->Distortion[MS_SSIM] == 1) + find_ms_ssim(p_Vid, p_Inp, &p_Vid->imgRGB_ref, &p_Vid->imgRGB_src, &p_Dist->metric[MS_SSIM_RGB]); + } + } +} diff --git a/lencod/src/img_luma.c b/lencod/src/img_luma.c new file mode 100644 index 0000000..aca6337 --- /dev/null +++ b/lencod/src/img_luma.c @@ -0,0 +1,680 @@ +/*! +************************************************************************************* +* \file img_luma_uint8.c +* +* \brief +* Luma interpolation functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +* - Yuwen He +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "img_luma.h" +#include "memalloc.h" + + +/*! + ************************************************************************ + * \brief + * Copy Integer Samples to image [0][0] + * + * \param s + * pointer to StorablePicture structure + * \param dstImg + * destination image + * \param srcImg + * source image + ************************************************************************ + */ +static void getSubImageInteger( StorablePicture *s, imgpel **dstImg, imgpel **srcImg) +{ + int i, j; + int size_x_minus1 = s->size_x - 1; + + imgpel *wBufSrc, *wBufDst; + + // Copy top line + wBufDst = &( dstImg[-IMG_PAD_SIZE_Y][-IMG_PAD_SIZE_X] ); + wBufSrc = srcImg[0]; + // left IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; i++) + *(wBufDst++) = wBufSrc[0]; + // center 0-(s->size_x) + memcpy(wBufDst, wBufSrc, s->size_x * sizeof(imgpel)); + wBufDst += s->size_x; + // right IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; i++) + *(wBufDst++) = wBufSrc[size_x_minus1]; + + // Now copy remaining pad lines + for (j = -IMG_PAD_SIZE_Y+1; j < 1; ++j) + { + memcpy(dstImg[j]-IMG_PAD_SIZE_X, dstImg[j - 1]-IMG_PAD_SIZE_X, s->size_x_padded * sizeof(imgpel)); + } + + for (j = 1; j < s->size_y; j++) + { + wBufDst = &( dstImg[j][-IMG_PAD_SIZE_X] ); + wBufSrc = srcImg[j]; + // left IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; i++) + *(wBufDst++) = wBufSrc[0]; + // center 0-(s->size_x) + memcpy(wBufDst, wBufSrc, s->size_x * sizeof(imgpel)); + wBufDst += s->size_x; + // right IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; i++) + *(wBufDst++) = wBufSrc[size_x_minus1]; + } + + // Replicate bottom pad lines + for (j = s->size_y; j < s->size_y+IMG_PAD_SIZE_Y; j++) + { + memcpy(dstImg[j]-IMG_PAD_SIZE_X, dstImg[j - 1]-IMG_PAD_SIZE_X, s->size_x_padded * sizeof(imgpel)); + } +} + +static void getSubImageInteger_s( StorablePicture *s, imgpel **dstImg, imgpel **srcImg) +{ + int i, j; + int size_x_minus1 = s->size_x - 1; + + imgpel *wBufSrc, *wBufDst; + + // Copy top line + wBufDst = &( dstImg[-IMG_PAD_SIZE_Y][-IMG_PAD_SIZE_X] ); + wBufSrc = srcImg[0]; + // left IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; ++i) + *(wBufDst++) = wBufSrc[0]; + // center 0-(s->size_x) + memcpy(wBufDst, wBufSrc, s->size_x * sizeof(imgpel)); + wBufDst += s->size_x; + // right IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; ++i) + *(wBufDst++) = wBufSrc[size_x_minus1]; + + // Now copy remaining pad lines + for (j = -IMG_PAD_SIZE_Y+1; j < 1; ++j) + { + memcpy(dstImg[j]-IMG_PAD_SIZE_X, dstImg[j - 1]-IMG_PAD_SIZE_X, s->size_x_padded * sizeof(imgpel)); + } + + for (j = 1; j < s->size_y; ++j) + { + wBufDst = &( dstImg[j][-IMG_PAD_SIZE_X] ); + wBufSrc = srcImg[j]; + // left IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; ++i) + *(wBufDst++) = wBufSrc[0]; + // center 0-(s->size_x) + //memcpy(wBufDst, wBufSrc, s->size_x * sizeof(imgpel)); + wBufDst += s->size_x; + // right IMG_PAD_SIZE + for (i = 0; i < IMG_PAD_SIZE_X; ++i) + *(wBufDst++) = wBufSrc[size_x_minus1]; + } + + // Replicate bottom pad lines + for (j = s->size_y; j < s->size_y+IMG_PAD_SIZE_Y; ++j) + { + memcpy(dstImg[j]-IMG_PAD_SIZE_X, dstImg[j - 1]-IMG_PAD_SIZE_X, s->size_x_padded * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Does _horizontal_ interpolation using the SIX TAP filters + * + * \param p_Vid + * pointer to VideoParameters structure + * \param s + * pointer to StorablePicture structure + * \param dstImg + * destination image + * \param srcImg + * source image + ************************************************************************ + */ +static void getHorSubImageSixTap( VideoParameters *p_Vid, StorablePicture *s, imgpel **dstImg, imgpel **srcImg) +{ + int is, jpad, ipad; + int ypadded_size = s->size_y_padded; + int xpadded_size = s->size_x_padded; + + imgpel *wBufSrc, *wBufDst; + imgpel *srcImgA, *srcImgB, *srcImgC, *srcImgD, *srcImgE, *srcImgF; + int *iBufDst; + const int tap0 = ONE_FOURTH_TAP[0][0]; + const int tap1 = ONE_FOURTH_TAP[0][1]; + const int tap2 = ONE_FOURTH_TAP[0][2]; + + for (jpad = -IMG_PAD_SIZE_Y; jpad < ypadded_size-IMG_PAD_SIZE_Y; jpad++) + { + wBufSrc = srcImg[jpad]-IMG_PAD_SIZE_X; + wBufDst = dstImg[jpad]-IMG_PAD_SIZE_X; + iBufDst = p_Vid->imgY_sub_tmp[jpad]-IMG_PAD_SIZE_X; + + srcImgA = &wBufSrc[0]; + srcImgB = &wBufSrc[0]; + srcImgC = &wBufSrc[0]; + srcImgD = &wBufSrc[1]; + srcImgE = &wBufSrc[2]; + srcImgF = &wBufSrc[3]; + + // left padded area + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB + *srcImgE++) + + tap2 * (*srcImgC + *srcImgF++)); + + *iBufDst++ = is; + *wBufDst++ = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC + *srcImgF++)); + + *iBufDst++ = is; + *wBufDst++ = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + + // center + for (ipad = 2; ipad < xpadded_size - 4; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + *iBufDst++ = is; + *wBufDst++ = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + } + + is = ( + tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF )); + + *iBufDst++ = is; + *wBufDst++ = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + + // right padded area + is = ( + tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE) + + tap2 * (*srcImgC++ + *srcImgF)); + + *iBufDst++ = is; + *wBufDst++ = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + + is = ( + tap0 * (*srcImgA++ + *srcImgD) + + tap1 * (*srcImgB++ + *srcImgE) + + tap2 * (*srcImgC++ + *srcImgF)); + + *iBufDst++ = is; + *wBufDst++ = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + + is = ( + tap0 * (*srcImgA + *srcImgD) + + tap1 * (*srcImgB + *srcImgE) + + tap2 * (*srcImgC + *srcImgF)); + + *iBufDst = is; + *wBufDst = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + + } +} + +/*! + ************************************************************************ + * \brief + * Does _vertical_ interpolation using the SIX TAP filters + * + * \param p_Vid + * pointer to VideoParameters structure + * \param s + * pointer to StorablePicture structure + * \param dstImg + * pointer to target image + * \param srcImg + * pointer to source image + ************************************************************************ + */ +static void getVerSubImageSixTap( VideoParameters *p_Vid, StorablePicture *s, imgpel **dstImg, imgpel **srcImg) +{ + int is, jpad, ipad; + int ypadded_size = s->size_y_padded; + int xpadded_size = s->size_x_padded; + int maxy = ypadded_size - 1-IMG_PAD_SIZE_Y; + + imgpel *wxLineDst; + imgpel *srcImgA, *srcImgB, *srcImgC, *srcImgD, *srcImgE, *srcImgF; + const int tap0 = ONE_FOURTH_TAP[0][0]; + const int tap1 = ONE_FOURTH_TAP[0][1]; + const int tap2 = ONE_FOURTH_TAP[0][2]; + + // branches within the j loop + // top + for (jpad = -IMG_PAD_SIZE_Y; jpad < 2-IMG_PAD_SIZE_Y; jpad++) + { + wxLineDst = dstImg[jpad]-IMG_PAD_SIZE_X; + srcImgA = srcImg[jpad ]-IMG_PAD_SIZE_X; + srcImgB = srcImg[0-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + srcImgC = srcImg[0-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + srcImgD = srcImg[jpad + 1]-IMG_PAD_SIZE_X; + srcImgE = srcImg[jpad + 2]-IMG_PAD_SIZE_X; + srcImgF = srcImg[jpad + 3]-IMG_PAD_SIZE_X; + for (ipad = 0; ipad < xpadded_size; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + wxLineDst[ipad] = (imgpel) iClip1 (p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + } + } + // center + for (jpad = 2-IMG_PAD_SIZE_Y; jpad < ypadded_size - 3-IMG_PAD_SIZE_Y; jpad++) + { + wxLineDst = dstImg[jpad]-IMG_PAD_SIZE_X; + srcImgA = srcImg[jpad ]-IMG_PAD_SIZE_X; + srcImgB = srcImg[jpad - 1]-IMG_PAD_SIZE_X; + srcImgC = srcImg[jpad - 2]-IMG_PAD_SIZE_X; + srcImgD = srcImg[jpad + 1]-IMG_PAD_SIZE_X; + srcImgE = srcImg[jpad + 2]-IMG_PAD_SIZE_X; + srcImgF = srcImg[jpad + 3]-IMG_PAD_SIZE_X; + for (ipad = 0; ipad < xpadded_size; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + wxLineDst[ipad] = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + } + } + + // bottom + for (jpad = ypadded_size - 3-IMG_PAD_SIZE_Y; jpad < ypadded_size-IMG_PAD_SIZE_Y; jpad++) + { + wxLineDst = dstImg[jpad]-IMG_PAD_SIZE_X; + srcImgA = srcImg[jpad ]-IMG_PAD_SIZE_X; + srcImgB = srcImg[jpad - 1]-IMG_PAD_SIZE_X; + srcImgC = srcImg[jpad - 2]-IMG_PAD_SIZE_X; + srcImgD = srcImg[imin (maxy, jpad + 1)]-IMG_PAD_SIZE_X; + srcImgE = srcImg[maxy]-IMG_PAD_SIZE_X; + srcImgF = srcImg[maxy]-IMG_PAD_SIZE_X; + for (ipad = 0; ipad < xpadded_size; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + wxLineDst[ipad] = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 5 ) ); + } + } +} + +/*! + ************************************************************************ + * \brief + * Does _vertical_ interpolation using the SIX TAP filters + * + * \param p_Vid + * pointer to VideoParameters structure + * \param s + * pointer to StorablePicture structure + * \param dstImg + * pointer to source image + ************************************************************************ + */ +static void getVerSubImageSixTapTmp( VideoParameters *p_Vid, StorablePicture *s, imgpel **dstImg) +{ + int is, jpad, ipad; + int ypadded_size = s->size_y_padded; + int xpadded_size = s->size_x_padded; + int maxy = ypadded_size - 1-IMG_PAD_SIZE_Y; + + imgpel *wxLineDst; + int *srcImgA, *srcImgB, *srcImgC, *srcImgD, *srcImgE, *srcImgF; + const int tap0 = ONE_FOURTH_TAP[0][0]; + const int tap1 = ONE_FOURTH_TAP[0][1]; + const int tap2 = ONE_FOURTH_TAP[0][2]; + + // top + for (jpad = -IMG_PAD_SIZE_Y; jpad < 2-IMG_PAD_SIZE_Y; jpad++) + { + wxLineDst = dstImg[jpad]-IMG_PAD_SIZE_X; + srcImgA = p_Vid->imgY_sub_tmp[jpad ]-IMG_PAD_SIZE_X; + srcImgB = p_Vid->imgY_sub_tmp[0-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + srcImgC = p_Vid->imgY_sub_tmp[0-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + srcImgD = p_Vid->imgY_sub_tmp[jpad + 1]-IMG_PAD_SIZE_X; + srcImgE = p_Vid->imgY_sub_tmp[jpad + 2]-IMG_PAD_SIZE_X; + srcImgF = p_Vid->imgY_sub_tmp[jpad + 3]-IMG_PAD_SIZE_X; + + for (ipad = 0; ipad < xpadded_size; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + wxLineDst[ipad] = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 10 ) ); + } + } + + // center + for (jpad = 2-IMG_PAD_SIZE_Y; jpad < ypadded_size - 3-IMG_PAD_SIZE_Y; jpad++) + { + wxLineDst = dstImg[jpad]-IMG_PAD_SIZE_X; + srcImgA = p_Vid->imgY_sub_tmp[jpad ]-IMG_PAD_SIZE_X; + srcImgB = p_Vid->imgY_sub_tmp[jpad - 1]-IMG_PAD_SIZE_X; + srcImgC = p_Vid->imgY_sub_tmp[jpad - 2]-IMG_PAD_SIZE_X; + srcImgD = p_Vid->imgY_sub_tmp[jpad + 1]-IMG_PAD_SIZE_X; + srcImgE = p_Vid->imgY_sub_tmp[jpad + 2]-IMG_PAD_SIZE_X; + srcImgF = p_Vid->imgY_sub_tmp[jpad + 3]-IMG_PAD_SIZE_X; + for (ipad = 0; ipad < xpadded_size; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + wxLineDst[ipad] = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 10 ) ); + } + } + + // bottom + for (jpad = ypadded_size - 3-IMG_PAD_SIZE_Y; jpad < ypadded_size-IMG_PAD_SIZE_Y; jpad++) + { + wxLineDst = dstImg[jpad]-IMG_PAD_SIZE_X; + srcImgA = p_Vid->imgY_sub_tmp[jpad ]-IMG_PAD_SIZE_X; + srcImgB = p_Vid->imgY_sub_tmp[jpad - 1]-IMG_PAD_SIZE_X; + srcImgC = p_Vid->imgY_sub_tmp[jpad - 2]-IMG_PAD_SIZE_X; + srcImgD = p_Vid->imgY_sub_tmp[imin (maxy, jpad + 1)]-IMG_PAD_SIZE_X; + srcImgE = p_Vid->imgY_sub_tmp[maxy]-IMG_PAD_SIZE_X; + srcImgF = p_Vid->imgY_sub_tmp[maxy]-IMG_PAD_SIZE_X; + for (ipad = 0; ipad < xpadded_size; ipad++) + { + is = + (tap0 * (*srcImgA++ + *srcImgD++) + + tap1 * (*srcImgB++ + *srcImgE++) + + tap2 * (*srcImgC++ + *srcImgF++)); + + wxLineDst[ipad] = (imgpel) iClip1 ( p_Vid->max_imgpel_value, rshift_rnd_sf( is, 10 ) ); + } + } +} + +/*! + ************************************************************************ + * \brief + * Does _horizontal_ interpolation using the BiLinear filter + * + * \param s + * pointer to StorablePicture structure + * \param dstImg + * destination Image + * \param srcImgL + * source left image + * \param srcImgR + * source right image + ************************************************************************ + */ +static void getSubImageBiLinear( StorablePicture *s, imgpel **dstImg, imgpel **srcImgL, imgpel **srcImgR) +{ + int jpad, ipad; + int ypadded_size = s->size_y_padded; + int xpadded_size = s->size_x_padded; + + imgpel *wBufSrcL, *wBufSrcR, *wBufDst; + + for (jpad = -IMG_PAD_SIZE_Y; jpad < ypadded_size-IMG_PAD_SIZE_Y; jpad++) + { + wBufSrcL = srcImgL[jpad]-IMG_PAD_SIZE_X; + wBufSrcR = srcImgR[jpad]-IMG_PAD_SIZE_X; + wBufDst = dstImg[jpad]-IMG_PAD_SIZE_X; + + for (ipad = 0; ipad < xpadded_size; ipad++) + { + *wBufDst++ = (imgpel) rshift_rnd_sf( *wBufSrcL++ + *wBufSrcR++, 1 ); + } + } +} + + +/*! + ************************************************************************ + * \brief + * Does _horizontal_ interpolation using the BiLinear filter + * + * \param s + * pointer to StorablePicture structure + * \param dstImg + * destination Image + * \param srcImgL + * source left image + * \param srcImgR + * source right image + ************************************************************************ + */ +static void getHorSubImageBiLinear( StorablePicture *s, imgpel **dstImg, imgpel **srcImgL, imgpel **srcImgR) +{ + int jpad, ipad; + int ypadded_size = s->size_y_padded; + int xpadded_size = s->size_x_padded - 1; + + imgpel *wBufSrcL, *wBufSrcR, *wBufDst; + + for (jpad = -IMG_PAD_SIZE_Y; jpad < ypadded_size-IMG_PAD_SIZE_Y; jpad++) + { + wBufSrcL = srcImgL[jpad]-IMG_PAD_SIZE_X; + wBufSrcR = &srcImgR[jpad][1-IMG_PAD_SIZE_X]; + wBufDst = dstImg[jpad]-IMG_PAD_SIZE_X; + + // left padded area + center + for (ipad = 0; ipad < xpadded_size; ipad++) + { + *wBufDst++ = (imgpel) rshift_rnd_sf( *wBufSrcL++ + *wBufSrcR++, 1 ); + } + // right padded area + *wBufDst++ = (imgpel) rshift_rnd_sf( *wBufSrcL++ + wBufSrcR[-1], 1 ); + } +} + + +/*! + ************************************************************************ + * \brief + * Does _vertical_ interpolation using the BiLinear filter + * + * \param s + * pointer to StorablePicture structure + * \param dstImg + * destination Image + * \param srcImgT + * source top image + * \param srcImgB + * source bottom image + ************************************************************************ + */ +static void getVerSubImageBiLinear( StorablePicture *s, imgpel **dstImg, imgpel **srcImgT, imgpel **srcImgB) +{ + int jpad, ipad; + int ypadded_size = s->size_y_padded - 1; + int xpadded_size = s->size_x_padded; + + imgpel *wBufSrcT, *wBufSrcB, *wBufDst; + + // top + for (jpad = -IMG_PAD_SIZE_Y; jpad < ypadded_size-IMG_PAD_SIZE_Y; jpad++) + { + wBufSrcT = srcImgT[jpad]-IMG_PAD_SIZE_X; + wBufDst = dstImg[jpad]-IMG_PAD_SIZE_X; + wBufSrcB = srcImgB[jpad + 1]-IMG_PAD_SIZE_X; + + for (ipad = 0; ipad < xpadded_size; ipad++) + { + *wBufDst++ = (imgpel) rshift_rnd_sf(*wBufSrcT++ + *wBufSrcB++, 1); + } + } + // bottom + wBufSrcT = srcImgT[ypadded_size-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + wBufDst = dstImg[ypadded_size-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + wBufSrcB = srcImgB[ypadded_size-IMG_PAD_SIZE_Y]-IMG_PAD_SIZE_X; + + for (ipad = 0; ipad < xpadded_size; ipad++) + { + *wBufDst++ = (imgpel) rshift_rnd_sf(*wBufSrcT++ + *wBufSrcB++, 1); + } +} + + +/*! + ************************************************************************ + * \brief + * Does _diagonal_ interpolation using the BiLinear filter + * + * \param s + * pointer to StorablePicture structure + * \param dstImg + * destination Image + * \param srcImgT + * source top/left image + * \param srcImgB + * source bottom/right image + ************************************************************************ + */ +static void getDiagSubImageBiLinear( StorablePicture *s, imgpel **dstImg, imgpel **srcImgT, imgpel **srcImgB ) +{ + int jpad, ipad; + int maxx = s->size_x_padded - 1-IMG_PAD_SIZE_X; + int maxy = s->size_y_padded - 1-IMG_PAD_SIZE_Y; + + imgpel *wBufSrcL, *wBufSrcR, *wBufDst; + + for (jpad = -IMG_PAD_SIZE_Y; jpad < maxy; jpad++) + { + wBufSrcL = srcImgT[jpad + 1]-IMG_PAD_SIZE_X; + wBufSrcR = &srcImgB[jpad][1-IMG_PAD_SIZE_X]; + wBufDst = dstImg[jpad]-IMG_PAD_SIZE_X; + + for (ipad = -IMG_PAD_SIZE_X; ipad < maxx; ipad++) + { + *wBufDst++ = (imgpel) rshift_rnd_sf(*wBufSrcL++ + *wBufSrcR++, 1); + } + + *wBufDst++ = (imgpel) rshift_rnd_sf(*wBufSrcL++ + wBufSrcR[-1], 1); + } + + wBufSrcL = srcImgT[maxy]-IMG_PAD_SIZE_X; + wBufSrcR = &srcImgB[maxy][1-IMG_PAD_SIZE_X]; + wBufDst = dstImg[maxy]-IMG_PAD_SIZE_X; + + for (ipad = -IMG_PAD_SIZE_X; ipad < maxx; ipad++) + { + *wBufDst++ = (imgpel) rshift_rnd_sf(*wBufSrcL++ + *wBufSrcR++, 1); + } + + *wBufDst++ = (imgpel) rshift_rnd_sf(*wBufSrcL++ + wBufSrcR[-1], 1); +} + +/*! + ************************************************************************ + * \brief + * Creates the 4x4 = 16 images that contain quarter-pel samples + * sub-sampled at different spatial orientations; + * enables more efficient implementation + * + * \param p_Vid + * pointer to VideoParameters structure + * \param s + * pointer to StorablePicture structure + s************************************************************************ + */ +void getSubImagesLuma( VideoParameters *p_Vid, StorablePicture *s ) +{ + imgpel ****cImgSub = s->p_curr_img_sub; + int otf_shift = ( p_Vid->p_Inp->OnTheFlyFractMCP == OTF_L1 ) ? (1) : (0) ; + + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + + //// INTEGER PEL POSITIONS //// + + // sub-image 0 [0][0] + // simply copy the integer pels + if (cImgSub[0][0][0] != s->p_curr_img[0]) + { + getSubImageInteger( s, cImgSub[0][0], s->p_curr_img); + } + else + { + getSubImageInteger_s( s, cImgSub[0][0], s->p_curr_img); + } + + //// HALF-PEL POSITIONS: SIX-TAP FILTER //// + + // sub-image 2 [0][2] + // HOR interpolate (six-tap) sub-image [0][0] + getHorSubImageSixTap( p_Vid, s, cImgSub[0][2>>otf_shift], cImgSub[0][0] ); + + // sub-image 8 [2][0] + // VER interpolate (six-tap) sub-image [0][0] + getVerSubImageSixTap( p_Vid, s, cImgSub[2>>otf_shift][0], cImgSub[0][0]); + + // sub-image 10 [2][2] + // VER interpolate (six-tap) sub-image [0][2] + getVerSubImageSixTapTmp( p_Vid, s, cImgSub[2>>otf_shift][2>>otf_shift]); + + if( !p_Vid->p_Inp->OnTheFlyFractMCP ) + { + //// QUARTER-PEL POSITIONS: BI-LINEAR INTERPOLATION //// + + // sub-image 1 [0][1] + getSubImageBiLinear ( s, cImgSub[0][1], cImgSub[0][0], cImgSub[0][2]); + // sub-image 4 [1][0] + getSubImageBiLinear ( s, cImgSub[1][0], cImgSub[0][0], cImgSub[2][0]); + // sub-image 5 [1][1] + getSubImageBiLinear ( s, cImgSub[1][1], cImgSub[0][2], cImgSub[2][0]); + // sub-image 6 [1][2] + getSubImageBiLinear ( s, cImgSub[1][2], cImgSub[0][2], cImgSub[2][2]); + // sub-image 9 [2][1] + getSubImageBiLinear ( s, cImgSub[2][1], cImgSub[2][0], cImgSub[2][2]); + + // sub-image 3 [0][3] + getHorSubImageBiLinear ( s, cImgSub[0][3], cImgSub[0][2], cImgSub[0][0]); + // sub-image 7 [1][3] + getHorSubImageBiLinear ( s, cImgSub[1][3], cImgSub[0][2], cImgSub[2][0]); + // sub-image 11 [2][3] + getHorSubImageBiLinear ( s, cImgSub[2][3], cImgSub[2][2], cImgSub[2][0]); + + // sub-image 12 [3][0] + getVerSubImageBiLinear ( s, cImgSub[3][0], cImgSub[2][0], cImgSub[0][0]); + // sub-image 13 [3][1] + getVerSubImageBiLinear ( s, cImgSub[3][1], cImgSub[2][0], cImgSub[0][2]); + // sub-image 14 [3][2] + getVerSubImageBiLinear ( s, cImgSub[3][2], cImgSub[2][2], cImgSub[0][2]); + + // sub-image 15 [3][3] + getDiagSubImageBiLinear( s, cImgSub[3][3], cImgSub[0][2], cImgSub[2][0]); + } +} diff --git a/lencod/src/intra16x16.c b/lencod/src/intra16x16.c new file mode 100644 index 0000000..c17e880 --- /dev/null +++ b/lencod/src/intra16x16.c @@ -0,0 +1,517 @@ +/*! +************************************************************************************* + * \file intra16x16.c + * + * \brief + * Intra 16x16 mode functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "transform.h" +#include "memalloc.h" + +/*! + ************************************************************************ + * \brief + * Vertical 16x16 Prediction + ************************************************************************ + */ +static inline void get_i16x16_vertical(imgpel **cur_pred, imgpel *PredPel) +{ + int j; + for (j = 0; j < MB_BLOCK_SIZE; j++) + memcpy(cur_pred[j], &PredPel[1], MB_BLOCK_SIZE * sizeof(imgpel)); +} + + +/*! + ************************************************************************ + * \brief + * Horizontal 16x16 Prediction + ************************************************************************ + */ +static inline void get_i16x16_horizontal(imgpel **cur_pred, imgpel *PredPel) +{ + int i, j; + imgpel *prediction = &PredPel[16]; + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + prediction++; + for (i = 0; i < MB_BLOCK_SIZE; i++) + { + cur_pred[j][i] = *prediction; + } + } +} + +/*! + ************************************************************************ + * \brief + * DC 16x16 Prediction + ************************************************************************ + */ +static inline void get_i16x16_dc(imgpel **cur_pred, imgpel *PredPel, int left_available, int up_available) +{ + int i, j, s0 = 0, s1 = 0, s2 = 0; + + if (up_available) + { + for (i = 1; i < MB_BLOCK_SIZE + 1; ++i) + s1 += PredPel[i]; + } + + if (left_available) + { + for (i = 17; i < 33; ++i) + s2 += PredPel[i]; // sum vert pix + } + + if (up_available) + { + s0 = left_available + ? rshift_rnd_sf((s1 + s2),(MB_BLOCK_SHIFT + 1)) // no edge + : rshift_rnd_sf(s1, MB_BLOCK_SHIFT); // left edge + } + else + { + s0 = left_available + ? rshift_rnd_sf(s2, MB_BLOCK_SHIFT) // upper edge + : PredPel[1]; // top left corner, nothing to predict from + } + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + for (i = 0; i < MB_BLOCK_SIZE; i++) + cur_pred[j][i] = (imgpel) s0; + } +} + +/*! + ************************************************************************ + * \brief + * Plane 16x16 Prediction + ************************************************************************ + */ +static inline void get_i16x16_plane(imgpel **cur_pred, imgpel *PredPel, int max_imgpel_value) +{ + int i, j; + // plane prediction + int ih=0, iv=0; + int ib, ic, iaa; + imgpel *t_pred = &PredPel[25]; + imgpel *u_pred = &PredPel[8]; + imgpel *b_pred = &PredPel[23]; + + for (i = 1; i < 8;++i) + { + ih += i*(*(u_pred + i) - *(u_pred - i)); + iv += i*(*t_pred++ - *b_pred--); + } + ih += 8 * (*(u_pred + 8) - PredPel[0]); + iv += 8 * (*t_pred++ - PredPel[0]); + + ib = (5 * ih + 32) >> 6; + ic = (5 * iv + 32) >> 6; + + iaa=16 * (PredPel[16] + PredPel[32]); + + for (j=0;j< MB_BLOCK_SIZE;++j) + { + for (i=0;i< MB_BLOCK_SIZE;++i) + { + cur_pred[j][i]= (imgpel) iClip1( max_imgpel_value, rshift_rnd_sf((iaa + (i - 7) * ib + (j - 7) * ic), 5));// store plane prediction + } + } +} + +/*! + ************************************************************************ + * \brief + * Set intra 16x16 prediction samples + * + * \par Input: + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_16x16(Macroblock *currMB, ColorPlane pl, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i; + imgpel *PredPel = currMB->intra16x16_pred[pl]; // array of predictor pels + imgpel **img_enc = (currMB->p_Slice->P444_joined)? p_Vid->enc_picture->p_img[pl]: p_Vid->enc_picture->p_curr_img; + + PixelPos pix_b; + PixelPos pix_a; + PixelPos pix_d; + + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + p_Vid->getNeighbour(currMB, -1, -1, mb_size, &pix_d); + p_Vid->getNeighbour(currMB, -1, 0, mb_size, &pix_a); + p_Vid->getNeighbour(currMB, 0, -1, mb_size, &pix_b); + + if (p_Inp->UseConstrainedIntraPred == 0) + { + *up_available = pix_b.available; + *left_available = pix_a.available; + *all_available = pix_d.available; + } + else + { + *up_available = pix_b.available ? p_Vid->intra_block[pix_b.mb_addr] : 0; + *left_available = pix_a.available ? p_Vid->intra_block[pix_a.mb_addr] : 0; + *all_available = pix_d.available ? p_Vid->intra_block[pix_d.mb_addr] : 0; + } + + // form predictor pels + if (*up_available) + { + memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], MB_BLOCK_SIZE * sizeof(imgpel)); + } + else + { + for (i = 1; i < 17; ++i) + PredPel[i] = (imgpel) p_Vid->dc_pred_value; + } + + if (*left_available) + { + int pos_y = pix_a.pos_y; + int pos_x = pix_a.pos_x; + + for (i = 1; i < MB_BLOCK_SIZE + 1; ++i) + PredPel[i + 16] = img_enc[pos_y++][pos_x]; + } + else + { + for (i = 17; i < 33; ++i) + PredPel[i] = (imgpel) p_Vid->dc_pred_value; + } + + if (*all_available) + { + PredPel[0] = img_enc[pix_d.pos_y][pix_d.pos_x]; + } + else + { + PredPel[0] = p_Vid->dc_pred_value; + } +} + + +/*! + ************************************************************************ + * \brief + * Set intra 16x16 prediction samples (MBAFF) + * + * \par Input: + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_16x16_mbaff(Macroblock *currMB, ColorPlane pl, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i; + imgpel *PredPel = currMB->intra16x16_pred[pl]; // array of predictor pels + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + + PixelPos pix_b; + PixelPos pix_a[17]; + + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i = 0; i < 17; ++i) + { + p_Vid->getNeighbour(currMB, -1, i - 1, mb_size, &pix_a[i]); + } + + p_Vid->getNeighbour(currMB, 0, -1, mb_size, &pix_b); + + if (p_Inp->UseConstrainedIntraPred == 0) + { + *up_available = pix_b.available; + *left_available = pix_a[1].available; + *all_available = pix_a[0].available; + } + else + { + *up_available = pix_b.available ? p_Vid->intra_block[pix_b.mb_addr] : 0; + for (i=1, *left_available=1; i<17;++i) + *left_available &= pix_a[i].available ? p_Vid->intra_block[pix_a[i].mb_addr]: 0; + *all_available = pix_a[0].available ? p_Vid->intra_block[pix_a[0].mb_addr]: 0; + } + + // form predictor pels + if (*up_available) + { + memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], MB_BLOCK_SIZE * sizeof(imgpel)); + } + else + { + for (i = 1; i < 17; ++i) + PredPel[i] = (imgpel) p_Vid->dc_pred_value; + } + + if (*left_available) + { + for (i = 1; i < MB_BLOCK_SIZE + 1; ++i) + PredPel[i + 16] = img_enc[pix_a[i].pos_y][pix_a[i].pos_x]; + } + else + { + for (i = 17; i < 33; ++i) + PredPel[i] = (imgpel) p_Vid->dc_pred_value; + } + + if (*all_available) + { + PredPel[0] = img_enc[pix_a[0].pos_y][pix_a[0].pos_x]; + } + else + { + PredPel[0] = p_Vid->dc_pred_value; + } +} + + +/*! + ************************************************************************ + * \brief + * Generate 16x16 intra prediction block + * + * \par Input: + * Starting point of current 16x16 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void get_intrapred_16x16(Macroblock *currMB, ColorPlane pl, int i16x16_mode, int left_available, int up_available) +{ + imgpel *PredPel = currMB->intra16x16_pred[pl]; // array of predictor pels + imgpel ***curr_mpr_16x16 = currMB->p_Slice->mpr_16x16[pl]; + + switch (i16x16_mode) + { + case VERT_PRED_16 : + get_i16x16_vertical(curr_mpr_16x16[VERT_PRED_16], PredPel); + break; + case HOR_PRED_16 : + get_i16x16_horizontal(curr_mpr_16x16[HOR_PRED_16], PredPel); + break; + case DC_PRED_16 : + get_i16x16_dc(curr_mpr_16x16[DC_PRED_16], PredPel, left_available, up_available); + break; + case PLANE_16 : + get_i16x16_plane(curr_mpr_16x16[PLANE_16], PredPel, currMB->p_Vid->max_imgpel_value); + break; + default: + printf("invalid prediction mode \n"); + break; + } +} + +distblk distI16x16_satd(Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost) +{ + Slice *currSlice = currMB->p_Slice; + int **M7 = NULL; + int **tblk4x4 = currSlice->tblk4x4; + int ****i16blk4x4 = currSlice->i16blk4x4; + imgpel *cur_img, *prd_img; + distblk current_intra_sad_2 = 0; + int ii, jj, i, j, i32Cost = 0; + int imin_cost = dist_down(min_cost); + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + cur_img = &img_org[currMB->opix_y + j][currMB->pix_x]; + prd_img = pred_img[j]; + for (i = 0; i < MB_BLOCK_SIZE; i++) + { + i16blk4x4[j >> 2][i >> 2][j & 0x03][i & 0x03] = cur_img[i] - prd_img[i]; + } + } + + for (jj = 0; jj < 4; jj++) + { + for (ii = 0; ii < 4;ii++) + { + M7 = i16blk4x4[jj][ii]; + hadamard4x4(M7, M7); + i32Cost += iabs(M7[0][1]); + i32Cost += iabs(M7[0][2]); + i32Cost += iabs(M7[0][3]); + + if (i32Cost > imin_cost) + return (min_cost); + + for (j = 1; j < 4; j++) + { + //i32Cost =0; + i32Cost += iabs(M7[j][0]); + i32Cost += iabs(M7[j][1]); + i32Cost += iabs(M7[j][2]); + i32Cost += iabs(M7[j][3]); + + if (i32Cost > imin_cost) + return (min_cost); + } + } + } + + for (j = 0; j < 4;j++) + { + tblk4x4[j][0] = (i16blk4x4[j][0][0][0] >> 1); + tblk4x4[j][1] = (i16blk4x4[j][1][0][0] >> 1); + tblk4x4[j][2] = (i16blk4x4[j][2][0][0] >> 1); + tblk4x4[j][3] = (i16blk4x4[j][3][0][0] >> 1); + } + + // Hadamard of DC coeff + hadamard4x4(tblk4x4, tblk4x4); + + for (j = 0; j < 4; j++) + { + i32Cost += iabs(tblk4x4[j][0]); + i32Cost += iabs(tblk4x4[j][1]); + i32Cost += iabs(tblk4x4[j][2]); + i32Cost += iabs(tblk4x4[j][3]); + + if (i32Cost > imin_cost) + return (min_cost); + } + + current_intra_sad_2 += (dist_scale((distblk)i32Cost)); + return current_intra_sad_2; +} + +distblk distI16x16_sad(Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost) +{ + imgpel *cur_img, *prd_img; + int i32Cost = 0; + int i, j; + int imin_cost = dist_down(min_cost); + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + cur_img = &img_org[currMB->opix_y + j][currMB->pix_x]; + prd_img = pred_img[j]; + for (i = 0; i < MB_BLOCK_SIZE; i++) + { + i32Cost += iabs( *cur_img++ - *prd_img++ ); + } + + if (i32Cost > imin_cost) + return (min_cost); + } + + return (dist_scale((distblk) i32Cost)); +} + +distblk distI16x16_sse(Macroblock *currMB, imgpel **img_org, imgpel **pred_img, distblk min_cost) +{ + imgpel *cur_img, *prd_img; + int i, j, i32Cost = 0; + int imin_cost = dist_down(min_cost); + + for (j = 0; j < MB_BLOCK_SIZE;j++) + { + cur_img = &img_org[currMB->opix_y + j][currMB->pix_x]; + prd_img = pred_img[j]; + for (i = 0; i < MB_BLOCK_SIZE; i++) + { + i32Cost += iabs2( *cur_img++ - *prd_img++ ); + } + + if (i32Cost > imin_cost) + return (min_cost); + } + + return (dist_scale((distblk) i32Cost)); +} + + +/*! + ************************************************************************ + * \brief + * Find best 16x16 based intra mode + * + * \par Input: + * Image parameters, pointer to best 16x16 intra mode + * + * \par Output: + * best 16x16 based SAD + ************************************************************************/ +distblk find_sad_16x16_JM(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + distblk current_intra_sad_2, best_intra_sad2 = DISTBLK_MAX; + int k; + imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[0]; + + int up_avail, left_avail, left_up_avail; + + currMB->i16mode = DC_PRED_16; + + currSlice->set_intrapred_16x16(currMB, PLANE_Y, &left_avail, &up_avail, &left_up_avail); + // For speed purposes, we should just unify all planes + if (currSlice->P444_joined) + { + currSlice->set_intrapred_16x16(currMB, PLANE_U, &left_avail, &up_avail, &left_up_avail); + currSlice->set_intrapred_16x16(currMB, PLANE_V, &left_avail, &up_avail, &left_up_avail); + } + + for (k = VERT_PRED_16; k <= PLANE_16; k++) + { + if (p_Inp->IntraDisableInterOnly == 0 || (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) ) + { + if (p_Inp->Intra16x16ParDisable && (k == VERT_PRED_16||k == HOR_PRED_16)) + continue; + + if (p_Inp->Intra16x16PlaneDisable && k == PLANE_16) + continue; + } + //check if there are neighbours to predict from + if (!((k == VERT_PRED_16 && !up_avail) || (k == HOR_PRED_16 && !left_avail) || (k == PLANE_16 && (!left_avail || !up_avail || !left_up_avail)))) + { + get_intrapred_16x16(currMB, PLANE_Y, k, left_avail, up_avail); + current_intra_sad_2 = currSlice->distI16x16(currMB, p_Vid->pCurImg, curr_mpr_16x16[k], best_intra_sad2); + if (currSlice->P444_joined) + { + get_intrapred_16x16(currMB, PLANE_U, k, left_avail, up_avail); + current_intra_sad_2 += currSlice->distI16x16(currMB, p_Vid->pImgOrg[1], currSlice->mpr_16x16[1][k], best_intra_sad2); + get_intrapred_16x16(currMB, PLANE_V, k, left_avail, up_avail); + current_intra_sad_2 += currSlice->distI16x16(currMB, p_Vid->pImgOrg[2], currSlice->mpr_16x16[2][k], best_intra_sad2); + } + + if (current_intra_sad_2 < best_intra_sad2) + { + best_intra_sad2 = current_intra_sad_2; + currMB->i16mode = (char) k; // update best intra mode + } + } + } + + return best_intra_sad2; +} + diff --git a/lencod/src/intra4x4.c b/lencod/src/intra4x4.c new file mode 100644 index 0000000..f89ed62 --- /dev/null +++ b/lencod/src/intra4x4.c @@ -0,0 +1,561 @@ + +/*! + ************************************************************************************* + * \file intra4x4.c + * + * \brief + * Intra 4x4 mode functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "mb_access.h" + +void generate_pred_error_4x4(imgpel **cur_img, imgpel **prd_img, imgpel **cur_prd, int **m7, int pic_opix_x, int block_x) +{ + int j, i, *m7_line; + imgpel *cur_line, *prd_line; + + for (j = 0; j < BLOCK_SIZE; j++) + { + m7_line = &m7[j][block_x]; + cur_line = &cur_img[j][pic_opix_x]; + prd_line = prd_img[j]; + memcpy(&cur_prd[j][block_x], prd_line, BLOCK_SIZE * sizeof(imgpel)); + + for (i = 0; i < BLOCK_SIZE; i++) + { + *m7_line++ = (int) (*cur_line++ - *prd_line++); + } + } +} + +// Notation for comments regarding prediction and predictors. +// The pels of the 4x4 block are labelled a..p. The predictor pels above +// are labelled A..H, from the left I..P, and from above left X, as follows: +// +// X A B C D E F G H +// I a b c d +// J e f g h +// K i j k l +// L m n o p +// + +// Predictor array index definitions +#define P_X (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) + +/*! + ************************************************************************ + * \brief + * Vertical 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_vertical(imgpel **cur_pred, imgpel *PredPel) +{ + memcpy(cur_pred[0], &PredPel[1], BLOCK_SIZE * sizeof(imgpel)); + memcpy(cur_pred[1], &PredPel[1], BLOCK_SIZE * sizeof(imgpel)); + memcpy(cur_pred[2], &PredPel[1], BLOCK_SIZE * sizeof(imgpel)); + memcpy(cur_pred[3], &PredPel[1], BLOCK_SIZE * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Horizontal 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_horizontal(imgpel **cur_pred, imgpel *PredPel) +{ + int i; + + for (i=0; i < BLOCK_SIZE; i++) + { + cur_pred[i][0] = + cur_pred[i][1] = + cur_pred[i][2] = + cur_pred[i][3] = (imgpel) (&P_I)[i]; + } +} + +/*! + ************************************************************************ + * \brief + * DC 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_dc(imgpel **cur_pred, imgpel *PredPel, int left_available, int up_available) +{ + int i, j, s0 = 0; + if (up_available && left_available) + { + // no edge + s0 = (P_A + P_B + P_C + P_D + P_I + P_J + P_K + P_L + 4) >> (BLOCK_SHIFT + 1); + } + else if (!up_available && left_available) + { + // upper edge + s0 = (P_I + P_J + P_K + P_L + 2) >> BLOCK_SHIFT;; + } + else if (up_available && !left_available) + { + // left edge + s0 = (P_A + P_B + P_C + P_D + 2) >> BLOCK_SHIFT; + } + else //if (!up_available && !left_available) + { + // top left corner, nothing to predict from + s0 = P_A; // P_A already set to p_Vid->dc_pred_value; + } + + for (j=0; j < BLOCK_SIZE; j++) + { + for (i=0; i < BLOCK_SIZE; i++) + cur_pred[j][i] = (imgpel) s0; + } +} + +/*! + ************************************************************************ + * \brief + * Diagonal Down Left 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_downleft(imgpel **cur_pred, imgpel *PredPel) +{ + cur_pred[0][0] = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + cur_pred[0][1] = + cur_pred[1][0] = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + cur_pred[0][2] = + cur_pred[1][1] = + cur_pred[2][0] = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + cur_pred[0][3] = + cur_pred[1][2] = + cur_pred[2][1] = + cur_pred[3][0] = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + cur_pred[1][3] = + cur_pred[2][2] = + cur_pred[3][1] = (imgpel) ((P_E + P_G + ((P_F)<<1) + 2) >> 2); + cur_pred[2][3] = + cur_pred[3][2] = (imgpel) ((P_F + P_H + ((P_G)<<1) + 2) >> 2); + cur_pred[3][3] = (imgpel) ((P_G + 3*(P_H) + 2) >> 2); +} + +/*! + ************************************************************************ + * \brief + * Diagonal Down Right 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_downright(imgpel **cur_pred, imgpel *PredPel) +{ + cur_pred[3][0] = (imgpel) ((P_L + 2*P_K + P_J + 2) >> 2); + cur_pred[2][0] = + cur_pred[3][1] = (imgpel) ((P_K + 2*P_J + P_I + 2) >> 2); + cur_pred[1][0] = + cur_pred[2][1] = + cur_pred[3][2] = (imgpel) ((P_J + 2*P_I + P_X + 2) >> 2); + cur_pred[0][0] = + cur_pred[1][1] = + cur_pred[2][2] = + cur_pred[3][3] = (imgpel) ((P_I + 2*P_X + P_A + 2) >> 2); + cur_pred[0][1] = + cur_pred[1][2] = + cur_pred[2][3] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + cur_pred[0][2] = + cur_pred[1][3] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + cur_pred[0][3] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); +} + + +/*! + ************************************************************************ + * \brief + * Vertical Left 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_vertleft(imgpel **cur_pred, imgpel *PredPel) +{ + cur_pred[0][0] = (imgpel) ((P_A + P_B + 1) >> 1); + cur_pred[0][1] = + cur_pred[2][0] = (imgpel) ((P_B + P_C + 1) >> 1); + cur_pred[0][2] = + cur_pred[2][1] = (imgpel) ((P_C + P_D + 1) >> 1); + cur_pred[0][3] = + cur_pred[2][2] = (imgpel) ((P_D + P_E + 1) >> 1); + cur_pred[2][3] = (imgpel) ((P_E + P_F + 1) >> 1); + cur_pred[1][0] = (imgpel) ((P_A + ((P_B)<<1) + P_C + 2) >> 2); + cur_pred[1][1] = + cur_pred[3][0] = (imgpel) ((P_B + ((P_C)<<1) + P_D + 2) >> 2); + cur_pred[1][2] = + cur_pred[3][1] = (imgpel) ((P_C + ((P_D)<<1) + P_E + 2) >> 2); + cur_pred[1][3] = + cur_pred[3][2] = (imgpel) ((P_D + ((P_E)<<1) + P_F + 2) >> 2); + cur_pred[3][3] = (imgpel) ((P_E + ((P_F)<<1) + P_G + 2) >> 2); +} + +/*! + ************************************************************************ + * \brief + * Vertical Right 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_vertright(imgpel **cur_pred, imgpel *PredPel) +{ + cur_pred[0][0] = + cur_pred[2][1] = (imgpel) ((P_X + P_A + 1) >> 1); + cur_pred[0][1] = + cur_pred[2][2] = (imgpel) ((P_A + P_B + 1) >> 1); + cur_pred[0][2] = + cur_pred[2][3] = (imgpel) ((P_B + P_C + 1) >> 1); + cur_pred[0][3] = (imgpel) ((P_C + P_D + 1) >> 1); + cur_pred[1][0] = + cur_pred[3][1] = (imgpel) ((P_I + 2*P_X + P_A + 2) >> 2); + cur_pred[1][1] = + cur_pred[3][2] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + cur_pred[1][2] = + cur_pred[3][3] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + cur_pred[1][3] = (imgpel) ((P_B + 2*P_C + P_D + 2) >> 2); + cur_pred[2][0] = (imgpel) ((P_X + 2*P_I + P_J + 2) >> 2); + cur_pred[3][0] = (imgpel) ((P_I + 2*P_J + P_K + 2) >> 2); +} + +/*! + ************************************************************************ + * \brief + * Horizontal Down 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_hordown(imgpel **cur_pred, imgpel *PredPel) +{ + cur_pred[0][0] = + cur_pred[1][2] = (imgpel) ((P_X + P_I + 1) >> 1); + cur_pred[0][1] = + cur_pred[1][3] = (imgpel) ((P_I + 2*P_X + P_A + 2) >> 2); + cur_pred[0][2] = (imgpel) ((P_X + 2*P_A + P_B + 2) >> 2); + cur_pred[0][3] = (imgpel) ((P_A + 2*P_B + P_C + 2) >> 2); + cur_pred[1][0] = + cur_pred[2][2] = (imgpel) ((P_I + P_J + 1) >> 1); + cur_pred[1][1] = + cur_pred[2][3] = (imgpel) ((P_X + 2*P_I + P_J + 2) >> 2); + cur_pred[2][0] = + cur_pred[3][2] = (imgpel) ((P_J + P_K + 1) >> 1); + cur_pred[2][1] = + cur_pred[3][3] = (imgpel) ((P_I + 2*P_J + P_K + 2) >> 2); + cur_pred[3][0] = (imgpel) ((P_K + P_L + 1) >> 1); + cur_pred[3][1] = (imgpel) ((P_J + 2*P_K + P_L + 2) >> 2); +} + + +/*! + ************************************************************************ + * \brief + * Horizontal Up 4x4 Prediction + ************************************************************************ + */ +static inline void get_i4x4_horup(imgpel **cur_pred, imgpel *PredPel) +{ + cur_pred[0][0] = (imgpel) ((P_I + P_J + 1) >> 1); + cur_pred[0][1] = (imgpel) ((P_I + 2*P_J + P_K + 2) >> 2); + cur_pred[0][2] = + cur_pred[1][0] = (imgpel) ((P_J + P_K + 1) >> 1); + cur_pred[0][3] = + cur_pred[1][1] = (imgpel) ((P_J + 2*P_K + P_L + 2) >> 2); + cur_pred[1][2] = + cur_pred[2][0] = (imgpel) ((P_K + P_L + 1) >> 1); + cur_pred[1][3] = + cur_pred[2][1] = (imgpel) ((P_K + 2*P_L + P_L + 2) >> 2); + cur_pred[3][0] = + cur_pred[2][2] = + cur_pred[2][3] = + cur_pred[3][1] = + cur_pred[3][2] = + cur_pred[3][3] = (imgpel) P_L; +} + +/*! + ************************************************************************ + * \brief + * Make intra 4x4 prediction according to all 9 prediction modes. + * The routine uses left and upper neighbouring points from + * previous coded blocks to do this (if available). Notice that + * inaccessible neighbouring points are signalled with a negative + * value in the predmode array . + * + * \par Input: + * Starting point of current 4x4 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_4x4_mbaff(Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i; + imgpel *PredPel = currMB->intra4x4_pred[pl]; // array of predictor pels + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + + int ioff = (img_x & 15); + int joff = (img_y & 15); + + PixelPos pix_a[4]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + for (i = 0; i < 4; i++) + { + p_Vid->getNeighbour(currMB, ioff -1 , joff + i , mb_size, &pix_a[i]); + } + + p_Vid->getNeighbour(currMB, ioff , joff -1 , mb_size, &pix_b); + p_Vid->getNeighbour(currMB, ioff + 4 , joff -1 , mb_size, &pix_c); + p_Vid->getNeighbour(currMB, ioff - 1 , joff -1 , mb_size, &pix_d); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Inp->UseConstrainedIntraPred) + { + for (i=0, block_available_left=1; i<4;i++) + block_available_left &= pix_a[i].available ? p_Vid->intra_block[pix_a[i].mb_addr]: 0; + block_available_up = pix_b.available ? p_Vid->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? p_Vid->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? p_Vid->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + *left_available = block_available_left; + *up_available = block_available_up; + *all_available = block_available_up && block_available_left && block_available_up_left; + + i = (img_x & 15); + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { + P_A = P_B = P_C = P_D = (imgpel) p_Vid->dc_pred_value; + } + + if (block_available_up_right) + { + memcpy(&PredPel[5], &img_enc[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { + P_E = P_F = P_G = P_H = P_D; + } + + if (block_available_left) + { + P_I = img_enc[pix_a[0].pos_y][pix_a[0].pos_x]; + P_J = img_enc[pix_a[1].pos_y][pix_a[1].pos_x]; + P_K = img_enc[pix_a[2].pos_y][pix_a[2].pos_x]; + P_L = img_enc[pix_a[3].pos_y][pix_a[3].pos_x]; + } + else + { + P_I = P_J = P_K = P_L = p_Vid->dc_pred_value; + } + + if (block_available_up_left) + { + P_X = img_enc[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_X = p_Vid->dc_pred_value; + } +} + +/*! + ************************************************************************ + * \brief + * Make intra 4x4 prediction according to all 9 prediction modes. + * The routine uses left and upper neighbouring points from + * previous coded blocks to do this (if available). Notice that + * inaccessible neighbouring points are signalled with a negative + * value in the predmode array . + * + * \par Input: + * Starting point of current 4x4 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_4x4(Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + imgpel *PredPel = currMB->intra4x4_pred[pl]; // array of predictor pels + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + + int ioff = (img_x & 15); + int joff = (img_y & 15); + + PixelPos pix_a, pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + p_Vid->getNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + p_Vid->getNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + p_Vid->getNeighbour(currMB, ioff + 4, joff - 1, mb_size, &pix_c); + p_Vid->getNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available && !((ioff==4) && ((joff==4)||(joff==12))); + + if (p_Inp->UseConstrainedIntraPred) + { + block_available_left = pix_a.available ? p_Vid->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? p_Vid->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? p_Vid->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? p_Vid->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + *left_available = block_available_left; + *up_available = block_available_up; + *all_available = block_available_up && block_available_left && block_available_up_left; + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { + P_A = P_B = P_C = P_D = (imgpel) p_Vid->dc_pred_value; + } + + if (block_available_up_right) + { + memcpy(&PredPel[5], &img_enc[pix_c.pos_y][pix_c.pos_x], BLOCK_SIZE * sizeof(imgpel)); + } + else + { + P_E = P_F = P_G = P_H = P_D; + } + + if (block_available_left) + { + int pos_y = pix_a.pos_y; + int pos_x = pix_a.pos_x; + P_I = img_enc[pos_y++][pos_x]; + P_J = img_enc[pos_y++][pos_x]; + P_K = img_enc[pos_y++][pos_x]; + P_L = img_enc[pos_y ][pos_x]; + } + else + { + P_I = P_J = P_K = P_L = p_Vid->dc_pred_value; + } + + if (block_available_up_left) + { + P_X = img_enc[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_X = p_Vid->dc_pred_value; + } +} + +/*! + ************************************************************************ + * \brief + * Generate 4x4 intra prediction block + * + * \par Input: + * Starting point of current 4x4 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void get_intrapred_4x4(Macroblock *currMB, ColorPlane pl, int i4x4_mode, int img_x, int img_y, int left_available, int up_available) +{ + imgpel *PredPel = currMB->intra4x4_pred[pl]; // array of predictor pels + imgpel ***curr_mpr_4x4 = currMB->p_Slice->mpr_4x4[pl]; + + // Note that currently prediction values are always placed starting from (0,0) and not according to block position. + + switch (i4x4_mode) + { + case VERT_PRED : + get_i4x4_vertical(curr_mpr_4x4[VERT_PRED], PredPel); + break; + case HOR_PRED : + get_i4x4_horizontal(curr_mpr_4x4[HOR_PRED], PredPel); + break; + case DC_PRED : + get_i4x4_dc(curr_mpr_4x4[DC_PRED], PredPel, left_available, up_available); + break; + case DIAG_DOWN_LEFT_PRED : + get_i4x4_downleft(curr_mpr_4x4[DIAG_DOWN_LEFT_PRED], PredPel); + break; + case DIAG_DOWN_RIGHT_PRED : + get_i4x4_downright(curr_mpr_4x4[DIAG_DOWN_RIGHT_PRED], PredPel); + break; + case VERT_RIGHT_PRED : + get_i4x4_vertright(curr_mpr_4x4[VERT_RIGHT_PRED], PredPel); + break; + case HOR_DOWN_PRED : + get_i4x4_hordown(curr_mpr_4x4[HOR_DOWN_PRED], PredPel); + break; + case VERT_LEFT_PRED : + get_i4x4_vertleft(curr_mpr_4x4[VERT_LEFT_PRED], PredPel); + break; + case HOR_UP_PRED : + get_i4x4_horup(curr_mpr_4x4[HOR_UP_PRED], PredPel); + break; + default: + printf("invalid prediction mode \n"); + break; + } +} diff --git a/lencod/src/intra8x8.c b/lencod/src/intra8x8.c new file mode 100644 index 0000000..56b9dd4 --- /dev/null +++ b/lencod/src/intra8x8.c @@ -0,0 +1,756 @@ +/*! + ************************************************************************************* + * \file intra8x8.c + * + * \brief + * Intra 8x8 mode functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "intra8x8.h" + +// Notation for comments regarding prediction and predictors. +// The pels of the 8x8 block are labelled a1..h8. The predictor pels above +// are labelled A..P, from the left Q..X, and from above left Z, as follows: +// +// Z A B C D E F G H I J K L M N O P +// Q a1 b1 c1 d1 e1 f1 g1 h1 +// R a2 b2 c2 d2 e2 f2 g2 h2 +// S a3 b3 c3 d3 e3 f3 g3 h3 +// T a4 b4 c4 d4 e4 f4 g4 h4 +// U a5 b5 c5 d5 e5 f5 g5 h5 +// V a6 b6 c6 d6 e6 f6 g6 h6 +// W a7 b7 c7 d7 e7 f7 g7 h7 +// X a8 b8 c8 d8 e8 f8 g8 h8 + +// Predictor array index definitions +#define P_Z (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) +#define P_M (PredPel[13]) +#define P_N (PredPel[14]) +#define P_O (PredPel[15]) +#define P_P (PredPel[16]) +#define P_Q (PredPel[17]) +#define P_R (PredPel[18]) +#define P_S (PredPel[19]) +#define P_T (PredPel[20]) +#define P_U (PredPel[21]) +#define P_V (PredPel[22]) +#define P_W (PredPel[23]) +#define P_X (PredPel[24]) + +void generate_pred_error_8x8(imgpel **cur_img, imgpel **prd_img, imgpel **cur_prd, + int **m7, int pic_opix_x, int block_x) +{ + int j, i, *m7_line; + imgpel *cur_line, *prd_line; + + for (j=0; j < BLOCK_SIZE_8x8; j++) + { + prd_line = prd_img[j]; + memcpy(&cur_prd[j][block_x], prd_line, BLOCK_SIZE_8x8 * sizeof(imgpel)); + cur_line = &cur_img[j][pic_opix_x]; + m7_line = &m7[j][block_x]; + for (i = 0; i < BLOCK_SIZE_8x8; i++) + { + *m7_line++ = (int) (*cur_line++ - *prd_line++); + } + } +} + +/*! + ************************************************************************************* + * \brief + * Prefiltering for Intra8x8 prediction + ************************************************************************************* + */ +void LowPassForIntra8x8Pred(imgpel *PredPel, int block_up_left, int block_up, int block_left) +{ + int i; + imgpel LoopArray[25]; + + memcpy(LoopArray,PredPel, 25 * sizeof(imgpel)); + + if(block_up) + { + if(block_up_left) + { + LoopArray[1] = (imgpel) ((PredPel[0] + (PredPel[1]<<1) + PredPel[2] + 2) >> 2); + } + else + LoopArray[1] = (imgpel) ((PredPel[1] + (PredPel[1]<<1) + PredPel[2] + 2) >> 2); + + + for(i = 2; i <16; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2) >> 2); + } + LoopArray[16] = (imgpel) ((PredPel[15] + PredPel[16] + (PredPel[16]<<1) + 2) >> 2); + } + + if(block_up_left) + { + if(block_up && block_left) + { + LoopArray[0] = (imgpel) (((PredPel[0] << 1) + PredPel[1] + PredPel[17] + 2) >> 2); + } + else + { + if(block_up) + LoopArray[0] = (imgpel) ((PredPel[0] + (PredPel[0] << 1) + PredPel[1] + 2) >> 2); + else + if(block_left) + LoopArray[0] = (imgpel) ((PredPel[0] + (PredPel[0] << 1) + PredPel[17] + 2) >> 2); + } + } + + if(block_left) + { + if(block_up_left) + LoopArray[17] = (imgpel) ((PredPel[0] + (PredPel[17] << 1) + PredPel[18] + 2) >> 2); + else + LoopArray[17] = (imgpel) ((PredPel[17] + (PredPel[17] << 1) + PredPel[18] + 2) >> 2); + + for(i = 18; i <24; i++) + { + LoopArray[i] = (imgpel) ((PredPel[i-1] + (PredPel[i]<<1) + PredPel[i+1] + 2) >> 2); + } + LoopArray[24] = (imgpel) ((PredPel[23] + (PredPel[24] << 1) + PredPel[24] + 2) >> 2); + } + + memcpy(PredPel, LoopArray, 25 * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Vertical 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_vertical(imgpel **cur_pred, imgpel *PredPel) +{ + int j; + for (j=0; j < BLOCK_SIZE_8x8; j++) + memcpy(cur_pred[j], &P_A, BLOCK_SIZE_8x8 * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Horizontal 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_horizontal(imgpel **cur_pred, imgpel *PredPel) +{ + int i; + for (i=0; i < BLOCK_SIZE_8x8; i++) + { + cur_pred[i][0] = + cur_pred[i][1] = + cur_pred[i][2] = + cur_pred[i][3] = + cur_pred[i][4] = + cur_pred[i][5] = + cur_pred[i][6] = + cur_pred[i][7] = (imgpel) (&P_Q)[i]; + } +} + +/*! + ************************************************************************ + * \brief + * DC 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_dc(imgpel **cur_pred, imgpel *PredPel, int left_available, int up_available) +{ + int i, j, s0 = 0; + if (up_available && left_available) + { + // no edge + s0 = rshift_rnd_sf((P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H + P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X), 4); + } + else if (!up_available && left_available) + { + // upper edge + s0 = rshift_rnd_sf((P_Q + P_R + P_S + P_T + P_U + P_V + P_W + P_X), 3); + } + else if (up_available && !left_available) + { + // left edge + s0 = rshift_rnd_sf((P_A + P_B + P_C + P_D + P_E + P_F + P_G + P_H), 3); + } + else //if (!up_available && !left_available) + { + // top left corner, nothing to predict from + s0 = P_A; //p_Vid->dc_pred_value; + } + + // First line + for (i=0; i < BLOCK_SIZE_8x8; i++) + { + cur_pred[0][i] = (imgpel) s0; + } + + for (j=0; j < BLOCK_SIZE_8x8 - 1; j++) + { + memcpy (cur_pred[j + 1], cur_pred[j], BLOCK_SIZE_8x8 * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Diagonal Down Left 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_downleft(imgpel **cur_pred, imgpel *PredPel) +{ + imgpel PredArray[16]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + + // Mode DIAG_DOWN_LEFT_PRED + *Pred++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_G + P_I + ((P_H) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_H + P_J + ((P_I) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_I + P_K + ((P_J) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_J + P_L + ((P_K) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_K + P_M + ((P_L) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_L + P_N + ((P_M) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_M + P_O + ((P_N) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_N + P_P + ((P_O) << 1) + 2) >> 2); + *Pred = (imgpel) ((P_O + P_P + ((P_P) << 1) + 2) >> 2); + + Pred = &PredArray[ 0]; + + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred++, 8 * sizeof(imgpel)); + memcpy(*cur_pred , Pred , 8 * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Diagonal Down Right 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_downright(imgpel **cur_pred, imgpel *PredPel) +{ + imgpel PredArray[16]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + + // Mode DIAG_DOWN_RIGHT_PRED + *Pred++ = (imgpel) ((P_X + P_V + ((P_W) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_W + P_U + ((P_V) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_V + P_T + ((P_U) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_U + P_S + ((P_T) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_T + P_R + ((P_S) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_S + P_Q + ((P_R) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_R + P_Z + ((P_Q) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Q + P_A + ((P_Z) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Z + P_B + ((P_A) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *Pred = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + + Pred = &PredArray[7]; + + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred++, Pred--, 8 * sizeof(imgpel)); + memcpy(*cur_pred , Pred , 8 * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Vertical Left 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_vertleft(imgpel **cur_pred, imgpel *PredPel) +{ + imgpel PredArray[22]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + + *Pred++ = (imgpel) ((P_A + P_B + 1) >> 1); + *Pred++ = (imgpel) ((P_B + P_C + 1) >> 1); + *Pred++ = (imgpel) ((P_C + P_D + 1) >> 1); + *Pred++ = (imgpel) ((P_D + P_E + 1) >> 1); + *Pred++ = (imgpel) ((P_E + P_F + 1) >> 1); + *Pred++ = (imgpel) ((P_F + P_G + 1) >> 1); + *Pred++ = (imgpel) ((P_G + P_H + 1) >> 1); + *Pred++ = (imgpel) ((P_H + P_I + 1) >> 1); + *Pred++ = (imgpel) ((P_I + P_J + 1) >> 1); + *Pred++ = (imgpel) ((P_J + P_K + 1) >> 1); + *Pred++ = (imgpel) ((P_K + P_L + 1) >> 1); + *Pred++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_G + P_I + ((P_H) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_H + P_J + ((P_I) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_I + P_K + ((P_J) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_J + P_L + ((P_K) << 1) + 2) >> 2); + *Pred = (imgpel) ((P_K + P_M + ((P_L) << 1) + 2) >> 2); + + memcpy(*cur_pred++, &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[11], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[12], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[13], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy(*cur_pred , &PredArray[14], 8 * sizeof(imgpel)); +} + + +/*! + ************************************************************************ + * \brief + * Vertical Right 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_vertright(imgpel **cur_pred, imgpel *PredPel) +{ + imgpel PredArray[22]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + + *Pred++ = (imgpel) ((P_V + P_T + ((P_U) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_T + P_R + ((P_S) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_R + P_Z + ((P_Q) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Z + P_A + 1) >> 1); + *Pred++ = (imgpel) ((P_A + P_B + 1) >> 1); + *Pred++ = (imgpel) ((P_B + P_C + 1) >> 1); + *Pred++ = (imgpel) ((P_C + P_D + 1) >> 1); + *Pred++ = (imgpel) ((P_D + P_E + 1) >> 1); + *Pred++ = (imgpel) ((P_E + P_F + 1) >> 1); + *Pred++ = (imgpel) ((P_F + P_G + 1) >> 1); + *Pred++ = (imgpel) ((P_G + P_H + 1) >> 1); + + *Pred++ = (imgpel) ((P_W + P_U + ((P_V) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_U + P_S + ((P_T) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_S + P_Q + ((P_R) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Q + P_A + ((P_Z) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Z + P_B + ((P_A) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + *Pred = (imgpel) ((P_F + P_H + ((P_G) << 1) + 2) >> 2); + + memcpy(*cur_pred++, &PredArray[ 3], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[14], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[13], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 1], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[12], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(*cur_pred , &PredArray[11], 8 * sizeof(imgpel)); +} + +/*! + ************************************************************************ + * \brief + * Horizontal Down 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_hordown(imgpel **cur_pred, imgpel *PredPel) +{ + imgpel PredArray[22]; // array of final prediction values + imgpel *Pred = &PredArray[0]; + + *Pred++ = (imgpel) ((P_X + P_W + 1) >> 1); + *Pred++ = (imgpel) ((P_V + P_X + (P_W << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_W + P_V + 1) >> 1); + *Pred++ = (imgpel) ((P_U + P_W + ((P_V) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_V + P_U + 1) >> 1); + *Pred++ = (imgpel) ((P_T + P_V + ((P_U) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_U + P_T + 1) >> 1); + *Pred++ = (imgpel) ((P_S + P_U + ((P_T) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_T + P_S + 1) >> 1); + *Pred++ = (imgpel) ((P_R + P_T + ((P_S) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_S + P_R + 1) >> 1); + *Pred++ = (imgpel) ((P_Q + P_S + ((P_R) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_R + P_Q + 1) >> 1); + *Pred++ = (imgpel) ((P_Z + P_R + ((P_Q) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Q + P_Z + 1) >> 1); + *Pred++ = (imgpel) ((P_Q + P_A + ((P_Z) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_Z + P_B + ((P_A) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_A + P_C + ((P_B) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_B + P_D + ((P_C) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_C + P_E + ((P_D) << 1) + 2) >> 2); + *Pred++ = (imgpel) ((P_D + P_F + ((P_E) << 1) + 2) >> 2); + *Pred = (imgpel) ((P_E + P_G + ((P_F) << 1) + 2) >> 2); + + Pred = &PredArray[14]; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred++, Pred, 8 * sizeof(imgpel)); + Pred -= 2; + memcpy(*cur_pred , Pred, 8 * sizeof(imgpel)); +} + + +/*! + ************************************************************************ + * \brief + * Horizontal Up 8x8 Prediction + ************************************************************************ + */ +static inline void get_i8x8_horup(imgpel **cur_pred, imgpel *PredPel) +{ + imgpel PredArray[22]; + PredArray[ 0] = (imgpel) ((P_Q + P_R + 1) >> 1); + PredArray[ 1] = (imgpel) ((P_S + P_Q + ((P_R) << 1) + 2) >> 2); + PredArray[ 2] = (imgpel) ((P_R + P_S + 1) >> 1); + PredArray[ 3] = (imgpel) ((P_T + P_R + ((P_S) << 1) + 2) >> 2); + PredArray[ 4] = (imgpel) ((P_S + P_T + 1) >> 1); + PredArray[ 5] = (imgpel) ((P_U + P_S + ((P_T) << 1) + 2) >> 2); + PredArray[ 6] = (imgpel) ((P_T + P_U + 1) >> 1); + PredArray[ 7] = (imgpel) ((P_V + P_T + ((P_U) << 1) + 2) >> 2); + PredArray[ 8] = (imgpel) ((P_U + P_V + 1) >> 1); + PredArray[ 9] = (imgpel) ((P_W + P_U + ((P_V) << 1) + 2) >> 2); + PredArray[10] = (imgpel) ((P_V + P_W + 1) >> 1); + PredArray[11] = (imgpel) ((P_X + P_V + ((P_W) << 1) + 2) >> 2); + PredArray[12] = (imgpel) ((P_W + P_X + 1) >> 1); + PredArray[13] = (imgpel) ((P_W + P_X + ((P_X) << 1) + 2) >> 2); + PredArray[14] = (imgpel) P_X; + PredArray[15] = (imgpel) P_X; + PredArray[16] = (imgpel) P_X; + PredArray[17] = (imgpel) P_X; + PredArray[18] = (imgpel) P_X; + PredArray[19] = (imgpel) P_X; + PredArray[20] = (imgpel) P_X; + PredArray[21] = (imgpel) P_X; + + memcpy(*cur_pred++, &PredArray[ 0], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 2], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 4], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 6], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[ 8], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[10], 8 * sizeof(imgpel)); + memcpy(*cur_pred++, &PredArray[12], 8 * sizeof(imgpel)); + memcpy(*cur_pred , &PredArray[14], 8 * sizeof(imgpel)); +} + + +/*! + ************************************************************************ + * \brief + * Set intra 8x8 prediction samples + * + * \par Input: + * Starting point of current 8x8 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_8x8(Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + imgpel *PredPel = currMB->intra8x8_pred[pl]; // array of predictor pels + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + int ioff = (img_x & 15); + int joff = (img_y & 15); + + PixelPos pix_a, pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + p_Vid->getNeighbour(currMB, ioff - 1, joff , mb_size, &pix_a); + p_Vid->getNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + p_Vid->getNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + p_Vid->getNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Inp->UseConstrainedIntraPred) + { + block_available_left = pix_a.available ? p_Vid->intra_block [pix_a.mb_addr]: 0; + block_available_up = pix_b.available ? p_Vid->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? p_Vid->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? p_Vid->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a.available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + *left_available = block_available_left; + *up_available = block_available_up; + *all_available = block_available_up && block_available_left && block_available_up_left; + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], 8 * sizeof(imgpel)); + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = p_Vid->dc_pred_value; + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &img_enc[pix_c.pos_y][pix_c.pos_x], 8 * sizeof(imgpel)); + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + int pos_y = pix_a.pos_y; + int pos_x = pix_a.pos_x; + P_Q = img_enc[pos_y++][pos_x]; + P_R = img_enc[pos_y++][pos_x]; + P_S = img_enc[pos_y++][pos_x]; + P_T = img_enc[pos_y++][pos_x]; + P_U = img_enc[pos_y++][pos_x]; + P_V = img_enc[pos_y++][pos_x]; + P_W = img_enc[pos_y++][pos_x]; + P_X = img_enc[pos_y ][pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = p_Vid->dc_pred_value; + } + + if (block_available_up_left) + { + P_Z = img_enc[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = p_Vid->dc_pred_value; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); +} + + +/*! + ************************************************************************ + * \brief + * Set intra 8x8 prediction samples + * + * \par Input: + * Starting point of current 8x8 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_8x8_mbaff(Macroblock *currMB, ColorPlane pl, int img_x,int img_y, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i; + imgpel *PredPel = currMB->intra8x8_pred[pl]; // array of predictor pels + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + int ioff = (img_x & 15); + int joff = (img_y & 15); + + PixelPos pix_a[8]; + PixelPos pix_b, pix_c, pix_d; + + int block_available_up; + int block_available_left; + int block_available_up_left; + int block_available_up_right; + + for (i=0;i<8;i++) + { + p_Vid->getNeighbour(currMB, ioff - 1, joff + i , mb_size, &pix_a[i]); + } + + p_Vid->getNeighbour(currMB, ioff , joff - 1, mb_size, &pix_b); + p_Vid->getNeighbour(currMB, ioff + 8, joff - 1, mb_size, &pix_c); + p_Vid->getNeighbour(currMB, ioff - 1, joff - 1, mb_size, &pix_d); + + pix_c.available = pix_c.available &&!(ioff == 8 && joff == 8); + + if (p_Inp->UseConstrainedIntraPred) + { + for (i=0, block_available_left=1; i<8;i++) + block_available_left &= pix_a[i].available ? p_Vid->intra_block[pix_a[i].mb_addr]: 0; + + block_available_up = pix_b.available ? p_Vid->intra_block [pix_b.mb_addr] : 0; + block_available_up_right = pix_c.available ? p_Vid->intra_block [pix_c.mb_addr] : 0; + block_available_up_left = pix_d.available ? p_Vid->intra_block [pix_d.mb_addr] : 0; + } + else + { + block_available_left = pix_a[0].available; + block_available_up = pix_b.available; + block_available_up_right = pix_c.available; + block_available_up_left = pix_d.available; + } + + *left_available = block_available_left; + *up_available = block_available_up; + *all_available = block_available_up && block_available_left && block_available_up_left; + + // form predictor pels + if (block_available_up) + { + memcpy(&PredPel[1], &img_enc[pix_b.pos_y][pix_b.pos_x], 8 * sizeof(imgpel)); + } + else + { + P_A = P_B = P_C = P_D = P_E = P_F = P_G = P_H = p_Vid->dc_pred_value; + } + + if (block_available_up_right) + { + memcpy(&PredPel[9], &img_enc[pix_c.pos_y][pix_c.pos_x], 8 * sizeof(imgpel)); + } + else + { + P_I = P_J = P_K = P_L = P_M = P_N = P_O = P_P = P_H; + } + + if (block_available_left) + { + P_Q = img_enc[pix_a[0].pos_y][pix_a[0].pos_x]; + P_R = img_enc[pix_a[1].pos_y][pix_a[1].pos_x]; + P_S = img_enc[pix_a[2].pos_y][pix_a[2].pos_x]; + P_T = img_enc[pix_a[3].pos_y][pix_a[3].pos_x]; + P_U = img_enc[pix_a[4].pos_y][pix_a[4].pos_x]; + P_V = img_enc[pix_a[5].pos_y][pix_a[5].pos_x]; + P_W = img_enc[pix_a[6].pos_y][pix_a[6].pos_x]; + P_X = img_enc[pix_a[7].pos_y][pix_a[7].pos_x]; + } + else + { + P_Q = P_R = P_S = P_T = P_U = P_V = P_W = P_X = p_Vid->dc_pred_value; + } + + if (block_available_up_left) + { + P_Z = img_enc[pix_d.pos_y][pix_d.pos_x]; + } + else + { + P_Z = p_Vid->dc_pred_value; + } + + LowPassForIntra8x8Pred(PredPel, block_available_up_left, block_available_up, block_available_left); +} + +/*! + ************************************************************************ + * \brief + * Generate 8x8 intra prediction block + * + * \par Input: + * Starting point of current 8x8 block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void get_intrapred_8x8(Macroblock *currMB, ColorPlane pl, int i8x8_mode, int left_available, int up_available) +{ + imgpel *PredPel = currMB->intra8x8_pred[pl]; // array of predictor pels + Slice *currSlice = currMB->p_Slice; + imgpel ***curr_mpr_8x8 = currSlice->mpr_8x8[pl]; + + switch (i8x8_mode) + { + case VERT_PRED : + get_i8x8_vertical(curr_mpr_8x8[VERT_PRED], PredPel); + break; + case HOR_PRED : + get_i8x8_horizontal(curr_mpr_8x8[HOR_PRED], PredPel); + break; + case DC_PRED : + get_i8x8_dc(curr_mpr_8x8[DC_PRED], PredPel, left_available, up_available); + break; + case DIAG_DOWN_LEFT_PRED : + get_i8x8_downleft(curr_mpr_8x8[DIAG_DOWN_LEFT_PRED], PredPel); + break; + case DIAG_DOWN_RIGHT_PRED : + get_i8x8_downright(curr_mpr_8x8[DIAG_DOWN_RIGHT_PRED], PredPel); + break; + case VERT_RIGHT_PRED : + get_i8x8_vertright(curr_mpr_8x8[VERT_RIGHT_PRED], PredPel); + break; + case HOR_DOWN_PRED : + get_i8x8_hordown(curr_mpr_8x8[HOR_DOWN_PRED], PredPel); + break; + case VERT_LEFT_PRED : + get_i8x8_vertleft(curr_mpr_8x8[VERT_LEFT_PRED], PredPel); + break; + case HOR_UP_PRED : + get_i8x8_horup(curr_mpr_8x8[HOR_UP_PRED], PredPel); + break; + default: + printf("invalid prediction mode \n"); + break; + } +} + diff --git a/lencod/src/intra_chroma.c b/lencod/src/intra_chroma.c new file mode 100644 index 0000000..ec7b851 --- /dev/null +++ b/lencod/src/intra_chroma.c @@ -0,0 +1,1215 @@ +/*! +************************************************************************************* + * \file intra_chroma.c + * + * \brief + * Intra chroma mode functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "block.h" +#include "mv_search.h" + +void get_difference_4x4(imgpel **src, imgpel **prd, short *diff, int pos_x, int block_x) +{ + int i, j; + short *p_diff = diff; + imgpel *img_prd, *img_src; + for (j = 0; j < BLOCK_SIZE; j++) + { + img_src = &src[j][pos_x + block_x]; + img_prd = &prd[j][block_x]; + + for (i = 0; i < BLOCK_SIZE; i++) + *p_diff++ = img_src[i] - img_prd[i]; + } +} + +/*! + ************************************************************************ + * \brief + * Vertical Chroma Prediction + ************************************************************************ + */ +static inline void get_iChroma_vertical(imgpel **cur_pred, imgpel *PredPel, int cr_MB_x, int cr_MB_y) +{ + int j; + for (j = 0; j < cr_MB_y; j++) + memcpy(cur_pred[j], &PredPel[1], cr_MB_x * sizeof(imgpel)); +} + + +/*! + ************************************************************************ + * \brief + * Horizontal Chroma Prediction + ************************************************************************ + */ +static inline void get_iChroma_horizontal(imgpel **cur_pred, imgpel *PredPel, int cr_MB_x, int cr_MB_y) +{ + int i, j; + imgpel *prediction = &PredPel[16]; + + for (j = 0; j < cr_MB_y; j++) + { + prediction++; + for (i = 0; i < cr_MB_x; i++) + { + cur_pred[j][i] = *prediction; + } + } +} + +/*! + ************************************************************************ + * \brief + * DC Chroma Prediction + ************************************************************************ + */ +static inline void get_iChroma_dc(imgpel **cur_pred, imgpel *PredPel, int left_available, int up_available) +{ + int i, j, s0 = 0, s1 = 0, s2 = 0; + + if (up_available) + { + for (i = 1; i < MB_BLOCK_SIZE + 1; ++i) + s1 += PredPel[i]; + } + + if (left_available) + { + for (i = 17; i < 33; ++i) + s2 += PredPel[i]; // sum vert pix + } + + if (up_available) + { + s0 = left_available + ? rshift_rnd_sf((s1 + s2),(MB_BLOCK_SHIFT + 1)) // no edge + : rshift_rnd_sf(s1, MB_BLOCK_SHIFT); // left edge + } + else + { + s0 = left_available + ? rshift_rnd_sf(s2, MB_BLOCK_SHIFT) // upper edge + : PredPel[1]; // top left corner, nothing to predict from + } + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + for (i = 0; i < MB_BLOCK_SIZE; i++) + cur_pred[j][i] = (imgpel) s0; + } +} + +/*! + ************************************************************************ + * \brief + * Plane Chroma Prediction + ************************************************************************ + */ +static inline void get_iChroma_plane(imgpel **cur_pred, imgpel *PredPel, int max_imgpel_value) +{ + int i, j; + // plane prediction + int ih=0, iv=0; + int ib, ic, iaa; + imgpel *t_pred = &PredPel[25]; + imgpel *u_pred = &PredPel[8]; + imgpel *b_pred = &PredPel[23]; + + for (i = 1; i < 8;++i) + { + ih += i*(*(u_pred + i) - *(u_pred - i)); + iv += i*(*t_pred++ - *b_pred--); + } + ih += 8 * (*(u_pred + 8) - PredPel[0]); + iv += 8 * (*t_pred++ - PredPel[0]); + + ib = (5 * ih + 32) >> 6; + ic = (5 * iv + 32) >> 6; + + iaa=16 * (PredPel[16] + PredPel[32]); + + for (j=0;j< MB_BLOCK_SIZE;++j) + { + for (i=0;i< MB_BLOCK_SIZE;++i) + { + cur_pred[j][i]= (imgpel) iClip1( max_imgpel_value, rshift_rnd_sf((iaa + (i - 7) * ib + (j - 7) * ic), 5));// store plane prediction + } + } +} + +/*! + ************************************************************************ + * \brief + * Set intra Chroma prediction samples + * + * \par Input: + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_chroma(Macroblock *currMB, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i; + imgpel *PredPelU = currMB->intra16x16_pred[PLANE_U]; // array of predictor pels + imgpel *PredPelV = currMB->intra16x16_pred[PLANE_V]; // array of predictor pels + imgpel **img_enc_u = p_Vid->enc_picture->imgUV[0]; + imgpel **img_enc_v = p_Vid->enc_picture->imgUV[1]; + + PixelPos pix_b; + PixelPos pix_a; + PixelPos pix_d; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + + imgpel dc_pred_value_chroma = p_Vid->dc_pred_value_comp[1]; + + int *mb_size = p_Vid->mb_size[IS_CHROMA]; + + p_Vid->getNeighbour(currMB, -1, -1, mb_size, &pix_d); + p_Vid->getNeighbour(currMB, -1, 0, mb_size, &pix_a); + p_Vid->getNeighbour(currMB, 0, -1, mb_size, &pix_b); + + if (p_Inp->UseConstrainedIntraPred == 0) + { + *up_available = pix_b.available; + *left_available = pix_a.available; + *all_available = pix_d.available; + } + else + { + *up_available = pix_b.available ? p_Vid->intra_block[pix_b.mb_addr] : 0; + *left_available = pix_a.available ? p_Vid->intra_block[pix_a.mb_addr] : 0; + *all_available = pix_d.available ? p_Vid->intra_block[pix_d.mb_addr] : 0; + } + + // form predictor pels + if (*up_available) + { + memcpy(&PredPelU[1], &img_enc_u[pix_b.pos_y][pix_b.pos_x], cr_MB_x * sizeof(imgpel)); + memcpy(&PredPelV[1], &img_enc_v[pix_b.pos_y][pix_b.pos_x], cr_MB_x * sizeof(imgpel)); + } + else + { + for (i = 1; i < cr_MB_x + 1; ++i) + PredPelU[i] = (imgpel) dc_pred_value_chroma; + for (i = 1; i < cr_MB_x + 1; ++i) + PredPelV[i] = (imgpel) dc_pred_value_chroma; + } + + if (*left_available) + { + int pos_y = pix_a.pos_y; + int pos_x = pix_a.pos_x; + + for (i = 1; i < cr_MB_y + 1; ++i) + { + PredPelU[i + cr_MB_x] = img_enc_u[pos_y ][pos_x]; + PredPelV[i + cr_MB_x] = img_enc_v[pos_y++][pos_x]; + } + } + else + { + for (i = cr_MB_x + 1; i < cr_MB_x + cr_MB_y + 1; ++i) + PredPelU[i] = (imgpel) dc_pred_value_chroma; + for (i = cr_MB_x + 1; i < cr_MB_x + cr_MB_y + 1; ++i) + PredPelV[i] = (imgpel) dc_pred_value_chroma; + } + + if (*all_available) + { + PredPelU[0] = img_enc_u[pix_d.pos_y][pix_d.pos_x]; + PredPelV[0] = img_enc_v[pix_d.pos_y][pix_d.pos_x]; + } + else + { + PredPelU[0] = dc_pred_value_chroma; + PredPelV[0] = dc_pred_value_chroma; + } +} + + +/*! + ************************************************************************ + * \brief + * Set intra Chroma prediction samples (MBAFF) + * + * \par Input: + * + * \par Output: + * none + ************************************************************************ + */ +void set_intrapred_chroma_mbaff(Macroblock *currMB, ColorPlane pl, int *left_available, int *up_available, int *all_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i; + imgpel *PredPelU = currMB->intra16x16_pred[PLANE_U]; // array of predictor pels + imgpel *PredPelV = currMB->intra16x16_pred[PLANE_V]; // array of predictor pels + imgpel **img_enc_u = p_Vid->enc_picture->imgUV[0]; + imgpel **img_enc_v = p_Vid->enc_picture->imgUV[1]; + + PixelPos pix_b; + PixelPos pix_a[17]; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + + imgpel dc_pred_value_chroma = p_Vid->dc_pred_value_comp[1]; + + int *mb_size = p_Vid->mb_size[IS_CHROMA]; + + for (i = 0; i < cr_MB_y + 1; ++i) + { + p_Vid->getNeighbour(currMB, -1, i - 1, mb_size, &pix_a[i]); + } + + p_Vid->getNeighbour(currMB, 0, -1, mb_size, &pix_b); + + if (p_Inp->UseConstrainedIntraPred == 0) + { + *up_available = pix_b.available; + *left_available = pix_a[1].available; + *all_available = pix_a[0].available; + } + else + { + *up_available = pix_b.available ? p_Vid->intra_block[pix_b.mb_addr] : 0; + for (i=1, *left_available=1; i<17;++i) + *left_available &= pix_a[i].available ? p_Vid->intra_block[pix_a[i].mb_addr]: 0; + *all_available = pix_a[0].available ? p_Vid->intra_block[pix_a[0].mb_addr]: 0; + } + + // form predictor pels + if (*up_available) + { + memcpy(&PredPelU[1], &img_enc_u[pix_b.pos_y][pix_b.pos_x], cr_MB_x * sizeof(imgpel)); + memcpy(&PredPelV[1], &img_enc_v[pix_b.pos_y][pix_b.pos_x], cr_MB_x * sizeof(imgpel)); + } + else + { + for (i = 1; i < cr_MB_x + 1; ++i) + PredPelU[i] = (imgpel) dc_pred_value_chroma; + for (i = 1; i < cr_MB_x + 1; ++i) + PredPelV[i] = (imgpel) dc_pred_value_chroma; + } + + if (*left_available) + { + for (i = 1; i < cr_MB_y + 1; ++i) + PredPelU[i + cr_MB_x] = img_enc_u[pix_a[i].pos_y][pix_a[i].pos_x]; + for (i = 1; i < cr_MB_y + 1; ++i) + PredPelV[i + cr_MB_x] = img_enc_v[pix_a[i].pos_y][pix_a[i].pos_x]; + } + else + { + for (i = cr_MB_x + 1; i < cr_MB_x + cr_MB_y + 1; ++i) + PredPelU[i] = (imgpel) dc_pred_value_chroma; + for (i = cr_MB_x + 1; i < cr_MB_x + cr_MB_y + 1; ++i) + PredPelV[i] = (imgpel) dc_pred_value_chroma; + } + + if (*all_available) + { + PredPelU[0] = img_enc_u[pix_a[0].pos_y][pix_a[0].pos_x]; + PredPelV[0] = img_enc_v[pix_a[0].pos_y][pix_a[0].pos_x]; + } + else + { + PredPelU[0] = dc_pred_value_chroma; + PredPelV[0] = dc_pred_value_chroma; + } +} + + +/*! + ************************************************************************ + * \brief + * Generate Chroma intra prediction block + * + * \par Input: + * Starting point of current Chroma block image posision + * + * \par Output: + * none + ************************************************************************ + */ +void get_intrapred_chroma(Macroblock *currMB, ColorPlane pl, int iChroma_mode, int left_available, int up_available) +{ + VideoParameters *p_Vid = currMB->p_Vid; + imgpel *PredPel = currMB->intra16x16_pred[pl]; // array of predictor pels + imgpel ***curr_mpr_16x16 = currMB->p_Slice->mpr_16x16[pl]; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + + switch (iChroma_mode) + { + case VERT_PRED_8 : + get_iChroma_vertical(curr_mpr_16x16[VERT_PRED_16], PredPel, cr_MB_x, cr_MB_y); + break; + case HOR_PRED_8 : + get_iChroma_horizontal(curr_mpr_16x16[HOR_PRED_16], PredPel, cr_MB_x, cr_MB_y); + break; + case DC_PRED_8 : + get_iChroma_dc(curr_mpr_16x16[DC_PRED_16], PredPel, left_available, up_available); + break; + case PLANE_8 : + get_iChroma_plane(curr_mpr_16x16[PLANE_16], PredPel, currMB->p_Vid->max_imgpel_value); + break; + default: + printf("invalid prediction mode \n"); + break; + } +} + +void rdo_low_intra_chroma_decision_mbaff(Macroblock *currMB, int mb_available_up, int mb_available_left[2], int mb_available_up_left) +{ // since ipredmodes could be overwritten => encoder-decoder-mismatches + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int i, j, uv; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + int block_x, block_y; + PixelPos pix_a[17]; //!< pixel positions p(-1, -1..15) + imgpel **image = NULL; + imgpel ***curr_mpr_16x16 = NULL; + + + short diff [16]; + short *p_diff; + distblk cost, min_cost = DISTBLK_MAX; + int mode; + int best_mode = DC_PRED_8; //just an initilaization here, should always be overwritten + imgpel *img_org = NULL, *img_prd = NULL; + + for (i=0;igetNeighbour(currMB, 0 , i, p_Vid->mb_size[IS_CHROMA], &pix_a[i]); + } + + if ( p_Vid->mb_aff_frame_flag && p_Vid->field_mode ) + { + for (i=0;i> 1; + } + } + + for (mode=DC_PRED_8; mode<=PLANE_8; mode++) + { + if (((currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && mode!=DC_PRED_8) + continue; + + if ((mode==VERT_PRED_8 && !mb_available_up) || + (mode==HOR_PRED_8 && (!mb_available_left[0] || !mb_available_left[1])) || + (mode==PLANE_8 && (!mb_available_left[0] || !mb_available_left[1] || !mb_available_up || !mb_available_up_left))) + continue; + + cost = 0; + for (uv = 1; uv < 3; uv++) + { + image = p_Vid->pImgOrg[uv]; + curr_mpr_16x16 = currSlice->mpr_16x16[uv]; + + for (block_y = 0; block_y < cr_MB_y; block_y += 4) + { + for (block_x = 0; block_x < cr_MB_x; block_x += 4) + { + p_diff = &diff[0]; + for (j = block_y; j < block_y + 4; j++) + { + img_prd = curr_mpr_16x16[mode][j]; + img_org = &image[pix_a[j].pos_y][pix_a[j].pos_x]; + for (i = block_x; i < block_x + 4; i++) + *p_diff++ = img_org[i] - img_prd[i]; + } + cost += p_Vid->distortion4x4(diff, min_cost); + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + if (cost < min_cost) + { + best_mode = mode; + min_cost = cost; + } + } + currMB->c_ipred_mode = (char) best_mode; +} + + +void rdo_low_intra_chroma_decision(Macroblock *currMB, int mb_available_up, int mb_available_left[2], int mb_available_up_left) +{ // since ipredmodes could be overwritten => encoder-decoder-mismatches + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int uv; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + int block_x, block_y; + PixelPos pix_a; //!< pixel positions p(-1, 0) + + imgpel **image = NULL; + imgpel ***curr_mpr_16x16 = NULL; + + short diff [16]; + + distblk cost, min_cost = DISTBLK_MAX; + int mode; + int best_mode = DC_PRED_8; //just an initialization here, should always be overwritten + + p_Vid->getNeighbour(currMB, 0 , 0, p_Vid->mb_size[IS_CHROMA], &pix_a); + + for (mode = DC_PRED_8; mode <= PLANE_8; mode++) + { + if (((currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && mode!=DC_PRED_8) + continue; + + if ((mode==VERT_PRED_8 && !mb_available_up) || + (mode==HOR_PRED_8 && (!mb_available_left[0] || !mb_available_left[1])) || + (mode==PLANE_8 && (!mb_available_left[0] || !mb_available_left[1] || !mb_available_up || !mb_available_up_left))) + continue; + + cost = 0; + + for (uv = 1; uv < 3; uv++) + { + int pos_x = pix_a.pos_x; + int pos_y = pix_a.pos_y; + image = p_Vid->pImgOrg[uv]; + curr_mpr_16x16 = currSlice->mpr_16x16[uv]; + + for (block_y = 0; block_y < cr_MB_y; block_y += BLOCK_SIZE) + { + for (block_x = 0; block_x < cr_MB_x; block_x += BLOCK_SIZE) + { + get_difference_4x4(&image[pos_y + block_y], &curr_mpr_16x16[mode][block_y], diff, pos_x, block_x); + cost += p_Vid->distortion4x4(diff, min_cost); + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + + if (cost < min_cost) + { + best_mode = mode; + min_cost = cost; + } + } + currMB->c_ipred_mode = (char) best_mode; +} + + +/*! + ************************************************************************ + * \brief + * Intra prediction of the chrminance layers of one macroblock + ************************************************************************ + */ +void intra_chroma_prediction (Macroblock *currMB, int *mb_up, int *mb_left, int*mb_up_left) +{ + int s, i, j; + + int uv; + int b8, b4; + imgpel vline[16]; + + int mb_available_up; + int mb_available_left[2]; + int mb_available_up_left; + + PixelPos pix_c; //!< pixel position p(0,-1) + PixelPos pix_d; + PixelPos pix_a; //!< pixel positions p(-1, -1..15) + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + imgpel **cur_pred = NULL; + + imgpel *hline = NULL; + + int yuv = p_Vid->yuv_format - 1; + int dc_pred_value_chroma = p_Vid->dc_pred_value_comp[1]; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + static const int block_pos[3][4][4]= //[yuv][b8][b4] + { + { {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}} + }; + + p_Vid->getNeighbour(currMB, -1, -1, p_Vid->mb_size[IS_CHROMA], &pix_d); + p_Vid->getNeighbour(currMB, -1, 0, p_Vid->mb_size[IS_CHROMA], &pix_a); + p_Vid->getNeighbour(currMB, 0, -1, p_Vid->mb_size[IS_CHROMA], &pix_c); + + mb_available_up = pix_c.available; + mb_available_up_left = pix_d.available; + mb_available_left[0] = mb_available_left[1] = pix_a.available; + + if(p_Inp->UseConstrainedIntraPred) + { + mb_available_up = pix_c.available ? p_Vid->intra_block[pix_c.mb_addr] : 0; + mb_available_left[0] = mb_available_left[1] = pix_a.available ? p_Vid->intra_block[pix_a.mb_addr] : 0; + mb_available_up_left = pix_d.available ? p_Vid->intra_block[pix_d.mb_addr] : 0; + } + + if (mb_up) + *mb_up = mb_available_up; + if (mb_left) + *mb_left = mb_available_left[0]; + if (mb_up_left) + *mb_up_left = mb_available_up_left; + + // compute all chroma intra prediction modes for both U and V + for (uv=0; uv<2; uv++) + { + imgpel **image = p_Vid->enc_picture->imgUV[uv]; + imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[uv + 1]; + + // DC prediction + for(b8=0; b8num_blk8x8_uv >> 1;b8++) + { + for (b4 = 0; b4 < 4; b4++) + { + int block_y = subblk_offset_y[yuv][b8][b4]; + int block_x = subblk_offset_x[yuv][b8][b4]; + int blk_x = block_x; + + s = dc_pred_value_chroma; + + //===== get prediction value ===== + switch (block_pos[yuv][b8][b4]) + { + case 0: //===== TOP LEFT ===== + { + int s0 = 0, s2 = 0; + if (mb_available_up) + { + int pos_x = pix_c.pos_x + blk_x; + int pos_y = pix_c.pos_y; + + for (i = 0; i < BLOCK_SIZE; i++) + s0 += image[pos_y][pos_x++]; + } + if (mb_available_left[0]) + { + int pos_x = pix_a.pos_x; + int pos_y = pix_a.pos_y + block_y; + + for (i = 0; i < BLOCK_SIZE;i++) + s2 += image[pos_y++][pos_x]; + } + if (mb_available_up && mb_available_left[0]) + s = (s0 + s2 + 4) >> 3; + else if (mb_available_up) + s = (s0 + 2) >> 2; + else if (mb_available_left[0]) + s = (s2 + 2) >> 2; + } + break; + case 1: //===== TOP RIGHT ===== + { + int s1 = 0, s2 = 0; + if (mb_available_up) + { + int pos_x = pix_c.pos_x + blk_x; + int pos_y = pix_c.pos_y; + for (i = 0; i < BLOCK_SIZE; i++) + s1 += image[pos_y][pos_x++]; + } + else if (mb_available_left[0]) + { + int pos_x = pix_a.pos_x; + int pos_y = pix_a.pos_y + block_y; + + for (i = 0; i < BLOCK_SIZE; i++) + s2 += image[pos_y++][pos_x]; + } + if (mb_available_up) + s = (s1 +2) >> 2; + else if (mb_available_left[0]) + s = (s2 +2) >> 2; + } + break; + case 2: //===== BOTTOM LEFT ===== + if (mb_available_left[0]) + { + int pos_x = pix_a.pos_x; + int pos_y = pix_a.pos_y + block_y; + int s3 = 0; + + for (i = 0; i < BLOCK_SIZE; i++) + s3 += image[pos_y++][pos_x]; + s = (s3 + 2) >> 2; + } + else if (mb_available_up) + { + int pos_x = pix_c.pos_x + blk_x; + int pos_y = pix_c.pos_y; + + int s0 = 0; + for (i = 0; i < BLOCK_SIZE; i++) + s0 += image[pos_y][pos_x++]; + s = (s0 + 2) >> 2; + } + break; + case 3: //===== BOTTOM RIGHT ===== + { + int s1 = 0, s3 = 0; + if (mb_available_up) + for (i=blk_x;i<(blk_x+4);i++) + s1 += image[pix_c.pos_y][pix_c.pos_x + i]; + if (mb_available_left[0]) + { + int pos_x = pix_a.pos_x; + int pos_y = pix_a.pos_y + block_y; + for (i = 0; i < BLOCK_SIZE;i++) + s3 += image[pos_y++][pos_x]; + } + if (mb_available_up && mb_available_left[0]) + s = (s1 + s3 + 4) >> 3; + else if (mb_available_up) + s = (s1 + 2) >> 2; + else if (mb_available_left[0]) + s = (s3 + 2) >> 2; + } + break; + } + + //===== prediction ===== + cur_pred = curr_mpr_16x16[DC_PRED_8]; + for (j = block_y; j < block_y+4; j++) + { + for (i = block_x; i < block_x+4; i++) + { + cur_pred[j][i] = (imgpel) s; + } + } + } + } + + // vertical prediction + if (mb_available_up) + { + cur_pred = curr_mpr_16x16[VERT_PRED_8]; + hline = &image[pix_c.pos_y][pix_c.pos_x]; + for (j=0; j> 1); + int cr_y = (cr_MB_y >> 1); + + int iaa, iv, ib, ic; + int ih = cr_x * (hline[cr_MB_x-1] - image[pix_d.pos_y][pix_d.pos_x]); + + for (i = 0; i < cr_x - 1; i++) + ih += (i + 1)*(hline[cr_x + i] - hline[cr_x - 2 - i]); + + iv = cr_y * (vline[cr_MB_y-1] - image[pix_d.pos_y][pix_d.pos_x]); + for (i = 0; i < cr_y - 1; i++) + iv += (i + 1) * (vline[cr_y + i] - vline[cr_y - 2 - i]); + + if (cr_MB_x == 8) + ib = (17 * ih + 2 * cr_MB_x) >> 5; + else + ib = ( 5 * ih + 2 * cr_MB_x) >> 6; + + if (cr_MB_y == 8) + ic = (17 * iv + 2 * cr_MB_y) >> 5; + else + ic = ( 5 * iv + 2 * cr_MB_y) >> 6; + + iaa = 16 * (hline[cr_MB_x - 1] + vline[cr_MB_y - 1]); + cur_pred = curr_mpr_16x16[PLANE_8]; + iaa += (1 - cr_x) * ib + (1 - cr_y) * ic; + for (j = 0; j < cr_MB_y; j++) + for (i = 0; i < cr_MB_x; i++) + cur_pred[j][i]= (imgpel) iClip1( max_imgpel_value_uv, (iaa + i * ib + j * ic + 16)>>5); + } + } + + if (!p_Inp->rdopt) // the rd-opt part does not work correctly (see encode_one_macroblock) + { // since ipredmodes could be overwritten => encoder-decoder-mismatches + currSlice->rdo_low_intra_chroma_decision(currMB, mb_available_up, mb_available_left, mb_available_up_left); + } +} + +/*! + ************************************************************************ + * \brief + * Intra prediction of the chrminance layers of one macroblock + ************************************************************************ + */ +void intra_chroma_prediction_mbaff(Macroblock *currMB, int *mb_up, int *mb_left, int*mb_up_left) +{ + int s, i, j; + + int uv; + int b8,b4; + imgpel vline[16]; + + int mb_available_up; + int mb_available_left[2]; + int mb_available_up_left; + + PixelPos pix_b; //!< pixel position p(0,-1) + PixelPos pix_a[17]; //!< pixel positions p(-1, -1..15) + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + imgpel **cur_pred = NULL; + imgpel ***curr_mpr_16x16 = NULL; + imgpel *hline = NULL; + + int yuv = p_Vid->yuv_format - 1; + int dc_pred_value_chroma = p_Vid->dc_pred_value_comp[1]; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + int *mb_size = p_Vid->mb_size[IS_CHROMA]; + + static const int block_pos[3][4][4]= //[yuv][b8][b4] + { + { {0, 1, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{2, 3, 2, 3},{0, 0, 0, 0},{0, 0, 0, 0}}, + { {0, 1, 2, 3},{1, 1, 3, 3},{2, 3, 2, 3},{3, 3, 3, 3}} + }; + + for (i = 0; i < cr_MB_y + 1; ++i) + { + p_Vid->getNeighbour(currMB, -1 , i-1 , mb_size, &pix_a[i]); + } + + p_Vid->getNeighbour(currMB, 0 , -1 , mb_size, &pix_b); + + if (p_Inp->UseConstrainedIntraPred == 0) + { + mb_available_up = pix_b.available; + mb_available_up_left = pix_a[0].available; + mb_available_left[0] = mb_available_left[1] = pix_a[1].available; + } + else + { + mb_available_up = pix_b.available ? p_Vid->intra_block[pix_b.mb_addr] : 0; + for (i=0, mb_available_left[0] = 1; i < (cr_MB_y >> 1); i++) + mb_available_left[0] &= pix_a[i + 1].available ? p_Vid->intra_block[pix_a[i+1].mb_addr]: 0; + for (i=(cr_MB_y>>1), mb_available_left[1]=1; iintra_block[pix_a[i+1].mb_addr]: 0; + mb_available_up_left = pix_a[0].available ? p_Vid->intra_block[pix_a[0].mb_addr]: 0; + } + + if (mb_up) + *mb_up = mb_available_up; + if (mb_left) + *mb_left = mb_available_left[0] && mb_available_left[1]; + if (mb_up_left) + *mb_up_left = mb_available_up_left; + + + // compute all chroma intra prediction modes for both U and V + for (uv=0; uv<2; uv++) + { + imgpel **image = p_Vid->enc_picture->imgUV[uv]; + curr_mpr_16x16 = currSlice->mpr_16x16[uv + 1]; + + // DC prediction + for(b8=0; b8num_blk8x8_uv >> 1;b8++) + { + for (b4 = 0; b4 < 4; b4++) + { + int block_y = subblk_offset_y[yuv][b8][b4]; + int block_x = subblk_offset_x[yuv][b8][b4]; + int blk_x = block_x; + int blk_y = block_y + 1; + + s = dc_pred_value_chroma; + + //===== get prediction value ===== + switch (block_pos[yuv][b8][b4]) + { + case 0: //===== TOP LEFT ===== + { + int s0 = 0, s2 = 0; + if (mb_available_up) + for (i = blk_x; i < (blk_x + 4); i++) + s0 += image[pix_b.pos_y][pix_b.pos_x + i]; + if (mb_available_left[0]) + for (i = blk_y; i < (blk_y + 4);i++) + s2 += image[pix_a[i].pos_y][pix_a[i].pos_x]; + if (mb_available_up && mb_available_left[0]) + s = (s0 + s2 + 4) >> 3; + else if (mb_available_up) + s = (s0 + 2) >> 2; + else if (mb_available_left[0]) + s = (s2 + 2) >> 2; + } + break; + case 1: //===== TOP RIGHT ===== + { + int s1 = 0, s2 = 0; + if (mb_available_up) + for (i=blk_x;i<(blk_x+4);i++) + s1 += image[pix_b.pos_y][pix_b.pos_x + i]; + else if (mb_available_left[0]) + for (i=blk_y;i<(blk_y+4);i++) + s2 += image[pix_a[i].pos_y][pix_a[i].pos_x]; + if (mb_available_up) + s = (s1 +2) >> 2; + else if (mb_available_left[0]) + s = (s2 +2) >> 2; + } + break; + case 2: //===== BOTTOM LEFT ===== + if (mb_available_left[1]) + { + int s3 = 0; + for (i=blk_y;i<(blk_y+4);i++) + s3 += image[pix_a[i].pos_y][pix_a[i].pos_x]; + s = (s3 + 2) >> 2; + } + else if (mb_available_up) + { + int s0 = 0; + for (i=blk_x;i<(blk_x+4);i++) + s0 += image[pix_b.pos_y][pix_b.pos_x + i]; + s = (s0 + 2) >> 2; + } + break; + case 3: //===== BOTTOM RIGHT ===== + { + int s1 = 0, s3 = 0; + if (mb_available_up) + for (i=blk_x;i<(blk_x+4);i++) + s1 += image[pix_b.pos_y][pix_b.pos_x + i]; + if (mb_available_left[1]) + for (i=blk_y;i<(blk_y+4);i++) + s3 += image[pix_a[i].pos_y][pix_a[i].pos_x]; + if (mb_available_up && mb_available_left[1]) + s = (s1 + s3 + 4) >> 3; + else if (mb_available_up) + s = (s1 + 2) >> 2; + else if (mb_available_left[1]) + s = (s3 + 2) >> 2; + } + break; + } + + //===== prediction ===== + cur_pred = curr_mpr_16x16[DC_PRED_8]; + for (j = block_y; j < block_y+4; j++) + { + for (i = block_x; i < block_x+4; i++) + { + cur_pred[j][i] = (imgpel) s; + } + } + } + } + + // vertical prediction + if (mb_available_up) + { + cur_pred = curr_mpr_16x16[VERT_PRED_8]; + hline = &image[pix_b.pos_y][pix_b.pos_x]; + for (j=0; j> 1); + int cr_y = (cr_MB_y >> 1); + + int iaa, iv, ib, ic; + int ih = cr_x * (hline[cr_MB_x-1] - image[pix_a[0].pos_y][pix_a[0].pos_x]); + for (i = 0; i < cr_x - 1; i++) + ih += (i+1)*(hline[cr_x + i] - hline[cr_x - 2 - i]); + + iv = cr_y * (vline[cr_MB_y-1] - image[pix_a[0].pos_y][pix_a[0].pos_x]); + for (i = 0; i < cr_y - 1; i++) + iv += (i + 1) * (vline[cr_y + i] - vline[cr_y - 2 - i]); + + if (cr_MB_x == 8) + ib = (17 * ih + 2 * cr_MB_x) >> 5; + else + ib = ( 5 * ih + 2 * cr_MB_x) >> 6; + if (cr_MB_y == 8) + ic = (17 * iv + 2 * cr_MB_y) >> 5; + else + ic = ( 5 * iv + 2 * cr_MB_y) >> 6; + + iaa = 16 * (hline[cr_MB_x - 1] + vline[cr_MB_y - 1]); + cur_pred = curr_mpr_16x16[PLANE_8]; + iaa += (1 - cr_x) * ib + (1 - cr_y) * ic; + for (j = 0; j < cr_MB_y; j++) + for (i = 0; i < cr_MB_x; i++) + cur_pred[j][i]= (imgpel) iClip1( max_imgpel_value_uv, (iaa + i * ib + j * ic + 16)>>5); + } + } + + if (!p_Inp->rdopt) // the rd-opt part does not work correctly (see encode_one_macroblock) + { // since ipredmodes could be overwritten => encoder-decoder-mismatches + currSlice->rdo_low_intra_chroma_decision(currMB, mb_available_up, mb_available_left, mb_available_up_left); + } +} + +/*! + ************************************************************************************** + * \brief + * RD Decision for Intra prediction mode of the chrominance layers of one macroblock + ************************************************************************************** + */ +void intra_chroma_RD_decision (Macroblock *currMB, RD_PARAMS *enc_mb) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + imgpel** image; + int block_x, block_y; + int mb_available_up; + int mb_available_left; + int mb_available_up_left; + int uv; + int mode; + int best_mode = DC_PRED_8; //just an initialization here, should always be overwritten + distblk cost; + // pick lowest cost prediction mode + distblk min_cost = DISTBLK_MAX; + + PixelPos pix_a; //!< pixel positions p(-1, -1..15) + PixelPos pix_b; //!< pixel position p(-1, -1) + PixelPos pix_c; //!< pixel position p( 0, -1) + PixelPos pix_d; + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + imgpel ***curr_mpr_16x16; + + short diff [16]; + + p_Vid->getNeighbour(currMB, -1 , -1 , p_Vid->mb_size[IS_CHROMA], &pix_b); + p_Vid->getNeighbour(currMB, -1 , 0 , p_Vid->mb_size[IS_CHROMA], &pix_d); + p_Vid->getNeighbour(currMB, 0 , -1 , p_Vid->mb_size[IS_CHROMA], &pix_c); + p_Vid->getNeighbour(currMB, 0 , 0 , p_Vid->mb_size[IS_CHROMA], &pix_a); + + mb_available_up = pix_c.available; + mb_available_up_left = pix_b.available; + mb_available_left = pix_d.available; + + if(p_Inp->UseConstrainedIntraPred) + { + mb_available_up = pix_c.available ? p_Vid->intra_block[pix_c.mb_addr] : 0; + mb_available_left = pix_d.available ? p_Vid->intra_block[pix_d.mb_addr] : 0; + mb_available_up_left = pix_b.available ? p_Vid->intra_block[pix_b.mb_addr] : 0; + } + + //printf("af pix_a %d %d\n", pix_a.pos_x, pix_a.pos_y); + for (mode = DC_PRED_8; mode <= PLANE_8; ++mode) + { + if ((mode==VERT_PRED_8 && !mb_available_up) || + (mode==HOR_PRED_8 && (!mb_available_left)) || + (mode==PLANE_8 && (!mb_available_left || !mb_available_up || !mb_available_up_left))) + continue; + + cost = weight_cost(enc_mb->lambda_mf[Q_PEL], p_Vid->mvbits[ mode ]); // exp golomb coding cost for mode signaling + + for (uv = 1; uv < 3; ++uv) + { + int pos_x = pix_a.pos_x; + int pos_y = pix_a.pos_y; + image = p_Vid->pImgOrg[uv]; + curr_mpr_16x16 = currSlice->mpr_16x16[uv]; + + for (block_y=0; block_ydistortion4x4(diff, min_cost); + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + + if (cost < min_cost) + { + best_mode = mode; + min_cost = cost; + } + } + currMB->c_ipred_mode = (char) best_mode; +} + +/*! + ************************************************************************************** + * \brief + * RD Decision for Intra prediction mode of the chrominance layers of one macroblock + ************************************************************************************** + */ +void intra_chroma_RD_decision_mbaff (Macroblock *currMB, RD_PARAMS *enc_mb) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + int i, j, k; + imgpel** image; + int block_x, block_y; + int mb_available_up; + int mb_available_left[2]; + int mb_available_up_left; + int uv; + int mode; + int best_mode = DC_PRED_8; //just an initialization here, should always be overwritten + distblk cost; + // pick lowest cost prediction mode + distblk min_cost = DISTBLK_MAX; + + PixelPos pix_c; //!< pixel position p(0,-1) + PixelPos pix_a[17]; //!< pixel positions p(-1, -1..15) + int cr_MB_x = p_Vid->mb_cr_size_x; + int cr_MB_y = p_Vid->mb_cr_size_y; + imgpel *img_org, *img_prd; + imgpel ***curr_mpr_16x16; + short diff [16]; + + for (i=0;igetNeighbour(currMB, -1 , i-1 , p_Vid->mb_size[IS_CHROMA], &pix_a[i]); + } + p_Vid->getNeighbour(currMB, 0 , -1 , p_Vid->mb_size[IS_CHROMA], &pix_c); + + mb_available_up = pix_c.available; + mb_available_up_left = pix_a[0].available; + mb_available_left[0] = mb_available_left[1] = pix_a[1].available; + + if(p_Inp->UseConstrainedIntraPred) + { + mb_available_up = pix_c.available ? p_Vid->intra_block[pix_c.mb_addr] : 0; + for (i=1, mb_available_left[0] = 1; i < (cr_MB_y>>1) + 1; ++i) + mb_available_left[0] &= pix_a[i].available ? p_Vid->intra_block[pix_a[i].mb_addr]: 0; + + for (i=(cr_MB_y>>1) + 1, mb_available_left[1]=1; i < cr_MB_y + 1;++i) + mb_available_left[1] &= pix_a[i].available ? p_Vid->intra_block[pix_a[i].mb_addr]: 0; + + mb_available_up_left = pix_a[0].available ? p_Vid->intra_block[pix_a[0].mb_addr]: 0; + } + + for (i=0;igetNeighbour(currMB, 0, i, p_Vid->mb_size[IS_CHROMA], &pix_a[i]); + } + if ( currSlice->mb_aff_frame_flag && p_Vid->field_mode ) + { + for (i=0;i> 1; + } + } + + for (mode=DC_PRED_8; mode<=PLANE_8; ++mode) + { + if ((mode==VERT_PRED_8 && !mb_available_up) || + (mode==HOR_PRED_8 && (!mb_available_left[0] || !mb_available_left[1])) || + (mode==PLANE_8 && (!mb_available_left[0] || !mb_available_left[1] || !mb_available_up || !mb_available_up_left))) + continue; + + cost = 0; + for (uv = 1; uv < 3; ++uv) + { + image = p_Vid->pImgOrg[uv]; + curr_mpr_16x16 = currSlice->mpr_16x16[uv]; + for (block_y=0; block_ydistortion4x4(diff, min_cost); + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + if (cost > min_cost) break; + } + + //cost += (int) (enc_mb->lambda_me[Q_PEL] * p_Vid->mvbits[ mode ]); // exp golomb coding cost for mode signaling + cost += weight_cost(enc_mb->lambda_mf[Q_PEL], p_Vid->mvbits[ mode ]); // exp golomb coding cost for mode signaling + + if (cost < min_cost) + { + best_mode = mode; + min_cost = cost; + } + } + currMB->c_ipred_mode = (char) best_mode; +} diff --git a/lencod/src/intrarefresh.c b/lencod/src/intrarefresh.c new file mode 100644 index 0000000..63b135a --- /dev/null +++ b/lencod/src/intrarefresh.c @@ -0,0 +1,125 @@ + +/*! + ***************************************************************************** + * + * \file intrarefresh.c + * + * \brief + * Encoder support for pseudo-random intra macroblock refresh + * + * \date + * 16 June 2002 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + +#include "global.h" + + +/*! + ************************************************************************ + * \brief + * RandomIntraInit: Initializes Random Intra module. Should be called + * only after initialization (or changes) of the picture size or the + * random intra refresh value. In version jm2.1 it is impossible to + * change those values on-the-fly, hence RandomIntraInit should be + * called immediately after the parsing of the config file + * + * \par Input: + * xsize, ysize: size of the picture (in MBs) + * refresh : refresh rate in MBs per picture + ************************************************************************ + */ +void RandomIntraInit(VideoParameters *p_Vid, int xsize, int ysize, int refresh) +{ + int i, pos; + + srand (1); // A fixed random initializer to make things reproducible + p_Vid->NumberOfMBs = xsize * ysize; + p_Vid->NumberIntraPerPicture = refresh; + + if (refresh != 0) + { + p_Vid->RefreshPattern = malloc (sizeof (int) * p_Vid->NumberOfMBs); + if (p_Vid->RefreshPattern == NULL) no_mem_exit("RandomIntraInit: p_Vid->RefreshPattern"); + + p_Vid->IntraMBs = malloc (sizeof (int) * refresh); + if (p_Vid->IntraMBs == NULL) no_mem_exit("RandomIntraInit: p_Vid->IntraMBs"); + + for (i= 0; iNumberOfMBs; i++) + p_Vid->RefreshPattern[i] = -1; + + for (i=0; iNumberOfMBs; i++) + { + do + { + pos = rand() % p_Vid->NumberOfMBs; + } while (p_Vid->RefreshPattern [pos] != -1); + p_Vid->RefreshPattern [pos] = i; + } + /* + for (i=0; iNumberOfMBs; i++) printf ("%d\t", p_Vid->RefreshPattern[i]); + getchar(); + */ + } + else + { + p_Vid->RefreshPattern = NULL; + p_Vid->IntraMBs = NULL; + } +} + +/*! + ************************************************************************ + * \brief + * RandomIntra: Code an MB as Intra? + * + * \par Input + * MacroblockNumberInScanOrder + * \par Output + * 1 if an MB should be forced to Intra, according the the + * RefreshPattern + * 0 otherwise + * + ************************************************************************ + */ +int RandomIntra (VideoParameters *p_Vid, int mb) +{ + int i; + + for (i=0; iNumberIntraPerPicture; i++) + if (p_Vid->IntraMBs[i] == mb) + return 1; + return 0; +} + + +/*! + ************************************************************************ + * \brief + * RandomIntraNewPicture: Selects new set of MBs for forced Intra + * + * \par + * This function should be called exactly once per picture, and + * requires a finished initialization + * + ************************************************************************ + */ +void RandomIntraNewPicture (VideoParameters *p_Vid) +{ + int i, j; + + p_Vid->WalkAround += p_Vid->NumberIntraPerPicture; + for (j=0, i = p_Vid->WalkAround; jNumberIntraPerPicture; j++, i++) + p_Vid->IntraMBs[j] = p_Vid->RefreshPattern [i%p_Vid->NumberOfMBs]; +} + +void RandomIntraUninit(VideoParameters *p_Vid) +{ + if (p_Vid->NumberIntraPerPicture >0 ) + { + free(p_Vid->RefreshPattern); + free(p_Vid->IntraMBs); + } +} diff --git a/lencod/src/lambda.c b/lencod/src/lambda.c new file mode 100644 index 0000000..d24b40e --- /dev/null +++ b/lencod/src/lambda.c @@ -0,0 +1,365 @@ +/*! +*************************************************************************** +* +* \file lambda.c +* +* \brief +* Lambda computation related functions +* +* \date +* 13 September 2009 +* +* \author +* Alexis Michael Tourapis alexismt@ieee.org +**************************************************************************/ + +#include "global.h" +#include "slice.h" + +static void SetLambda(VideoParameters *p_Vid, int j, int qp, double lambda_scale) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int k; + p_Vid->lambda_md[j][qp] *= lambda_scale; + + for (k = F_PEL; k <= Q_PEL; k++) + { + //p_Vid->lambda_me[j][qp][k] = (p_Inp->MEErrorMetric[k] == ERROR_SSE) ? p_Vid->lambda_md[j][qp] : sqrt(p_Vid->lambda_md[j][qp]); + //p_Vid->lambda_me[j][qp][k] = sqrt(p_Vid->lambda_md[j][qp]); + p_Vid->lambda_me[j][qp][k] = (p_Inp->MEErrorMetric[k] == ERROR_SSE && p_Inp->MESoftenSSEMetric == 0) ? p_Vid->lambda_md[j][qp] : sqrt(p_Vid->lambda_md[j][qp]); + p_Vid->lambda_mf[j][qp][k] = LAMBDA_FACTOR (p_Vid->lambda_me[j][qp][k]); + } +} + +static void CalcMaxLamdaMD(VideoParameters *p_Vid, double *p_lambda_md) +{ + double max_lambda_md; + int iBits; + + if(p_Vid->p_Inp->ProfileIDC >= FREXT_HP) + iBits=128; //Spec. Page 306 + else + iBits=80; + + if(p_Vid->yuv_format == YUV420) + iBits += 3072; //(256+128)*8; + else if(p_Vid->yuv_format == YUV422) + iBits += 4096; //(256+256)*8; + else if(p_Vid->yuv_format == YUV444) + iBits += 6144; //(256*3)*8; + else if(p_Vid->yuv_format == YUV400) + iBits += 2048; //256*8; + + max_lambda_md = floor(((double)DISTBLK_MAX)/iBits/(1<=0 && cost<=DISTBLK_MAX); + } +#endif + *p_lambda_md = max_lambda_md; +} + +static void ClipLambda(double *p_lambda_max, double *p_lambda) +{ + if(*p_lambda > *p_lambda_max) + { + //printf("Clip: %lf -> %lf\n", *p_lambda, *p_lambda_max); + *p_lambda = *p_lambda_max; + } +} + +void set_rdoq_lambda( Slice *currSlice ) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + int qp, j = currSlice->slice_type; + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + p_Vid->lambda_rdoq[j][qp] = p_Vid->lambda_md[j][qp]; + } +} + +void get_implicit_lambda_p_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int qp; + double qp_temp; + double lambda_md; + double lambda_scale = 1.0 - dClip3(0.0,0.5,0.05 * (double) p_Inp->jumpd); + //limit lambda for mode decison; + int bLimitsLambdaMD = ((p_Inp->EnableIPCM > 0) && (IMGTYPE==0)); + double dMaxLambdaMD =0; + + if(bLimitsLambdaMD) + CalcMaxLamdaMD(p_Vid, &dMaxLambdaMD); + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + qp_temp = (double)qp + currSlice->bitdepth_luma_qp_scale - SHIFT_QP; + + if (p_Inp->NumberBFrames > 0) + { + lambda_md = 0.68 * pow (2.0, qp_temp/3.0); + } + else + lambda_md = 0.85 * pow (2.0, qp_temp/3.0); + + // Scale lambda due to hadamard qpel only consideration + lambda_md = ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95) * lambda_md; + p_Vid->lambda_md[P_SLICE][qp] = lambda_scale * lambda_md; + + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[P_SLICE][qp]); + + SetLambda(p_Vid, P_SLICE, qp, 1.0); + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + int lambda_qp = (qp >= 32 && !p_Inp->RCEnable) ? imax(0, qp - 4) : imax(0, qp - 6); + p_Vid->lambda_mf_factor[P_SLICE][qp] = log (p_Vid->lambda_me[P_SLICE][lambda_qp][Q_PEL] + 1.0) / log (2.0); + } + } +} + +void get_implicit_lambda_b_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int qp; + double qp_temp; + double lambda_md; + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + //limit lambda for mode decison; + int bLimitsLambdaMD = ((p_Inp->EnableIPCM > 0) && (IMGTYPE==0)); + double dMaxLambdaMD =0; + + if(bLimitsLambdaMD) + CalcMaxLamdaMD(p_Vid, &dMaxLambdaMD); + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + qp_temp = (double)qp + currSlice->bitdepth_luma_qp_scale - SHIFT_QP; + + if (p_Inp->NumberBFrames > 0) + { + lambda_md = 0.68 * pow (2.0, qp_temp/3.0) + * (p_cur_frm->layer != 0 ? dClip3(2.00, 4.00, (qp_temp / 6.0)) : 1.0); + } + else + lambda_md = 0.85 * pow (2.0, qp_temp/3.0); + + // Scale lambda due to hadamard qpel only consideration + lambda_md = ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95) * lambda_md; + + if (p_cur_frm->layer != 0 && currSlice->nal_reference_idc) + { + if (p_Inp->HierarchicalCoding == 2) + lambda_md *= (1.0 - dmin(0.4, 0.2 * (double) (p_cur_frm->p_atom->gop_levels - p_cur_frm->layer))); + else + lambda_md *= 0.80; + } + p_Vid->lambda_md[B_SLICE][qp] = lambda_md; + + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[B_SLICE][qp]); + + SetLambda(p_Vid, B_SLICE, qp, 1.0); + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + int lambda_qp = (qp >= 32 && !p_Inp->RCEnable) ? imax(0, qp - 4) : imax(0, qp - 6); + p_Vid->lambda_mf_factor[B_SLICE][qp] = log (p_Vid->lambda_me[B_SLICE][lambda_qp][Q_PEL] + 1.0) / log (2.0); + } + } +} + +void get_implicit_lambda_i_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int qp; + double qp_temp; + double lambda_md; + double lambda_scale = 1.0 - dClip3(0.0,0.5,0.05 * (double) p_Inp->jumpd); + //limit lambda for mode decison; + int bLimitsLambdaMD = ((p_Inp->EnableIPCM > 0) && (IMGTYPE==0)); + double dMaxLambdaMD =0; + + if(bLimitsLambdaMD) + CalcMaxLamdaMD(p_Vid, &dMaxLambdaMD); + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + qp_temp = (double)qp + currSlice->bitdepth_luma_qp_scale - SHIFT_QP; + + if(p_Inp->UseRDOQuant && p_Vid->qp==qp) + lambda_md = 0.57 * pow (2.0, qp_temp/3.0); + else if (p_Inp->NumberBFrames > 0) + { + lambda_md = 0.68 * pow (2.0, qp_temp/3.0); + } + else + lambda_md = 0.85 * pow (2.0, qp_temp/3.0); + + // Scale lambda due to hadamard qpel only consideration + lambda_md = ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95) * lambda_md; + p_Vid->lambda_md[I_SLICE][qp] = lambda_scale * lambda_md; + + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[I_SLICE][qp]); + + SetLambda(p_Vid, I_SLICE, qp, 1.0); + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + int lambda_qp = (qp >= 32 && !p_Inp->RCEnable) ? imax(0, qp - 4) : imax(0, qp - 6); + p_Vid->lambda_mf_factor[I_SLICE][qp] = log (p_Vid->lambda_me[I_SLICE][lambda_qp][Q_PEL] + 1.0) / log (2.0); + } + } +} + +void get_implicit_lambda_sp_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int qp; + double qp_temp; + double lambda_md; + double lambda_scale = 1.0 - dClip3(0.0,0.5,0.05 * (double) p_Inp->jumpd); + //limit lambda for mode decison; + int bLimitsLambdaMD = ((p_Inp->EnableIPCM > 0) && (IMGTYPE==0)); + double dMaxLambdaMD =0; + + int slice_index = currSlice->slice_type; + + if(bLimitsLambdaMD) + CalcMaxLamdaMD(p_Vid, &dMaxLambdaMD); + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + qp_temp = (double)qp + currSlice->bitdepth_luma_qp_scale - SHIFT_QP; + + if(p_Inp->UseRDOQuant && p_Vid->type == I_SLICE && p_Vid->qp==qp) + lambda_md = 0.57 * pow (2.0, qp_temp/3.0); + else if (p_Inp->NumberBFrames > 0) + { + lambda_md = 0.68 * pow (2.0, qp_temp/3.0) * dClip3(1.4,3.0,(qp_temp / 12.0)); + } + else + lambda_md = 0.85 * pow (2.0, qp_temp/3.0) * dClip3(1.4, 3.0,(qp_temp / 12.0)); + + // Scale lambda due to hadamard qpel only consideration + lambda_md = ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95) * lambda_md; + + p_Vid->lambda_md[slice_index][qp] = lambda_scale * lambda_md; + + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[slice_index][qp]); + + SetLambda(p_Vid, slice_index, qp, 1.0); + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + int lambda_qp = (qp >= 32 && !p_Inp->RCEnable) ? imax(0, qp - 4) : imax(0, qp - 6); + p_Vid->lambda_mf_factor[slice_index][qp] = log (p_Vid->lambda_me[slice_index][lambda_qp][Q_PEL] + 1.0) / log (2.0); + } + } +} + +void get_explicit_lambda(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int qp; + double qp_temp; + double lambda_scale = 1.0 - dClip3(0.0,0.5,0.05 * (double) p_Inp->jumpd); + //limit lambda for mode decison; + int bLimitsLambdaMD = ((p_Inp->EnableIPCM > 0) && (IMGTYPE==0)); + double dMaxLambdaMD =0; +#if (MVC_EXTENSION_ENABLE) + double tmp_lambda_md = 0.0; +#endif + + int j = currSlice->slice_type; + + if(bLimitsLambdaMD) + CalcMaxLamdaMD(p_Vid, &dMaxLambdaMD); + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + qp_temp = (double)qp + currSlice->bitdepth_luma_qp_scale - SHIFT_QP; + + if (j == B_SLICE && currSlice->nal_reference_idc) + p_Vid->lambda_md[j][qp] = p_Inp->LambdaWeight[5] * pow (2, qp_temp/3.0); + else + p_Vid->lambda_md[j][qp] = p_Inp->LambdaWeight[j] * pow (2, qp_temp/3.0); + +#if (MVC_EXTENSION_ENABLE) + tmp_lambda_md = p_Vid->lambda_md[j][qp]; + + if (currSlice->view_id) + { + p_Vid->lambda_md[j][qp] = p_Vid->lambda_md[j][qp] * p_Inp->enh_layer_me_lambda_multiplier; + } +#endif + + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[j][qp]); + + SetLambda(p_Vid, j, qp, ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95)); + +#if (MVC_EXTENSION_ENABLE) + if (currSlice->view_id) + { + p_Vid->lambda_md[j][qp] = tmp_lambda_md * p_Inp->enh_layer_lambda_multiplier; + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[j][qp]); + p_Vid->lambda_md[j][qp] *= ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95); + } +#endif + } + + if (j != B_SLICE) + { + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + p_Vid->lambda_md[j][qp] *= lambda_scale; + } +} + + +void get_fixed_lambda(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int qp; + //limit lambda for mode decison; + int bLimitsLambdaMD = ((p_Inp->EnableIPCM > 0) && (IMGTYPE==0)); + double dMaxLambdaMD =0; + + int j = currSlice->slice_type; + + if(bLimitsLambdaMD) + CalcMaxLamdaMD(p_Vid, &dMaxLambdaMD); + + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + if (j == B_SLICE && currSlice->nal_reference_idc) + p_Vid->lambda_md[j][qp] = p_Inp->FixedLambda[5]; + else + p_Vid->lambda_md[j][qp] = p_Inp->FixedLambda[j]; + //clip lambda; + if(bLimitsLambdaMD) + ClipLambda(&dMaxLambdaMD, &p_Vid->lambda_md[j][qp]); + + SetLambda(p_Vid, j, qp, ((p_Inp->MEErrorMetric[H_PEL] == ERROR_SATD && p_Inp->MEErrorMetric[Q_PEL] == ERROR_SATD) ? 1.00 : 0.95)); + } +} + diff --git a/lencod/src/leaky_bucket.c b/lencod/src/leaky_bucket.c new file mode 100644 index 0000000..875e536 --- /dev/null +++ b/lencod/src/leaky_bucket.c @@ -0,0 +1,314 @@ + +/*! + *************************************************************************** + * \file leaky_bucket.c + * + * \brief + * calculate Leaky Buffer parameters + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Shankar Regunathan + *************************************************************************** + */ + +#include "contributors.h" +#include "global.h" + +#ifdef _LEAKYBUCKET_ + +/*! + *********************************************************************** + * \brief + * Function to get Leaky Bucket rates from rate file + * \param NumberLeakyBuckets + * Number of Leaky Bucket Parameters + * \param Rmin + * Rate values for each Bucket. + * \return + * returns 1 if successful; else returns zero. + * \para SideEffects + * None. + * \para Notes + * Failure if LeakyBucketRate is missing or if it does not have + * the correct number of entries. + * \author + * Shankar Regunathan shanre@microsoft.com + * \date + * December 06, 2001. + *********************************************************************** + */ + +int get_LeakyBucketRate(InputParameters *p_Inp, unsigned long NumberLeakyBuckets, unsigned long *Rmin) +{ + FILE *f; + unsigned long i, buf; + + if((f = fopen(p_Inp->LeakyBucketRateFile, "r")) == NULL) + { + printf(" LeakyBucketRate File does not exist. Using rate calculated from avg. rate \n"); + return 0; + } + + for(i=0; i> 0x18) & 0xFF, fp); + fputc((dw >> 0x10) & 0xFF, fp); + fputc((dw >> 0x08) & 0xFF, fp); + fputc(dw & 0xFF, fp); +} + +/*! + *********************************************************************** + * \brief + * Stores the Leaky BucketParameters in file p_Inp->LeakyBucketParamFile. + * \param NumberLeakyBuckets + * Number of LeakyBuckets. + * \param Rmin + * Rate values of the buckets. + * \param Bmin + * Minimum buffer values of the buckets. + * \param Fmin + * Minimum initial buffer fullness of the buckets + * \return + * None. + * \para + * Returns error if LeakyBucketParamFile cannot be opened. + * \para SideEffects + * Prints the LeakyBucket Parameters in standard output. + * \author + * Shankar Regunathan shanre@microsoft.com + * \date + * December 06, 2001. + *********************************************************************** + */ + + +void write_buffer(InputParameters *p_Inp, unsigned long NumberLeakyBuckets, unsigned long Rmin[], unsigned long Bmin[], unsigned long Fmin[]) +{ + FILE *outf; + unsigned long iBucket; + + if ((outf = fopen(p_Inp->LeakyBucketParamFile,"wb"))==NULL) + { + snprintf(errortext, ET_SIZE, "Error open file lk %s \n",p_Inp->LeakyBucketParamFile); + error(errortext,1); + } + + PutBigDoubleWord(NumberLeakyBuckets, outf); + if (p_Inp->Verbose != 0) + printf(" Number Leaky Buckets: %ld \n Rmin Bmin Fmin \n", NumberLeakyBuckets); + for(iBucket =0; iBucket < NumberLeakyBuckets; iBucket++) + { + //assert(Rmin[iBucket]<4294967296); //Overflow should be corrected already. + //assert(Bmin[iBucket]<4294967296); + //assert(Fmin[iBucket]<4294967296); + PutBigDoubleWord(Rmin[iBucket], outf); + PutBigDoubleWord(Bmin[iBucket], outf); + PutBigDoubleWord(Fmin[iBucket], outf); + if (p_Inp->Verbose != 0) + printf(" %8ld %8ld %8ld \n", Rmin[iBucket], Bmin[iBucket], Fmin[iBucket]); + } + fclose(outf); +} + +/*! + *********************************************************************** + * \brief + * Sorts the rate array in ascending order. + * \param NumberLeakyBuckets + * Number of LeakyBuckets. + * \param Rmin + * Rate values of the buckets. + * \return + * None. + * \author + * Shankar Regunathan shanre@microsoft.com + * \date + * December 06, 2001. + *********************************************************************** + */ + + +void Sort(unsigned long NumberLeakyBuckets, unsigned long *Rmin) +{ + unsigned long i, j; + unsigned long temp; + for(i=0; i< NumberLeakyBuckets-1; i++) + { + for(j=i+1; j Rmin[j]) + { + temp = Rmin[i]; + Rmin[i] = Rmin[j]; + Rmin[j] = temp; + } + } + } +} + +/*! + *********************************************************************** + * \brief + * Main Routine to calculate Leaky Buffer parameters + * \param NumberLeakyBuckets + * None. + * \return + * None. + * \author + * Shankar Regunathan shanre@microsoft.com + * \date + * December 06, 2001. + *********************************************************************** + */ + +void calc_buffer(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + unsigned long AvgRate, TotalRate, NumberLeakyBuckets; + long *buffer_frame, minB; + unsigned long iBucket, iFrame, FrameIndex = 0; + long maxBuffer, actualBuffer, InitFullness, iChannelRate; + unsigned long *Rmin, *Bmin, *Fmin; + + switch (p_Inp->Verbose) + { + case 1: + fprintf(stdout,"-------------------------------------------------------------------------------\n"); + break; + case 2: + fprintf(stdout,"------------------------------------------------------------------------------------------------\n"); + break; + case 3: + fprintf(stdout,"-------------------------------------------------------------------------------------------------------\n"); + break; + case 0: + default: + fprintf(stdout,"\n-------------------------------------------------------------------------------\n"); + break; + } + printf(" Total Frames: %ld \n", p_Vid->total_frame_buffer); + NumberLeakyBuckets = (unsigned long) p_Inp->NumberLeakyBuckets; + buffer_frame = calloc(p_Vid->total_frame_buffer + 1, sizeof(long)); + if(!buffer_frame) + no_mem_exit("init_buffer: buffer_frame"); + Rmin = calloc(NumberLeakyBuckets, sizeof(unsigned long)); + if(!Rmin) + no_mem_exit("init_buffer: Rmin"); + Bmin = calloc(NumberLeakyBuckets, sizeof(unsigned long)); + if(!Bmin) + no_mem_exit("init_buffer: Bmin"); + Fmin = calloc(NumberLeakyBuckets, sizeof(unsigned long)); + if(!Fmin) + no_mem_exit("init_buffer: Fmin"); + + TotalRate = 0; + for(iFrame=0; iFrame < p_Vid->total_frame_buffer; iFrame++) + { + TotalRate += (unsigned long) p_Vid->Bit_Buffer[iFrame]; + } + AvgRate = (unsigned long) ((float) TotalRate/ p_Vid->total_frame_buffer); + + if(1 != get_LeakyBucketRate(p_Inp, NumberLeakyBuckets, Rmin)) + { /* if rate file is not present, use default calculated from avg.rate */ + for(iBucket=0; iBucket < NumberLeakyBuckets; iBucket++) + { + if(iBucket == 0) + Rmin[iBucket] = (unsigned long)((float) AvgRate * p_Vid->framerate); /* convert bits/frame to bits/second */ + else + Rmin[iBucket] = (unsigned long) ((float) Rmin[iBucket-1] + (AvgRate/4) * (p_Vid->framerate)); + } + } + Sort(NumberLeakyBuckets, Rmin); + + maxBuffer = AvgRate * 20; /* any initialization is good. */ + for(iBucket=0; iBucket< NumberLeakyBuckets; iBucket++) + { + iChannelRate = (long) (Rmin[iBucket] / (p_Vid->framerate)); /* converts bits/second to bits/frame */ + /* To calculate initial buffer size */ + InitFullness = maxBuffer; /* set Initial Fullness to be buffer size */ + buffer_frame[0] = InitFullness; + minB = maxBuffer; + + for(iFrame=0; iFrame < p_Vid->total_frame_buffer ; iFrame++) + { + buffer_frame[iFrame] = buffer_frame[iFrame] - p_Vid->Bit_Buffer[iFrame]; + if(buffer_frame[iFrame] < minB) + { + minB = buffer_frame[iFrame]; + FrameIndex = iFrame; + } + + if ( iFrame < p_Vid->total_frame_buffer ) + { + buffer_frame[iFrame+1] = buffer_frame[iFrame] + iChannelRate; + if(buffer_frame[iFrame+1] > maxBuffer) + buffer_frame[iFrame+1] = maxBuffer; + } + } + actualBuffer = (maxBuffer - minB); + + /* To calculate initial buffer Fullness */ + InitFullness = p_Vid->Bit_Buffer[0]; + buffer_frame[0] = InitFullness; + for(iFrame=0; iFrame < FrameIndex+1; iFrame++) + { + buffer_frame[iFrame] = buffer_frame[iFrame] - p_Vid->Bit_Buffer[iFrame]; + if(buffer_frame[iFrame] < 0) + { + InitFullness -= buffer_frame[iFrame]; + buffer_frame[iFrame] = 0; + } + if ( iFrame < p_Vid->total_frame_buffer ) + { + buffer_frame[iFrame+1] = buffer_frame[iFrame] + iChannelRate; + if(buffer_frame[iFrame+1] > actualBuffer) + break; + } + } + Bmin[iBucket] = (unsigned long) actualBuffer; + Fmin[iBucket] = (unsigned long) InitFullness; + } + + write_buffer(p_Inp, NumberLeakyBuckets, Rmin, Bmin, Fmin); + + free_pointer(buffer_frame); + free_pointer(Rmin); + free_pointer(Bmin); + free_pointer(Fmin); + return; +} +#endif + diff --git a/lencod/src/lencod.c b/lencod/src/lencod.c new file mode 100644 index 0000000..bc81c85 --- /dev/null +++ b/lencod/src/lencod.c @@ -0,0 +1,2639 @@ +/*! +*********************************************************************** +* \mainpage +* This is the H.264/AVC encoder reference software. For detailed documentation +* see the comments in each file. +* +* The JM software web site is located at: +* http://iphome.hhi.de/suehring/tml +* +* For bug reporting and known issues see: +* https://ipbt.hhi.fraunhofer.de +* +* \author +* The main contributors are listed in contributors.h +* +* \version +* JM 18.2 (FRExt) +* +* \note +* tags are used for document system "doxygen" +* available at http://www.doxygen.org +*/ +/*! +* \file +* lencod.c +* \brief +* H.264/AVC reference encoder project main() +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Inge Lille-Langoy +* - Rickard Sjoberg +* - Stephan Wenger +* - Jani Lainema +* - Byeong-Moon Jeon +* - Yoon-Seong Soh +* - Thomas Stockhammer +* - Detlev Marpe +* - Guido Heising +* - Valeri George +* - Karsten Suehring +* - Alexis Michael Tourapis +* - Athanasios Leontaris +*********************************************************************** +*/ + + +#if (_DEBUG) +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include "contributors.h" + +#include +#include +#include "win32.h" +#include "global.h" +#include "cconv_yuv2rgb.h" +#include "configfile.h" +#include "conformance.h" +#include "context_ini.h" +#include "explicit_gop.h" +#include "explicit_seq.h" +#include "filehandle.h" +#include "image.h" +#include "input.h" +#include "img_io.h" +#include "slice.h" +#include "intrarefresh.h" +#include "leaky_bucket.h" +#include "mc_prediction.h" +#include "mc_prediction_otf.h" +#include "memalloc.h" +#include "me_epzs_common.h" +#include "me_epzs_int.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "output.h" +#include "parset.h" +#include "q_matrix.h" +#include "q_offsets.h" +#include "ratectl.h" +#include "report.h" +#include "rdoq.h" +#include "errdo.h" +#include "rdopt.h" +#include "wp_mcprec.h" +#include "mv_search.h" +#include "img_process.h" +#include "q_offsets.h" +#include "pred_struct.h" +#include "blk_prediction.h" +#include "img_luma.h" +#include "img_chroma.h" +#include "mc_prediction.h" +#include "me_distortion.h" +#include "me_distortion_otf.h" +#include "md_distortion.h" +#include "mode_decision.h" +#include "transform8x8.h" +#include "intra16x16.h" +#include "intra4x4.h" +#include "intra8x8.h" +//#include "resize.h" +#include "md_common.h" +#include "macroblock.h" +#include "get_block_otf.h" +//! Edited by Joao Carreira +#include "transcode_enc.h" + +#include "wp.h" + +//check the scaling factor to avoid overflow; +#if !IMGTYPE +#if JCOST_CALC_SCALEUP && (LAMBDA_ACCURACY_BITS>8) +#error "LAMBDA_ACCURACY_BITS is greater than 8. Overflow!" +#endif +#endif +static const int mb_width_cr[4] = {0, 8, 8,16}; +static const int mb_height_cr[4]= {0, 8,16,16}; + +EncoderParams *p_Enc = NULL; + +static void set_level_indices (VideoParameters *p_Vid); +static void chroma_mc_setup (VideoParameters *p_Vid); +static void init_img (VideoParameters *p_Vid); +static void init_encoder (VideoParameters *p_Vid, InputParameters *p_Inp); +static int init_global_buffers (VideoParameters *p_Vid, InputParameters *p_Inp); +static void free_global_buffers (VideoParameters *p_Vid, InputParameters *p_Inp); +static void free_img (VideoParameters *p_Vid, InputParameters *p_Inp); +static void free_params (InputParameters *p_Inp); + +static void encode_sequence (VideoParameters *p_Vid, InputParameters *p_Inp); + + +static void generate_encode_parameters(VideoParameters *p_Vid); +static void free_encode_parameters(VideoParameters *p_Vid); + + +void init_stats (InputParameters *p_Inp, StatParameters *p_Stats) +{ + memset(p_Stats, 0, sizeof(StatParameters)); + p_Stats->NumberBFrames = p_Inp->NumberBFrames; +} + +void init_dstats (DistortionParams *p_Dist) +{ + p_Dist->frame_ctr = 0; + memset(p_Dist->metric, 0, TOTAL_DIST_TYPES * sizeof(DistMetric)); +} + +/*! +*********************************************************************** +* \brief +* Allocate the Video Parameters structure +* \par Output: +* Video Parameters VideoParameters *p_Vid +*********************************************************************** +*/ +static void alloc_video_params( VideoParameters **p_Vid) +{ + if ((*p_Vid = (VideoParameters *) calloc(1, sizeof(VideoParameters)))==NULL) + no_mem_exit("alloc_video_params: p_Vid"); + if ((((*p_Vid)->p_Dist) = (DistortionParams *) calloc(1, sizeof(DistortionParams)))==NULL) + no_mem_exit("alloc_video_params: p_Dist"); + if ((((*p_Vid)->p_Stats) = (StatParameters *) calloc(1, sizeof(StatParameters)))==NULL) + no_mem_exit("alloc_video_params: p_Stats"); + if (((*p_Vid)->p_Dpb_layer[0] = (DecodedPictureBuffer *) calloc(MAX_NUM_DPB_LAYERS, sizeof(DecodedPictureBuffer)))==NULL) + no_mem_exit("alloc_video_params: p_Dpb_layer"); + { + int i; + for(i=1; ip_Dpb_layer[i] = (*p_Vid)->p_Dpb_layer[i-1] + 1; + (*p_Vid)->p_Dpb_layer[i]->layer_id = i; + } + } + if ((((*p_Vid)->p_Quant) = (QuantParameters *) calloc(1, sizeof(QuantParameters)))==NULL) + no_mem_exit("alloc_video_params: p_Quant"); + if ((((*p_Vid)->p_QScale) = (ScaleParameters *) calloc(1, sizeof(ScaleParameters)))==NULL) + no_mem_exit("alloc_video_params: p_QScale"); + if ((((*p_Vid)->p_SEI) = (SEIParameters *) calloc(1, sizeof(SEIParameters)))==NULL) + no_mem_exit("alloc_video_params: p_SEI"); + + + (*p_Vid)->p_dec = -1; +#if (MVC_EXTENSION_ENABLE) + (*p_Vid)->p_dec2 = -1; +#endif + (*p_Vid)->p_log = NULL; + (*p_Vid)->f_annexb = NULL; + // Init rtp related info + (*p_Vid)->f_rtp = NULL; + (*p_Vid)->CurrentRTPTimestamp = 0; + (*p_Vid)->CurrentRTPSequenceNumber = 0; +} + +/*! +*********************************************************************** +* \brief +* Allocate the Input structure +* \par Output: +* Input Parameters InputParameters *p_Vid +*********************************************************************** +*/ +static void alloc_params( InputParameters **p_Inp ) +{ + if ((*p_Inp = (InputParameters *) calloc(1, sizeof(InputParameters)))==NULL) + no_mem_exit("alloc_params: p_Inp"); + + (*p_Inp)->top_left = NULL; + (*p_Inp)->bottom_right = NULL; + (*p_Inp)->slice_group_id = NULL; + (*p_Inp)->run_length_minus1 = NULL; +} + + +/*! +*********************************************************************** +* \brief +* Allocate the Encoder Structure +* \par Output: +* Encoder Parameters +*********************************************************************** +*/ +static void alloc_encoder( EncoderParams **p_Enc) +{ + if ((*p_Enc = (EncoderParams *) calloc(1, sizeof(EncoderParams)))==NULL) + no_mem_exit("alloc_encoder: p_Enc"); + + alloc_video_params(&((*p_Enc)->p_Vid)); + alloc_params(&((*p_Enc)->p_Inp)); + (*p_Enc)->p_trace = NULL; + (*p_Enc)->bufferSize = 0; +} + +/*! +*********************************************************************** +* \brief +* Free the Encoder Structure +*********************************************************************** +*/ +static void free_encoder (EncoderParams *p_Enc) +{ + free_pointer( p_Enc ); +} + +/*! +*********************************************************************** +* \brief +* Main function for encoder. +* \param argc +* number of command line arguments +* \param argv +* command line arguments +* \return +* exit code +*********************************************************************** +*/ +int main(int argc, char **argv) +{ + init_time(); + +#if MEMORY_DEBUG + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); +#endif + + alloc_encoder(&p_Enc); + + Configure (p_Enc->p_Vid, p_Enc->p_Inp, argc, argv); + + // init encoder + init_encoder(p_Enc->p_Vid, p_Enc->p_Inp); + + // encode sequence + encode_sequence(p_Enc->p_Vid, p_Enc->p_Inp); + + // terminate sequence + free_encoder_memory(p_Enc->p_Vid, p_Enc->p_Inp); + + free_params (p_Enc->p_Inp); + free_encoder(p_Enc); + +#if (_DEBUG ) + _CrtDumpMemoryLeaks(); +#if( WIN32 ) + system("pause"); +#endif +#endif + return 0; +} + + +/*! +************************************************************************ +* \brief +* calculate Ceil(Log2(uiVal)) +************************************************************************ +*/ +static unsigned CeilLog2( unsigned uiVal) +{ + unsigned uiTmp = uiVal-1; + unsigned uiRet = 0; + + while( uiTmp != 0 ) + { + uiTmp >>= 1; + uiRet++; + } + return uiRet; +} + +void set_dpb_layer_id(VideoParameters *p_Vid, int idx) +{ + assert(idx>=0 && idx<2); + p_Vid->dpb_layer_id = idx; +} + +void setup_dpb_layer(DecodedPictureBuffer *p_Dpb, VideoParameters *p_Vid, InputParameters *p_Inp) +{ + // on-the-fly interpolation init + switch ( p_Inp->OnTheFlyFractMCP ) + { + case OTF_L1: + p_Dpb->pf_computeSAD = computeSAD_otf; + p_Dpb->pf_computeSADWP = computeSADWP_otf; + p_Dpb->pf_computeSATD = computeSATD_otf; + p_Dpb->pf_computeSATDWP = computeSATDWP_otf; + p_Dpb->pf_computeBiPredSAD1 = computeBiPredSAD1_otf; + p_Dpb->pf_computeBiPredSAD2 = computeBiPredSAD2_otf; + p_Dpb->pf_computeBiPredSATD1 = computeBiPredSATD1_otf; + p_Dpb->pf_computeBiPredSATD2 = computeBiPredSATD2_otf; + p_Dpb->pf_computeSSE = computeSSE_otf; + p_Dpb->pf_computeSSEWP = computeSSEWP_otf; + p_Dpb->pf_computeBiPredSSE1 = computeBiPredSSE1_otf; + p_Dpb->pf_computeBiPredSSE2 = computeBiPredSSE2_otf; + p_Dpb->pf_luma_prediction = luma_prediction_otf ; + p_Dpb->pf_luma_prediction_bi = luma_prediction_bi_otf ; + p_Dpb->pf_chroma_prediction = chroma_prediction_otf ; + p_Dpb->pf_get_block_luma = get_block_luma_otf_L1 ; + p_Dpb->pf_get_block_chroma[OTF_ME] = (p_Vid->P444_joined) ? ( get_block_luma_otf_L1 ) : ( me_get_block_chroma_otf_L1 ) ; + p_Dpb->pf_get_block_chroma[OTF_MC] = (p_Vid->P444_joined) ? ( get_block_luma_otf_L1 ) : ( mc_get_block_chroma_otf_L1 ) ; + p_Dpb->pf_OneComponentChromaPrediction4x4_regenerate = OneComponentChromaPrediction4x4_regenerate; + p_Dpb->pf_OneComponentChromaPrediction4x4_retrieve = OneComponentChromaPrediction4x4_regenerate; + break; + case OTF_L2: + p_Dpb->pf_computeSAD = computeSAD_otf; + p_Dpb->pf_computeSADWP = computeSADWP_otf; + p_Dpb->pf_computeSATD = computeSATD_otf; + p_Dpb->pf_computeSATDWP = computeSATDWP_otf; + p_Dpb->pf_computeBiPredSAD1 = computeBiPredSAD1_otf; + p_Dpb->pf_computeBiPredSAD2 = computeBiPredSAD2_otf; + p_Dpb->pf_computeBiPredSATD1 = computeBiPredSATD1_otf; + p_Dpb->pf_computeBiPredSATD2 = computeBiPredSATD2_otf; + p_Dpb->pf_computeSSE = computeSSE_otf; + p_Dpb->pf_computeSSEWP = computeSSEWP_otf; + p_Dpb->pf_computeBiPredSSE1 = computeBiPredSSE1_otf; + p_Dpb->pf_computeBiPredSSE2 = computeBiPredSSE2_otf; + p_Dpb->pf_luma_prediction = luma_prediction_otf ; + p_Dpb->pf_luma_prediction_bi = luma_prediction_bi_otf ; + p_Dpb->pf_chroma_prediction = chroma_prediction_otf ; + p_Dpb->pf_get_block_luma = get_block_luma_otf_L2 ; + p_Dpb->pf_get_block_chroma[OTF_ME] = p_Dpb->pf_get_block_chroma[OTF_MC] = (p_Vid->P444_joined) ? ( get_block_luma_otf_L2 ) : ( get_block_chroma_otf_L2 ) ; + p_Dpb->pf_OneComponentChromaPrediction4x4_regenerate = OneComponentChromaPrediction4x4_regenerate; + p_Dpb->pf_OneComponentChromaPrediction4x4_retrieve = OneComponentChromaPrediction4x4_regenerate; + break; + default: // otf not used + p_Dpb->pf_computeSAD = computeSAD; + p_Dpb->pf_computeSADWP = computeSADWP; + p_Dpb->pf_computeSATD = computeSATD; + p_Dpb->pf_computeSATDWP = computeSATDWP; + p_Dpb->pf_computeBiPredSAD1 = computeBiPredSAD1; + p_Dpb->pf_computeBiPredSAD2 = computeBiPredSAD2; + p_Dpb->pf_computeBiPredSATD1 = computeBiPredSATD1; + p_Dpb->pf_computeBiPredSATD2 = computeBiPredSATD2; + p_Dpb->pf_computeSSE = computeSSE; + p_Dpb->pf_computeSSEWP = computeSSEWP; + p_Dpb->pf_computeBiPredSSE1 = computeBiPredSSE1; + p_Dpb->pf_computeBiPredSSE2 = computeBiPredSSE2; + p_Dpb->pf_luma_prediction = luma_prediction; + p_Dpb->pf_luma_prediction_bi = luma_prediction_bi; + p_Dpb->pf_chroma_prediction = chroma_prediction; + p_Dpb->pf_OneComponentChromaPrediction4x4_regenerate = OneComponentChromaPrediction4x4_regenerate; + p_Dpb->pf_OneComponentChromaPrediction4x4_retrieve = OneComponentChromaPrediction4x4_retrieve; + break; + } +} + +static void set_storage_format(VideoParameters *p_Vid, FrameFormat *p_src, FrameFormat *p_dst) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + *p_dst = *p_src; + p_dst->width[0] = (p_Inp->output.width[0] + p_Vid->auto_crop_right); + p_dst->height[0] = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom); + p_dst->width[1] = p_dst->width[2] = p_dst->width[0] * mb_width_cr [p_dst->yuv_format] / 16; + p_dst->height[1]= p_dst->height[2] = p_dst->height[0] * mb_height_cr[p_dst->yuv_format] / 16; + p_dst->size_cmp[0] = p_dst->width[0] * p_dst->height[0]; + p_dst->size_cmp[2] = p_dst->size_cmp[1] = p_dst->width[1] * p_dst->height[1]; + p_dst->size = p_dst->size_cmp[0] + p_dst->size_cmp[1] + p_dst->size_cmp[2]; +} + +/*! +*********************************************************************** +* \brief +* Initialize encoder +*********************************************************************** +*/ +static void init_encoder(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i; + p_Vid->p_Inp = p_Inp; + p_Vid->giRDOpt_B8OnlyFlag = FALSE; + p_Vid->p_log = NULL; + + //set coding layer number; + p_Vid->num_of_layers = p_Inp->num_of_views; + + p_Vid->cabac_encoding = 0; + p_Vid->frame_statistic_start = 1; + + if (p_Inp->Log2MaxFNumMinus4 == -1) + { + p_Vid->log2_max_frame_num_minus4 = iClip3(0,12, (int) (CeilLog2(p_Inp->no_frames) - 4)); // hack for now... + } + else + p_Vid->log2_max_frame_num_minus4 = p_Inp->Log2MaxFNumMinus4; + + if (p_Vid->log2_max_frame_num_minus4 == 0 && p_Inp->num_ref_frames == 16) + { + snprintf(errortext, ET_SIZE, " NumberReferenceFrames=%d and Log2MaxFNumMinus4=%d may lead to an invalid value of frame_num.", p_Inp->num_ref_frames, p_Inp-> Log2MaxFNumMinus4); + error (errortext, 500); + } + + // set proper p_Vid->log2_max_pic_order_cnt_lsb_minus4. + if (p_Inp->Log2MaxPOCLsbMinus4 == - 1) + p_Vid->log2_max_pic_order_cnt_lsb_minus4 = iClip3(0,12, (int) (CeilLog2( imax( p_Inp->no_frames, (p_Inp->NumberBFrames + 1) << 1 ) << 1 ) - 4)); // hack for now + else + p_Vid->log2_max_pic_order_cnt_lsb_minus4 = p_Inp->Log2MaxPOCLsbMinus4; + + if (((1<<(p_Vid->log2_max_pic_order_cnt_lsb_minus4 + 3)) < p_Inp->jumpd * 4) && p_Inp->Log2MaxPOCLsbMinus4 != -1) + error("log2_max_pic_order_cnt_lsb_minus4 might not be sufficient for encoding. Increase value.",400); + + if (strlen (p_Inp->ReconFile) > 0 && (p_Vid->p_dec = open(p_Inp->ReconFile, OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s", p_Inp->ReconFile); + error (errortext, 500); + } + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2) + { + if (strlen (p_Inp->ReconFile2) > 0 && (p_Vid->p_dec2 = open(p_Inp->ReconFile2, OPENFLAGS_WRITE, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s", p_Inp->ReconFile2); + error (errortext, 500); + } + } +#endif + if ((p_Inp->output.width[0] & 0x0F) != 0) + { + p_Vid->auto_crop_right = 16 - (p_Inp->output.width[0] & 0x0F); + } + else + { + p_Vid->auto_crop_right = 0; + } + + if (p_Inp->PicInterlace || p_Inp->MbInterlace) + { + if ((p_Inp->output.height[0] & 0x01) != 0) + { + error ("even number of lines required for interlaced coding", 500); + } + + if ((p_Inp->output.height[0] & 0x1F) != 0) + { + p_Vid->auto_crop_bottom = 32 - (p_Inp->output.height[0] & 0x1F); + } + else + { + p_Vid->auto_crop_bottom=0; + } + } + else + { + if ((p_Inp->output.height[0] & 0x0F) != 0) + { + p_Vid->auto_crop_bottom = 16 - (p_Inp->output.height[0] & 0x0F); + } + else + { + p_Vid->auto_crop_bottom = 0; + } + } + if (p_Vid->auto_crop_bottom || p_Vid->auto_crop_right) + { + fprintf (stdout, "Warning: Automatic cropping activated: Coded frame Size: %dx%d\n", + p_Inp->output.width[0] + p_Vid->auto_crop_right, p_Inp->output.height[0] + p_Vid->auto_crop_bottom); + } + + // read the slice group configuration file. Only for types 0, 2 or 6 + if ( 0 != p_Inp->num_slice_groups_minus1 ) + { + read_slice_group_info(p_Vid, p_Inp); + } + //! the number of slice groups is forced to be 1 for slice group type 3-5 + if(p_Inp->num_slice_groups_minus1 > 0) + { + if( (p_Inp->slice_group_map_type >= 3) && (p_Inp->slice_group_map_type<=5) ) + p_Inp->num_slice_groups_minus1 = 1; + } + + if(p_Inp->RCEnable) + { + if (p_Inp->basicunit == 0) + p_Inp->basicunit = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom)*(p_Inp->output.width[0] + p_Vid->auto_crop_right)/256; + + if ( ((p_Inp->output.height[0] + p_Vid->auto_crop_bottom)*(p_Inp->output.width[0] + p_Vid->auto_crop_right)/256) % p_Inp->basicunit != 0) + { + snprintf(errortext, ET_SIZE, "Frame size in macroblocks must be a multiple of BasicUnit."); + error (errortext, 500); + } + } + + level_check(p_Vid, p_Inp); + + // Open Files + OpenFiles(&p_Inp->input_file1); +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers==2) + { + OpenFiles(&p_Inp->input_file2); + } + p_Vid->prev_view_is_anchor = 0; + p_Vid->view_id = 0; // initialise view_id + set_dpb_layer_id(p_Vid, p_Vid->view_id); +#endif + + //init dpb storage formage; + p_Vid->output_format[0] = p_Inp->output; + set_storage_format(p_Vid, &(p_Inp->source), &(p_Vid->p_Dpb_layer[0]->storage_format)); + if(p_Vid->num_of_layers == 2) + { + { + p_Vid->output_format[1] = p_Inp->output; + set_storage_format(p_Vid, &(p_Inp->source), &(p_Vid->p_Dpb_layer[1]->storage_format)); + } + } + //end; + + init_qmatrix(p_Vid, p_Inp); + init_qoffset(p_Vid); + + init_poc(p_Vid); + generate_parameter_sets(p_Vid); + generate_encode_parameters(p_Vid); + set_level_indices(p_Vid); + + init_img (p_Vid); + + if (p_Inp->rdopt == 3) + { + init_error_conceal(p_Vid,p_Inp->ErrorConcealment); + //Zhifeng 090611 + init_distortion_estimation(p_Vid,p_Inp->de); + } + +#ifdef _LEAKYBUCKET_ + p_Vid->initial_Bframes = 0; +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2) + p_Vid->Bit_Buffer = (long *)malloc(((p_Inp->no_frames << 1) + 1) * sizeof(long)); + else + p_Vid->Bit_Buffer = (long *)malloc((p_Inp->no_frames + 1) * sizeof(long)); +#else + p_Vid->Bit_Buffer = (long *)malloc((p_Inp->no_frames + 1) * sizeof(long)); +#endif + p_Vid->total_frame_buffer = 0; +#endif + + // Prepare hierarchical coding structures. + // Code could be extended in the future to allow structure adaptation. + if (p_Inp->NumberBFrames && p_Inp->HierarchicalCoding == 3) + { + init_gop_structure(p_Vid, p_Inp); + interpret_gop_structure(p_Vid, p_Inp); + } + + // Initialize dpb for each layer + for(i=0; ip_Dpb_layer[i]->init_done = 0; + } + for(i=0; inum_of_layers, MAX_NUM_DPB_LAYERS); i++) + { + init_dpb(p_Vid, p_Vid->p_Dpb_layer[i]); + } + + init_out_buffer(p_Vid); + init_stats (p_Inp, p_Vid->p_Stats); + init_dstats(p_Vid->p_Dist); + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2) + { + p_Vid->p_Dist->frame_ctr_v[0] = 0; + p_Vid->p_Dist->frame_ctr_v[1] = 0; + memset(p_Vid->p_Dist->metric_v[0], 0, TOTAL_DIST_TYPES * sizeof(DistMetric)); + memset(p_Vid->p_Dist->metric_v[1], 0, TOTAL_DIST_TYPES * sizeof(DistMetric)); + } +#endif + + p_Vid->enc_picture = NULL; + + init_global_buffers(p_Vid, p_Inp); + + if ( p_Inp->WPMCPrecision ) + wpxInitWPXPasses(p_Vid, p_Inp); + + init_motion_search_module (p_Vid, p_Inp); + information_init(p_Vid, p_Inp, p_Vid->p_Stats); + + if(p_Inp->DistortionYUVtoRGB) + init_YUVtoRGB(p_Vid, p_Inp); + + //Rate control + if (p_Inp->RCEnable) + rc_init_sequence(p_Vid, p_Inp); + + p_Vid->last_valid_reference = 0; + p_Vid->tot_time = 0; // time for total encoding session + p_Vid->last_bit_ctr_n = 0; + + p_Vid->initial_Bframes = p_Inp->NumberBFrames; + + p_Vid->type = I_SLICE; + // Write sequence header (with parameter sets) + p_Vid->p_Stats->bit_ctr_filler_data = 0; + p_Vid->p_Stats->bit_ctr_filler_data_n = 0; + p_Vid->p_Stats->bit_ctr_parametersets = 0; + +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->num_of_layers == 2 ) + { + p_Vid->p_Stats->bit_ctr_filler_data_v[0] = 0; + p_Vid->p_Stats->bit_ctr_filler_data_v[1] = 0; + p_Vid->p_Stats->bit_ctr_filler_data_n_v[0] = 0; + p_Vid->p_Stats->bit_ctr_filler_data_n_v[1] = 0; + p_Vid->p_Stats->bit_ctr_parametersets_v[0] = 0; + p_Vid->p_Stats->bit_ctr_parametersets_v[1] = 0; + } +#endif + + p_Vid->p_Stats->bit_slice = start_sequence(p_Vid, p_Inp); + + if (p_Inp->UseRDOQuant) + precalculate_unary_exp_golomb_level(p_Vid); + + if (p_Inp->ExplicitSeqCoding) + OpenExplicitSeqFile(p_Vid, p_Inp); + + p_Vid->searchRange.min_x = -p_Inp->search_range[0] << 2; + p_Vid->searchRange.max_x = p_Inp->search_range[0] << 2; + p_Vid->searchRange.min_y = -p_Inp->search_range[0] << 2; + p_Vid->searchRange.max_y = p_Inp->search_range[0] << 2; + + for ( i = 0; i < p_Vid->num_of_layers; i++ ) + { + setup_dpb_layer(p_Vid->p_Dpb_layer[i], p_Vid, p_Inp); + } + + initTranscodeModule( p_Vid ); +} + +void setup_coding_layer(VideoParameters *p_Vid) +{ + //setup the buffers; + int i; + int dpb_layer_id = p_Vid->dpb_layer_id; + InputParameters *p_Inp = p_Vid->p_Inp; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[dpb_layer_id]; + + p_Vid->active_sps = p_Vid->sps[dpb_layer_id]; + p_Vid->p_CurrEncodePar = p_Vid->p_EncodePar[dpb_layer_id]; + + if (p_Vid->p_CurrEncodePar->last_ref_idc == 1) + { + p_Vid->p_CurrEncodePar->frame_num++; + p_Vid->p_CurrEncodePar->frame_num %= p_Vid->max_frame_num; + } + p_Vid->frame_num = p_Vid->p_CurrEncodePar->frame_num; + + //set bitdepth info; + if(p_Vid->num_of_layers >1) + { + //all these initializations will be removed later; + CodingParameters *cps = p_Vid->p_CurrEncodePar; + + p_Vid->yuv_format = cps->yuv_format; + p_Vid->P444_joined = cps->P444_joined; + p_Vid->bitdepth_luma = cps->bitdepth_luma; + p_Vid->bitdepth_scale[0] = cps->bitdepth_scale[0]; + p_Vid->bitdepth_lambda_scale = cps->bitdepth_lambda_scale; + p_Vid->bitdepth_luma_qp_scale = cps->bitdepth_luma_qp_scale; + p_Vid->dc_pred_value_comp[0] = cps->dc_pred_value_comp[0]; + + p_Vid->max_pel_value_comp[0] = cps->max_pel_value_comp[0]; + p_Vid->max_imgpel_value_comp_sq[0] = cps->max_imgpel_value_comp_sq[0]; + p_Vid->mb_size[0][0] = p_Vid->mb_size[0][1] = cps->mb_size[0][0]; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->chroma_qp_offset[0] = p_Vid->active_pps->cb_qp_index_offset; + p_Vid->chroma_qp_offset[1] = p_Vid->active_pps->cr_qp_index_offset; + } + else + { + p_Vid->chroma_qp_offset[0] = 0; + p_Vid->chroma_qp_offset[1] = 0; + } + p_Vid->bitdepth_chroma = cps->bitdepth_chroma; + p_Vid->bitdepth_scale[1] = cps->bitdepth_scale[1]; + p_Vid->dc_pred_value_comp[2] = p_Vid->dc_pred_value_comp[1] = cps->dc_pred_value_comp[1]; + p_Vid->max_pel_value_comp[2] = p_Vid->max_pel_value_comp[1] = cps->max_pel_value_comp[1]; + p_Vid->max_imgpel_value_comp_sq[1] = cps->max_imgpel_value_comp_sq[1]; + p_Vid->max_imgpel_value_comp_sq[2] = cps->max_imgpel_value_comp_sq[2]; + p_Vid->num_blk8x8_uv = cps->num_blk8x8_uv; + p_Vid->num_cdc_coeff = cps->num_cdc_coeff; + p_Vid->mb_size[1][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = cps->mb_cr_size_x; + p_Vid->mb_size[1][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = cps->mb_cr_size_y; + p_Vid->bitdepth_chroma_qp_scale = cps->bitdepth_chroma_qp_scale; + p_Vid->max_bitCount = cps->max_bitCount; + + ////if ( p_Inp->ChromaMCBuffer ) + //chroma_mc_setup(p_Vid); + p_Vid->pad_size_uv_x = cps->pad_size_uv_x; + p_Vid->pad_size_uv_y = cps->pad_size_uv_y; + p_Vid->chroma_mask_mv_y = cps->chroma_mask_mv_y; + p_Vid->chroma_mask_mv_x = cps->chroma_mask_mv_x; + p_Vid->chroma_shift_y = cps->chroma_shift_y; + p_Vid->chroma_shift_x = cps->chroma_shift_x; + p_Vid->shift_cr_y = cps->shift_cr_y; + p_Vid->shift_cr_x = cps->shift_cr_x; + + p_Vid->padded_size_x = cps->padded_size_x; + p_Vid->padded_size_x_m8x8 = cps->padded_size_x_m8x8; + p_Vid->padded_size_x_m4x4 = cps->padded_size_x_m4x4; + p_Vid->cr_padded_size_x = cps->cr_padded_size_x; + p_Vid->cr_padded_size_x2 = cps->cr_padded_size_x2; + p_Vid->cr_padded_size_x4 = cps->cr_padded_size_x4; + p_Vid->cr_padded_size_x_m8 = cps->cr_padded_size_x_m8; + //end; + + p_Vid->dc_pred_value = p_Vid->dc_pred_value_comp[0]; // set defaults + p_Vid->max_imgpel_value = (short) p_Vid->max_pel_value_comp[0]; + + p_Vid->lambda = p_Vid->lambda_buf[dpb_layer_id]; + p_Vid->lambda_md = p_Vid->lambda_md_buf[dpb_layer_id]; + p_Vid->lambda_me = p_Vid->lambda_me_buf[dpb_layer_id]; + p_Vid->lambda_mf = p_Vid->lambda_mf_buf[dpb_layer_id]; + if ( p_Inp->UseRDOQuant ) + { + p_Vid->lambda_rdoq = p_Vid->lambda_rdoq_buf[dpb_layer_id]; + } + if (p_Inp->CtxAdptLagrangeMult == 1) + { + p_Vid->lambda_mf_factor = p_Vid->lambda_mf_factor_buf[dpb_layer_id]; + } + + setup_mbs(p_Vid->mb_data, p_Vid->FrameSizeInMbs, dpb_layer_id); + p_Vid->nz_coeff = p_Vid->nz_coeff_buf[dpb_layer_id]; + } + + if(p_Vid->imgY_com_buf[0]) + { + p_Vid->imgY_com = p_Vid->imgY_com_buf[dpb_layer_id]; + p_Vid->imgUV_com[0] = p_Vid->imgUV_com_buf[dpb_layer_id][0]; + p_Vid->imgUV_com[1] = p_Vid->imgUV_com_buf[dpb_layer_id][1]; + } + if(p_Vid->imgY_tmp_buf[0]) + { + p_Vid->imgY_tmp = p_Vid->imgY_tmp_buf[dpb_layer_id]; + p_Vid->imgUV_tmp[0] = p_Vid->imgUV_tmp_buf[dpb_layer_id][0]; + p_Vid->imgUV_tmp[1] = p_Vid->imgUV_tmp_buf[dpb_layer_id][1]; + } + if ( p_Inp->ChromaMCBuffer ) + p_Vid->OneComponentChromaPrediction4x4 = p_Dpb->pf_OneComponentChromaPrediction4x4_retrieve; + else + p_Vid->OneComponentChromaPrediction4x4 = p_Dpb->pf_OneComponentChromaPrediction4x4_regenerate; + + select_distortion(p_Vid, p_Inp); + // Setup Distortion Metrics depending on refinement level + for (i=0; i<3; i++) + { + switch(p_Inp->MEErrorMetric[i]) + { + case ERROR_SAD: + p_Vid->computeUniPred[i] = p_Dpb->pf_computeSAD; + p_Vid->computeUniPred[i + 3] = p_Dpb->pf_computeSADWP; + p_Vid->computeBiPred1[i] = p_Dpb->pf_computeBiPredSAD1; + p_Vid->computeBiPred2[i] = p_Dpb->pf_computeBiPredSAD2; + break; + case ERROR_SSE: + p_Vid->computeUniPred[i] = p_Dpb->pf_computeSSE; + p_Vid->computeUniPred[i + 3] = p_Dpb->pf_computeSSEWP; + p_Vid->computeBiPred1[i] = p_Dpb->pf_computeBiPredSSE1; + p_Vid->computeBiPred2[i] = p_Dpb->pf_computeBiPredSSE2; + break; + case ERROR_SATD : + default: + p_Vid->computeUniPred[i] = p_Dpb->pf_computeSATD; + p_Vid->computeUniPred[i + 3] = p_Dpb->pf_computeSATDWP; + p_Vid->computeBiPred1[i] = p_Dpb->pf_computeBiPredSATD1; + p_Vid->computeBiPred2[i] = p_Dpb->pf_computeBiPredSATD2; + break; + } + } + +} + +/*! +************************************************************************ +* \brief +* Prepare parameters for the current frame +************************************************************************ +*/ +static void prepare_frame_params(VideoParameters *p_Vid, InputParameters *p_Inp, int curr_frame_to_code) +{ + SeqStructure *p_seq_struct = p_Vid->p_pred; + FrameUnitStruct *p_cur_frm = p_Vid->p_curr_frm_struct; + int i; + + setup_coding_layer(p_Vid); + + if ( p_Inp->ExplicitSeqCoding ) + { + ExpFrameInfo *info = &p_Vid->expSeq->info[curr_frame_to_code % p_Vid->expSeq->no_frames]; + ReadExplicitSeqFile(p_Vid->expSeq, p_Vid->expSFile, curr_frame_to_code); + // override and overwrite whatever was in p_cur_frm + populate_frame_explicit( info, p_Inp, p_cur_frm, p_seq_struct->max_num_slices ); + } + + // populate coding parameters for the current frame (frame_no, slice_type, nal_ref_idc, poc, reset frame_num) + p_Vid->frame_no = p_cur_frm->frame_no; + p_Vid->frm_no_in_file = (1 + p_Inp->frame_skip) * p_Vid->frame_no; + if ( p_cur_frm->type == SI_SLICE ) + { + set_slice_type( p_Vid, p_Inp, SP_SLICE ); + } + else + { + set_slice_type( p_Vid, p_Inp, p_cur_frm->type ); // dominant slice type; perhaps it is better to use the type of the first slice? + } + p_Vid->nal_reference_idc = p_cur_frm->nal_ref_idc; + switch( p_Vid->pic_order_cnt_type ) + { + case 0: + get_poc_type_zero( p_Vid, p_Inp, p_cur_frm ); + break; + case 1: + get_poc_type_one( p_Vid, p_Inp, p_cur_frm ); + break; + default: + case 2: + get_poc_type_zero( p_Vid, p_Inp, p_cur_frm ); + break; + } + + if (p_cur_frm->idr_flag == 1) + { + for (i = 0; i < p_Vid->num_of_layers; i++) + { + p_Vid->p_EncodePar[i]->frame_num = 0; + } + p_Vid->frame_num = 0; + } + + //Rate control + if (p_Inp->RCEnable && p_Vid->type == I_SLICE) + rc_init_gop_params(p_Vid, p_Inp); + + // which layer does the image belong to? + p_Vid->layer = ((p_Vid->curr_frm_idx - p_Vid->last_idr_code_order) % (p_Inp->NumFramesInELSubSeq + 1)) ? 0 : 1; +} + +/*! +*********************************************************************** +* \brief +* Encode a sequence +*********************************************************************** +*/ +static void encode_sequence(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int curr_frame_to_code; + int frames_to_code; + int frame_num_bak = 0, frame_coded; + int frm_struct_buffer; + SeqStructure *p_seq_struct = p_Vid->p_pred; + FrameUnitStruct *p_frm; + +#if (MVC_EXTENSION_ENABLE) + int tmp_rate_control_enable = p_Inp->RCEnable; + + if ( p_Inp->num_of_views == 2 ) + { + frames_to_code = p_Inp->no_frames << 1; + p_frm = p_seq_struct->p_frm_mvc; + frm_struct_buffer = p_seq_struct->num_frames_mvc; + } + else +#endif + { + frames_to_code = p_Inp->no_frames; + p_frm = p_seq_struct->p_frm; + frm_struct_buffer = p_Vid->frm_struct_buffer; + } + + for (curr_frame_to_code = 0; curr_frame_to_code < frames_to_code; curr_frame_to_code++) + { +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->num_of_views == 2 ) + { + if ( (curr_frame_to_code & 1) == 0 ) // call only for view_id 0 + { + // determine whether to populate additional frames in the prediction structure + if ( (curr_frame_to_code >> 1) >= p_Vid->p_pred->pop_start_frame ) + { + int start = p_seq_struct->pop_start_frame, end; + + populate_frm_struct( p_Vid, p_Inp, p_seq_struct, p_Inp->FrmStructBufferLength, frames_to_code >> 1 ); + end = p_seq_struct->pop_start_frame; + populate_frm_struct_mvc( p_Vid, p_Inp, p_seq_struct, start, end ); + } + } + + p_Vid->curr_frm_idx = curr_frame_to_code; + p_Vid->p_curr_frm_struct = p_frm + ( p_Vid->curr_frm_idx % frm_struct_buffer ); // pointer to current frame structure + p_Vid->number = curr_frame_to_code; + + p_Vid->view_id = p_Vid->p_curr_frm_struct->view_id; + set_dpb_layer_id(p_Vid, p_Vid->view_id); + if ( p_Vid->view_id == 1 ) + { + p_Vid->curr_frm_idx = p_Vid->number = (curr_frame_to_code - 1) >> 1; + p_Vid->p_curr_frm_struct->qp = p_Vid->qp = iClip3( -p_Vid->bitdepth_luma_qp_scale, MAX_QP, p_Vid->AverageFrameQP + p_Inp->View1QPOffset ); + } + else + { + p_Vid->curr_frm_idx = p_Vid->number = curr_frame_to_code >> 1; + } + if ( p_Vid->view_id == 1 && tmp_rate_control_enable ) + { + p_Inp->RCEnable = 0; + } + else + { + p_Inp->RCEnable = tmp_rate_control_enable; + } + } + else +#endif + { + // determine whether to populate additional frames in the prediction structure + if ( curr_frame_to_code >= p_Vid->p_pred->pop_start_frame ) + { + populate_frm_struct( p_Vid, p_Inp, p_seq_struct, p_Inp->FrmStructBufferLength, frames_to_code ); + } + p_Vid->curr_frm_idx = curr_frame_to_code; + p_Vid->p_curr_frm_struct = p_frm + ( p_Vid->curr_frm_idx % frm_struct_buffer ); // pointer to current frame structure + p_Vid->number = curr_frame_to_code; + + } + + if ( p_Vid->p_curr_frm_struct->frame_no >= p_Inp->no_frames ) + { + continue; + } + + // Update frame_num counter + frame_num_bak = p_Vid->p_EncodePar[p_Vid->dpb_layer_id]->frame_num; + + prepare_frame_params(p_Vid, p_Inp, curr_frame_to_code); + + // redundant frame initialization and allocation + if (p_Inp->redundant_pic_flag) + { + init_redundant_frame(p_Vid, p_Inp); + set_redundant_frame(p_Vid, p_Inp); + } + + frame_coded = encode_one_frame(p_Vid, p_Inp); // encode one frame; + if ( !frame_coded ) + { + p_Vid->frame_num = p_Vid->p_CurrEncodePar->frame_num = frame_num_bak; + continue; + } + + p_Vid->p_CurrEncodePar->last_ref_idc = p_Vid->nal_reference_idc ? 1 : 0; + + // if key frame is encoded, encode one redundant frame + if (p_Inp->redundant_pic_flag && p_Vid->key_frame) + { + encode_one_redundant_frame(p_Vid, p_Inp); + } + + if (p_Inp->EnableOpenGOP && p_Vid->p_curr_frm_struct->random_access) + { + if (p_Inp->PicInterlace) + { + if (p_Vid->p_curr_frm_struct->p_top_fld_pic->p_Slice[0].type == I_SLICE && p_Vid->p_curr_frm_struct->random_access) //Currently encoder always codes top field as I + { + p_Vid->last_valid_reference = p_Vid->ThisPOC & (~( (signed int)1 )); + //printf("last valid ref: %d", p_Vid->last_valid_reference); + } + } + else if (p_Vid->type == I_SLICE) + { + p_Vid->last_valid_reference = p_Vid->ThisPOC; + //printf("last valid ref: %d", p_Vid->last_valid_reference); + } + } + + if (p_Inp->ReportFrameStats) + { + report_frame_statistic(p_Vid, p_Inp); + } + + } + +#if EOS_OUTPUT + end_of_stream(p_Vid); +#endif + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views == 2) //? it should use num_of_layers; + { + p_Inp->RCEnable = tmp_rate_control_enable; + } +#endif +} + + +/*! +*********************************************************************** +* \brief +* Free memory allocated for the encoder +*********************************************************************** +*/ + +void free_encoder_memory(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + //! Edited by Joao Carreira + closeTranscodeModule( p_Vid ); + + terminate_sequence(p_Vid, p_Inp); + flush_dpb(p_Vid->p_Dpb_layer[0], &p_Inp->output); + flush_dpb(p_Vid->p_Dpb_layer[1], &p_Inp->output); + CloseFiles(&p_Inp->input_file1); + + if (-1 != p_Vid->p_dec) + close(p_Vid->p_dec); + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers==2) + CloseFiles(&p_Inp->input_file2); + if (-1 != p_Vid->p_dec2) + close(p_Vid->p_dec2); +#endif + + if (p_Enc->p_trace) + fclose(p_Enc->p_trace); + + clear_motion_search_module (p_Vid, p_Inp); + + RandomIntraUninit(p_Vid); + FmoUninit(p_Vid); + + if (p_Inp->NumberBFrames && p_Inp->HierarchicalCoding == 3) + { + clear_gop_structure (p_Vid); + } + +#ifdef _LEAKYBUCKET_ + calc_buffer(p_Vid, p_Inp); +#endif + + // report everything + report(p_Vid, p_Inp, p_Vid->p_Stats); + +#ifdef _LEAKYBUCKET_ + free_pointer(p_Vid->Bit_Buffer); +#endif + free_dpb(p_Vid->p_Dpb_layer[0]); + free_dpb(p_Vid->p_Dpb_layer[1]); + uninit_out_buffer(p_Vid); + + free_global_buffers(p_Vid, p_Inp); + + FreeParameterSets(p_Vid); + + if (p_Inp->ExplicitSeqCoding) + CloseExplicitSeqFile(p_Vid); + + // free image mem + free_img (p_Vid, p_Inp); +} + +/*! +*********************************************************************** +* \brief +* Initializes the Image structure with appropriate parameters. +* \par Input: +* Input Parameters InputParameters *inp +* \par Output: +* Image Parameters VideoParameters *p_Vid +*********************************************************************** +*/ +static void init_img( VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j; + + p_Vid->number = -1; + + p_Vid->last_idr_code_order = 0; + p_Vid->last_idr_disp_order = 0; + p_Vid->last_mmco_5_code_order = -1; + p_Vid->last_mmco_5_disp_order = -1; + // Color format + p_Vid->yuv_format = p_Inp->output.yuv_format; + p_Vid->P444_joined = (p_Vid->yuv_format == YUV444 && (p_Inp->separate_colour_plane_flag == 0)); + + //pel bitdepth init + p_Vid->bitdepth_luma = (short) p_Inp->output.bit_depth[0]; + p_Vid->bitdepth_scale[0] = 1 << (p_Vid->bitdepth_luma - 8); + p_Vid->bitdepth_lambda_scale = 2 * (p_Vid->bitdepth_luma - 8); + p_Vid->bitdepth_luma_qp_scale = 3 * p_Vid->bitdepth_lambda_scale; + p_Vid->dc_pred_value_comp[0] = (imgpel) (1<<(p_Vid->bitdepth_luma - 1)); + p_Vid->max_pel_value_comp[0] = (1<bitdepth_luma) - 1; + p_Vid->max_imgpel_value_comp_sq[0] = p_Vid->max_pel_value_comp[0] * p_Vid->max_pel_value_comp[0]; + + p_Vid->dc_pred_value = p_Vid->dc_pred_value_comp[0]; // set defaults + p_Vid->max_imgpel_value = (short) p_Vid->max_pel_value_comp[0]; + p_Vid->mb_size[0][0] = p_Vid->mb_size[0][1] = MB_BLOCK_SIZE; + + // Initialization for RC QP parameters (could be placed in ratectl.c) + p_Vid->RCMinQP = p_Inp->RCMinQP[P_SLICE]; + p_Vid->RCMaxQP = p_Inp->RCMaxQP[P_SLICE]; + + p_Vid->WalkAround = 0; + p_Vid->NumberOfMBs = 0; + + // Set current residue & prediction array pointers + + if (p_Vid->active_sps->profile_idc == BASELINE || p_Vid->active_sps->profile_idc == MAIN || p_Vid->active_sps->profile_idc == EXTENDED) + p_Vid->min_IPCM_value = 1; // See Annex A for restriction in pcm sample values for pre FRExt profiles + else + p_Vid->min_IPCM_value = 0; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->bitdepth_chroma = (short) p_Inp->output.bit_depth[1]; + p_Vid->bitdepth_scale[1] = 1 << (p_Vid->bitdepth_chroma - 8); + p_Vid->dc_pred_value_comp[1] = (imgpel) (1<<(p_Vid->bitdepth_chroma - 1)); + p_Vid->dc_pred_value_comp[2] = p_Vid->dc_pred_value_comp[1]; + p_Vid->max_pel_value_comp[1] = (1<bitdepth_chroma) - 1; + p_Vid->max_pel_value_comp[2] = p_Vid->max_pel_value_comp[1]; + p_Vid->max_imgpel_value_comp_sq[1] = p_Vid->max_pel_value_comp[1] * p_Vid->max_pel_value_comp[1]; + p_Vid->max_imgpel_value_comp_sq[2] = p_Vid->max_pel_value_comp[2] * p_Vid->max_pel_value_comp[2]; + p_Vid->num_blk8x8_uv = (1<yuv_format)&(~(0x1)); + p_Vid->num_cdc_coeff = p_Vid->num_blk8x8_uv << 1; + + p_Vid->mb_size[1][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = (p_Vid->yuv_format == YUV420 || p_Vid->yuv_format == YUV422) ? 8 : 16; + p_Vid->mb_size[1][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = (p_Vid->yuv_format == YUV444 || p_Vid->yuv_format == YUV422) ? 16 : 8; + + p_Vid->bitdepth_chroma_qp_scale = 6*(p_Vid->bitdepth_chroma - 8); + + p_Vid->chroma_qp_offset[0] = p_Vid->active_pps->cb_qp_index_offset; + p_Vid->chroma_qp_offset[1] = p_Vid->active_pps->cr_qp_index_offset; + } + else + { + p_Vid->bitdepth_chroma = 0; + p_Vid->bitdepth_scale[1] = 0; + p_Vid->max_pel_value_comp[1] = 0; + p_Vid->max_pel_value_comp[2] = p_Vid->max_pel_value_comp[1]; + p_Vid->max_imgpel_value_comp_sq[1] = p_Vid->max_pel_value_comp[1] * p_Vid->max_pel_value_comp[1]; + p_Vid->max_imgpel_value_comp_sq[2] = p_Vid->max_pel_value_comp[2] * p_Vid->max_pel_value_comp[2]; + p_Vid->num_blk8x8_uv = 0; + p_Vid->num_cdc_coeff = 0; + p_Vid->mb_size[1][0] = p_Vid->mb_size[2][0] = p_Vid->mb_cr_size_x = 0; + p_Vid->mb_size[1][1] = p_Vid->mb_size[2][1] = p_Vid->mb_cr_size_y = 0; + + p_Vid->bitdepth_chroma_qp_scale = 0; + + p_Vid->chroma_qp_offset[0] = 0; + p_Vid->chroma_qp_offset[1] = 0; + } + + p_Vid->max_bitCount = 128 + 256 * p_Vid->bitdepth_luma + 2 * p_Vid->mb_cr_size_y * p_Vid->mb_cr_size_x * p_Vid->bitdepth_chroma; + //p_Vid->max_bitCount = (128 + 256 * p_Vid->bitdepth_luma + 2 *p_Vid->mb_cr_size_y * p_Vid->mb_cr_size_x * p_Vid->bitdepth_chroma)*2; + + p_Vid->max_qp_delta = (25 + (p_Vid->bitdepth_luma_qp_scale>>1)); + p_Vid->min_qp_delta = p_Vid->max_qp_delta + 1; + + p_Vid->num_ref_frames = p_Vid->active_sps->num_ref_frames; + p_Vid->max_num_references = p_Vid->active_sps->frame_mbs_only_flag ? p_Vid->active_sps->num_ref_frames : 2 * p_Vid->active_sps->num_ref_frames; + +#if (MVC_EXTENSION_ENABLE) + p_Vid->sec_view_force_fld = 0; +#endif + + p_Vid->base_dist = p_Inp->jumpd + 1; + + // Intra/IDR related parameters + p_Vid->lastIntraNumber = 0; + p_Vid->lastINTRA = 0; + p_Vid->last_ref_idc = 0; + p_Vid->idr_refresh = 0; + + p_Vid->framerate = (float) p_Inp->output.frame_rate; // The basic frame rate (of the original sequence) + + if (p_Inp->AdaptiveRounding) + { + if (p_Vid->yuv_format != 0) + { + get_mem4Dint(&(p_Vid->ARCofAdj4x4), 3, MAXMODE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); //all modes + get_mem4Dint(&(p_Vid->ARCofAdj8x8), p_Vid->P444_joined ? 3 : 1, MAXMODE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); //modes 0, 1, 2, 3, P8x8 + } + else + { + get_mem4Dint(&(p_Vid->ARCofAdj4x4), 1, MAXMODE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); //all modes + get_mem4Dint(&(p_Vid->ARCofAdj8x8), 1, MAXMODE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); //modes 0, 1, 2, 3, P8x8 + } + } + + p_Vid->width = (p_Inp->output.width[0] + p_Vid->auto_crop_right); + p_Vid->height = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom); + p_Vid->width_blk = p_Vid->width / BLOCK_SIZE; + p_Vid->height_blk = p_Vid->height / BLOCK_SIZE; + p_Vid->width_padded = p_Vid->width + 2 * IMG_PAD_SIZE_X; + p_Vid->height_padded = p_Vid->height + 2 * IMG_PAD_SIZE_Y; + + if (p_Vid->yuv_format != YUV400) + { + p_Vid->width_cr = p_Vid->width * mb_width_cr [p_Vid->yuv_format] / 16; + p_Vid->height_cr= p_Vid->height * mb_height_cr[p_Vid->yuv_format] / 16; + } + else + { + p_Vid->width_cr = 0; + p_Vid->height_cr= 0; + } + + p_Vid->height_cr_frame = p_Vid->height_cr; + + p_Vid->size = p_Vid->width * p_Vid->height; + p_Vid->size_cr = p_Vid->width_cr * p_Vid->height_cr; + + p_Vid->PicWidthInMbs = p_Vid->width / MB_BLOCK_SIZE; + p_Vid->FrameHeightInMbs = p_Vid->height / MB_BLOCK_SIZE; + p_Vid->FrameSizeInMbs = p_Vid->PicWidthInMbs * p_Vid->FrameHeightInMbs; + + p_Vid->PicHeightInMapUnits = ( p_Vid->active_sps->frame_mbs_only_flag ? p_Vid->FrameHeightInMbs : p_Vid->FrameHeightInMbs >> 1 ); + + if ((p_Vid->b8x8info = (Block8x8Info *) calloc(1, sizeof(Block8x8Info))) == NULL) + no_mem_exit("init_img: p_Vid->block8x8info"); + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( i = 0; i < MAX_PLANE; i++ ){ + //if ((p_Vid->mb_data_JV[i] = (Macroblock *) calloc(p_Vid->FrameSizeInMbs,sizeof(Macroblock))) == NULL) + if((p_Vid->mb_data_JV[i] = alloc_mbs(p_Vid, p_Vid->FrameSizeInMbs, p_Vid->num_of_layers)) == NULL) + no_mem_exit("init_img: p_Vid->mb_data_JV"); + } + p_Vid->mb_data = NULL; + } + else + { + //if ((p_Vid->mb_data = (Macroblock *) calloc(p_Vid->FrameSizeInMbs, sizeof(Macroblock))) == NULL) + if ((p_Vid->mb_data = alloc_mbs(p_Vid, p_Vid->FrameSizeInMbs, p_Vid->num_of_layers)) == NULL) + no_mem_exit("init_img: p_Vid->mb_data"); + } + + if (p_Inp->UseConstrainedIntraPred) + { + if ((p_Vid->intra_block = (short*) calloc(p_Vid->FrameSizeInMbs, sizeof(short))) == NULL) + no_mem_exit("init_img: p_Vid->intra_block"); + } + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + if ((p_Vid->mb16x16_cost_frame = (double*)calloc(p_Vid->FrameSizeInMbs, sizeof(double))) == NULL) + { + no_mem_exit("init p_Vid->mb16x16_cost_frame"); + } + } + get_mem2D((byte***)&(p_Vid->ipredmode), p_Vid->height_blk, p_Vid->width_blk); //need two extra rows at right and bottom + get_mem2D((byte***)&(p_Vid->ipredmode8x8), p_Vid->height_blk, p_Vid->width_blk); // help storage for ipredmode 8x8, inserted by YV + memset(&(p_Vid->ipredmode[0][0]) , -1, p_Vid->height_blk * p_Vid->width_blk *sizeof(char)); + memset(&(p_Vid->ipredmode8x8[0][0]), -1, p_Vid->height_blk * p_Vid->width_blk *sizeof(char)); + + + // CAVLC mem + if(p_Vid->num_of_layers>1) + { + get_mem3Dint(&(p_Vid->nz_coeff_buf[0]), p_Vid->FrameSizeInMbs, 4, 4+p_Vid->num_blk8x8_uv); + if(p_Vid->p_Dpb_layer[1]->storage_format.yuv_format != YUV400 && p_Vid->p_Dpb_layer[1]->storage_format.yuv_format != p_Vid->p_Dpb_layer[0]->storage_format.yuv_format) + { + int num_blk8x8_uv = (1<p_Dpb_layer[1]->storage_format.yuv_format)&(~(0x1)); + get_mem3Dint(&(p_Vid->nz_coeff_buf[1]), p_Vid->FrameSizeInMbs, 4, 4+num_blk8x8_uv); + } + else + p_Vid->nz_coeff_buf[1] = p_Vid->nz_coeff_buf[0]; + p_Vid->nz_coeff = p_Vid->nz_coeff_buf[0]; + } + else + { + get_mem3Dint(&(p_Vid->nz_coeff_buf[0]), p_Vid->FrameSizeInMbs, 4, 4+p_Vid->num_blk8x8_uv); + p_Vid->nz_coeff = p_Vid->nz_coeff_buf[0]; + p_Vid->nz_coeff_buf[1] = NULL; + } + + get_mem2Dolm (&(p_Vid->lambda_buf[0]) , 10, 52 + p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda = p_Vid->lambda_buf[0]; + get_mem2Dodouble (&(p_Vid->lambda_md_buf[0]), 10, 52 + p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_md = p_Vid->lambda_md_buf[0]; + get_mem3Dodouble (&(p_Vid->lambda_me_buf[0]), 10, 52 + p_Vid->bitdepth_luma_qp_scale, 3, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_me = p_Vid->lambda_me_buf[0]; + get_mem3Doint (&(p_Vid->lambda_mf_buf[0]), 10, 52 + p_Vid->bitdepth_luma_qp_scale, 3, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_mf = p_Vid->lambda_mf_buf[0]; + if ( p_Inp->UseRDOQuant ) + { + get_mem2Dodouble (&(p_Vid->lambda_rdoq_buf[0]), 10, 52 + p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_rdoq = p_Vid->lambda_rdoq_buf[0]; + } + if (p_Inp->CtxAdptLagrangeMult == 1) + { + get_mem2Dodouble(&(p_Vid->lambda_mf_factor_buf[0]), 10, 52 + p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_mf_factor = p_Vid->lambda_mf_factor_buf[0]; + } + if(p_Vid->num_of_layers>1) + { + p_Vid->lambda_buf[1] = p_Vid->lambda_buf[0]; + p_Vid->lambda_md_buf[1] = p_Vid->lambda_md_buf[0]; + p_Vid->lambda_me_buf[1] = p_Vid->lambda_me_buf[0]; + p_Vid->lambda_mf_buf[1] = p_Vid->lambda_mf_buf[0]; + p_Vid->lambda_rdoq_buf[1] = p_Vid->lambda_rdoq_buf[0]; + p_Vid->lambda_mf_factor_buf[1] = p_Vid->lambda_mf_factor_buf[0]; + } + + p_Vid->mb_y_upd = 0; + + if(((p_Inp->RDPictureDecision) && p_Inp->GenerateMultiplePPS) || (p_Inp->WeightedPrediction || p_Inp->WeightedBiprediction)) + { + int num_slices; + + if(p_Inp->slice_mode == 1) + { + num_slices = p_Vid->FrameSizeInMbs/p_Inp->slice_argument; + if((unsigned int)(num_slices * p_Inp->slice_argument) < p_Vid->FrameSizeInMbs) + num_slices++; + } + else + num_slices = 1; + + // All weight structures assigned using "MAX_REFERENCE_PICTURES". This plays it safe since one may + // consider reordering or use this for MVC/FCFR coding where references are expanded by 1. + p_Vid->num_slices_wp = num_slices; + get_mem4Dshort(&(p_Vid->wp_weights), 3, 2, MAX_REFERENCE_PICTURES, num_slices); + get_mem4Dshort(&(p_Vid->wp_offsets), 3, 2, MAX_REFERENCE_PICTURES, num_slices); + get_mem5Dshort(&(p_Vid->wbp_weight), 3, 2, MAX_REFERENCE_PICTURES, MAX_REFERENCE_PICTURES, num_slices); + } + else + { + p_Vid->num_slices_wp = 0; + p_Vid->wp_weights = NULL; + p_Vid->wp_offsets = NULL; + p_Vid->wbp_weight = NULL; + } + + RandomIntraInit (p_Vid, p_Vid->PicWidthInMbs, p_Vid->FrameHeightInMbs, p_Inp->RandomIntraMBRefresh); + + InitSEIMessages(p_Vid, p_Inp); + + initInput(p_Vid, &p_Inp->source, &p_Inp->output); + + // Allocate I/O Frame memory + AllocateFrameMemory(p_Vid, p_Inp, &p_Inp->source); + + // Initialize filtering parameters. If sending parameters, the offsets are + // multiplied by 2 since inputs are taken in "div 2" format. + // If not sending parameters, all fields are cleared + if (p_Inp->DFSendParameters) + { + for (j = 0; j < 2; j++) + { + for (i = 0; i < NUM_SLICE_TYPES; i++) + { + p_Inp->DFAlpha[j][i] <<= 1; + p_Inp->DFBeta [j][i] <<= 1; +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->num_of_layers == 2) + { + p_Inp->EnhLayerDFAlpha[j][i] <<= 1; + p_Inp->EnhLayerDFBeta [j][i] <<= 1; + } +#endif + } + } + } + else + { + for (j = 0; j < 2; j++) + { + for (i = 0; i < NUM_SLICE_TYPES; i++) + { + p_Inp->DFDisableIdc[j][i] = 0; + p_Inp->DFAlpha [j][i] = 0; + p_Inp->DFBeta [j][i] = 0; +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->num_of_layers == 2) + { + p_Inp->EnhLayerDFDisableIdc[j][i] = 0; + p_Inp->EnhLayerDFAlpha[j][i] = 0; + p_Inp->EnhLayerDFBeta [j][i] = 0; + } +#endif + } + } + } + + p_Vid->ChromaArrayType = p_Inp->separate_colour_plane_flag ? 0 : p_Inp->output.yuv_format; + p_Vid->colour_plane_id = 0; + + if (p_Inp->RDPictureDecision) + p_Vid->frm_iter = 3; + else + p_Vid->frm_iter = 1; + + p_Vid->max_frame_num = 1 << (p_Vid->log2_max_frame_num_minus4 + 4); + p_Vid->max_pic_order_cnt_lsb = 1 << (p_Vid->log2_max_pic_order_cnt_lsb_minus4 + 4); + + p_Vid->prev_frame_no = 0; // POC200301 + p_Vid->consecutive_non_reference_pictures = 0; // POC200301 + + p_Vid->fld_type = 0; + + p_Vid->p_Inp = p_Inp; + + create_context_memory (p_Vid, p_Inp); + +} + + +/*! +*********************************************************************** +* \brief +* Free the Image structures +* \par Input: +* Image Parameters VideoParameters *p_Vid +*********************************************************************** +*/ +static void free_img (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + // Delete Frame memory + DeleteFrameMemory(p_Vid); + + CloseSEIMessages(p_Vid, p_Inp); + + free_context_memory (p_Vid); + + if (p_Inp->AdaptiveRounding) + { + free_mem4Dint(p_Vid->ARCofAdj4x4); + free_mem4Dint(p_Vid->ARCofAdj8x8); + } + + if (p_Vid->wp_weights) + free_mem4Dshort(p_Vid->wp_weights); + if (p_Vid->wp_offsets) + free_mem4Dshort(p_Vid->wp_offsets); + if (p_Vid->wbp_weight) + free_mem5Dshort(p_Vid->wbp_weight); + + + free_pointer (p_Vid->p_SEI); + free_pointer (p_Vid->p_QScale); + free_pointer (p_Vid->p_Quant); + free_pointer(p_Vid->p_Dpb_layer[0]); + p_Vid->p_Dpb_layer[0] = p_Vid->p_Dpb_layer[1] = NULL; + free_pointer (p_Vid->p_Stats); + free_pointer (p_Vid->p_Dist); + // + free_encode_parameters(p_Vid); + free_pointer (p_Vid); +} + + +/*! +*********************************************************************** +* \brief +* Free the Input structures +* \par Input: +* Input Parameters InputParameters *p_Inp +*********************************************************************** +*/ +static void free_params (InputParameters *p_Inp) +{ + if ( p_Inp != NULL ) + { + free_pointer( p_Inp->top_left ); + free_pointer( p_Inp->bottom_right ); + free_pointer( p_Inp->slice_group_id ); + free_pointer( p_Inp->run_length_minus1 ); + free_pointer( p_Inp ); + } +} + + +/*! +************************************************************************ +* \brief +* Allocates the picture structure along with its dependent +* data structures +* \return +* Pointer to a Picture +************************************************************************ +*/ +Picture *malloc_picture() +{ + Picture *pic; + if ((pic = calloc (1, sizeof (Picture))) == NULL) no_mem_exit ("malloc_picture: Picture structure"); + //! Note: slice structures are allocated as needed in code_a_picture + return pic; +} + +/*! +************************************************************************ +* \brief +* Frees a picture +* \param +* pic: POinter to a Picture to be freed +************************************************************************ +*/ +void free_picture(Picture *pic) +{ + if (pic != NULL) + { + free_slice_list(pic); + free_pointer (pic); + } +} + + +/*! +************************************************************************ +* \brief +* memory allocation for original picture buffers +************************************************************************ +*/ +int init_orig_buffers(VideoParameters *p_Vid, ImageData *imgData) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int memory_size = 0; + int nplane; + + // allocate memory for reference frame buffers: imgData->frm_data + imgData->format = p_Inp->output; + imgData->format.width[0] = p_Vid->width; + imgData->format.width[1] = p_Vid->width_cr; + imgData->format.width[2] = p_Vid->width_cr; + imgData->format.height[0] = p_Vid->height; + imgData->format.height[1] = p_Vid->height_cr; + imgData->format.height[2] = p_Vid->height_cr; + imgData->format.yuv_format = p_Vid->yuv_format; + imgData->format.auto_crop_bottom = p_Vid->auto_crop_bottom; + imgData->format.auto_crop_right = p_Vid->auto_crop_right; + imgData->format.auto_crop_bottom_cr = (p_Vid->auto_crop_bottom * mb_height_cr [p_Vid->yuv_format]) / MB_BLOCK_SIZE; + imgData->format.auto_crop_right_cr = (p_Vid->auto_crop_right * mb_width_cr [p_Vid->yuv_format]) / MB_BLOCK_SIZE; + imgData->frm_stride[0] = p_Vid->width; + imgData->frm_stride[1] = imgData->frm_stride[2] = p_Vid->width_cr; + imgData->top_stride[0] = imgData->bot_stride[0] = imgData->frm_stride[0] << 1; + imgData->top_stride[1] = imgData->top_stride[2] = imgData->bot_stride[1] = imgData->bot_stride[2] = imgData->frm_stride[1] << 1; + + imgData->frm_data_buf[0][0] = imgData->frm_data_buf[0][1] = imgData->frm_data_buf[0][2] = NULL; + imgData->frm_data_buf[1][0] = imgData->frm_data_buf[1][1] = imgData->frm_data_buf[1][2] = NULL; + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplanefrm_data[nplane]), p_Vid->height, p_Vid->width); + } + } + else + { + //imgData->format = p_Inp->input_file1.format; + memory_size += get_mem2Dpel(&(imgData->frm_data[0]), p_Vid->height, p_Vid->width); + + if (p_Vid->yuv_format != YUV400) + { + int i, j, k; + memory_size += get_mem2Dpel(&(imgData->frm_data[1]), p_Vid->height_cr, p_Vid->width_cr); + memory_size += get_mem2Dpel(&(imgData->frm_data[2]), p_Vid->height_cr, p_Vid->width_cr); + + if (sizeof(imgpel) == sizeof(unsigned char)) + { + for (k = 1; k < 3; k++) + memset(&(imgData->frm_data[k][0][0]), 128, p_Vid->height_cr * p_Vid->width_cr * sizeof(imgpel)); + } + else + { + for (k = 1; k < 3; k++) + for (j = 0; j < p_Vid->height_cr; j++) + for (i = 0; i < p_Vid->width_cr; i++) + imgData->frm_data[k][j][i] = 128; + } + } + } + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + // allocate memory for field reference frame buffers + memory_size += init_top_bot_planes(imgData->frm_data[0], p_Vid->height, &(imgData->top_data[0]), &(imgData->bot_data[0])); + + if (p_Vid->yuv_format != YUV400) + { + memory_size += 4*(sizeof(imgpel**)); + + memory_size += init_top_bot_planes(imgData->frm_data[1], p_Vid->height_cr, &(imgData->top_data[1]), &(imgData->bot_data[1])); + memory_size += init_top_bot_planes(imgData->frm_data[2], p_Vid->height_cr, &(imgData->top_data[2]), &(imgData->bot_data[2])); + } + } + return memory_size; +} + +/*! +************************************************************************ +* \brief +* Dynamic memory allocation of frame size related global buffers +* buffers are defined in global.h, allocated memory must be freed in +* void free_global_buffers() +* \par Input: +* Input Parameters InputParameters *inp, \n +* Image Parameters VideoParameters *p_Vid +* \return Number of allocated bytes +************************************************************************ +*/ +static int init_global_buffers(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int j, memory_size=0; + + if ((p_Vid->enc_frame_picture = (StorablePicture**)malloc(6 * sizeof(StorablePicture*))) == NULL) + no_mem_exit("init_global_buffers: *p_Vid->enc_frame_picture"); + + for (j = 0; j < 6; j++) + p_Vid->enc_frame_picture[j] = NULL; + + if ((p_Vid->enc_field_picture = (StorablePicture**)malloc(2 * sizeof(StorablePicture*))) == NULL) + no_mem_exit("init_global_buffers: *p_Vid->enc_field_picture"); + + for (j = 0; j < 2; j++) + p_Vid->enc_field_picture[j] = NULL; + + if ((p_Vid->frame_pic = (Picture**)malloc(p_Vid->frm_iter * sizeof(Picture*))) == NULL) + no_mem_exit("init_global_buffers: *p_Vid->frame_pic"); + + for (j = 0; j < p_Vid->frm_iter; j++) + p_Vid->frame_pic[j] = malloc_picture(); + + if (p_Inp->si_frame_indicator || p_Inp->sp_periodicity) + { + p_Vid->number_sp2_frames=0; + p_Vid->frame_pic_si = malloc_picture();//picture buffer for the encoded SI picture + //allocation of lrec and p_Vid->lrec_uv for SI picture + get_mem2Dint (&p_Vid->lrec, p_Vid->height, p_Vid->width); + get_mem3Dint (&p_Vid->lrec_uv, 2, p_Vid->height, p_Vid->width); + } + +#if (MVC_EXTENSION_ENABLE) + p_Vid->field_pic_ptr = NULL; + p_Vid->field_pic1 = NULL; + p_Vid->field_pic2 = NULL; + + // Allocate memory for field picture coding + if (p_Inp->PicInterlace != FRAME_CODING) + { + if ((p_Vid->field_pic1 = (Picture**)malloc(2 * sizeof(Picture*))) == NULL) + no_mem_exit("init_global_buffers: *p_Vid->field_pic1"); + + for (j = 0; j < 2; j++) + p_Vid->field_pic1[j] = malloc_picture(); + + if(p_Vid->num_of_layers==2) + { + if ((p_Vid->field_pic2 = (Picture**)malloc(2 * sizeof(Picture*))) == NULL) + no_mem_exit("init_global_buffers: *p_Vid->field_pic2"); + + for (j = 0; j < 2; j++) + p_Vid->field_pic2[j] = malloc_picture(); + } + } +#else + // Allocate memory for field picture coding + if (p_Inp->PicInterlace != FRAME_CODING) + { + if ((p_Vid->field_pic = (Picture**)malloc(2 * sizeof(Picture*))) == NULL) + no_mem_exit("init_global_buffers: *p_Vid->field_pic"); + + for (j = 0; j < 2; j++) + p_Vid->field_pic[j] = malloc_picture(); + } +#endif + + // Init memory data for input & encoded images + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgData); + + if ( p_Inp->MDReference[0] || p_Inp->MDReference[1] ) + { + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgRefData); + } + + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgData0); + + if (p_Inp->enable_32_pulldown) + { + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgData32); + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgData4); + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgData5); + memory_size += init_orig_buffers(p_Vid, &p_Vid->imgData6); + } + + + //memory_size += get_mem2Dshort(&PicPos, p_Vid->FrameSizeInMbs + 1, 2); + p_Vid->PicPos = calloc(p_Vid->FrameSizeInMbs + 1, sizeof(BlockPos)); + + for (j = 0; j < (int) p_Vid->FrameSizeInMbs + 1; j++) + { + p_Vid->PicPos[j].x = (short) (j % p_Vid->PicWidthInMbs); + p_Vid->PicPos[j].y = (short) (j / p_Vid->PicWidthInMbs); + } + + + if (p_Inp->rdopt == 3) + { + memory_size += allocate_errdo_mem(p_Vid, p_Inp); + } + + if (p_Inp->RestrictRef) + { + memory_size += get_mem2D(&p_Vid->pixel_map, p_Vid->height, p_Vid->width); + memory_size += get_mem2D(&p_Vid->refresh_map, p_Vid->height >> 3, p_Vid->width >> 3); + } + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + for(j=0; jnum_of_layers; j++) + { + CodingParameters *cps = p_Vid->p_EncodePar[j]; + memory_size += get_mem2Dpel(&(p_Vid->imgY_com_buf[j]), cps->height, cps->width); + if (cps->yuv_format != YUV400) + { + memory_size += get_mem2Dpel(&(p_Vid->imgUV_com_buf[j][0]), cps->height_cr, cps->width_cr); + memory_size += get_mem2Dpel(&(p_Vid->imgUV_com_buf[j][1]), cps->height_cr, cps->width_cr); + } + } + //set; + p_Vid->imgY_com = p_Vid->imgY_com_buf[0]; + p_Vid->imgUV_com[0] = p_Vid->imgUV_com_buf[0][0]; + p_Vid->imgUV_com[1] = p_Vid->imgUV_com_buf[0][1]; + } + + // allocate and set memory relating to motion estimation + if (!p_Inp->IntraProfile) + { + if (p_Inp->SearchMode[0] == UM_HEX || p_Inp->SearchMode[1] == UM_HEX) + { + if ((p_Vid->p_UMHex = (UMHexStruct*)calloc(1, sizeof(UMHexStruct))) == NULL) + no_mem_exit("init_mv_block: p_Vid->p_UMHex"); + memory_size += UMHEX_get_mem(p_Vid, p_Inp); + } + if (p_Inp->SearchMode[0] == UM_HEX_SIMPLE || p_Inp->SearchMode[1] == UM_HEX_SIMPLE) + { + if ((p_Vid->p_UMHexSMP = (UMHexSMPStruct*)calloc(1, sizeof(UMHexSMPStruct))) == NULL) + no_mem_exit("init_mv_block: p_Vid->p_UMHexSMP"); + + smpUMHEX_init(p_Vid); + memory_size += smpUMHEX_get_mem(p_Vid); + } + if (p_Inp->SearchMode[0] == EPZS || p_Inp->SearchMode[1] == EPZS) + { + memory_size += EPZSInit(p_Vid); + } + } + + if (p_Inp->RCEnable) + rc_allocate_memory(p_Vid, p_Inp); + + if (p_Inp->redundant_pic_flag) + { + for(j=0; jnum_of_layers; j++) + { + CodingParameters *cps = p_Vid->p_EncodePar[j]; + memory_size += get_mem2Dpel(&p_Vid->imgY_tmp_buf[j], cps->height, cps->width); + memory_size += get_mem2Dpel(&p_Vid->imgUV_tmp_buf[j][0], cps->height_cr, cps->width_cr); + memory_size += get_mem2Dpel(&p_Vid->imgUV_tmp_buf[j][1], cps->height_cr, cps->width_cr); + } + p_Vid->imgY_tmp = p_Vid->imgY_tmp_buf[0]; + p_Vid->imgUV_tmp[0] = p_Vid->imgUV_tmp_buf[0][0]; + p_Vid->imgUV_tmp[1] = p_Vid->imgUV_tmp_buf[0][1]; + } + + if( !(p_Inp->OnTheFlyFractMCP) || (p_Inp->OnTheFlyFractMCP==OTF_L1) ) // JLT : on-the-fly compatibility + { + memory_size += get_mem2Dint_pad (&p_Vid->imgY_sub_tmp, p_Vid->height, p_Vid->width, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + } + + //if ( p_Inp->ChromaMCBuffer ) + chroma_mc_setup(p_Vid); + + p_Vid->padded_size_x = (p_Vid->width + 2 * IMG_PAD_SIZE_X); + p_Vid->padded_size_x_m8x8 = (p_Vid->padded_size_x - BLOCK_SIZE_8x8); + p_Vid->padded_size_x_m4x4 = (p_Vid->padded_size_x - BLOCK_SIZE); + p_Vid->cr_padded_size_x = (p_Vid->width_cr + 2 * p_Vid->pad_size_uv_x); + p_Vid->cr_padded_size_x2 = (p_Vid->cr_padded_size_x << 1); + p_Vid->cr_padded_size_x4 = (p_Vid->cr_padded_size_x << 2); + p_Vid->cr_padded_size_x_m8 = (p_Vid->cr_padded_size_x - 8); + + // RGB images for distortion calculation + // Recommended to do this allocation (and de-allocation) in + // the appropriate file instead of here. + if(p_Inp->DistortionYUVtoRGB) + { + memory_size += create_RGB_memory(p_Vid); + } + + p_Vid->pWPX = NULL; + if ( p_Inp->WPMCPrecision ) + { + wpxInitWPXObject(p_Vid); + } + + memory_size += init_process_image( p_Vid, p_Inp ); + + p_Vid->p_pred = init_seq_structure( p_Vid, p_Inp, &memory_size ); + + return memory_size; +} + +/*! +************************************************************************ +* \brief +* Free allocated memory of original picture buffers +************************************************************************ +*/ +void free_orig_planes(VideoParameters *p_Vid, ImageData *imgData) +{ + if( (p_Vid->p_Inp->separate_colour_plane_flag != 0) ) + { + int nplane; + for( nplane=0; nplanefrm_data[nplane]); + imgData->frm_data[nplane] = NULL; + } + } + else + { + free_mem2Dpel(imgData->frm_data[0]); // free ref frame buffers + imgData->frm_data[0] = NULL; + if (imgData->format.yuv_format != YUV400) + { + free_mem2Dpel(imgData->frm_data[1]); + imgData->frm_data[1] = NULL; + free_mem2Dpel(imgData->frm_data[2]); + imgData->frm_data[2] = NULL; + } + } + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + free_top_bot_planes(imgData->top_data[0], imgData->bot_data[0]); + if (imgData->format.yuv_format != YUV400) + { + free_top_bot_planes(imgData->top_data[1], imgData->bot_data[1]); + free_top_bot_planes(imgData->top_data[2], imgData->bot_data[2]); + } + imgData->top_data[0] = imgData->bot_data[0] = NULL; + imgData->top_data[1] = imgData->bot_data[1] = NULL; + imgData->top_data[2] = imgData->bot_data[2] = NULL; + } +} + + +/*! +************************************************************************ +* \brief +* Free allocated memory of frame size related global buffers +* buffers are defined in global.h, allocated memory is allocated in +* int get_mem4global_buffers() +* \par Input: +* Input Parameters InputParameters *inp, \n +* Image Parameters VideoParameters *p_Vid +* \par Output: +* none +************************************************************************ +*/ +static void free_global_buffers(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i,j; + + free_pointer (p_Vid->enc_frame_picture); + + if (p_Vid->frame_pic) + { + for (j = 0; j < p_Vid->frm_iter; j++) + { + if (p_Vid->frame_pic[j]) + free_picture (p_Vid->frame_pic[j]); + } + free_pointer (p_Vid->frame_pic); + } + + free_pointer (p_Vid->enc_field_picture); + +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->field_pic1) + { + for (j = 0; j < 2; j++) + { + if (p_Vid->field_pic1[j]) + free_picture (p_Vid->field_pic1[j]); + } + free_pointer (p_Vid->field_pic1); + + if(p_Vid->num_of_layers==2) + { + for (j = 0; j < 2; j++) + { + if (p_Vid->field_pic2[j]) + free_picture (p_Vid->field_pic2[j]); + } + free_pointer (p_Vid->field_pic2); + } + } +#else + if (p_Vid->field_pic) + { + for (j = 0; j < 2; j++) + { + if (p_Vid->field_pic[j]) + free_picture (p_Vid->field_pic[j]); + } + free_pointer (p_Vid->field_pic); + } +#endif + + // Deallocation of SI picture related memory + if (p_Inp->si_frame_indicator || p_Inp->sp_periodicity) + { + free_picture (p_Vid->frame_pic_si); + //deallocation of lrec and p_Vid->lrec_uv for SI frames + free_mem2Dint (p_Vid->lrec); + free_mem3Dint (p_Vid->lrec_uv); + } + + free_orig_planes(p_Vid, &p_Vid->imgData); + if ( p_Vid->p_Inp->MDReference[0] || p_Vid->p_Inp->MDReference[1] ) + { + free_orig_planes(p_Vid, &p_Vid->imgRefData); + } + + free_orig_planes(p_Vid, &p_Vid->imgData0); + + if (p_Inp->enable_32_pulldown) + { + free_orig_planes(p_Vid, &p_Vid->imgData32); + free_orig_planes(p_Vid, &p_Vid->imgData4); + free_orig_planes(p_Vid, &p_Vid->imgData5); + free_orig_planes(p_Vid, &p_Vid->imgData6); + } + + // free lookup memory which helps avoid divides with PicWidthInMbs + //free_mem2Dshort(PicPos); + free_pointer(p_Vid->PicPos); + // Free Qmatrices and offsets + free_QMatrix(p_Vid->p_Quant); + free_QOffsets(p_Vid->p_Quant, p_Inp); + + + if ( p_Inp->WPMCPrecision ) + { + wpxFreeWPXObject(p_Vid); + } + + if (p_Vid->imgY_sub_tmp) // free temp quarter pel frame buffers + { + free_mem2Dint_pad (p_Vid->imgY_sub_tmp, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + p_Vid->imgY_sub_tmp = NULL; + } + + // free mem, allocated in init_img() + // free intra pred mode buffer for blocks + free_mem2D((byte**)p_Vid->ipredmode); + free_mem2D((byte**)p_Vid->ipredmode8x8); + + if(p_Vid->ipredmode4x4_line) + { + free_mem2D((byte**)p_Vid->ipredmode4x4_line); + p_Vid->ipredmode4x4_line=NULL; + } + if(p_Vid->ipredmode8x8_line) + { + free_mem2D((byte **)p_Vid->ipredmode8x8_line); + p_Vid->ipredmode8x8_line = NULL; + } + + free_pointer( p_Vid->b8x8info ); + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( i=0; imb_data_JV[i], p_Vid->FrameSizeInMbs); + } + } + else + { + //free_pointer(p_Vid->mb_data); + free_mbs(p_Vid->mb_data, p_Vid->FrameSizeInMbs); + } + + if(p_Inp->UseConstrainedIntraPred) + { + free_pointer (p_Vid->intra_block); + } + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + free_pointer(p_Vid->mb16x16_cost_frame); + } + + if (p_Inp->rdopt == 3) + { + free_errdo_mem(p_Vid); + } + + if (p_Inp->RestrictRef) + { + free_pointer(p_Vid->pixel_map[0]); + free_pointer(p_Vid->pixel_map); + free_pointer(p_Vid->refresh_map[0]); + free_pointer(p_Vid->refresh_map); + } + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + for(i=0; inum_of_layers; i++) + { + free_mem2Dpel(p_Vid->imgY_com_buf[i]); + free_mem2Dpel(p_Vid->imgUV_com_buf[i][0]); + free_mem2Dpel(p_Vid->imgUV_com_buf[i][1]); + } + p_Vid->imgY_com = NULL; + p_Vid->imgUV_com[0] = p_Vid->imgUV_com[1] = NULL; + } + + if(p_Vid->num_of_layers>1) + { + int bEqual = p_Vid->nz_coeff_buf[0] == p_Vid->nz_coeff_buf[1]; + free_mem3Dint(p_Vid->nz_coeff_buf[0]); + p_Vid->nz_coeff_buf[0] = NULL; + if(!bEqual && p_Vid->nz_coeff_buf[1]) + free_mem3Dint(p_Vid->nz_coeff_buf[1]); + p_Vid->nz_coeff_buf[1] = NULL; + } + else + free_mem3Dint(p_Vid->nz_coeff_buf[0]); + p_Vid->nz_coeff = NULL; + + free_mem2Dolm (p_Vid->lambda_buf[0], p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda = p_Vid->lambda_buf[0] = p_Vid->lambda_buf[1] = NULL; + free_mem2Dodouble (p_Vid->lambda_md_buf[0], p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_md = p_Vid->lambda_md_buf[0] = p_Vid->lambda_md_buf[1] = NULL; + free_mem3Dodouble (p_Vid->lambda_me_buf[0], 10, 52 + p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_me = p_Vid->lambda_me_buf[0] = p_Vid->lambda_me_buf[1] = NULL; + free_mem3Doint (p_Vid->lambda_mf_buf[0], 10, 52 + p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_mf = p_Vid->lambda_mf_buf[0] = p_Vid->lambda_mf_buf[1] = NULL; + if ( p_Inp->UseRDOQuant ) + { + free_mem2Dodouble (p_Vid->lambda_rdoq_buf[0], p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_rdoq = p_Vid->lambda_rdoq_buf[0] = p_Vid->lambda_rdoq_buf[1] = NULL; + } + if (p_Inp->CtxAdptLagrangeMult == 1) + { + free_mem2Dodouble(p_Vid->lambda_mf_factor_buf[0], p_Vid->bitdepth_luma_qp_scale); + p_Vid->lambda_mf_factor = p_Vid->lambda_mf_factor_buf[0] = p_Vid->lambda_mf_factor_buf[1] = NULL; + } + + if (!p_Inp->IntraProfile) + { + if (p_Inp->SearchMode[0] == UM_HEX || p_Inp->SearchMode[1] == UM_HEX) + { + UMHEX_free_mem(p_Vid, p_Inp); + } + if (p_Inp->SearchMode[0] == UM_HEX_SIMPLE || p_Inp->SearchMode[1] == UM_HEX_SIMPLE) + { + smpUMHEX_free_mem(p_Vid); + } + if (p_Inp->SearchMode[0] == EPZS || p_Inp->SearchMode[1] == EPZS) + { + EPZSDelete(p_Vid); + } + } + + if (p_Inp->RCEnable) + rc_free_memory(p_Vid, p_Inp); + + if (p_Inp->redundant_pic_flag) + { + for(i=0; inum_of_layers; i++) + { + free_mem2Dpel(p_Vid->imgY_tmp_buf[i]); + free_mem2Dpel(p_Vid->imgUV_tmp_buf[i][0]); + free_mem2Dpel(p_Vid->imgUV_tmp_buf[i][1]); + } + p_Vid->imgY_tmp = NULL; + p_Vid->imgUV_tmp[0] = NULL; + p_Vid->imgUV_tmp[1] = NULL; + } + + // Again process should be moved into cconv_yuv2rgb.c file for cleanliness + // These should not be globals but instead only be visible through that code. + if(p_Inp->DistortionYUVtoRGB) + { + delete_RGB_memory(p_Vid); + } + + clear_process_image( p_Vid, p_Inp ); + free_seq_structure( p_Vid->p_pred ); +} + + +/*! +************************************************************************ +* \brief +* Allocate memory for AC coefficients +************************************************************************ +*/ +int get_mem_ACcoeff (VideoParameters *p_Vid, int***** cofAC) +{ + int num_blk8x8 = BLOCK_SIZE + p_Vid->num_blk8x8_uv; + + get_mem4Dint(cofAC, num_blk8x8, BLOCK_SIZE, 2, 65); + + return num_blk8x8 * BLOCK_SIZE * 2 * 65 * sizeof(int);// 18->65 for ABT +} + +/*! +************************************************************************ +* \brief +* Allocate memory for AC coefficients +************************************************************************ +*/ +int get_mem_ACcoeff_new (int****** cofAC, int chroma) +{ + get_mem5Dint(cofAC, BLOCK_SIZE, chroma, BLOCK_SIZE, 2, 65); + return chroma * BLOCK_PIXELS * 2 * 65 * sizeof(int);// 18->65 for ABT +} + +/*! +************************************************************************ +* \brief +* Allocate memory for DC coefficients +************************************************************************ +*/ +int get_mem_DCcoeff (int**** cofDC) +{ + get_mem3Dint(cofDC, 3, 2, 18); + return 3 * 2 * 18 * sizeof(int); +} + + +/*! +************************************************************************ +* \brief +* Free memory of AC coefficients +************************************************************************ +*/ +void free_mem_ACcoeff (int**** cofAC) +{ + free_mem4Dint(cofAC); +} + +/*! +************************************************************************ +* \brief +* Free memory of AC coefficients +************************************************************************ +*/ +void free_mem_ACcoeff_new (int***** cofAC) +{ + free_mem5Dint(cofAC); +} + +/*! +************************************************************************ +* \brief +* Free memory of DC coefficients +************************************************************************ +*/ +void free_mem_DCcoeff (int*** cofDC) +{ + free_mem3Dint(cofDC); +} + +/*! +************************************************************************ +* \brief +* Sets indices to appropriate level constraints, depending on +* current level_idc +************************************************************************ +*/ +static void set_level_indices(VideoParameters *p_Vid) +{ + switch(p_Vid->active_sps->level_idc) + { + case 9: + p_Vid->LevelIndex=1; + break; + case 10: + p_Vid->LevelIndex=0; + break; + case 11: + if (!is_FREXT_profile(p_Vid->active_sps->profile_idc) && (p_Vid->active_sps->constrained_set3_flag == 0)) + p_Vid->LevelIndex=2; + else + p_Vid->LevelIndex=1; + break; + case 12: + p_Vid->LevelIndex=3; + break; + case 13: + p_Vid->LevelIndex=4; + break; + case 20: + p_Vid->LevelIndex=5; + break; + case 21: + p_Vid->LevelIndex=6; + break; + case 22: + p_Vid->LevelIndex=7; + break; + case 30: + p_Vid->LevelIndex=8; + break; + case 31: + p_Vid->LevelIndex=9; + break; + case 32: + p_Vid->LevelIndex=10; + break; + case 40: + p_Vid->LevelIndex=11; + break; + case 41: + p_Vid->LevelIndex=12; + break; + case 42: + if (!is_FREXT_profile(p_Vid->active_sps->profile_idc)) + p_Vid->LevelIndex=13; + else + p_Vid->LevelIndex=14; + break; + case 50: + p_Vid->LevelIndex=15; + break; + case 51: + p_Vid->LevelIndex=16; + break; + default: + fprintf ( stdout, "Warning: unknown LevelIDC, using maximum level 5.1 \n" ); + p_Vid->LevelIndex=16; + break; + } +} + +/*! +************************************************************************ +* \brief +* initialize key frames and corresponding redundant frames. +************************************************************************ +*/ +void init_redundant_frame(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + if (p_Inp->redundant_pic_flag) + { + if (p_Inp->NumberBFrames) + { + error("B frame not supported when redundant picture used!", 100); + } + + if (p_Inp->PicInterlace) + { + error("Interlace not supported when redundant picture used!", 100); + } + + if (p_Inp->num_ref_frames < p_Inp->PrimaryGOPLength) + { + error("NumberReferenceFrames must be no less than PrimaryGOPLength", 100); + } + + if ((1<NumRedundantHierarchy) > p_Inp->PrimaryGOPLength) + { + error("PrimaryGOPLength must be greater than 2^NumRedundantHeirarchy", 100); + } + + if (p_Inp->Verbose != 1) + { + error("Redundant slices not supported when Verbose != 1", 100); + } + } + + p_Vid->key_frame = 0; + p_Vid->redundant_coding = 0; + p_Vid->redundant_pic_cnt = 0; + p_Vid->frameNuminGOP = p_Vid->curr_frm_idx % p_Inp->PrimaryGOPLength; + if (p_Vid->curr_frm_idx == 0) + { + p_Vid->frameNuminGOP = -1; + } +} + +/*! +************************************************************************ +* \brief +* allocate redundant frames in a primary GOP. +************************************************************************ +*/ +void set_redundant_frame(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int GOPlength = p_Inp->PrimaryGOPLength; + + //start frame of GOP + if (p_Vid->frameNuminGOP == 0) + { + p_Vid->redundant_coding = 0; + p_Vid->key_frame = 1; + p_Vid->redundant_ref_idx = GOPlength; + } + + //1/2 position + if (p_Inp->NumRedundantHierarchy > 0) + { + if (p_Vid->frameNuminGOP == GOPlength >> 1) + { + p_Vid->redundant_coding = 0; + p_Vid->key_frame = 1; + p_Vid->redundant_ref_idx = GOPlength >> 1; + } + } + + //1/4, 3/4 position + if (p_Inp->NumRedundantHierarchy > 1) + { + if (p_Vid->frameNuminGOP == (GOPlength >> 2) || p_Vid->frameNuminGOP == ((GOPlength*3) >> 2)) + { + p_Vid->redundant_coding = 0; + p_Vid->key_frame = 1; + p_Vid->redundant_ref_idx = GOPlength >> 2; + } + } + + //1/8, 3/8, 5/8, 7/8 position + if (p_Inp->NumRedundantHierarchy > 2) + { + if (p_Vid->frameNuminGOP == GOPlength >> 3 || p_Vid->frameNuminGOP == ((GOPlength*3) >> 3) + || p_Vid->frameNuminGOP == ((GOPlength*5) >> 3) || p_Vid->frameNuminGOP == ((GOPlength*7) & 0x03)) + { + p_Vid->redundant_coding = 0; + p_Vid->key_frame = 1; + p_Vid->redundant_ref_idx = GOPlength >> 3; + } + } + + //1/16, 3/16, 5/16, 7/16, 9/16, 11/16, 13/16 position + if (p_Inp->NumRedundantHierarchy > 3) + { + if (p_Vid->frameNuminGOP == (GOPlength >> 4) || p_Vid->frameNuminGOP == ((GOPlength*3) >> 4) + || p_Vid->frameNuminGOP == ((GOPlength*5) >> 4) || p_Vid->frameNuminGOP == ((GOPlength*7) >> 4) + || p_Vid->frameNuminGOP == ((GOPlength*9) >> 4) || p_Vid->frameNuminGOP == ((GOPlength*11) >> 4) + || p_Vid->frameNuminGOP == ((GOPlength*13) >> 4)) + { + p_Vid->redundant_coding = 0; + p_Vid->key_frame = 1; + p_Vid->redundant_ref_idx = GOPlength >> 4; + } + } +} + +/*! +************************************************************************ +* \brief +* encode one redundant frame. +************************************************************************ +*/ +void encode_one_redundant_frame(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + p_Vid->key_frame = 0; + p_Vid->redundant_coding = 1; + p_Vid->redundant_pic_cnt = 1; + + if (!p_Vid->currentPicture->idr_flag) + { + if (p_Vid->type == I_SLICE) + { + set_slice_type( p_Vid, p_Inp, P_SLICE ); + } + } + + encode_one_frame(p_Vid, p_Inp); +} + +/*! +************************************************************************ +* \brief +* Setup Chroma MC Variables +************************************************************************ +*/ +static void chroma_mc_setup(VideoParameters *p_Vid) +{ + // initialize global variables used for chroma interpolation and buffering + if ( p_Vid->yuv_format == YUV420 ) + { + p_Vid->pad_size_uv_x = IMG_PAD_SIZE_X >> 1; + p_Vid->pad_size_uv_y = IMG_PAD_SIZE_Y >> 1; + p_Vid->chroma_mask_mv_y = 7; + p_Vid->chroma_mask_mv_x = 7; + p_Vid->chroma_shift_x = 3; + p_Vid->chroma_shift_y = 3; + } + else if ( p_Vid->yuv_format == YUV422 ) + { + p_Vid->pad_size_uv_x = IMG_PAD_SIZE_X >> 1; + p_Vid->pad_size_uv_y = IMG_PAD_SIZE_Y; + p_Vid->chroma_mask_mv_y = 3; + p_Vid->chroma_mask_mv_x = 7; + p_Vid->chroma_shift_y = 2; + p_Vid->chroma_shift_x = 3; + } + else + { // YUV444 + p_Vid->pad_size_uv_x = IMG_PAD_SIZE_X; + p_Vid->pad_size_uv_y = IMG_PAD_SIZE_Y; + p_Vid->chroma_mask_mv_y = 3; + p_Vid->chroma_mask_mv_x = 3; + p_Vid->chroma_shift_y = 2; + p_Vid->chroma_shift_x = 2; + } + p_Vid->shift_cr_y = p_Vid->chroma_shift_y - 2; + p_Vid->shift_cr_x = p_Vid->chroma_shift_x - 2; +} + + +static void gen_enc_par(VideoParameters *p_Vid, int layer_idx) +{ + CodingParameters *cps; + DecodedPictureBuffer *p_Dpb; + InputParameters *p_Inp = p_Vid->p_Inp; + + cps = p_Vid->p_EncodePar[layer_idx]; + p_Dpb = p_Vid->p_Dpb_layer[layer_idx]; + + cps->layer_id = layer_idx; + cps->yuv_format = p_Dpb->storage_format.yuv_format; + cps->P444_joined = (cps->yuv_format == YUV444 && (p_Inp->separate_colour_plane_flag == 0)); + cps->bitdepth_luma = (short)p_Dpb->storage_format.bit_depth[0]; + cps->bitdepth_scale[0] = 1 << (cps->bitdepth_luma - 8); + cps->bitdepth_lambda_scale = 2 * (cps->bitdepth_luma - 8); + cps->bitdepth_luma_qp_scale = 3 * cps->bitdepth_lambda_scale; + cps->dc_pred_value_comp[0] = (uint32) (1<<(cps->bitdepth_luma - 1)); + cps->max_pel_value_comp[0] = (1<bitdepth_luma) - 1; + cps->max_imgpel_value_comp_sq[0] = cps->max_pel_value_comp[0] * cps->max_pel_value_comp[0]; + cps->mb_size[0][0] = cps->mb_size[0][1] = MB_BLOCK_SIZE; + if (cps->yuv_format != YUV400) + { + cps->bitdepth_chroma = (short)p_Dpb->storage_format.bit_depth[1]; + cps->bitdepth_scale[1] = 1 << (cps->bitdepth_chroma - 8); + cps->dc_pred_value_comp[1] = (uint32) (1<<(cps->bitdepth_chroma - 1)); + cps->dc_pred_value_comp[2] = cps->dc_pred_value_comp[1]; + cps->max_pel_value_comp[1] = (1<bitdepth_chroma) - 1; + cps->max_pel_value_comp[2] = cps->max_pel_value_comp[1]; + cps->max_imgpel_value_comp_sq[1] = cps->max_pel_value_comp[1] * cps->max_pel_value_comp[1]; + cps->max_imgpel_value_comp_sq[2] = cps->max_pel_value_comp[2] * cps->max_pel_value_comp[2]; + cps->num_blk8x8_uv = (1<yuv_format)&(~(0x1)); + cps->num_cdc_coeff = cps->num_blk8x8_uv << 1; + cps->mb_size[1][0] = cps->mb_size[2][0] = cps->mb_cr_size_x = (cps->yuv_format == YUV420 || cps->yuv_format == YUV422) ? 8 : 16; + cps->mb_size[1][1] = cps->mb_size[2][1] = cps->mb_cr_size_y = (cps->yuv_format == YUV444 || cps->yuv_format == YUV422) ? 16 : 8; + cps->bitdepth_chroma_qp_scale = 6*(cps->bitdepth_chroma - 8); + } + else + { + cps->bitdepth_chroma = 0; + cps->bitdepth_scale[1] = 0; + cps->max_pel_value_comp[1] = 0; + cps->max_pel_value_comp[2] = cps->max_pel_value_comp[1]; + cps->max_imgpel_value_comp_sq[1] = cps->max_pel_value_comp[1] * cps->max_pel_value_comp[1]; + cps->max_imgpel_value_comp_sq[2] = cps->max_pel_value_comp[2] * cps->max_pel_value_comp[2]; + cps->num_blk8x8_uv = 0; + cps->num_cdc_coeff = 0; + cps->mb_size[1][0] = cps->mb_size[2][0] = cps->mb_cr_size_x = 0; + cps->mb_size[1][1] = cps->mb_size[2][1] = cps->mb_cr_size_y = 0; + + cps->bitdepth_chroma_qp_scale = 0; + } + cps->max_bitCount = 128 + 256 * cps->bitdepth_luma + 2 * cps->mb_cr_size_y * cps->mb_cr_size_x * cps->bitdepth_chroma; + cps->width = (p_Inp->output.width[0] + p_Vid->auto_crop_right); + cps->height = (p_Inp->output.height[0] + p_Vid->auto_crop_bottom); + cps->width_blk = cps->width / BLOCK_SIZE; + cps->height_blk = cps->height / BLOCK_SIZE; + cps->width_padded = cps->width + 2 * IMG_PAD_SIZE_X; + cps->height_padded = cps->height + 2 * IMG_PAD_SIZE_Y; + + if (cps->yuv_format != YUV400) + { + cps->width_cr = cps->width * mb_width_cr [cps->yuv_format] / 16; + cps->height_cr= cps->height * mb_height_cr[cps->yuv_format] / 16; + } + else + { + cps->width_cr = 0; + cps->height_cr= 0; + } + + cps->height_cr_frame = cps->height_cr; + cps->size = cps->width * cps->height; + cps->size_cr = cps->width_cr * cps->height_cr; + + cps->PicWidthInMbs = cps->width / MB_BLOCK_SIZE; + cps->FrameHeightInMbs = cps->height / MB_BLOCK_SIZE; + cps->FrameSizeInMbs = cps->PicWidthInMbs * cps->FrameHeightInMbs; + cps->PicHeightInMapUnits = ( p_Vid->sps[layer_idx]->frame_mbs_only_flag ? cps->FrameHeightInMbs : cps->FrameHeightInMbs >> 1 ); + + if ( cps->yuv_format == YUV420 ) + { + cps->pad_size_uv_x = IMG_PAD_SIZE_X >> 1; + cps->pad_size_uv_y = IMG_PAD_SIZE_Y >> 1; + cps->chroma_mask_mv_y = 7; + cps->chroma_mask_mv_x = 7; + cps->chroma_shift_x = 3; + cps->chroma_shift_y = 3; + } + else if ( cps->yuv_format == YUV422 ) + { + cps->pad_size_uv_x = IMG_PAD_SIZE_X >> 1; + cps->pad_size_uv_y = IMG_PAD_SIZE_Y; + cps->chroma_mask_mv_y = 3; + cps->chroma_mask_mv_x = 7; + cps->chroma_shift_y = 2; + cps->chroma_shift_x = 3; + } + else + { // YUV444 + cps->pad_size_uv_x = IMG_PAD_SIZE_X; + cps->pad_size_uv_y = IMG_PAD_SIZE_Y; + cps->chroma_mask_mv_y = 3; + cps->chroma_mask_mv_x = 3; + cps->chroma_shift_y = 2; + cps->chroma_shift_x = 2; + } + cps->shift_cr_y = cps->chroma_shift_y - 2; + cps->shift_cr_x = cps->chroma_shift_x - 2; + + cps->padded_size_x = (cps->width + 2 * IMG_PAD_SIZE_X); + cps->padded_size_x_m8x8 = (cps->padded_size_x - BLOCK_SIZE_8x8); + cps->padded_size_x_m4x4 = (cps->padded_size_x - BLOCK_SIZE); + cps->cr_padded_size_x = (cps->width_cr + 2 * cps->pad_size_uv_x); + cps->cr_padded_size_x2 = (cps->cr_padded_size_x << 1); + cps->cr_padded_size_x4 = (cps->cr_padded_size_x << 2); + cps->cr_padded_size_x_m8 = (cps->cr_padded_size_x - 8); + +} + +static void generate_encode_parameters(VideoParameters *p_Vid) +{ + int i; + p_Vid->p_EncodePar[0] = (CodingParameters *)calloc(p_Vid->num_of_layers, sizeof(CodingParameters)); + //init; + for(i=0; inum_of_layers; i++) + { + p_Vid->p_EncodePar[i] = p_Vid->p_EncodePar[0]+i; + gen_enc_par(p_Vid, i); + } + p_Vid->p_CurrEncodePar = p_Vid->p_EncodePar[0]; +} + +static void free_encode_parameters(VideoParameters *p_Vid) +{ + int i; + if(p_Vid->p_EncodePar[0]) + { + free_pointer(p_Vid->p_EncodePar[0]); + } + for(i=0; inum_of_layers; i++) + { + p_Vid->p_EncodePar[i] = NULL; + } + p_Vid->p_CurrEncodePar = NULL; +} + +int init_process_image( VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int memory_size = 0; + switch( p_Inp->ProcessInput ) + { + default: + break; + case 0: + if( (p_Vid->num_of_layers == 2) && is_MVC_profile(p_Inp->ProfileIDC) ) + memory_size += init_orig_buffers(p_Vid, &p_Vid->tempData3); + break; + } + return memory_size; +} + +void clear_process_image( VideoParameters *p_Vid, InputParameters *p_Inp) +{ + switch( p_Inp->ProcessInput ) + { + default: + break; + case 0: + if( (p_Vid->num_of_layers == 2) && is_MVC_profile(p_Inp->ProfileIDC) ) + free_orig_planes(p_Vid, &p_Vid->tempData3); + break; + } +} diff --git a/lencod/src/list_reorder.c b/lencod/src/list_reorder.c new file mode 100644 index 0000000..707bdb0 --- /dev/null +++ b/lencod/src/list_reorder.c @@ -0,0 +1,1411 @@ +/*! + ************************************************************************************** + * \file + * slice.c + * \brief + * generate the slice header, setup the bit buffer for slices, + * and generates the slice NALU(s) + + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Athanasios Leontaris + * - Karsten Suehring + * - Alexis Michael Tourapis + *************************************************************************************** + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "image.h" +#include "wp.h" +#include "list_reorder.h" + +static void poc_ref_pic_reorder_dummy(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no); +static void reorder_lists_dummy( Slice *currSlice ); + +/*! + ************************************************************************ + * \brief + * init_ref_pic_list_reordering initializations should go here + ************************************************************************ + */ +void init_ref_pic_list_reordering(Slice* currSlice, int refReorderMethod) +{ + currSlice->ref_pic_list_reordering_flag[LIST_0] = 0; + currSlice->ref_pic_list_reordering_flag[LIST_1] = 0; + + if (refReorderMethod == 2) + { + currSlice->poc_ref_pic_reorder_frame = tlyr_ref_pic_reorder_frame_default; + currSlice->reorder_lists = reorder_lists; + } +#if (MVC_EXTENSION_ENABLE) + else if ((refReorderMethod == 1) && (currSlice->layer_id > 0) && (currSlice->p_Inp->MVCInterViewReorder > 0 )) + { + currSlice->poc_ref_pic_reorder_frame = poc_ref_pic_reorder_frame_enh; + currSlice->reorder_lists = reorder_lists; + } + else if ((refReorderMethod == 0) && (currSlice->layer_id > 0) && (currSlice->p_Inp->MVCInterViewReorder > 0 )) + { + currSlice->poc_ref_pic_reorder_frame = poc_ref_pic_reorder_frame_enh; + currSlice->reorder_lists = reorder_lists; + } +#endif + else if ((refReorderMethod == 0) || (currSlice->slice_type == I_SLICE) || (currSlice->slice_type == SI_SLICE)) + { + currSlice->poc_ref_pic_reorder_frame = poc_ref_pic_reorder_dummy; + currSlice->reorder_lists = reorder_lists_dummy; + } + else + { + currSlice->poc_ref_pic_reorder_frame = poc_ref_pic_reorder_frame_enh; + currSlice->reorder_lists = reorder_lists; + } +} + +/*! +************************************************************************ +* \brief +* decide reference picture reordering, Frame only +************************************************************************ +*/ +void poc_ref_pic_reorder_frame_default(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no) +{ + StorablePicture **list = currSlice->listX[list_no]; + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[list_no]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[list_no]; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + StorablePicture *p_Enc_Pic = p_Vid->enc_picture; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + int i,j,k; + + int currPicNum, picNumLXPred; + + int default_order[32]; + int re_order[32]; + int tmp_reorder[32]; + int list_sign[32]; + int reorder_stop, no_reorder; + int poc_diff[32]; + int diff; + + int abs_poc_dist; + int maxPicNum; + unsigned int num_refs; + + maxPicNum = p_Vid->max_frame_num; + currPicNum = p_Vid->frame_num; + + picNumLXPred = currPicNum; + + // First assign default list order. + for (i=0; i<(int)num_ref_idx_lX_active; i++) + { + default_order[i] = list[i]->pic_num; + } + + // Now access all references in buffer and assign them + // to a potential reordering list. For each one of these + // references compute the poc distance compared to current + // frame. + num_refs = currSlice->p_Dpb->ref_frames_in_buffer; + for (i = 0; i < (int)p_Dpb->ref_frames_in_buffer; i++) + { + poc_diff[i] = 0xFFFF; + re_order[i] = p_Dpb->fs_ref[i]->frame->pic_num; + + if (p_Dpb->fs_ref[i]->is_used==3 && (p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + abs_poc_dist = iabs(p_Dpb->fs_ref[i]->frame->poc - p_Enc_Pic->poc) ; + poc_diff[i] = abs_poc_dist; + if (list_no == LIST_0) + { + list_sign[i] = (p_Enc_Pic->poc < p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + else + { + list_sign[i] = (p_Enc_Pic->poc > p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + } + } + + // now sort these references based on poc (temporal) distance + for (i = 0; i < ((int)num_refs - 1); i++) + { + for (j = i + 1; j < (int)num_refs; j++) + { + if (poc_diff[i]>poc_diff[j] || (poc_diff[i] == poc_diff[j] && list_sign[j] > list_sign[i])) + { + i32_swap(poc_diff[i], poc_diff[j]); + i32_swap(re_order[i], re_order[j]); + i32_swap(list_sign[i], list_sign[j]); + } + } + } + + // populate list with selections from the pre-analysis stage + if ( p_Inp->WPMCPrecision + && p_Vid->pWPX->curr_wp_rd_pass->algorithm != WP_REGULAR + && p_Vid->pWPX->num_wp_ref_list[list_no] ) + { + for (i=0; i<(int)num_ref_idx_lX_active; i++) + { + re_order[i] = p_Vid->pWPX->wp_ref_list[list_no][i].PicNum; + } + } + + if (p_Inp->EnableOpenGOP) + { + int counter = 0; + for (i = 0; i < currSlice->listXsize[list_no]; i++) + { + if (currSlice->listX[list_no][i]->poc < p_Vid->last_valid_reference && p_Vid->ThisPOC > p_Vid->last_valid_reference) + { + counter++; + } + } + + currSlice->listXsize[list_no] -= counter; + num_ref_idx_lX_active = currSlice->listXsize[list_no]; + } + + // Check versus default list to see if any + // change has happened + no_reorder = 1; + for (i=0; i<(int)num_ref_idx_lX_active; i++) + { + if (default_order[i] != re_order[i]) + { + no_reorder = 0; + } + } + + // If different, then signal reordering + if (no_reorder==0) + { + for (i=0; i<(int)num_ref_idx_lX_active; i++) + { + diff = re_order[i]-picNumLXPred; + if (diff <= 0) + { + modification_of_pic_nums_idc[i] = 0; + abs_diff_pic_num_minus1[i] = iabs(diff)-1; + if (abs_diff_pic_num_minus1[i] < 0) + abs_diff_pic_num_minus1[i] = maxPicNum -1; + } + else + { + modification_of_pic_nums_idc[i] = 1; + abs_diff_pic_num_minus1[i] = iabs(diff)-1; + } + picNumLXPred = re_order[i]; + + tmp_reorder[i] = re_order[i]; + + k = i; + for (j=i; j<(int)num_ref_idx_lX_active; j++) + { + if (default_order[j] != re_order[i]) + { + ++k; + tmp_reorder[k] = default_order[j]; + } + } + reorder_stop = 1; + for(j=i+1; j<(int)num_ref_idx_lX_active; j++) + { + if (tmp_reorder[j] != re_order[j]) + { + reorder_stop = 0; + break; + } + } + + if (reorder_stop==1) + { + ++i; + break; + } + memcpy ( default_order, tmp_reorder, num_ref_idx_lX_active * sizeof(int)); + + } + modification_of_pic_nums_idc[i] = 3; + + memcpy ( default_order, tmp_reorder, num_ref_idx_lX_active * sizeof(int)); + + if (list_no==0) + { + currSlice->ref_pic_list_reordering_flag[LIST_0] = 1; + } + else + { + currSlice->ref_pic_list_reordering_flag[LIST_1] = 1; + } + } +} + +/*! +************************************************************************ +* \brief +* Dummy reference reordering decision function +************************************************************************ +*/ +static void poc_ref_pic_reorder_dummy(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no) +{ +} + +/*! +************************************************************************ +* \brief +* decide reference picture reordering, Frame only, for enh layer. +************************************************************************ +*/ +void poc_ref_pic_reorder_frame_enh(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no) +{ + StorablePicture **list = currSlice->listX[list_no]; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + StorablePicture *p_Enc_Pic = p_Vid->enc_picture; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + int i, j, k; + int found = 0; + + StorablePicture *re_order[32]; + StorablePicture *inter_layer_ref[32]; + StorablePicture *tmp_pic_value; + + int list_sign[32]; + int poc_diff[32]; + int inter_layer_ref_idx[32]; + + int abs_poc_dist; + int num_refs; + int pic_num; + + // First find inter view ref/s + // This code is idiotic since this can be found immediately given that reference is in p_Dpb->fs_ilref + + if (currSlice->layer_id > 0) + { + for (i = 0; i < (int) num_ref_idx_lX_active; i++) + { + if (list[i]->view_id < currSlice->layer_id) + { + inter_layer_ref[found] = list[i]; + inter_layer_ref_idx[found] = i; + found++; + } + } + } + + // Now access all references in buffer and assign them + // to a potential reordering list. For each one of these + // references compute the poc distance compared to current + // frame. + num_refs = p_Dpb->ref_frames_in_buffer; + for (i = 0; i < num_refs; i++) + { + poc_diff[i] = 0xFFFF; + re_order[i] = p_Dpb->fs_ref[i]->frame; + + // following code seems to exclude long term references + if (p_Dpb->fs_ref[i]->is_used==3 && (p_Dpb->fs_ref[i]->frame->used_for_reference) && (!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + abs_poc_dist = iabs(p_Dpb->fs_ref[i]->frame->poc - p_Enc_Pic->poc) ; + poc_diff[i] = abs_poc_dist; + if (list_no == LIST_0) + { + list_sign[i] = (p_Enc_Pic->poc < p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + else + { + list_sign[i] = (p_Enc_Pic->poc > p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + } + } + + // now sort these references based on poc (temporal) distance + for (i = 0; i < (num_refs - 1); i++) + { + for (j = i + 1; j < num_refs; j++) + { + if (poc_diff[i] > poc_diff[j] || (poc_diff[i] == poc_diff[j] && list_sign[j] > list_sign[i])) + { + i32_swap(poc_diff[i], poc_diff[j]); + tmp_pic_value = re_order[i]; + re_order[i] = re_order[j]; + re_order[j] = tmp_pic_value ; + i32_swap(list_sign[i], list_sign[j]); + } + } + } + + // populate list with selections from the pre-analysis stage + if ( p_Inp->WPMCPrecision + && p_Vid->pWPX->curr_wp_rd_pass->algorithm != WP_REGULAR + && p_Vid->pWPX->num_wp_ref_list[list_no] ) + { + for (i = 0; i < (int) num_ref_idx_lX_active; i++) + { + pic_num = p_Vid->pWPX->wp_ref_list[list_no][i].PicNum; + for (j = 0; j < (int) p_Dpb->ref_frames_in_buffer; j++) + { + if (pic_num == p_Dpb->fs_ref[i]->frame->pic_num) + { + re_order[i] = p_Dpb->fs_ref[i]->frame; + break; + } + } + } + } + + if (currSlice->layer_id > 0) + { + // This code currently only supports a single inter-layer reference. + // We need to have a flag in the code that points to how many such references + // exist and appropriately scan fl_ilref. + j = 0; + k = 0; + for (i = 0; i < (int) num_ref_idx_lX_active+found; i++) + { + if ((found > 0) && (i == inter_layer_ref_idx[k])) + { + list[i] = inter_layer_ref[k++]; + //printf("values %d %d", (int) list[i], (int) p_Dpb->fs_ilref[0]->frame); + found--; + } + else + { + list[i] = re_order[j++]; + } + } + } + else + { + for (i = 0; i < (int) num_ref_idx_lX_active; i++) + { + list[i] = re_order[i]; + } + } +} + +/*! +************************************************************************ +* \brief +* decide reference picture reordering, Field. +************************************************************************ +*/ +void poc_ref_pic_reorder_field_enh(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no) +{ + StorablePicture **list = currSlice->listX[list_no]; + VideoParameters *p_Vid = currSlice->p_Vid; + //InputParameters *p_Inp = currSlice->p_Inp; + StorablePicture *p_Enc_Pic = p_Vid->enc_picture; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + int i,j,k; + int found = 0; + + StorablePicture *re_order[32]; + StorablePicture *tmp_reorder[32]; + StorablePicture *inter_layer_ref[32]; + StorablePicture *tmp_pic_value; + StorablePicture *pField[2]; // 0: TOP_FIELD, 1: BOTTOM_FIELD + FrameStore *pFrameStore; + + int list_sign[32]; + int poc_diff[32]; + int inter_layer_ref_idx[32]; + + int abs_poc_dist; + int num_refs; + + int field_used[2] = {1, 2}; + int fld_type[32]; + int num_flds, fld, idx; + int list_size = 0; + int top_idx = 0; + int bot_idx = 0; + + + // First find inter view ref + if (currSlice->layer_id > 0) + { + for (i = 0; i < (int) num_ref_idx_lX_active; i++) + { + if (list[i]->view_id < currSlice->layer_id) + { + inter_layer_ref[found] = list[i]; + inter_layer_ref_idx[found] = i; + found++; + } + } + } + + // Now access all references in buffer and assign them + // to a potential reordering list. For each one of these + // references compute the poc distance compared to current + // frame. + idx = 0; + num_refs = p_Dpb->ref_frames_in_buffer; + for (i = 0; i < num_refs; i++) + { + pFrameStore = p_Dpb->fs_ref[i]; + pField[0] = pFrameStore->top_field; + pField[1] = pFrameStore->bottom_field; + num_flds = (currSlice->structure == BOTTOM_FIELD && (p_Enc_Pic->poc == (pField[0]->poc + 1) ) ) ? 1 : 2; + + poc_diff[2*i ] = 0xFFFF; + poc_diff[2*i + 1] = 0xFFFF; + + for ( fld = 0; fld < num_flds; fld++ ) + { + if ( (pFrameStore->is_used & field_used[fld]) && pField[fld]->used_for_reference && !(pField[fld]->is_long_term)) + { + abs_poc_dist = iabs(pField[fld]->poc - p_Enc_Pic->poc) ; + poc_diff[idx] = abs_poc_dist; + re_order[idx] = pField[fld]; + fld_type[idx] = fld + 1; + + if (list_no == LIST_0) + { + list_sign[idx] = (p_Enc_Pic->poc < pField[fld]->poc) ? +1 : -1; + } + else + { + list_sign[idx] = (p_Enc_Pic->poc > pField[fld]->poc) ? +1 : -1; + } + idx++; + } + } + } + num_refs = idx; + + // now sort these references based on poc (temporal) distance + for (i=0; i < num_refs-1; i++) + { + for (j = (i + 1); j < num_refs; j++) + { + if (poc_diff[i] > poc_diff[j] || (poc_diff[i] == poc_diff[j] && list_sign[j] > list_sign[i])) + { + // poc_diff + i32_swap (poc_diff[i], poc_diff[j]); + // re_order (PicNum) + tmp_pic_value = re_order[i]; + re_order[i] = re_order[j]; + re_order[j] = tmp_pic_value; + // list_sign + i32_swap (list_sign[i], list_sign[j]); + // fld_type + i32_swap (fld_type[i], fld_type[j]); + } + } + } + + if (currSlice->structure == TOP_FIELD) + { + while ((top_idx < num_refs)||(bot_idx < num_refs)) + { + for ( ; top_idx < num_refs; top_idx++) + { + if ( fld_type[top_idx] == TOP_FIELD ) + { + tmp_reorder[list_size] = re_order[top_idx]; + list_size++; + top_idx++; + break; + } + } + for ( ; bot_idx < num_refs; bot_idx++) + { + if ( fld_type[bot_idx] == BOTTOM_FIELD ) + { + tmp_reorder[list_size] = re_order[bot_idx]; + list_size++; + bot_idx++; + break; + } + } + } + } + + if (currSlice->structure == BOTTOM_FIELD) + { + while ((top_idx < num_refs)||(bot_idx < num_refs)) + { + for ( ; bot_idx < num_refs; bot_idx++) + { + if ( fld_type[bot_idx] == BOTTOM_FIELD ) + { + tmp_reorder[list_size] = re_order[bot_idx]; + list_size++; + bot_idx++; + break; + } + } + for ( ; top_idx < num_refs; top_idx++) + { + if ( fld_type[top_idx] == TOP_FIELD ) + { + tmp_reorder[list_size] = re_order[top_idx]; + list_size++; + top_idx++; + break; + } + } + } + } + + j = 0; + k = 0; + for (i = 0; i < (int) num_ref_idx_lX_active; i++) + { + if ((found > 0) && (i == inter_layer_ref_idx[k])) + { + list[i] = inter_layer_ref[k++]; + found--; + } + else + { + list[i] = tmp_reorder[j++]; + } + } +} + +/*! +************************************************************************ +* \brief +* decide reference picture reordering, Field only +************************************************************************ +*/ +void poc_ref_pic_reorder_field(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no) +{ + StorablePicture **list = currSlice->listX[list_no]; + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[list_no]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[list_no]; + + VideoParameters *p_Vid = currSlice->p_Vid; + //InputParameters *p_Inp = currSlice->p_Inp; + StorablePicture *p_Enc_Pic = p_Vid->enc_picture; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i,j,k; + + int currPicNum, picNumLXPred; + + int default_order[32]; + int re_order[32]; + int tmp_reorder[32]; + int list_sign[32]; + int poc_diff[32]; + int fld_type[32]; + + int reorder_stop, no_reorder; + int tmp_value, diff; + + int abs_poc_dist; + int maxPicNum; + unsigned int num_refs; + + int field_used[2] = {1, 2}; + int fld, idx, num_flds; + + unsigned int top_idx = 0; + unsigned int bot_idx = 0; + unsigned int list_size = 0; + + StorablePicture *pField[2]; // 0: TOP_FIELD, 1: BOTTOM_FIELD + FrameStore *pFrameStore; + + maxPicNum = 2 * p_Vid->max_frame_num; + currPicNum = 2 * p_Vid->frame_num + 1; + + picNumLXPred = currPicNum; + + // First assign default list order. + for (i=0; ipic_num; + } + + // Now access all references in buffer and assign them + // to a potential reordering list. For each one of these + // references compute the poc distance compared to current + // frame. + // look for eligible fields + idx = 0; + + for (i=0; iref_frames_in_buffer; i++) + { + pFrameStore = p_Dpb->fs_ref[i]; + pField[0] = pFrameStore->top_field; + pField[1] = pFrameStore->bottom_field; + num_flds = (currSlice->structure == BOTTOM_FIELD && (p_Enc_Pic->poc == (pField[0]->poc + 1) ) ) ? 1 : 2; + + poc_diff[2*i ] = 0xFFFF; + poc_diff[2*i + 1] = 0xFFFF; + + for ( fld = 0; fld < num_flds; fld++ ) + { +#if (MVC_EXTENSION_ENABLE) + if ( (pFrameStore->is_used & field_used[fld]) && pField[fld]->used_for_reference && !(pField[fld]->is_long_term) + && (p_Vid->p_Inp->num_of_views==1 || pField[fld]->view_id==p_Vid->view_id)) +#else + if ( (pFrameStore->is_used & field_used[fld]) && pField[fld]->used_for_reference && !(pField[fld]->is_long_term)) +#endif + { + abs_poc_dist = iabs(pField[fld]->poc - p_Enc_Pic->poc) ; + poc_diff[idx] = abs_poc_dist; + re_order[idx] = pField[fld]->pic_num; + fld_type[idx] = fld + 1; + + if (list_no == LIST_0) + { + list_sign[idx] = (p_Enc_Pic->poc < pField[fld]->poc) ? +1 : -1; + } + else + { + list_sign[idx] = (p_Enc_Pic->poc > pField[fld]->poc) ? +1 : -1; + } + idx++; + } + } + } + num_refs = idx; + + // now sort these references based on poc (temporal) distance + for (i=0; i < num_refs-1; i++) + { + for (j = (i + 1); j < num_refs; j++) + { + if (poc_diff[i] > poc_diff[j] || (poc_diff[i] == poc_diff[j] && list_sign[j] > list_sign[i])) + { + // poc_diff + tmp_value = poc_diff[i]; + poc_diff[i] = poc_diff[j]; + poc_diff[j] = tmp_value; + // re_order (PicNum) + tmp_value = re_order[i]; + re_order[i] = re_order[j]; + re_order[j] = tmp_value; + // list_sign + tmp_value = list_sign[i]; + list_sign[i] = list_sign[j]; + list_sign[j] = tmp_value; + // fld_type + tmp_value = fld_type[i]; + fld_type[i] = fld_type[j]; + fld_type[j] = tmp_value ; + } + } + } + + if (currSlice->structure == TOP_FIELD) + { + while ((top_idx < num_refs)||(bot_idx < num_refs)) + { + for ( ; top_idx < num_refs; top_idx++) + { + if ( fld_type[top_idx] == TOP_FIELD ) + { + tmp_reorder[list_size] = re_order[top_idx]; + list_size++; + top_idx++; + break; + } + } + for ( ; bot_idx < num_refs; bot_idx++) + { + if ( fld_type[bot_idx] == BOTTOM_FIELD ) + { + tmp_reorder[list_size] = re_order[bot_idx]; + list_size++; + bot_idx++; + break; + } + } + } + } + if (currSlice->structure == BOTTOM_FIELD) + { + while ((top_idx < num_refs)||(bot_idx < num_refs)) + { + for ( ; bot_idx < num_refs; bot_idx++) + { + if ( fld_type[bot_idx] == BOTTOM_FIELD ) + { + tmp_reorder[list_size] = re_order[bot_idx]; + list_size++; + bot_idx++; + break; + } + } + for ( ; top_idx < num_refs; top_idx++) + { + if ( fld_type[top_idx] == TOP_FIELD ) + { + tmp_reorder[list_size] = re_order[top_idx]; + list_size++; + top_idx++; + break; + } + } + } + } + + // copy to final matrix + list_size = imin( list_size, 32 ); + for ( i = 0; i < list_size; i++ ) + { + re_order[i] = tmp_reorder[i]; + } + + // Check versus default list to see if any + // change has happened + no_reorder = 1; + for (i=0; iref_pic_list_reordering_flag[LIST_0] = 1; + } + else + { + currSlice->ref_pic_list_reordering_flag[LIST_1] = 1; + } + } +} + + +/*! +************************************************************************ +* \brief +* decide reference picture reordering based on temporal layer, Frame only +************************************************************************ +*/ +void tlyr_ref_pic_reorder_frame_default(Slice *currSlice, unsigned num_ref_idx_lX_active, int list_no) +{ + StorablePicture **list = currSlice->listX[list_no]; + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[list_no]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[list_no]; + + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + StorablePicture *p_Enc_Pic = p_Vid->enc_picture; + struct decoded_picture_buffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i,j,k; + + int currPicNum, picNumLXPred; + + int default_order[32]; + int re_order[32]; + int tmp_reorder[32]; + int list_sign[32]; + int reorder_stop, no_reorder; + int poc_diff[32]; + + int temporal_layer[32]; + + int diff; + + int abs_poc_dist; + int maxPicNum; + unsigned int num_refs; + + int tmp_poc_diff, tmp_re_order, tmp_list_sign, tmp_temporal_layer; + unsigned int beginIdx = 0; + char newSize = 0; + + + maxPicNum = p_Vid->max_frame_num; + currPicNum = p_Vid->frame_num; + + picNumLXPred = currPicNum; + + // First assign default list order. + for (i=0; ipic_num; + } + + // Now access all references in buffer and assign them + // to a potential reordering list. For each one of these + // references compute the poc distance compared to current + // frame. + num_refs = p_Dpb->ref_frames_in_buffer; + for (i=0; iref_frames_in_buffer; i++) + { + poc_diff[i] = 0xFFFF; + re_order[i] = p_Dpb->fs_ref[i]->frame->pic_num; + + temporal_layer[i] = p_Dpb->fs_ref[i]->frame->temporal_layer; + + if (p_Dpb->fs_ref[i]->is_used==3 && (p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + abs_poc_dist = iabs(p_Dpb->fs_ref[i]->frame->poc - p_Enc_Pic->poc) ; + poc_diff[i] = abs_poc_dist; + if (list_no == LIST_0) + { + list_sign[i] = (p_Enc_Pic->poc < p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + else + { + list_sign[i] = (p_Enc_Pic->poc > p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + } + } + + // first, sort the references based on poc (temporal) distance + for (i = 0; i < (num_refs - 1); i++) + { + for (j = i + 1; j < num_refs; j++) + { + if (list_sign[i] == list_sign[j] && poc_diff[i] > poc_diff[j]) + { + tmp_poc_diff = poc_diff[i]; + tmp_re_order = re_order[i]; + tmp_list_sign = list_sign[i]; + tmp_temporal_layer = temporal_layer[i]; + poc_diff[i] = poc_diff[j]; + re_order[i] = re_order[j]; + list_sign[i] = list_sign[j]; + temporal_layer[i] = temporal_layer[j]; + poc_diff[j] = tmp_poc_diff; + re_order[j] = tmp_re_order ; + list_sign[j] = tmp_list_sign; + temporal_layer[j] = tmp_temporal_layer; + } + } + } + + // use the closest valid reference frame + 3 temporal layer 0 frames + for (i = 0; i < num_refs; i++) + { + /* + if ( (i == 0 && temporal_layer[i] <= p_Enc_Pic->temporal_layer) || + (i && !temporal_layer[i]) ) // valid reference pic + */ + if (temporal_layer[i] <= p_Enc_Pic->temporal_layer) + { + tmp_poc_diff = poc_diff[i]; + tmp_re_order = re_order[i]; + tmp_list_sign = list_sign[i]; + tmp_temporal_layer = temporal_layer[i]; + for (j = i; j > beginIdx; j--) + { + poc_diff[j] = poc_diff[j-1]; + re_order[j] = re_order[j-1]; + list_sign[j] = list_sign[j-1]; + temporal_layer[j] = temporal_layer[j-1]; + } + poc_diff[beginIdx] = tmp_poc_diff; + re_order[beginIdx] = tmp_re_order; + list_sign[beginIdx] = tmp_list_sign; + temporal_layer[beginIdx] = tmp_temporal_layer; + beginIdx += 1; + + newSize++; + } + } + //currSlice->listXsize[0] = newSize; // update with valid size + + // populate list with selections from the pre-analysis stage + if ( p_Inp->WPMCPrecision + && p_Vid->pWPX->curr_wp_rd_pass->algorithm != WP_REGULAR + && p_Vid->pWPX->num_wp_ref_list[list_no] ) + { + for (i=0; ipWPX->wp_ref_list[list_no][i].PicNum; + } + } + + // Check versus default list to see if any + // change has happened + no_reorder = 1; + for (i=0; iref_pic_list_reordering_flag[LIST_0] = 1; + } + else + { + currSlice->ref_pic_list_reordering_flag[LIST_1] = 1; + } + } +} + + +/*! +************************************************************************ +* \brief +* Dummy function for reference list reordering. Used when +* p_Inp->ReferenceReorder is 0 or if an I/SI slice +************************************************************************ +*/ +static void reorder_lists_dummy( Slice *currSlice ) +{ +} + +/*! +************************************************************************ +* \brief +* Reorder lists +************************************************************************ +*/ + +void reorder_lists( Slice *currSlice ) +{ + InputParameters *p_Inp = currSlice->p_Inp; + + // Perform reordering based on poc distances for HierarchicalCoding + if ( p_Inp->ReferenceReorder && (currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE)) + { + int i, num_ref; + + for (i = 0; i < currSlice->num_ref_idx_active[LIST_0] + 1; i++) + { + currSlice->modification_of_pic_nums_idc[LIST_0][i] = 3; + currSlice->abs_diff_pic_num_minus1[LIST_0][i] = 0; + currSlice->long_term_pic_idx[LIST_0][i] = 0; + } + + num_ref = currSlice->num_ref_idx_active[LIST_0]; + + if ( p_Inp->ReferenceReorder == 2 ) // temporal layer based + { + if ( currSlice->structure == FRAME ) + currSlice->poc_ref_pic_reorder_frame(currSlice, num_ref, LIST_0); + } + else + { + if ( currSlice->structure == FRAME ) + currSlice->poc_ref_pic_reorder_frame(currSlice, num_ref, LIST_0); + else + { + poc_ref_pic_reorder_field_enh(currSlice, num_ref, LIST_0); + } + } + + currSlice->num_ref_idx_active[LIST_0] = currSlice->listXsize[0]; + + if (p_Inp->ReferenceReorder > 1) + { + free_ref_pic_list_reordering_buffer(currSlice); + alloc_ref_pic_list_reordering_buffer(currSlice); + reorder_ref_pic_list ( currSlice, LIST_0); + } + } + currSlice->num_ref_idx_active[LIST_0] = currSlice->listXsize[0]; + +#if KEEP_B_SAME_LIST + if ( currSlice->slice_type == B_SLICE && currSlice->p_Dpb->ref_frames_in_buffer >= 2 ) + { + int iSendAddtionalRPLR = 0; + iSendAddtionalRPLR = ( p_Inp->BIdenticalList == 1 && ( (currSlice->ThisPOC/2) % (p_Inp->NumberBFrames+1) ) == 0 ) || + ( p_Inp->BIdenticalList == 2 ); + + if ( iSendAddtionalRPLR ) + { + int i, num_ref, diff_num, last_frame_num; + + alloc_ref_pic_list_reordering_buffer(currSlice); + + for (i = 0; i < currSlice->num_ref_idx_active[LIST_1] + 1; i++) + { + currSlice->modification_of_pic_nums_idc[LIST_1][i] = 3; + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = 0; + currSlice->long_term_pic_idx[LIST_1][i] = 0; + } + + num_ref = currSlice->num_ref_idx_active[LIST_1]; + + last_frame_num = currSlice->frame_num; + for ( i=0; inum_ref_idx_active[LIST_1]; i++ ) + { + diff_num = currSlice->listX[LIST_0][i]->frame_num - last_frame_num; + last_frame_num = currSlice->listX[LIST_0][i]->frame_num; + if ( diff_num <= 0 ) + { + currSlice->modification_of_pic_nums_idc[LIST_1][i] = 0; + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = iabs(diff_num) - 1; + if ( currSlice->abs_diff_pic_num_minus1[LIST_1][i] < 0 ) + { + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = currSlice->max_frame_num - 1; + } + } + else + { + currSlice->modification_of_pic_nums_idc[LIST_1][i] = 1; + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = iabs(diff_num) - 1; + } + } + + currSlice->ref_pic_list_reordering_flag[LIST_1] = 1; + currSlice->num_ref_idx_active[LIST_1] = currSlice->listXsize[1]; + reorder_ref_pic_list ( currSlice, LIST_1); + currSlice->num_ref_idx_active[LIST_1] = currSlice->listXsize[1]; + + return; + } + } +#endif + +#if CRA + if ( p_Inp->useCRA ) + { + if ( currSlice->slice_type == B_SLICE && currSlice->p_Dpb->ref_frames_in_buffer >= 2 ) + { + if ( ( (currSlice->ThisPOC/2) - (p_Inp->NumberBFrames+1) ) % p_Inp->intra_period == 0 ) + { + int i, diff_num; + alloc_ref_pic_list_reordering_buffer(currSlice); + for (i = 0; i < currSlice->num_ref_idx_active[LIST_1] + 1; i++) + { + currSlice->modification_of_pic_nums_idc[LIST_1][i] = 3; + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = 0; + currSlice->long_term_pic_idx[LIST_1][i] = 0; + } + + diff_num = currSlice->listX[LIST_0][0]->frame_num - currSlice->frame_num; + if ( diff_num <= 0 ) + { + currSlice->modification_of_pic_nums_idc[LIST_1][0] = 0; + currSlice->abs_diff_pic_num_minus1[LIST_1][0] = iabs(diff_num) - 1; + if ( currSlice->abs_diff_pic_num_minus1[LIST_1][0] < 0 ) + { + currSlice->abs_diff_pic_num_minus1[LIST_1][0] = currSlice->max_frame_num - 1; + } + } + else + { + currSlice->modification_of_pic_nums_idc[LIST_1][0] = 1; + currSlice->abs_diff_pic_num_minus1[LIST_1][0] = iabs(diff_num) - 1; + } + + currSlice->ref_pic_list_reordering_flag[LIST_1] = 1; + currSlice->num_ref_idx_active[LIST_1] = currSlice->listXsize[1]; + reorder_ref_pic_list ( currSlice, LIST_1); + currSlice->num_ref_idx_active[LIST_1] = currSlice->listXsize[1]; + } + } + } +#endif +} + +/*! +************************************************************************ +* \brief +* Reorder lists +************************************************************************ +*/ + +void wp_mcprec_reorder_lists( Slice *currSlice ) +{ + + int i, num_ref; + + wpxModifyRefPicList( currSlice ); + + alloc_ref_pic_list_reordering_buffer(currSlice); + + for (i = 0; i < currSlice->num_ref_idx_active[LIST_0] + 1; i++) + { + currSlice->modification_of_pic_nums_idc[LIST_0][i] = 3; + currSlice->abs_diff_pic_num_minus1[LIST_0][i] = 0; + currSlice->long_term_pic_idx[LIST_0][i] = 0; + } + + if (currSlice->slice_type == B_SLICE) // type should be part of currSlice not p_Vid + { + for (i = 0; i < currSlice->num_ref_idx_active[LIST_1] + 1; i++) + { + currSlice->modification_of_pic_nums_idc[LIST_1][i] = 3; + currSlice->abs_diff_pic_num_minus1[LIST_1][i] = 0; + currSlice->long_term_pic_idx[LIST_1][i] = 0; + } + } + + // LIST_0 + num_ref = currSlice->num_ref_idx_active[LIST_0]; + + currSlice->poc_ref_pic_reorder_frame(currSlice, num_ref, LIST_0); + // reference picture reordering + reorder_ref_pic_list ( currSlice, LIST_0); + + if ( currSlice->slice_type == B_SLICE ) + { + // LIST_1 + num_ref = currSlice->num_ref_idx_active[LIST_1]; + + currSlice->poc_ref_pic_reorder_frame(currSlice, num_ref, LIST_1); + // reference picture reordering + reorder_ref_pic_list ( currSlice, LIST_1); + } +} + +void set_default_ref_pic_lists(Slice *currSlice) +{ + int list, ref; + + for(list = LIST_0; list <= (currSlice->slice_type == P_SLICE ? LIST_0:LIST_1); list++) + { + for(ref = 0; ref < currSlice->listXsize[list]; ref++) + { + currSlice->default_pic_num[list][ref] = currSlice->listX[list][ref]->pic_num; +#if MVC_EXTENSION_ENABLE + currSlice->default_view_id[list][ref] = currSlice->listX[list][ref]->view_id; +#endif + } + } +} + +void reorder_against_default_ref_pic_lists(Slice *currSlice, int cur_list) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[cur_list]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[cur_list]; + int *abs_diff_view_idx_minus1 = currSlice->abs_diff_view_idx_minus1[cur_list]; + int i; + + int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred; + int picViewIdxLX; + int maxViewIdx =0; + int currViewIdx = -1; + int picViewIdxLXPred=-1; + + int diff; + + if (p_Vid->structure==FRAME) + { + maxPicNum = p_Vid->max_frame_num; + currPicNum = p_Vid->frame_num; + } + else + { + maxPicNum = 2*p_Vid->max_frame_num; + currPicNum = 2*p_Vid->frame_num+1; + } + + currViewIdx = p_Vid->view_id; + maxViewIdx = 1; + picViewIdxLXPred=-1; + + picNumLXPred = currPicNum; + + currSlice->ref_pic_list_reordering_flag[cur_list] = 0; + for (i = 0; i < currSlice->listXsize[cur_list]; i++) + { + //printf("list %d %d : %d %d %d\n",currSlice->listXsize[cur_list], cur_list,i,currSlice->default_pic_num[cur_list][i], currSlice->listX[cur_list][i]->pic_num); + //if(currSlice->default_pic_num[cur_list][i] != currSlice->listX[cur_list][i]->pic_num) + if( +#if MVC_EXTENSION_ENABLE + currSlice->default_view_id[cur_list][i] != currSlice->listX[cur_list][i]->view_id || +#endif + currSlice->default_pic_num[cur_list][i] != currSlice->listX[cur_list][i]->pic_num) + { + currSlice->ref_pic_list_reordering_flag[cur_list] = 1; + break; + } + } + + if(!currSlice->ref_pic_list_reordering_flag[cur_list]) + return; + + // initialization + for (i = 0; i < currSlice->listXsize[cur_list]+1; i++) + modification_of_pic_nums_idc[i] = 3; + + for (i=0; i < currSlice->listXsize[cur_list]; i++) + { + StorablePicture *ref_pic = currSlice->listX[cur_list][i]; + // inter_view ref reordering + if(ref_pic->view_id != currViewIdx) + { + diff = 1; + + modification_of_pic_nums_idc[i] = 5; + abs_diff_view_idx_minus1[i] = iabs(diff)-1; + } + // temporal ref reordering + else + { + diff = ref_pic->pic_num-picNumLXPred; + if (diff <= 0) + { + modification_of_pic_nums_idc[i] = 0; + abs_diff_pic_num_minus1[i] = iabs(diff)-1; + if (abs_diff_pic_num_minus1[i] < 0) + abs_diff_pic_num_minus1[i] = maxPicNum-1; + } + else + { + modification_of_pic_nums_idc[i] = 1; + abs_diff_pic_num_minus1[i] = iabs(diff)-1; + } + } + + if (modification_of_pic_nums_idc[i] == 0 || modification_of_pic_nums_idc[i] == 1) + { + if (modification_of_pic_nums_idc[i] == 0) + { + if( picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) < 0 ) + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) + maxPicNum; + else + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ); + } + else // (modification_of_pic_nums_idc[i] == 1) + { + if( picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) >= maxPicNum ) + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) - maxPicNum; + else + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ); + } + picNumLXPred = picNumLXNoWrap; + } + else if (modification_of_pic_nums_idc[i] == 4 || modification_of_pic_nums_idc[i] == 5) + { + if(modification_of_pic_nums_idc[i] == 4) + { + picViewIdxLX = picViewIdxLXPred - (abs_diff_view_idx_minus1[i] + 1); + if( picViewIdxLX <0) + picViewIdxLX += maxViewIdx; + } + else //if(modification_of_pic_nums_idc[i] == 5) + { + picViewIdxLX = picViewIdxLXPred + (abs_diff_view_idx_minus1[i] + 1); + if( picViewIdxLX >= maxViewIdx) + picViewIdxLX -= maxViewIdx; + } + picViewIdxLXPred = picViewIdxLX; + } + } +} + diff --git a/lencod/src/lln_mc_prediction.c b/lencod/src/lln_mc_prediction.c new file mode 100644 index 0000000..b6a4d90 --- /dev/null +++ b/lencod/src/lln_mc_prediction.c @@ -0,0 +1,1316 @@ +/*! + ************************************************************************************* + * \file lln_mc_prediction.c + * + * \brief + * Functions for motion compensated prediction + * + * \author + * Main contributors (see contributors.h for copyright, + * address and affiliation details) + * - Alexis Michael Tourapis + * - Modified for encoder from ldecod/src/mc_prediction.c + * by Peshala V. Pahalawatta + ************************************************************************************* + */ +#include "global.h" +#include "mbuffer.h" +#include "mb_access.h" +#include "macroblock.h" +#include "errdo.h" +#include "block.h" +#include "lln_mc_prediction.h" + +static const int COEF[6] = { 1, -5, 20, 20, -5, 1 }; +/*! + ************************************************************************ + * \brief + * block single list prediction + ************************************************************************ + */ +static inline void mc_prediction(imgpel** mb_pred, + int block_size_y, + int block_size_x, + int ioff, + imgpel block[MB_BLOCK_SIZE][MB_BLOCK_SIZE]) +{ + int jj; + + if (block_size_x == MB_BLOCK_SIZE) + { + memcpy(&(mb_pred[0][ioff]), &(block[0][0]), block_size_x * block_size_y * sizeof(imgpel)); + } + else + { + for(jj = 0; jj < block_size_y; jj++) + { + memcpy(&(mb_pred[jj][ioff]), &(block[jj][0]), block_size_x * sizeof(imgpel)); + } + } +} + + + +/*! + ************************************************************************ + * \brief + * block single list weighted prediction + ************************************************************************ + */ +static inline void weighted_mc_prediction(imgpel** mb_pred, + int block_size_y, + int block_size_x, + int ioff, + imgpel block[MB_BLOCK_SIZE][MB_BLOCK_SIZE], + int wp_scale, + int wp_offset, + int weight_denom, + int color_clip) +{ + int ii, jj; + imgpel *mpr, *b0; + + for(jj=0;jjp_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int tmp_res[21][21]; + int *tmp_line; + imgpel *p0, *p1, *p2, *p3, *p4, *p5; + int *x0, *x1, *x2, *x3, *x4, *x5; + + imgpel **cur_imgY, *cur_lineY; + int ipos_m2, ipos_m1, ipos, ipos_p1, ipos_p2, ipos_p3; + imgpel *orig_line; + int tmp_pos; + + int dx = (x_pos & 3), dy = (y_pos & 3); + int i, j, jj; + int shift_x = dec_picture->size_x; + int maxold_x = dec_picture->size_x - 1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y >> 1) - 1 : dec_picture->size_y - 1; + int result; + int pres_x; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + cur_imgY = curr_ref->de_mem->p_dec_img[(short) p_Vid->colour_plane_id][decoder]; + } + else + { + cur_imgY = curr_ref->de_mem->p_dec_img[pl][decoder]; + } + + x_pos = x_pos >> 2; + y_pos = y_pos >> 2; + + if ( (y_pos > 1) && (y_pos < maxold_y - 2 - block_size_y) && (x_pos > 1) && (x_pos < maxold_x - 2 - block_size_x)) + { + cur_imgY = &cur_imgY[ y_pos]; + if (dx == 0 && dy == 0) + { /* fullpel position */ + for (j = 0; j < block_size_y; j++) + { + memcpy(&(block[j][0]), &(cur_imgY[j][x_pos]), block_size_x * sizeof(imgpel)); + } + } + else + { /* other positions */ + + if (dy == 0) + { /* No vertical interpolation */ + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[j][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) * COEF[0] + + (*(p1++) + *(p4++)) * COEF[1] + + (*(p2++) + *(p3++)) * COEF[2]; + + *orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + if ((dx&1) == 1) + { + for (j = 0; j < block_size_y; j++) + { + cur_lineY = &(cur_imgY[j][x_pos + (dx >> 1)]); + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + *(cur_lineY++) + 1 ) >> 1); + orig_line++; + } + } + } + } + else if (dx == 0) + { /* No horizontal interpolation */ + p0 = &(cur_imgY[ - 2][x_pos]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) * COEF[0] + + (*(p1++) + *(p4++)) * COEF[1] + + (*(p2++) + *(p3++)) * COEF[2]; + + *orig_line++ = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + p0 = p1 - block_size_x; + } + + if ((dy&1) == 1) + { + jj = (dy >> 1); + for (j = 0; j < block_size_y; j++) + { + cur_lineY = &(cur_imgY[jj++][x_pos]); + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + *(cur_lineY++) + 1 ) >> 1); + orig_line++; + } + } + } + } + else if (dx == 2) + { /* Vertical & horizontal interpolation */ + jj = - 2; + for (j = 0; j < block_size_y + 5; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + orig_line = block[j]; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) * COEF[0] + + (*(p1++) + *(p4++)) * COEF[1] + + (*(p2++) + *(p3++)) * COEF[2]; + } + } + + for (j = 0; j < block_size_y; j++) + { + x0 = tmp_res[j ]; + x1 = tmp_res[j + 1]; + x2 = tmp_res[j + 2]; + x3 = tmp_res[j + 3]; + x4 = tmp_res[j + 4]; + x5 = tmp_res[j + 5]; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) * COEF[0] + + (*x1++ + *x4++) * COEF[1] + + (*x2++ + *x3++) * COEF[2]; + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result+512)>>10)); + } + } + + if ((dy&1) == 1) + { + jj = 2 + (dy>>1); + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res[jj++]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16) >> 5)) + 1 )>> 1); + orig_line++; + } + } + } + } + else if (dy == 2) + { /* Horizontal & vertical interpolation */ + p0 = &(cur_imgY[ -2][x_pos - 2]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + tmp_line = tmp_res[j]; + + for (i = 0; i < block_size_x + 5; i++) + { + *(tmp_line++) = (*(p0++) + *(p5++)) * COEF[0] + + (*(p1++) + *(p4++)) * COEF[1] + + (*(p2++) + *(p3++)) * COEF[2]; + } + p0 = p1 - (block_size_x + 5); + } + + for (j = 0; j < block_size_y; j++) + { + orig_line = block[j]; + x0 = tmp_res[j]; + x1 = x0 + 1; + x2 = x1 + 1; + x3 = x2 + 1; + x4 = x3 + 1; + x5 = x4 + 1; + + for (i = 0; i < block_size_x; i++) + { + result = (*(x0++) + *(x5++)) * COEF[0] + + (*(x1++) + *(x4++)) * COEF[1] + + (*(x2++) + *(x3++)) * COEF[2]; + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + } + } + + if ((dx&1) == 1) + { + for (j = 0; j < block_size_y; j++) + { + tmp_line = &tmp_res[j][2 + (dx>>1)]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16)>>5))+1)>>1); + orig_line ++; + } + } + } + } + else + { /* Diagonal interpolation */ + jj = (dy == 1 ? 0 : 1); + + for (j = 0; j < block_size_y; j++) + { + p0 = &cur_imgY[jj++][x_pos - 2]; + p1 = p0 + 1; + p2 = p1 + 1; + p3 = p2 + 1; + p4 = p3 + 1; + p5 = p4 + 1; + + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) * COEF[0] + + (*(p1++) + *(p4++)) * COEF[1] + + (*(p2++) + *(p3++)) * COEF[2]; + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + p0 = &(cur_imgY[-2][(dx == 1 ? x_pos : x_pos + 1)]); + for (j = 0; j < block_size_y; j++) + { + p1 = p0 + shift_x; + p2 = p1 + shift_x; + p3 = p2 + shift_x; + p4 = p3 + shift_x; + p5 = p4 + shift_x; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*(p0++) + *(p5++)) * COEF[0] + + (*(p1++) + *(p4++)) * COEF[1] + + (*(p2++) + *(p3++)) * COEF[2]; + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result + 16) >> 5)) + 1) >> 1); + orig_line++; + } + p0 = p1 - block_size_x ; + } + } + } + } + else // unsafe positions + { + if (dx == 0 && dy == 0) + { /* fullpel position */ + for (j = 0; j < block_size_y; j++) + { + cur_lineY = cur_imgY[iClip3(0, maxold_y, y_pos + j)]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *(orig_line++) = cur_lineY[iClip3(0, maxold_x, x_pos + i )]; + } + } + } + else + { /* other positions */ + + if (dy == 0) + { /* No vertical interpolation */ + tmp_pos = x_pos - 2; + for (i = 0; i < block_size_x; i++) + { + ipos_m2 = iClip3(0, maxold_x, tmp_pos++); + ipos_m1 = iClip3(0, maxold_x, tmp_pos++); + ipos = iClip3(0, maxold_x, tmp_pos++); + ipos_p1 = iClip3(0, maxold_x, tmp_pos++); + ipos_p2 = iClip3(0, maxold_x, tmp_pos++); + ipos_p3 = iClip3(0, maxold_x, tmp_pos ); + tmp_pos -= 4; + + for (j = 0; j < block_size_y; j++) + { + cur_lineY = cur_imgY[iClip3(0,maxold_y,y_pos+j)]; + + result = (cur_lineY[ipos_m2] + cur_lineY[ipos_p3]) * COEF[0]; + result += (cur_lineY[ipos_m1] + cur_lineY[ipos_p2]) * COEF[1]; + result += (cur_lineY[ipos ] + cur_lineY[ipos_p1]) * COEF[2]; + + block[j][i] = (imgpel) iClip1(max_imgpel_value, ((result + 16)>>5)); + } + } + + if ((dx&1) == 1) + { + for (j = 0; j < block_size_y; j++) + { + cur_lineY = cur_imgY[iClip3(0,maxold_y,y_pos+j)]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + cur_lineY[iClip3(0, maxold_x, x_pos + i + (dx >> 1))] + 1 ) >> 1); + orig_line++; + } + } + } + } + else if (dx == 0) + { /* No horizontal interpolation */ + tmp_pos = y_pos - 2; + for (j = 0; j < block_size_y; j++) + { + p0 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p1 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p2 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p3 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p4 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p5 = cur_imgY[iClip3(0, maxold_y, tmp_pos )]; + + tmp_pos -= 4; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + pres_x = iClip3(0,maxold_x,x_pos+i); + + result = (p0[pres_x] + p5[pres_x]) * COEF[0]; + result += (p1[pres_x] + p4[pres_x]) * COEF[1]; + result += (p2[pres_x] + p3[pres_x]) * COEF[2]; + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result+16)>>5)); + } + } + + if ((dy&1) == 1) + { + for (j = 0; j < block_size_y; j++) + { + cur_lineY = cur_imgY[iClip3(0,maxold_y,y_pos+j+(dy>>1))]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + cur_lineY[iClip3(0, maxold_x, x_pos + i)] + 1 ) >> 1); + orig_line++; + } + } + } + } + else if (dx == 2) + { /* Vertical & horizontal interpolation */ + tmp_pos = x_pos - 2; + for (i = 0; i < block_size_x; i++) + { + ipos_m2 = iClip3(0, maxold_x, tmp_pos++); + ipos_m1 = iClip3(0, maxold_x, tmp_pos++); + ipos = iClip3(0, maxold_x, tmp_pos++); + ipos_p1 = iClip3(0, maxold_x, tmp_pos++); + ipos_p2 = iClip3(0, maxold_x, tmp_pos++); + ipos_p3 = iClip3(0, maxold_x, tmp_pos ); + tmp_pos -= 4; + + for (j = 0; j < block_size_y + 5; j++) + { + cur_lineY = cur_imgY[iClip3(0,maxold_y,y_pos + j - 2)]; + + tmp_res[j][i] = (cur_lineY[ipos_m2] + cur_lineY[ipos_p3]) * COEF[0]; + tmp_res[j][i] += (cur_lineY[ipos_m1] + cur_lineY[ipos_p2]) * COEF[1]; + tmp_res[j][i] += (cur_lineY[ipos ] + cur_lineY[ipos_p1]) * COEF[2]; + } + } + + for (j = 0; j < block_size_y; j++) + { + x0 = tmp_res[j ]; + x1 = tmp_res[j + 1]; + x2 = tmp_res[j + 2]; + x3 = tmp_res[j + 3]; + x4 = tmp_res[j + 4]; + x5 = tmp_res[j + 5]; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (*x0++ + *x5++) * COEF[0] + + (*x1++ + *x4++) * COEF[1] + + (*x2++ + *x3++) * COEF[2]; + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result+512)>>10)); + } + } + + if ((dy&1) == 1) + { + for (j = 0; j < block_size_y; j++) + { + tmp_line = tmp_res[j + 2 + (dy>>1)]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16) >> 5)) + 1 )>>1); + orig_line++; + } + } + } + } + else if (dy == 2) + { /* Horizontal & vertical interpolation */ + + tmp_pos = y_pos - 2; + for (j = 0; j < block_size_y; j++) + { + p0 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p1 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p2 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p3 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p4 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p5 = cur_imgY[iClip3(0, maxold_y, tmp_pos )]; + + tmp_pos -= 4; + + for (i = 0; i < block_size_x + 5; i++) + { + pres_x = iClip3(0,maxold_x, x_pos + i - 2); + result = (p0[pres_x] + p5[pres_x])*COEF[0] + + (p1[pres_x] + p4[pres_x])*COEF[1] + + (p2[pres_x] + p3[pres_x])*COEF[2]; + tmp_res[j][i] = result; + } + } + + for (j = 0; j < block_size_y; j++) + { + orig_line = block[j]; + tmp_line = tmp_res[j]; + x0 = tmp_res[j]; + x1 = x0 + 1; + x2 = x1 + 1; + x3 = x2 + 1; + x4 = x3 + 1; + x5 = x4 + 1; + + for (i = 0; i < block_size_x; i++) + { + result = (*(x0++) + *(x5++)) * COEF[0] + + (*(x1++) + *(x4++)) * COEF[1] + + (*(x2++) + *(x3++)) * COEF[2]; + + *(orig_line++) = (imgpel) iClip1(max_imgpel_value, ((result + 512)>>10)); + } + } + + if ((dx&1) == 1) + { + for (j = 0; j < block_size_y; j++) + { + tmp_line = &tmp_res[j][2 + (dx>>1)]; + orig_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((*(tmp_line++) + 16)>>5)) + 1)>> 1); + orig_line++; + } + } + } + } + else + { /* Diagonal interpolation */ + tmp_pos = x_pos - 2; + for (i = 0; i < block_size_x; i++) + { + ipos_m2 = iClip3(0, maxold_x, tmp_pos++); + ipos_m1 = iClip3(0, maxold_x, tmp_pos++); + ipos = iClip3(0, maxold_x, tmp_pos++); + ipos_p1 = iClip3(0, maxold_x, tmp_pos++); + ipos_p2 = iClip3(0, maxold_x, tmp_pos++); + ipos_p3 = iClip3(0, maxold_x, tmp_pos ); + tmp_pos -= 4; + + for (j = 0; j < block_size_y; j++) + { + cur_lineY = cur_imgY[iClip3(0,maxold_y,(dy == 1 ? y_pos+j : y_pos+j+1))]; + + result = (cur_lineY[ipos_m2] + cur_lineY[ipos_p3]) * COEF[0]; + result += (cur_lineY[ipos_m1] + cur_lineY[ipos_p2]) * COEF[1]; + result += (cur_lineY[ipos ] + cur_lineY[ipos_p1]) * COEF[2]; + + block[j][i] = (imgpel) iClip1(max_imgpel_value, ((result+16)>>5)); + } + } + + tmp_pos = y_pos - 2; + for (j = 0; j < block_size_y; j++) + { + p0 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p1 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p2 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p3 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p4 = cur_imgY[iClip3(0, maxold_y, tmp_pos++)]; + p5 = cur_imgY[iClip3(0, maxold_y, tmp_pos )]; + + tmp_pos -= 4; + orig_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + pres_x = dx == 1 ? x_pos+i : x_pos+i+1; + pres_x = iClip3(0, maxold_x, pres_x); + + result = (p0[pres_x] + p5[pres_x]) * COEF[0]; + result += (p1[pres_x] + p4[pres_x]) * COEF[1]; + result += (p2[pres_x] + p3[pres_x]) * COEF[2]; + + *orig_line = (imgpel) ((*orig_line + iClip1(max_imgpel_value, ((result+16)>>5)) + 1 ) >> 1); + orig_line++; + } + } + } + } + } +} + +void get_block_chroma(Macroblock *currMB, int decoder, int uv, StorablePicture* dec_picture, StorablePicture *curr_ref, int x_pos, int y_pos, int block_size_x, int block_size_y, imgpel block[MB_BLOCK_SIZE][MB_BLOCK_SIZE]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int subpel_x = p_Vid->mb_cr_size_x == 8 ? 7 : 3; + int subpel_y = p_Vid->mb_cr_size_y == 8 ? 7 : 3; + int shiftpel_x = p_Vid->mb_cr_size_x == 8 ? 3 : 2; + int shiftpel_y = p_Vid->mb_cr_size_y == 8 ? 3 : 2; + int total_scale = shiftpel_x + shiftpel_y; + + int dx = (x_pos & subpel_x); + int dy = (y_pos & subpel_y); + int dxcur = (subpel_x + 1 - dx); + int dycur = (subpel_y + 1 - dy); + + int w00 = dxcur * dycur; + int w01 = dxcur * dy; + int w10 = dx * dycur; + int w11 = dx * dy; + + int i, j; + int maxold_x = dec_picture->size_x_cr - 1; + int maxold_y = (currMB->mb_field) ? (dec_picture->size_y_cr >> 1) - 1 : dec_picture->size_y_cr - 1; + int result; + + imgpel **cur_img, *blk_line; + imgpel *cur_line, *cur_line_p1; + int tmp_pos; + int ipos, ipos_p1; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + cur_img = curr_ref->de_mem->p_dec_img[uv+1][decoder]; + + x_pos = x_pos >> shiftpel_x; + y_pos = y_pos >> shiftpel_y; + + if ((y_pos >= 0) && (y_pos < maxold_y - block_size_y) && (x_pos >= 0) && (x_pos < maxold_x - block_size_x)) + { + if (dx == 0 && dy == 0) + { /* fullpel position */ + for (j = 0; j < block_size_y; j++) + { + memcpy(&(block[j][0]), &(cur_img[ y_pos + j ][x_pos]), block_size_x * sizeof(imgpel)); + } + } + else if (dx == 0) + { + for (j = 0; j < block_size_y; j++) + { + cur_line = &cur_img[y_pos + j ][x_pos]; + cur_line_p1 = &cur_img[y_pos + j + 1][x_pos]; + blk_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *cur_line++ + w01 * *cur_line_p1++); + *(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + } + } + } + else if (dy == 0) + { + for (j = 0; j < block_size_y; j++) + { + cur_line = &cur_img[y_pos + j][x_pos]; + cur_line_p1 = cur_line + 1; + blk_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *cur_line++ + w10 * *cur_line_p1++); + *(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + } + } + } + else + { /* other positions */ + for (j = 0; j < block_size_y; j++) + { + cur_line = &cur_img[y_pos + j ][x_pos]; + cur_line_p1 = &cur_img[y_pos + j + 1][x_pos]; + blk_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + result = (w00 * *(cur_line++) + w01 * *(cur_line_p1++)); + result += (w10 * *(cur_line ) + w11 * *(cur_line_p1 )); + *(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + } + } + } + } + else // unsafe positions + { + if (dx == 0 && dy == 0) + { /* fullpel position */ + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_img[iClip3(0, maxold_y, y_pos + j)]; + blk_line = block[j]; + for (i = 0; i < block_size_x; i++) + { + *(blk_line++) = cur_line[iClip3(0, maxold_x, x_pos + i )]; + } + } + } + else if (dx == 0) + { + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_img[iClip3(0, maxold_y, y_pos + j)]; + cur_line_p1 = cur_img[iClip3(0, maxold_y, y_pos + j + 1)]; + tmp_pos = x_pos; + blk_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + ipos = iClip3(0, maxold_x, tmp_pos++); + + result = (w00 * cur_line[ipos] + w01 * cur_line_p1[ipos]); + *(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + } + } + } + else if (dy == 0) + { + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_img[iClip3(0, maxold_y, y_pos + j)]; + tmp_pos = x_pos; + blk_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + ipos = iClip3(0, maxold_x, tmp_pos++); + ipos_p1 = iClip3(0, maxold_x, tmp_pos ); + + result = (w00 * cur_line[ipos ] + w10 * cur_line[ipos_p1]); + *(blk_line++) = (imgpel)iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + } + } + } + else + { /* other positions */ + for (j = 0; j < block_size_y; j++) + { + cur_line = cur_img[iClip3(0, maxold_y, y_pos + j)]; + cur_line_p1 = cur_img[iClip3(0, maxold_y, y_pos + j + 1)]; + tmp_pos = x_pos; + blk_line = block[j]; + + for (i = 0; i < block_size_x; i++) + { + ipos = iClip3(0, maxold_x, tmp_pos++); + ipos_p1 = iClip3(0, maxold_x, tmp_pos ); + + result = ( + w00 * cur_line [ipos ] + + w10 * cur_line [ipos_p1] + + w01 * cur_line_p1[ipos ] + + w11 * cur_line_p1[ipos_p1]); + *(blk_line++) = (imgpel) iClip1(max_imgpel_value, rshift_rnd_sf(result, total_scale)); + } + } + } + } +} + +#if 0 +void intra_cr_decoding(Macroblock *currMB, int yuv, int smb) +{ + VideoParameters *p_Vid = currMB->p_Vid; + imgpel **curUV, *cur_img; + int (*m7UV)[16], *m7; + int uv; + int b8,b4; + int ioff, joff, ii, jj; + + for(uv = 0; uv < 2; uv++) + { + Boolean lossless_qpprime = (Boolean) ((p_Vid->lossless_qpprime_flag == 1) &&((p_Vid->qp + dec_picture->chroma_qp_offset[uv] + p_Vid->bitdepth_chroma_qp_scale) == 0)); + itrans_4x4 = (!lossless_qpprime) ? itrans4x4 : itrans4x4_ls; + + curUV = dec_picture->imgUV[uv]; + m7UV = p_Vid->currentSlice->mb_rres[uv+1]; + intrapred_chroma(currMB, uv); + + if (!smb && (currMB->cbp >> 4)) + { + for (b8 = 0; b8 < (p_Vid->num_uv_blocks); b8++) + { + for(b4 = 0; b4 < 4; b4++) + { + joff = subblk_offset_y[yuv][b8][b4]; + ioff = subblk_offset_x[yuv][b8][b4]; + + itrans_4x4(p_Vid, (ColorPlane) (uv + 1), ioff, joff); + + for(jj=joff; jjpix_c_y + jj][currMB->pix_c_x + ioff]; + m7 = &m7UV[jj][ioff]; + + for(ii=0; ii<4;ii++) + { + *cur_img++ = (imgpel) *m7++; + } + } + } + } + } + else if ((currMB->cbp >> 4) == 0) + { + for (b8 = 0; b8 < (p_Vid->num_uv_blocks); b8++) + { + for(b4 = 0; b4 < 4; b4++) + { + joff = subblk_offset_y[yuv][b8][b4]; + ioff = subblk_offset_x[yuv][b8][b4]; + + for(jj = joff; jj < 4 + joff;jj++) + memcpy(&(curUV[currMB->pix_c_y + jj][currMB->pix_c_x + ioff]), &(p_Vid->currentSlice->mb_pred[uv + 1][jj][ioff]), BLOCK_SIZE * sizeof(imgpel)); + } + } + } + else + { + itrans_sp_cr(p_Vid, uv); + + for (joff = 0; joff < 8; joff += 4) + { + for(ioff = 0; ioff < 8;ioff+=4) + { + itrans_4x4(p_Vid, (ColorPlane) (uv + 1), ioff, joff); + + for(jj = joff; jj < joff + 4; jj++) + for(ii = ioff; ii < ioff + 4; ii++) + { + curUV[currMB->pix_c_y+jj][ii + currMB->pix_c_x] = (imgpel) p_Vid->currentSlice->mb_rres[uv+1][jj][ii]; + } + } + } + } + } +} + +void prepare_direct_params(Macroblock *currMB, StorablePicture *dec_picture, MotionVector *pmvl0, MotionVector *pmvl1, char *l0_rFrame, char *l1_rFrame) +{ + VideoParameters *p_Vid = currMB->p_Vid; + char l0_rFrameL, l0_rFrameU, l0_rFrameUR; + char l1_rFrameL, l1_rFrameU, l1_rFrameUR; + PicMotionParamsOld *motion = &dec_picture->motion; + + PixelPos mb[4]; + + get_neighbors(currMB, mb, 0, 0, 16); + + if (!p_Vid->mb_aff_frame_flag) + { + l0_rFrameL = (char) (mb[0].available ? dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0] : -1); + l0_rFrameU = (char) (mb[1].available ? dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] : -1); + l0_rFrameUR = (char) (mb[2].available ? dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] : -1); + + l1_rFrameL = (char) (mb[0].available ? dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] : -1); + l1_rFrameU = (char) (mb[1].available ? dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] : -1); + l1_rFrameUR = (char) (mb[2].available ? dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] : -1); + } + else + { + if (currMB->mb_field) + { + l0_rFrameL = (char) (mb[0].available + ? p_Vid->mb_data[mb[0].mb_addr].mb_field || dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0] < 0 + ? dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0] + : dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0] * 2: -1); + + l0_rFrameU = (char) (mb[1].available + ? p_Vid->mb_data[mb[1].mb_addr].mb_field || dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] < 0 + ? dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] + : dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] * 2: -1); + + l0_rFrameUR = (char) (mb[2].available + ? p_Vid->mb_data[mb[2].mb_addr].mb_field || dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] < 0 + ? dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] + : dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] * 2: -1); + + l1_rFrameL = (char) (mb[0].available + ? p_Vid->mb_data[mb[0].mb_addr].mb_field || dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] < 0 + ? dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] + : dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] * 2: -1); + + l1_rFrameU = (char) (mb[1].available + ? p_Vid->mb_data[mb[1].mb_addr].mb_field || dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] < 0 + ? dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] + : dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] * 2: -1); + + l1_rFrameUR = (char) (mb[2].available + ? p_Vid->mb_data[mb[2].mb_addr].mb_field || dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] < 0 + ? dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] + : dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] * 2: -1); + } + else + { + l0_rFrameL = (char) (mb[0].available + ? p_Vid->mb_data[mb[0].mb_addr].mb_field || dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0] < 0 + ? dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0] >> 1 + : dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0]: -1); + + l0_rFrameU = (char) (mb[1].available + ? p_Vid->mb_data[mb[1].mb_addr].mb_field || dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] < 0 + ? dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] >> 1 + : dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0] : -1); + + l0_rFrameUR = (char) (mb[2].available + ? p_Vid->mb_data[mb[2].mb_addr].mb_field || dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] < 0 + ? dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] >> 1 + : dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_0] : -1); + + l1_rFrameL = (char) (mb[0].available + ? p_Vid->mb_data[mb[0].mb_addr].mb_field || dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] < 0 + ? dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] >> 1 + : dec_picture->mv_info[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_1] : -1); + + l1_rFrameU = (char) (mb[1].available + ? p_Vid->mb_data[mb[1].mb_addr].mb_field || dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] < 0 + ? dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] >> 1 + : dec_picture->mv_info[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_1] : -1); + + l1_rFrameUR = (char) (mb[2].available + ? p_Vid->mb_data[mb[2].mb_addr].mb_field || dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] < 0 + ? dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] >> 1 + : dec_picture->mv_info[mb[2].pos_y][mb[2].pos_x].ref_idx[LIST_1] : -1); + } + } + + *l0_rFrame = (char) ((l0_rFrameL >= 0 && l0_rFrameU >= 0) ? imin(l0_rFrameL,l0_rFrameU) : imax(l0_rFrameL,l0_rFrameU)); + *l0_rFrame = (char) ((*l0_rFrame >= 0 && l0_rFrameUR >= 0) ? imin(*l0_rFrame,l0_rFrameUR): imax(*l0_rFrame,l0_rFrameUR)); + + *l1_rFrame = (char) ((l1_rFrameL >= 0 && l1_rFrameU >= 0) ? imin(l1_rFrameL,l1_rFrameU) : imax(l1_rFrameL,l1_rFrameU)); + *l1_rFrame = (char) ((*l1_rFrame >= 0 && l1_rFrameUR >= 0) ? imin(*l1_rFrame,l1_rFrameUR): imax(*l1_rFrame,l1_rFrameUR)); + + if (*l0_rFrame >=0) + currMB->GetMVPredictor (currMB, mb, pmvl0, *l0_rFrame, dec_picture->mv_info, LIST_0, 0, 0, 16, 16); + + if (*l1_rFrame >=0) + currMB->GetMVPredictor (currMB, mb, pmvl1, *l1_rFrame, dec_picture->mv_info, LIST_1, 0, 0, 16, 16); +} + + +static void check_motion_vector_range(VideoParameters *p_Vid, const MotionVector *mv) +{ + if (mv->mv_x > 8191 || mv->mv_x < -8192) + { + fprintf(stdout,"WARNING! Horizontal motion vector %d is out of allowed range {-8192, 8191} in picture %d, macroblock %d\n", mv->mv_x, p_Vid->number, p_Vid->current_mb_nr); + //error("invalid stream: too big horizontal motion vector", 500); + } + + if (mv->mv_y > (p_Vid->max_mb_vmv_r - 1) || mv->mv_y < (-p_Vid->max_mb_vmv_r)) + { + fprintf(stdout,"WARNING! Vertical motion vector %d is out of allowed range {%d, %d} in picture %d, macroblock %d\n", mv->mv_y, (-p_Vid->max_mb_vmv_r), (p_Vid->max_mb_vmv_r - 1), p_Vid->number, p_Vid->current_mb_nr); + //error("invalid stream: too big vertical motion vector", 500); + } +} + +#endif + +void perform_mc(Macroblock* currMB, int decoder, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int l0_mode, int l1_mode, + PicMotionParams **mv_info, int i, int j, int block_size_x, int block_size_y, short bipred_me) +{ + imgpel tmp_block_l0[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; //!< l0 prediction + imgpel tmp_block_l1[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; //!< l1 prediction + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int vec1_x=0, vec1_y=0; + int vec2_x=0, vec2_y=0; + //int vec1_y_cr = 0, vec2_y_cr = 0; + int alpha_l0, alpha_l1, wp_off; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + int apply_weights = ( (p_Vid->active_pps->weighted_pred_flag && (currSlice->slice_type== P_SLICE || currSlice->slice_type == SP_SLICE)) || + (p_Vid->active_pps->weighted_bipred_idc && (currSlice->slice_type== B_SLICE))); + static const int mv_mul = 16; // 4 * 4 + + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int ioff = (i << 2); + int joff = (j << 2); + + assert (pred_dir<=2); + + if (pred_dir != 2) + { + //===== Single List Prediction ===== + short ref_idx = mv_info[j4][i4].ref_idx[pred_dir]; + short ref_idx_wp = ref_idx; + MotionVector **mv_array = currSlice->all_mv[pred_dir][ref_idx][l0_mode]; + StorablePicture **list = currSlice->listX[currMB->list_offset + pred_dir]; + + vec1_x = i4 * mv_mul + mv_array[j][i].mv_x; + vec1_y = j4 * mv_mul + mv_array[j][i].mv_y; + + get_block_luma (currMB, decoder, pl, dec_picture, list[ref_idx], vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0); + + if (apply_weights) + { + if (currMB->mb_field) + { + ref_idx_wp >>=1; + } + alpha_l0 = currSlice->wp_weight[pred_dir][ref_idx_wp][0]; + wp_off = currSlice->wp_offset[pred_dir][ref_idx_wp][0]; + + weighted_mc_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], block_size_y, block_size_x, ioff, tmp_block_l0, alpha_l0, wp_off, currSlice->luma_log_weight_denom, max_imgpel_value); + } + else + { + mc_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], block_size_y, block_size_x, ioff, tmp_block_l0); + } + +#if 0 + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444) ) + { + int uv; + + int ioff_cr = (p_Vid->mb_cr_size_x == MB_BLOCK_SIZE) ? ioff : ioff >> 1; + int joff_cr = (p_Vid->mb_cr_size_y == MB_BLOCK_SIZE) ? joff : joff >> 1; + int block_size_x_cr = p_Vid->mb_cr_size_x == MB_BLOCK_SIZE ? block_size_x : block_size_x >> 1; + int block_size_y_cr = p_Vid->mb_cr_size_y == MB_BLOCK_SIZE ? block_size_y : block_size_y >> 1; + + vec1_y_cr = vec1_y + ((active_sps->chroma_format_idc == 1)? list[ref_idx]->chroma_vector_adjustment : 0); + + for(uv=0;uv<2;uv++) + { + get_block_chroma (currMB, uv, list[ref_idx], vec1_x, vec1_y_cr, block_size_x_cr, block_size_y_cr, tmp_block_l0); + + if (p_Vid->apply_weights) + { + alpha_l0 = p_Vid->wp_weight[pred_dir][ref_idx_wp][uv + 1]; + wp_offset = p_Vid->wp_offset[pred_dir][ref_idx_wp][uv + 1]; + + weighted_mc_prediction(&currSlice->mb_pred[uv + 1][joff_cr], block_size_y_cr, block_size_x_cr, ioff_cr, tmp_block_l0, alpha_l0, wp_offset, p_Vid->chroma_log2_weight_denom, p_Vid->max_pel_value_comp[uv + 1]); + } + else + { + mc_prediction(&currSlice->mb_pred[uv + 1][joff_cr], block_size_y_cr, block_size_x_cr, ioff_cr, tmp_block_l0); + } + } + } +#endif + } + else + { + //===== BI-PREDICTION ===== + short l0_ref = mv_info[j4][i4].ref_idx[LIST_0]; + short l1_ref = mv_info[j4][i4].ref_idx[LIST_1]; + + MotionVector **l0_mv_array = (bipred_me ? currSlice->bipred_mv[bipred_me-1][LIST_0][l0_ref][l0_mode]:currSlice->all_mv[LIST_0][l0_ref][l0_mode]); + MotionVector **l1_mv_array = (bipred_me ? currSlice->bipred_mv[bipred_me-1][LIST_1][l1_ref][l1_mode]:currSlice->all_mv[LIST_1][l1_ref][l1_mode]); + + vec1_x = i4 * mv_mul + l0_mv_array[j][i].mv_x; + vec2_x = i4 * mv_mul + l1_mv_array[j][i].mv_x; + + vec1_y = j4 * mv_mul + l0_mv_array[j][i].mv_y; + vec2_y = j4 * mv_mul + l1_mv_array[j][i].mv_y; + + get_block_luma (currMB, decoder, pl, dec_picture, currSlice->listX[LIST_0 + currMB->list_offset][l0_ref], vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0); + get_block_luma (currMB, decoder, pl, dec_picture, currSlice->listX[LIST_1 + currMB->list_offset][l1_ref], vec2_x, vec2_y, block_size_x, block_size_y, tmp_block_l1); + + if(apply_weights) + { + int wt_list_offset = (p_Vid->active_pps->weighted_bipred_idc==2)? currMB->list_offset : 0; + + // This code existed in the original. Seems pointless but copying it here for reference and in case temporal direct breaks. + // if (mv_mode==0 && p_Vid->direct_spatial_mv_pred_flag==0 ) l1_ref_idx=0; + if (currMB->mb_field) + { + l0_ref >>=1; + l1_ref >>=1; + } + + alpha_l0 = currSlice->wbp_weight[LIST_0 + wt_list_offset][l0_ref][l1_ref][0]; + alpha_l1 = currSlice->wbp_weight[LIST_1 + wt_list_offset][l0_ref][l1_ref][0]; + wp_off = ((currSlice->wp_offset [LIST_0 + wt_list_offset][l0_ref][0] + currSlice->wp_offset[LIST_1 + wt_list_offset][l1_ref][0] + 1) >>1); + + weighted_bi_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], tmp_block_l0, tmp_block_l1, block_size_y, block_size_x, ioff, alpha_l0, alpha_l1, wp_off, (currSlice->luma_log_weight_denom + 1), max_imgpel_value); + } + else + { + bi_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], tmp_block_l0, tmp_block_l1, block_size_y, block_size_x, ioff); + } +#if 0 + if ((dec_picture->chroma_format_idc != YUV400) && (dec_picture->chroma_format_idc != YUV444) ) + { + int uv; + + int ioff_cr = p_Vid->mb_cr_size_x == MB_BLOCK_SIZE ? ioff : ioff >> 1; + int joff_cr = p_Vid->mb_cr_size_y == MB_BLOCK_SIZE ? joff : joff >> 1; + int block_size_x_cr = p_Vid->mb_cr_size_x == MB_BLOCK_SIZE ? block_size_x : block_size_x >> 1; + int block_size_y_cr = p_Vid->mb_cr_size_y == MB_BLOCK_SIZE ? block_size_y : block_size_y >> 1; + + vec1_y_cr = vec1_y + ((active_sps->chroma_format_idc == 1)? currSlice->listX[LIST_0 + list_offset][l0_refframe]->chroma_vector_adjustment : 0); + vec2_y_cr = vec2_y + ((active_sps->chroma_format_idc == 1)? currSlice->listX[LIST_1 + list_offset][l1_refframe]->chroma_vector_adjustment : 0); + + for(uv=0;uv<2;uv++) + { + get_block_chroma (currMB, uv, currSlice->listX[LIST_0 + list_offset][l0_refframe], vec1_x, vec1_y_cr, block_size_x_cr, block_size_y_cr, tmp_block_l0); + get_block_chroma (currMB, uv, currSlice->listX[LIST_1 + list_offset][l1_refframe], vec2_x, vec2_y_cr, block_size_x_cr, block_size_y_cr, tmp_block_l1); + + if(p_Vid->apply_weights) + { + int wt_list_offset = (active_pps->weighted_bipred_idc==2)? list_offset : 0; + + alpha_l0 = p_Vid->wbp_weight[LIST_0 + wt_list_offset][l0_ref_idx][l1_ref_idx][uv + 1]; + alpha_l1 = p_Vid->wbp_weight[LIST_1 + wt_list_offset][l0_ref_idx][l1_ref_idx][uv + 1]; + wp_offset = ((p_Vid->wp_offset [LIST_0 + wt_list_offset][l0_ref_idx][uv + 1] + p_Vid->wp_offset[LIST_1 + wt_list_offset][l1_ref_idx][uv + 1] + 1) >>1); + + weighted_bi_prediction(&currSlice->mb_pred[uv+1][joff_cr], tmp_block_l0, tmp_block_l1, block_size_y_cr, block_size_x_cr, ioff_cr, alpha_l0, alpha_l1, wp_offset, (p_Vid->chroma_log2_weight_denom + 1), p_Vid->max_pel_value_comp[uv + 1]); + } + else + { + bi_prediction(&p_Vid->currentSlice->mb_pred[uv + 1][joff_cr], tmp_block_l0, tmp_block_l1, block_size_y_cr, block_size_x_cr, ioff_cr); + } + } + } +#endif + } +} + +void perform_mc_concealment(Macroblock* currMB, int decoder, ColorPlane pl, StorablePicture *dec_picture, int pred_dir, int l0_mode, int l1_mode, + PicMotionParams **mv_info, int i, int j, int block_size_x, int block_size_y) +{ + imgpel tmp_block_l0[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; //!< l0 prediction + imgpel tmp_block_l1[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; //!< l1 prediction + + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int vec1_x=0, vec1_y=0; + int vec2_x=0, vec2_y=0; + //int vec1_y_cr = 0, vec2_y_cr = 0; + int alpha_l0, alpha_l1, wp_off; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + int apply_weights = ( (p_Vid->active_pps->weighted_pred_flag && (currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE)) || + (p_Vid->active_pps->weighted_bipred_idc && (currSlice->slice_type== B_SLICE))); + static const int mv_mul = 16; // 4 * 4 + + int i4 = currMB->block_x + i; + int j4 = currMB->block_y + j; + int ioff = (i << 2); + int joff = (j << 2); + + assert (pred_dir<=2); + + if (pred_dir != 2) + { + //===== Single List Prediction ===== + short ref_idx = mv_info[j4][i4].ref_idx[pred_dir]; + short ref_idx_wp = ref_idx; + PicMotionParams **motion = dec_picture->mv_info; + //MotionVector **mv_array = dec_picture->motion.mv[pred_dir]; + StorablePicture **list = currSlice->listX[currMB->list_offset + pred_dir]; + + vec1_x = i4 * mv_mul + motion[j4][i4].mv[pred_dir].mv_x; + //vec1_y = (currMB->block_y_aff + j) * mv_mul + mv_array[j4][i4][1]; + vec1_y = j4 * mv_mul + motion[j4][i4].mv[pred_dir].mv_y; + + get_block_luma (currMB, decoder, pl, dec_picture, list[ref_idx], vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0); + + if (apply_weights) + { + if (currMB->mb_field) + { + ref_idx_wp >>=1; + } + alpha_l0 = p_Vid->currentSlice->wp_weight[pred_dir][ref_idx_wp][0]; + wp_off = p_Vid->currentSlice->wp_offset[pred_dir][ref_idx_wp][0]; + + weighted_mc_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], block_size_y, block_size_x, ioff, tmp_block_l0, alpha_l0, wp_off, p_Vid->currentSlice->luma_log_weight_denom, max_imgpel_value); + } + else + { + mc_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], block_size_y, block_size_x, ioff, tmp_block_l0); + } + } + else + { + //===== BI-PREDICTION ===== + short l0_ref = mv_info[j4][i4].ref_idx[LIST_0]; + short l1_ref = mv_info[j4][i4].ref_idx[LIST_1]; + + vec1_x = i4 * mv_mul + dec_picture->mv_info[j4][i4].mv[LIST_0].mv_x; + vec2_x = i4 * mv_mul + dec_picture->mv_info[j4][i4].mv[LIST_1].mv_x; + + vec1_y = j4 * mv_mul + dec_picture->mv_info[j4][i4].mv[LIST_0].mv_y; + vec2_y = j4 * mv_mul + dec_picture->mv_info[j4][i4].mv[LIST_1].mv_y; + + get_block_luma (currMB, decoder, pl, dec_picture, currSlice->listX[LIST_0 + currMB->list_offset][l0_ref], vec1_x, vec1_y, block_size_x, block_size_y, tmp_block_l0); + get_block_luma (currMB, decoder, pl, dec_picture, currSlice->listX[LIST_1 + currMB->list_offset][l1_ref], vec2_x, vec2_y, block_size_x, block_size_y, tmp_block_l1); + + if(apply_weights) + { + int wt_list_offset = (p_Vid->active_pps->weighted_bipred_idc==2)? currMB->list_offset : 0; + + // This code existed in the original. Seems pointless but copying it here for reference and in case temporal direct breaks. + // if (mv_mode==0 && p_Vid->direct_spatial_mv_pred_flag==0 ) l1_ref_idx=0; + if (currMB->mb_field) + { + l0_ref >>=1; + l1_ref >>=1; + } + + alpha_l0 = p_Vid->currentSlice->wbp_weight[LIST_0 + wt_list_offset][l0_ref][l1_ref][0]; + alpha_l1 = p_Vid->currentSlice->wbp_weight[LIST_1 + wt_list_offset][l0_ref][l1_ref][0]; + wp_off = ((p_Vid->currentSlice->wp_offset [LIST_0 + wt_list_offset][l0_ref][0] + p_Vid->currentSlice->wp_offset[LIST_1 + wt_list_offset][l1_ref][0] + 1) >>1); + + weighted_bi_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], tmp_block_l0, tmp_block_l1, block_size_y, block_size_x, ioff, alpha_l0, alpha_l1, wp_off, (p_Vid->currentSlice->luma_log_weight_denom + 1), max_imgpel_value); + } + else + { + bi_prediction(&p_Vid->p_decs->dec_mb_pred[decoder][joff], tmp_block_l0, tmp_block_l1, block_size_y, block_size_x, ioff); + } + } +} diff --git a/lencod/src/loopFilter.c b/lencod/src/loopFilter.c new file mode 100644 index 0000000..2f5cefe --- /dev/null +++ b/lencod/src/loopFilter.c @@ -0,0 +1,294 @@ + +/*! + ************************************************************************************* + * \file loopFilter.c + * + * \brief + * Filter to reduce blocking artifacts on a macroblock level. + * The filter strength is QP dependent. + * + * \author + * Contributors: + * - Peter List Peter.List@t-systems.de: Original code (13-Aug-2001) + * - Jani Lainema Jani.Lainema@nokia.com: Some bug fixing, removal of recursiveness (16-Aug-2001) + * - Peter List Peter.List@t-systems.de: inplace filtering and various simplifications (10-Jan-2002) + * - Anthony Joch anthony@ubvideo.com: Simplified switching between filters and + * non-recursive default filter. (08-Jul-2002) + * - Cristina Gomila cristina.gomila@thomson.net: Simplification of the chroma deblocking + * from JVT-E089 (21-Nov-2002) + * - Alexis Michael Tourapis atour@dolby.com: Speed/Architecture improvements (08-Feb-2007) + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "loop_filter.h" + +extern void set_loop_filter_functions_mbaff (VideoParameters *p_Vid); +extern void set_loop_filter_functions_normal(VideoParameters *p_Vid); + +static void DeblockMb(VideoParameters *p_Vid, imgpel **imgY, imgpel ***imgUV, int MbQAddr); + +static void init_Deblock(VideoParameters *p_Vid) +{ + unsigned int i; + if (p_Vid->mb_aff_frame_flag == 1) + { + set_loop_filter_functions_mbaff(p_Vid); + } + else + { + set_loop_filter_functions_normal(p_Vid); + } + + for (i=0; i < p_Vid->PicSizeInMbs; i++) + { + if (p_Vid->mb_data[i].mb_type==IPCM) + { + p_Vid->mb_data[i].qp = 0; + p_Vid->mb_data[i].qpc[0] = 0; + p_Vid->mb_data[i].qpc[1] = 0; + } + } +} + +#if (JM_PARALLEL_DEBLOCK == 0) +/*! + ***************************************************************************************** + * \brief + * Filter all macroblocks in order of increasing macroblock address. + ***************************************************************************************** + */ +void DeblockFrame(VideoParameters *p_Vid, imgpel **imgY, imgpel ***imgUV) +{ + unsigned int i; + init_Deblock(p_Vid); + for (i=0; i < p_Vid->PicSizeInMbs; i++) + { + DeblockMb( p_Vid, imgY, imgUV, i ) ; + } +} +#else +static void DeblockParallel(VideoParameters *p_Vid, imgpel **imgY, imgpel ***imgUV, unsigned int column, int block, int n_last) +{ + int i, j; + + for (j = 0; j < GROUP_SIZE; j++) + { + i = block++ * (p_Vid->PicWidthInMbs - 2) + column; + + DeblockMb( p_Vid, imgY, imgUV, i ) ; + if (block == n_last) break; + } +} + +/*! + ***************************************************************************************** + * \brief + * Filter all macroblocks in a diagonal manner to enable parallelization. + ***************************************************************************************** + */ +void DeblockFrame(VideoParameters *p_Vid, imgpel **imgY, imgpel ***imgUV) +{ + int iheightMBs =(p_Vid->PicSizeInMbs/p_Vid->PicWidthInMbs); + unsigned int i, k = p_Vid->PicWidthInMbs + 2 * (iheightMBs - 1); + init_Deblock(p_Vid); + + for (i = 0; i < k; i++) + { + int nn; + int n_last = imin(iheightMBs, (i >> 1) + 1); + int n_start = (i < p_Vid->PicWidthInMbs) ? 0 : ((i - p_Vid->PicWidthInMbs) >> 1) + 1; + +#if defined(OPENMP) +#pragma omp parallel for +#endif + for (nn = n_start; nn < n_last; nn += GROUP_SIZE) + DeblockParallel(p_Vid, imgY, imgUV, i, nn, n_last); + } +} +#endif + +/*! + ***************************************************************************************** + * \brief + * Deblocking filter for one macroblock. + ***************************************************************************************** + */ + +static void DeblockMb(VideoParameters *p_Vid, imgpel **imgY, imgpel ***imgUV, int MbQAddr) +{ + int edge; + byte Strength[16]; + + int64 *p_Strength64 = (int64 *) Strength; + short mb_x, mb_y; + + int filterNon8x8LumaEdgesFlag[4] = {1,1,1,1}; + int filterLeftMbEdgeFlag; + int filterTopMbEdgeFlag; + int edge_cr; + Macroblock *MbQ = &(p_Vid->mb_data[MbQAddr]) ; // current Mb + Slice *currSlice = MbQ->p_Slice; + int mvlimit = (p_Vid->structure!=FRAME) || (p_Vid->mb_aff_frame_flag && MbQ->mb_field) ? 2 : 4; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + p_Vid->mixedModeEdgeFlag = 0; + + // return, if filter is disabled + if (MbQ->DFDisableIdc == 1) + { + MbQ->DeblockCall = 0; + return; + } + + MbQ->DeblockCall = 1; + get_mb_pos (p_Vid, MbQAddr, p_Vid->mb_size[IS_LUMA], &mb_x, &mb_y); + + if (MbQ->mb_type == I8MB) + assert(MbQ->luma_transform_size_8x8_flag); + + filterNon8x8LumaEdgesFlag[1] = + filterNon8x8LumaEdgesFlag[3] = !(MbQ->luma_transform_size_8x8_flag); + + filterLeftMbEdgeFlag = (mb_x != 0); + filterTopMbEdgeFlag = (mb_y != 0); + + if (p_Vid->mb_aff_frame_flag && mb_y == MB_BLOCK_SIZE && MbQ->mb_field) + filterTopMbEdgeFlag = 0; + + if (MbQ->DFDisableIdc==2) + { + // don't filter at slice boundaries + filterLeftMbEdgeFlag = MbQ->mbAvailA; + // if this the bottom of a frame macroblock pair then always filter the top edge + filterTopMbEdgeFlag = (p_Vid->mb_aff_frame_flag && !MbQ->mb_field && (MbQAddr & 0x01)) ? 1 : MbQ->mbAvailB; + } + + CheckAvailabilityOfNeighbors(MbQ); + + // Vertical deblocking + for (edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc!=YUV444) + continue; + else if (edge > 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if ((MbQ->mb_type == 0 && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == 1) || (MbQ->mb_type == 2)) + continue; + else if ((edge & 0x01) && ((MbQ->mb_type == 3) || ((edge & 0x01) && MbQ->mb_type == 0 && currSlice->slice_type == B_SLICE && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterLeftMbEdgeFlag ) + { + // Strength for 4 blks in 1 stripe + p_Vid->GetStrengthVer(Strength, MbQ, edge << 2, mvlimit); // Strength for 4 blks in 1 stripe + + if ((p_Strength64[0]) || (p_Strength64[1])) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaVer( PLANE_Y, imgY, Strength, MbQ, edge << 2) ; + if (p_Vid->P444_joined) + { + p_Vid->EdgeLoopLumaVer(PLANE_U, imgUV[0], Strength, MbQ, edge << 2); + p_Vid->EdgeLoopLumaVer(PLANE_V, imgUV[1], Strength, MbQ, edge << 2); + } + } + if(p_Vid->yuv_format==YUV420 || p_Vid->yuv_format==YUV422 ) + { + edge_cr = chroma_edge[0][edge][p_Vid->yuv_format]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaVer( imgUV[0], Strength, MbQ, edge_cr, 0); + p_Vid->EdgeLoopChromaVer( imgUV[1], Strength, MbQ, edge_cr, 1); + } + } + } + } + }//end edge + + // horizontal deblocking + for( edge = 0; edge < 4 ; ++edge ) + { + // If cbp == 0 then deblocking for some macroblock types could be skipped + if (MbQ->cbp == 0) + { + if (filterNon8x8LumaEdgesFlag[edge] == 0 && active_sps->chroma_format_idc==YUV420) + continue; + else if (edge > 0 && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + if (((MbQ->mb_type == PSKIP && currSlice->slice_type == P_SLICE) || (MbQ->mb_type == P16x16) || (MbQ->mb_type == P8x16))) + continue; + else if ((edge & 0x01) && (( MbQ->mb_type == P16x8) || (currSlice->slice_type == B_SLICE && MbQ->mb_type == BSKIP_DIRECT && active_sps->direct_8x8_inference_flag))) + continue; + } + } + + if( edge || filterTopMbEdgeFlag ) + { + // Strength for 4 blks in 1 stripe + p_Vid->GetStrengthHor(Strength, MbQ, edge << 2, mvlimit); + + if ((p_Strength64[0]) || (p_Strength64[1])) // only if one of the 16 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaHor( PLANE_Y, imgY, Strength, MbQ, edge << 2, p_Vid->width_padded) ; + if (p_Vid->P444_joined) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, edge << 2, p_Vid->width_padded); + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, edge << 2, p_Vid->width_padded); + } + } + if(p_Vid->yuv_format==YUV420 || p_Vid->yuv_format==YUV422 ) + { + edge_cr = chroma_edge[1][edge][p_Vid->yuv_format]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, edge_cr, p_Vid->width_cr + p_Vid->pad_size_uv_x * 2, 0); + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, edge_cr, p_Vid->width_cr + p_Vid->pad_size_uv_x * 2, 1); + } + } + } + + if (!edge && !MbQ->mb_field && p_Vid->mixedModeEdgeFlag) + { + // this is the extra horizontal edge between a frame macroblock pair and a field above it + MbQ->DeblockCall = 2; + p_Vid->GetStrengthHor(Strength, MbQ, MB_BLOCK_SIZE, mvlimit); // Strength for 4 blks in 1 stripe + //if( *((int*)Strength) ) // only if one of the 4 Strength bytes is != 0 + { + if (filterNon8x8LumaEdgesFlag[edge]) + { + p_Vid->EdgeLoopLumaHor( PLANE_Y, imgY, Strength, MbQ, MB_BLOCK_SIZE, p_Vid->width_padded) ; + if (p_Vid->P444_joined) + { + p_Vid->EdgeLoopLumaHor(PLANE_U, imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, p_Vid->width_padded) ; + p_Vid->EdgeLoopLumaHor(PLANE_V, imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, p_Vid->width_padded) ; + } + } + if( p_Vid->yuv_format == YUV420 || p_Vid->yuv_format==YUV422 ) + { + edge_cr = chroma_edge[1][edge][p_Vid->yuv_format]; + if( (imgUV != NULL) && (edge_cr >= 0)) + { + p_Vid->EdgeLoopChromaHor( imgUV[0], Strength, MbQ, MB_BLOCK_SIZE, p_Vid->width_cr+p_Vid->pad_size_uv_x*2, 0) ; + p_Vid->EdgeLoopChromaHor( imgUV[1], Strength, MbQ, MB_BLOCK_SIZE, p_Vid->width_cr+p_Vid->pad_size_uv_x*2, 1) ; + } + } + } + MbQ->DeblockCall = 1; + } + } + }//end edge + + MbQ->DeblockCall = 0; +} + + diff --git a/lencod/src/loop_filter_mbaff.c b/lencod/src/loop_filter_mbaff.c new file mode 100644 index 0000000..77d312a --- /dev/null +++ b/lencod/src/loop_filter_mbaff.c @@ -0,0 +1,709 @@ + +/*! + ************************************************************************************* + * \file loop_filter_mbaff.c + * + * \brief + * Loop Filter to reduce blocking artifacts on a macroblock level (MBAFF). + * The filter strength is QP dependent. + * + * \author + * Contributors: + * - Peter List Peter.List@t-systems.de: Original code (13-Aug-2001) + * - Jani Lainema Jani.Lainema@nokia.com: Some bug fixing, removal of recursiveness (16-Aug-2001) + * - Peter List Peter.List@t-systems.de: inplace filtering and various simplifications (10-Jan-2002) + * - Anthony Joch anthony@ubvideo.com: Simplified switching between filters and + * non-recursive default filter. (08-Jul-2002) + * - Cristina Gomila cristina.gomila@thomson.net: Simplification of the chroma deblocking + * from JVT-E089 (21-Nov-2002) + * - Alexis Michael Tourapis atour@dolby.com: Speed/Architecture improvements (08-Feb-2007) + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "loop_filter.h" + + + +static void get_strength_ver_MBAff (byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit); +static void get_strength_hor_MBAff (byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit); +static void edge_loop_luma_ver_MBAff (ColorPlane pl, imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge); +static void edge_loop_luma_hor_MBAff (ColorPlane pl, imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int width); +static void edge_loop_chroma_ver_MBAff (imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int uv); +static void edge_loop_chroma_hor_MBAff (imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int width, int uv); + + +void set_loop_filter_functions_mbaff(VideoParameters *p_Vid) +{ + p_Vid->GetStrengthVer = get_strength_ver_MBAff; + p_Vid->GetStrengthHor = get_strength_hor_MBAff; + p_Vid->EdgeLoopLumaVer = edge_loop_luma_ver_MBAff; + p_Vid->EdgeLoopLumaHor = edge_loop_luma_hor_MBAff; + p_Vid->EdgeLoopChromaVer = edge_loop_chroma_ver_MBAff; + p_Vid->EdgeLoopChromaHor = edge_loop_chroma_hor_MBAff; +} + +/*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for MBAFF) + ********************************************************************************************* + */ +static void get_strength_ver_MBAff(byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit) +{ + short blkP, blkQ, idx; + short blk_x, blk_x2, blk_y, blk_y2 ; + + int xQ, yQ; + short mb_x, mb_y; + + Macroblock *MbP; + + PixelPos pixP; + VideoParameters *p_Vid = MbQ->p_Vid; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + + for( idx = 0; idx < 16; ++idx ) + { + xQ = edge; + yQ = idx; + p_Vid->getNeighbour(MbQ, xQ - 1, yQ, p_Vid->mb_size[IS_LUMA], &pixP); + blkQ = (short) ((yQ & 0xFFFC) + (xQ >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + p_Vid->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + + if (p_Vid->type==SP_SLICE || p_Vid->type==SI_SLICE) + { + Strength[idx] = (edge == 0) ? 4 : 3; + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + Strength[idx] = (edge == 0) ? 4 : 3; + + if( !(MbP->mb_type==I4MB || MbP->mb_type==I16MB || MbP->mb_type==I8MB || MbP->mb_type==IPCM) + && !(MbQ->mb_type==I4MB || MbQ->mb_type==I16MB || MbQ->mb_type==I8MB || MbQ->mb_type==IPCM) ) + { + if( ((MbQ->cbp_blk & ((int64)1 << blkQ )) != 0) || ((MbP->cbp_blk & ((int64)1 << blkP)) != 0) ) + Strength[idx] = 2 ; + else + { + // if no coefs, but vector difference >= 1 set Strength=1 + // if this is a mixed mode edge then one set of reference pictures will be frame and the + // other will be field + if (p_Vid->mixedModeEdgeFlag) + { + (Strength[idx] = 1); + } + else + { + p_Vid->get_mb_block_pos (p_Vid->PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + blk_y = (short) ((mb_y<<2) + (blkQ >> 2)); + blk_x = (short) ((mb_x<<2) + (blkQ & 3)); + blk_y2 = (short) (pixP.pos_y >> 2); + blk_x2 = (short) (pixP.pos_x >> 2); + { + PicMotionParams *mv_info_p = &mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &mv_info[blk_y2][blk_x2]; + + StorablePicturePtr ref_p0 = mv_info_p->ref_idx[LIST_0] == -1 ? NULL : mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_idx[LIST_0] == -1 ? NULL : mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_idx[LIST_1] == -1 ? NULL : mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_idx[LIST_1] == -1 ? NULL : mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || + ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + Strength[idx]=0; + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0==ref_q0) + { + Strength[idx] = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)); + } + else + { + Strength[idx] = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit)); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + + Strength[idx] = (byte) (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + &&( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit))); + } + } + else + { + Strength[idx] = 1; + } + } + } + } + } + } + } +} + +/*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for MBAFF) + ********************************************************************************************* + */ +static void get_strength_hor_MBAff(byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit) +{ + short blkP, blkQ, idx; + short blk_x, blk_x2, blk_y, blk_y2 ; + + int xQ, yQ; + short mb_x, mb_y; + + Macroblock *MbP; + + PixelPos pixP; + VideoParameters *p_Vid = MbQ->p_Vid; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + + + for( idx = 0; idx < 16; ++idx ) + { + xQ = idx; + yQ = (edge < MB_BLOCK_SIZE ? edge : 1); + p_Vid->getNeighbour(MbQ, xQ, yQ - 1, p_Vid->mb_size[IS_LUMA], &pixP); + blkQ = (short) ((yQ & 0xFFFC) + (xQ >> 2)); + blkP = (short) ((pixP.y & 0xFFFC) + (pixP.x >> 2)); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + p_Vid->mixedModeEdgeFlag = (byte) (MbQ->mb_field != MbP->mb_field); + + if (p_Vid->type==SP_SLICE || p_Vid->type==SI_SLICE) + { + Strength[idx] = (edge == 0 && (((!p_Vid->mb_aff_frame_flag && (p_Vid->structure==FRAME)) || + (p_Vid->mb_aff_frame_flag && !MbP->mb_field && !MbQ->mb_field)))) ? 4 : 3; + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + Strength[idx] = (edge == 0 && (((!p_Vid->mb_aff_frame_flag && (p_Vid->structure==FRAME)) || + (p_Vid->mb_aff_frame_flag && !MbP->mb_field && !MbQ->mb_field)))) ? 4 : 3; + + if( !(MbP->mb_type==I4MB || MbP->mb_type==I16MB || MbP->mb_type==I8MB || MbP->mb_type==IPCM) + && !(MbQ->mb_type==I4MB || MbQ->mb_type==I16MB || MbQ->mb_type==I8MB || MbQ->mb_type==IPCM) ) + { + if( ((MbQ->cbp_blk & ((int64)1 << blkQ )) != 0) || ((MbP->cbp_blk & ((int64)1 << blkP)) != 0) ) + Strength[idx] = 2 ; + else + { + // if no coefs, but vector difference >= 1 set Strength=1 + // if this is a mixed mode edge then one set of reference pictures will be frame and the + // other will be field + if (p_Vid->mixedModeEdgeFlag) + { + (Strength[idx] = 1); + } + else + { + p_Vid->get_mb_block_pos (p_Vid->PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + blk_y = (short) ((mb_y<<2) + (blkQ >> 2)); + blk_x = (short) ((mb_x<<2) + (blkQ & 3)); + blk_y2 = (short) (pixP.pos_y >> 2); + blk_x2 = (short) (pixP.pos_x >> 2); + { + PicMotionParams *mv_info_p = &mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &mv_info[blk_y2][blk_x2]; + + StorablePicturePtr ref_p0 = mv_info_p->ref_idx[LIST_0] == -1 ? NULL : mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_idx[LIST_0] == -1 ? NULL : mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_idx[LIST_1] == -1 ? NULL : mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_idx[LIST_1] == -1 ? NULL : mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || + ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + Strength[idx]=0; + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0==ref_q0) + { + Strength[idx] = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)); + } + else + { + Strength[idx] = (byte) ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit)); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + + Strength[idx] = (byte) (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + &&( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) || + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit))); + } + } + else + { + Strength[idx] = 1; + } + } + } + } + } + } + } +} + + + + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Super MB Frame coded MBs + ***************************************************************************************** + */ +static void edge_loop_luma_ver_MBAff(ColorPlane pl, imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge) +{ + int pel, ap = 0, aq = 0, Strng ; + int C0, tc0, dif; + imgpel L2 = 0, L1, L0, R0, R1, R2 = 0, L3, R3; + int RL0; + int Alpha = 0, Beta = 0 ; + const byte* ClipTab = NULL; + int small_gap; + int indexA, indexB; + + int QP; + int xQ, yQ; + + PixelPos pixP, pixQ; + + VideoParameters *p_Vid = MbQ->p_Vid; + int bitdepth_scale = pl? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + + Macroblock *MbP; + imgpel *SrcPtrP, *SrcPtrQ; + + for( pel = 0 ; pel < MB_BLOCK_SIZE ; ++pel ) + { + xQ = edge; + yQ = pel; + p_Vid->getNeighbour(MbQ, xQ - 1, yQ, p_Vid->mb_size[IS_LUMA], &pixP); + + if (pixP.available || (MbQ->DFDisableIdc== 0)) + { + if( (Strng = Strength[pel]) != 0) + { + p_Vid->getNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_LUMA], &pixQ); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + + SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + // Average QP of the two blocks + QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + Beta = BETA_TABLE [indexB] * bitdepth_scale; + ClipTab = CLIP_TAB[indexA]; + + L3 = SrcPtrP[-3]; + L2 = SrcPtrP[-2]; + L1 = SrcPtrP[-1]; + L0 = SrcPtrP[0] ; + R0 = SrcPtrQ[0] ; + R1 = SrcPtrQ[ 1]; + R2 = SrcPtrQ[ 2]; + R3 = SrcPtrQ[ 3]; + + if( iabs( R0 - L0 ) < Alpha ) + { + if ((iabs( R0 - R1) < Beta ) && (iabs(L0 - L1) < Beta )) + { + if(Strng == 4 ) // INTRA strong filtering + { + RL0 = L0 + R0; + small_gap = (iabs( R0 - L0 ) < ((Alpha >> 2) + 2)); + aq = ( iabs( R0 - R2) < Beta ) & small_gap; + ap = ( iabs( L0 - L2) < Beta ) & small_gap; + + if (ap) + { + SrcPtrP[-2 ] = (imgpel) ((((L3 + L2) << 1) + L2 + L1 + RL0 + 4) >> 3); + SrcPtrP[-1 ] = (imgpel) (( L2 + L1 + L0 + R0 + 2) >> 2); + SrcPtrP[ 0 ] = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + } + else + { + SrcPtrP[ 0 ] = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2) ; + } + + if (aq) + { + SrcPtrQ[ 0 ] = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + SrcPtrQ[ 1 ] = (imgpel) (( R2 + R0 + R1 + L0 + 2) >> 2); + SrcPtrQ[ 2 ] = (imgpel) ((((R3 + R2) << 1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + SrcPtrQ[ 0 ] = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + else // normal filtering + { + RL0 = (L0 + R0 + 1) >> 1; + aq = (iabs( R0 - R2) < Beta); + ap = (iabs( L0 - L2) < Beta); + + C0 = ClipTab[ Strng ] * bitdepth_scale; + tc0 = (C0 + ap + aq) ; + dif = iClip3( -tc0, tc0, (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3) ; + + if( ap ) + *(SrcPtrP - 1) += iClip3( -C0, C0, ( L2 + RL0 - (L1 << 1)) >> 1 ) ; + + *SrcPtrP = (imgpel) iClip1 (max_imgpel_value, L0 + dif) ; + *SrcPtrQ = (imgpel) iClip1 (max_imgpel_value, R0 - dif) ; + + if( aq ) + *(SrcPtrQ + 1) += iClip3( -C0, C0, ( R2 + RL0 - (R1 << 1)) >> 1 ) ; + } + } + } + } + } + } +} + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Super MB Frame coded MBs + ***************************************************************************************** + */ +static void edge_loop_luma_hor_MBAff(ColorPlane pl, imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge, int width) +{ + int pel, ap = 0, aq = 0, Strng ; + int incP, incQ; + int C0, tc0, dif; + imgpel L2 = 0, L1, L0, R0, R1, R2 = 0, L3, R3; + int RL0; + int Alpha = 0, Beta = 0 ; + const byte* ClipTab = NULL; + int small_gap; + int indexA, indexB; + + int QP; + int xQ, yQ; + + PixelPos pixP, pixQ; + VideoParameters *p_Vid = MbQ->p_Vid; + int bitdepth_scale = pl? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + + Macroblock *MbP; + imgpel *SrcPtrP, *SrcPtrQ; + + for( pel = 0 ; pel < MB_BLOCK_SIZE ; ++pel ) + { + xQ = pel; + yQ = (edge < 16 ? edge : 1); + p_Vid->getNeighbour(MbQ, xQ, yQ - 1, p_Vid->mb_size[IS_LUMA], &pixP); + + if (pixP.available || (MbQ->DFDisableIdc== 0)) + { + if( (Strng = Strength[pel]) != 0) + { + p_Vid->getNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_LUMA], &pixQ); + + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + + incQ = ((MbP->mb_field && !MbQ->mb_field) ? 2 * width : width); + incP = ((MbQ->mb_field && !MbP->mb_field) ? 2 * width : width); + SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + // Average QP of the two blocks + QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + Beta = BETA_TABLE [indexB] * bitdepth_scale; + ClipTab = CLIP_TAB[indexA]; + + L3 = SrcPtrP[-incP*3]; + L2 = SrcPtrP[-incP*2]; + L1 = SrcPtrP[-incP]; + L0 = SrcPtrP[0] ; + R0 = SrcPtrQ[0] ; + R1 = SrcPtrQ[ incQ]; + R2 = SrcPtrQ[ incQ*2]; + R3 = SrcPtrQ[ incQ*3]; + + if( iabs( R0 - L0 ) < Alpha ) + { + if ((iabs( R0 - R1) < Beta ) && (iabs(L0 - L1) < Beta )) + { + if(Strng == 4 ) // INTRA strong filtering + { + RL0 = L0 + R0; + small_gap = (iabs( R0 - L0 ) < ((Alpha >> 2) + 2)); + aq = ( iabs( R0 - R2) < Beta ) & small_gap; + ap = ( iabs( L0 - L2) < Beta ) & small_gap; + + if (ap) + { + SrcPtrP[-incP * 2] = (imgpel) ((((L3 + L2) << 1) + L2 + L1 + RL0 + 4) >> 3); + SrcPtrP[-incP ] = (imgpel) (( L2 + L1 + L0 + R0 + 2) >> 2); + SrcPtrP[ 0 ] = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + } + else + { + SrcPtrP[ 0 ] = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2) ; + } + + if (aq) + { + SrcPtrQ[ 0 ] = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + SrcPtrQ[ incQ ] = (imgpel) (( R2 + R0 + R1 + L0 + 2) >> 2); + SrcPtrQ[ incQ * 2 ] = (imgpel) ((((R3 + R2) << 1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + SrcPtrQ[ 0 ] = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + else // normal filtering + { + RL0 = (L0 + R0 + 1) >> 1; + aq = (iabs( R0 - R2) < Beta); + ap = (iabs( L0 - L2) < Beta); + + C0 = ClipTab[ Strng ] * bitdepth_scale; + tc0 = (C0 + ap + aq) ; + dif = iClip3( -tc0, tc0, (((R0 - L0) << 2) + (L1 - R1) + 4) >> 3) ; + + if( ap ) + *(SrcPtrP - incP) += iClip3( -C0, C0, ( L2 + RL0 - (L1 << 1)) >> 1 ) ; + + *SrcPtrP = (imgpel) iClip1 (max_imgpel_value, L0 + dif) ; + *SrcPtrQ = (imgpel) iClip1 (max_imgpel_value, R0 - dif) ; + + if( aq ) + *(SrcPtrQ + incQ) += iClip3( -C0, C0, ( R2 + RL0 - (R1 << 1)) >> 1 ) ; + } + } + } + } + } + } +} + +/*! +***************************************************************************************** +* \brief +* Filters chroma block edge for MBAFF types +***************************************************************************************** + */ +static void edge_loop_chroma_ver_MBAff(imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge, int uv) +{ + int pel, Strng ; + int C0, tc0, dif; + imgpel L1, L0, R0, R1; + int Alpha = 0, Beta = 0; + const byte* ClipTab = NULL; + int indexA, indexB; + VideoParameters *p_Vid = MbQ->p_Vid; + int PelNum = pelnum_cr[0][p_Vid->yuv_format]; + int StrengthIdx; + int QP; + int xQ, yQ; + PixelPos pixP, pixQ; + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + Macroblock *MbP; + imgpel *SrcPtrP, *SrcPtrQ; + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + xQ = edge; + yQ = pel; + p_Vid->getNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_CHROMA], &pixQ); + p_Vid->getNeighbour(MbQ, xQ - 1, yQ, p_Vid->mb_size[IS_CHROMA], &pixP); + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + StrengthIdx = (PelNum == 8) ? ((MbQ->mb_field && !MbP->mb_field) ? pel << 1 :((pel >> 1) << 2) + (pel & 0x01)) : pel; + + if (pixP.available || (MbQ->DFDisableIdc == 0)) + { + if( (Strng = Strength[StrengthIdx]) != 0) + { + SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + // Average QP of the two blocks + QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + Beta = BETA_TABLE [indexB] * bitdepth_scale; + ClipTab = CLIP_TAB[indexA]; + + L1 = SrcPtrP[-1]; + L0 = SrcPtrP[0] ; + R0 = SrcPtrQ[0] ; + R1 = SrcPtrQ[ 1]; + + if( iabs( R0 - L0 ) < Alpha ) + { + if( ((iabs( R0 - R1) - Beta < 0) && (iabs(L0 - L1) - Beta < 0 )) ) + { + if( Strng == 4 ) // INTRA strong filtering + { + SrcPtrQ[0] = (imgpel) ( ((R1 << 1) + R0 + L1 + 2) >> 2 ); + SrcPtrP[0] = (imgpel) ( ((L1 << 1) + L0 + R1 + 2) >> 2 ); + } + else + { + C0 = ClipTab[ Strng ] * bitdepth_scale; + tc0 = (C0 + 1); + dif = iClip3( -tc0, tc0, ( ((R0 - L0) << 2) + (L1 - R1) + 4) >> 3 ); + + SrcPtrP[0] = (imgpel) iClip1 ( max_imgpel_value, L0 + dif ); + SrcPtrQ[0] = (imgpel) iClip1 ( max_imgpel_value, R0 - dif ); + } + } + } + } + } + } +} + +/*! +***************************************************************************************** +* \brief +* Filters chroma block edge for MBAFF types +***************************************************************************************** + */ +static void edge_loop_chroma_hor_MBAff(imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge, int width, int uv) +{ + int pel, Strng ; + int incP, incQ; + int C0, tc0, dif; + imgpel L1, L0, R0, R1; + int Alpha = 0, Beta = 0; + const byte* ClipTab = NULL; + int indexA, indexB; + VideoParameters *p_Vid = MbQ->p_Vid; + int PelNum = pelnum_cr[1][p_Vid->yuv_format]; + int StrengthIdx; + int QP; + int xQ, yQ; + PixelPos pixP, pixQ; + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + Macroblock *MbP; + imgpel *SrcPtrP, *SrcPtrQ; + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + xQ = pel; + yQ = (edge < 16? edge : 1); + p_Vid->getNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_CHROMA], &pixQ); + p_Vid->getNeighbour(MbQ, xQ, yQ - 1, p_Vid->mb_size[IS_CHROMA], &pixP); + MbP = &(p_Vid->mb_data[pixP.mb_addr]); + StrengthIdx = (PelNum == 8) ? ((MbQ->mb_field && !MbP->mb_field) ? pel << 1 :((pel >> 1) << 2) + (pel & 0x01)) : pel; + + if (pixP.available || (MbQ->DFDisableIdc == 0)) + { + if( (Strng = Strength[StrengthIdx]) != 0) + { + incQ = ((MbP->mb_field && !MbQ->mb_field) ? 2 * width : width); + incP = ((MbQ->mb_field && !MbP->mb_field) ? 2 * width : width); + SrcPtrQ = &(Img[pixQ.pos_y][pixQ.pos_x]); + SrcPtrP = &(Img[pixP.pos_y][pixP.pos_x]); + + // Average QP of the two blocks + QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + Beta = BETA_TABLE [indexB] * bitdepth_scale; + ClipTab = CLIP_TAB[indexA]; + + L1 = SrcPtrP[-incP]; + L0 = SrcPtrP[0] ; + R0 = SrcPtrQ[0] ; + R1 = SrcPtrQ[ incQ]; + + if( iabs( R0 - L0 ) < Alpha ) + { + if( ((iabs( R0 - R1) - Beta < 0) && (iabs(L0 - L1) - Beta < 0 )) ) + { + if( Strng == 4 ) // INTRA strong filtering + { + SrcPtrQ[0] = (imgpel) ( ((R1 << 1) + R0 + L1 + 2) >> 2 ); + SrcPtrP[0] = (imgpel) ( ((L1 << 1) + L0 + R1 + 2) >> 2 ); + } + else + { + C0 = ClipTab[ Strng ] * bitdepth_scale; + tc0 = (C0 + 1); + dif = iClip3( -tc0, tc0, ( ((R0 - L0) << 2) + (L1 - R1) + 4) >> 3 ); + + SrcPtrP[0] = (imgpel) iClip1 ( max_imgpel_value, L0 + dif ); + SrcPtrQ[0] = (imgpel) iClip1 ( max_imgpel_value, R0 - dif ); + } + } + } + } + } + } +} + + diff --git a/lencod/src/loop_filter_normal.c b/lencod/src/loop_filter_normal.c new file mode 100644 index 0000000..40a6487 --- /dev/null +++ b/lencod/src/loop_filter_normal.c @@ -0,0 +1,758 @@ + +/*! + ************************************************************************************* + * \file loop_filter_normal.c + * + * \brief + * Loop filter to reduce blocking artifacts on a macroblock level (normal). + * The filter strength is QP dependent. + * + * \author + * Contributors: + * - Peter List Peter.List@t-systems.de: Original code (13-Aug-2001) + * - Jani Lainema Jani.Lainema@nokia.com: Some bug fixing, removal of recursiveness (16-Aug-2001) + * - Peter List Peter.List@t-systems.de: inplace filtering and various simplifications (10-Jan-2002) + * - Anthony Joch anthony@ubvideo.com: Simplified switching between filters and + * non-recursive default filter. (08-Jul-2002) + * - Cristina Gomila cristina.gomila@thomson.net: Simplification of the chroma deblocking + * from JVT-E089 (21-Nov-2002) + * - Alexis Michael Tourapis atour@dolby.com: Speed/Architecture improvements (08-Feb-2007) + ************************************************************************************* + */ + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "loop_filter.h" + +static void GetStrengthVer (byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit); +static void GetStrengthHor (byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit); +static void EdgeLoopLumaVer (ColorPlane pl, imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge); +static void EdgeLoopLumaHor (ColorPlane pl, imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int width); +static void EdgeLoopChromaVer (imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int uv); +static void EdgeLoopChromaHor (imgpel** Img, byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int width, int uv); + + +void set_loop_filter_functions_normal(VideoParameters *p_Vid) +{ + p_Vid->GetStrengthVer = GetStrengthVer; + p_Vid->GetStrengthHor = GetStrengthHor; + p_Vid->EdgeLoopLumaVer = EdgeLoopLumaVer; + p_Vid->EdgeLoopLumaHor = EdgeLoopLumaHor; + p_Vid->EdgeLoopChromaVer = EdgeLoopChromaVer; + p_Vid->EdgeLoopChromaHor = EdgeLoopChromaHor; +} + + /*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for different Frame or Field types) + ********************************************************************************************* + */ +static void GetStrengthVer(byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + Slice *currSlice = MbQ->p_Slice; + int StrValue; + + if ((currSlice->slice_type==SP_SLICE)||(currSlice->slice_type==SI_SLICE) ) + { + // Set strength to either 3 or 4 regardless of pixel position + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + else + { + if (!(MbQ->mb_type==I4MB||MbQ->mb_type==I8MB||MbQ->mb_type==I16MB||MbQ->mb_type==IPCM)) + { + PixelPos pixMB; + Macroblock *MbP; + int xQ = edge - 1; + + getNonAffNeighbour(MbQ, xQ, 0, p_Vid->mb_size[IS_LUMA], &pixMB); + MbP = (edge) ? MbQ : &(p_Vid->mb_data[pixMB.mb_addr]); + + if (!(MbP->mb_type==I4MB||MbP->mb_type==I8MB||MbP->mb_type==I16MB||MbP->mb_type==IPCM)) + { + PixelPos pixP = pixMB; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + + int blkP, blkQ, idx; + + short mb_x, mb_y; + + get_mb_block_pos_normal (p_Vid->PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + mb_x <<= 2; + mb_y <<= 2; + + xQ ++; + + for( idx = 0 ; idx < MB_BLOCK_SIZE ; idx += BLOCK_SIZE ) + { + pixP.y = (short) (pixMB.y + idx); + pixP.pos_y = (short) (pixMB.pos_y + idx); + + blkQ = (idx & 0xFFFC) + (xQ >> 2); + blkP = (pixP.y & 0xFFFC) + (pixP.x >> 2); + + if (((MbQ->cbp_blk & i64_power2(blkQ)) != 0) || ((MbP->cbp_blk & i64_power2(blkP)) != 0)) + StrValue = 2; + else if (edge && ((MbQ->mb_type == 1) || (MbQ->mb_type == 2))) + StrValue = 0; // if internal edge of certain types, we already know StrValue should be 0 + else // for everything else, if no coefs, but vector difference >= 1 set Strength=1 + { + int blk_y = mb_y + (blkQ >> 2); + int blk_x = mb_x + (blkQ & 3); + int blk_y2 = pixP.pos_y >> 2; + int blk_x2 = pixP.pos_x >> 2; + + PicMotionParams *mv_info_p = &mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &mv_info[blk_y2][blk_x2]; + + StorablePicturePtr ref_p0 = mv_info_p->ref_idx[LIST_0] == -1 ? NULL : mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_idx[LIST_0] == -1 ? NULL : mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_idx[LIST_1] == -1 ? NULL : mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_idx[LIST_1] == -1 ? NULL : mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0 == ref_q0) + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit); + } + else + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + StrValue = (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + && ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit) + )); + } + } + else + StrValue = 1; + } + + //*(int*)(Strength+idx) = (StrValue<<24)|(StrValue<<16)|(StrValue<<8)|StrValue; + *(int*)(Strength+idx) = StrValue * 0x01010101; + } + } + else + { + // Start with Strength=3 or Strength=4 for Mb-edge + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + } +} + + /*! + ********************************************************************************************* + * \brief + * returns a buffer of 16 Strength values for one stripe in a mb (for different Frame or Field types) + ********************************************************************************************* + */ +static void GetStrengthHor(byte Strength[MB_BLOCK_SIZE], Macroblock *MbQ, int edge, int mvlimit) +{ + int StrValue; + Slice *currSlice = MbQ->p_Slice; + VideoParameters *p_Vid = MbQ->p_Vid; + + if ((currSlice->slice_type==SP_SLICE)||(currSlice->slice_type==SI_SLICE) ) + { + // Set strength to either 3 or 4 regardless of pixel position + StrValue = (edge == 0 && (p_Vid->structure == FRAME)) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + else + { + if (!(MbQ->mb_type==I4MB||MbQ->mb_type==I8MB||MbQ->mb_type==I16MB||MbQ->mb_type==IPCM)) + { + PixelPos pixMB; + Macroblock *MbP; + int yQ = (edge < 16 ? edge - 1: 0); + + getNonAffNeighbour(MbQ, 0, yQ, p_Vid->mb_size[IS_LUMA], &pixMB); + MbP = (edge) ? MbQ : &(p_Vid->mb_data[pixMB.mb_addr]); + + if (!(MbP->mb_type==I4MB||MbP->mb_type==I8MB||MbP->mb_type==I16MB||MbP->mb_type==IPCM)) + { + PixelPos pixP = pixMB; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + + int blkP, blkQ, idx; + + short mb_x, mb_y; + + get_mb_block_pos_normal (p_Vid->PicPos, MbQ->mbAddrX, &mb_x, &mb_y); + mb_x <<= 2; + mb_y <<= 2; + yQ ++; + + for( idx = 0 ; idx < MB_BLOCK_SIZE ; idx += BLOCK_SIZE ) + { + pixP.x = (short) (pixMB.x + idx); + pixP.pos_x = (short) (pixMB.pos_x + idx); + + blkQ = (yQ & 0xFFFC) + (idx >> 2); + blkP = (pixP.y & 0xFFFC) + (pixP.x >> 2); + + if( ((MbQ->cbp_blk & i64_power2(blkQ)) != 0) || ((MbP->cbp_blk & i64_power2(blkP)) != 0) ) + StrValue = 2; + else if (edge && ((MbQ->mb_type == 1) || (MbQ->mb_type == 3))) + StrValue = 0; // if internal edge of certain types, we already know StrValue should be 0 + else // for everything else, if no coefs, but vector difference >= 1 set Strength=1 + { + int blk_y = mb_y + (blkQ >> 2); + int blk_x = mb_x + (blkQ & 3); + int blk_y2 = pixP.pos_y >> 2; + int blk_x2 = pixP.pos_x >> 2; + + PicMotionParams *mv_info_p = &mv_info[blk_y ][blk_x ]; + PicMotionParams *mv_info_q = &mv_info[blk_y2][blk_x2]; + + StorablePicturePtr ref_p0 = mv_info_p->ref_idx[LIST_0] == -1 ? NULL : mv_info_p->ref_pic[LIST_0]; + StorablePicturePtr ref_q0 = mv_info_q->ref_idx[LIST_0] == -1 ? NULL : mv_info_q->ref_pic[LIST_0]; + StorablePicturePtr ref_p1 = mv_info_p->ref_idx[LIST_1] == -1 ? NULL : mv_info_p->ref_pic[LIST_1]; + StorablePicturePtr ref_q1 = mv_info_q->ref_idx[LIST_1] == -1 ? NULL : mv_info_q->ref_pic[LIST_1]; + + if ( ((ref_p0==ref_q0) && (ref_p1==ref_q1)) || ((ref_p0==ref_q1) && (ref_p1==ref_q0))) + { + // L0 and L1 reference pictures of p0 are different; q0 as well + if (ref_p0 != ref_p1) + { + // compare MV for the same reference picture + if (ref_p0 == ref_q0) + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit); + } + else + { + StrValue = + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit); + } + } + else + { // L0 and L1 reference pictures of p0 are the same; q0 as well + StrValue = (( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_0], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_1], mvlimit)) + && ( + compare_mvs(&mv_info_p->mv[LIST_0], &mv_info_q->mv[LIST_1], mvlimit) | + compare_mvs(&mv_info_p->mv[LIST_1], &mv_info_q->mv[LIST_0], mvlimit) + )); + } + } + else + StrValue = 1; + } + //*(int*)(Strength+idx) = (StrValue<<24)|(StrValue<<16)|(StrValue<<8)|StrValue; + *(int*)(Strength+idx) = StrValue * 0x01010101; + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0 && (p_Vid->structure == FRAME)) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + } + else + { + // Start with Strength=3. or Strength=4 for Mb-edge + StrValue = (edge == 0 && (p_Vid->structure == FRAME)) ? 4 : 3; + memset(Strength, (byte) StrValue, MB_BLOCK_SIZE * sizeof(byte)); + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Frame or Field coded MBs + ***************************************************************************************** + */ +static void EdgeLoopLumaVer(ColorPlane pl, imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + PixelPos pixMB1; + getNonAffNeighbour(MbQ, edge - 1, 0, p_Vid->mb_size[IS_LUMA], &pixMB1); + + if (pixMB1.available || (MbQ->DFDisableIdc== 0)) + { + int bitdepth_scale = pl ? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + + Macroblock *MbP = &(p_Vid->mb_data[pixMB1.mb_addr]); + + // Average QP of the two blocks + int QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + MbQ->DFAlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + MbQ->DFBetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + + if ((Alpha | Beta )!= 0) + { + const byte *ClipTab = CLIP_TAB[indexA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + + int pos_x1 = pixMB1.pos_x; + imgpel **cur_img = &Img[pixMB1.pos_y]; + int pel; + + for( pel = 0 ; pel < MB_BLOCK_SIZE ; pel += 4 ) + { + if(*Strength == 4 ) // INTRA strong filtering + { + int i; + for( i = 0 ; i < BLOCK_SIZE ; ++i ) + { + imgpel *SrcPtrP = *(cur_img++) + pos_x1; + imgpel *SrcPtrQ = SrcPtrP + 1; + imgpel L0 = *SrcPtrP; + imgpel R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + imgpel R1 = *(SrcPtrQ + 1); + imgpel L1 = *(SrcPtrP - 1); + if ((iabs( R0 - R1) < Beta) && (iabs(L0 - L1) < Beta)) + { + imgpel R2 = *(SrcPtrQ + 2); + imgpel L2 = *(SrcPtrP - 2); + int RL0 = L0 + R0; + int small_gap = (iabs( R0 - L0 ) < ((Alpha >> 2) + 2)); + int aq = ( iabs( R0 - R2) < Beta ) & small_gap; + int ap = ( iabs( L0 - L2) < Beta ) & small_gap; + + if (ap) + { + imgpel L3 = *(SrcPtrP - 3); + *(SrcPtrP--) = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + *(SrcPtrP--) = (imgpel) (( L2 + L1 + RL0 + 2) >> 2); + *(SrcPtrP ) = (imgpel) ((((L3 + L2) <<1) + L2 + L1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrP = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2); + } + + if (aq) + { + imgpel R3 = *(SrcPtrQ + 3); + *(SrcPtrQ++) = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + *(SrcPtrQ++) = (imgpel) (( R2 + R0 + L0 + R1 + 2) >> 2); + *(SrcPtrQ ) = (imgpel) ((((R3 + R2) <<1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrQ = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + } + } + } + else if( *Strength != 0) // normal filtering + { + int C0 = ClipTab[ *Strength ] * bitdepth_scale; + int i; + imgpel *SrcPtrP, *SrcPtrQ; + int edge_diff; + for( i = 0 ; i < BLOCK_SIZE ; ++i ) + { + SrcPtrP = *(cur_img++) + pos_x1; + SrcPtrQ = SrcPtrP + 1; + edge_diff = *SrcPtrQ - *SrcPtrP; + + if( iabs( edge_diff ) < Alpha ) + { + imgpel *SrcPtrQ1 = SrcPtrQ + 1; + imgpel *SrcPtrP1 = SrcPtrP - 1; + + if ((iabs( *SrcPtrQ - *SrcPtrQ1) < Beta) && (iabs(*SrcPtrP - *SrcPtrP1) < Beta)) + { + int RL0 = (*SrcPtrP + *SrcPtrQ + 1) >> 1; + imgpel R2 = *(SrcPtrQ1 + 1); + imgpel L2 = *(SrcPtrP1 - 1); + + int aq = (iabs(*SrcPtrQ - R2) < Beta); + int ap = (iabs(*SrcPtrP - L2) < Beta); + + int tc0 = (C0 + ap + aq) ; + int dif = iClip3( -tc0, tc0, (((edge_diff) << 2) + (*SrcPtrP1 - *SrcPtrQ1) + 4) >> 3 ); + + if( ap ) + *SrcPtrP1 += iClip3( -C0, C0, (L2 + RL0 - (*SrcPtrP1<<1)) >> 1 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1(max_imgpel_value, *SrcPtrP + dif); + *SrcPtrQ = (imgpel) iClip1(max_imgpel_value, *SrcPtrQ - dif); + } + if( aq ) + *SrcPtrQ1 += iClip3( -C0, C0, (R2 + RL0 - (*SrcPtrQ1<<1)) >> 1 ); + } + } + } + } + else + { + cur_img += 4; + } + Strength += 4; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters 16 pel block edge of Frame or Field coded MBs + ***************************************************************************************** + */ +static void EdgeLoopLumaHor(ColorPlane pl, imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge, int width) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + PixelPos pixMB1; + getNonAffNeighbour(MbQ, 0, (edge < MB_BLOCK_SIZE ? edge - 1: 0), p_Vid->mb_size[IS_LUMA], &pixMB1); + + if (pixMB1.available || (MbQ->DFDisableIdc== 0)) + { + int bitdepth_scale = pl ? p_Vid->bitdepth_scale[IS_CHROMA] : p_Vid->bitdepth_scale[IS_LUMA]; + + Macroblock *MbP = &(p_Vid->mb_data[pixMB1.mb_addr]); + + // Average QP of the two blocks + int QP = pl? ((MbP->qpc[pl-1] + MbQ->qpc[pl-1] + 1) >> 1) : (MbP->qp + MbQ->qp + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + MbQ->DFAlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + MbQ->DFBetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + if ((Alpha | Beta )!= 0) + { + const byte *ClipTab = CLIP_TAB[indexA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[pl]; + imgpel *imgP = &Img[pixMB1.pos_y ][pixMB1.pos_x]; + imgpel *imgQ = imgP + width; + int pel; + + for( pel = 0 ; pel < MB_BLOCK_SIZE ; pel += 4 ) + { + if(*Strength == 4 ) // INTRA strong filtering + { + int pixel; + int inc_dim2 = width * 2; + int inc_dim3 = width * 3; + for( pixel = 0 ; pixel < BLOCK_SIZE ; ++pixel ) + { + imgpel *SrcPtrP = imgP++; + imgpel *SrcPtrQ = imgQ++; + imgpel L0 = *SrcPtrP; + imgpel R0 = *SrcPtrQ; + + if( iabs( R0 - L0 ) < Alpha ) + { + imgpel L1 = *(SrcPtrP - width); + imgpel R1 = *(SrcPtrQ + width); + + if ((iabs( R0 - R1) < Beta) && (iabs(L0 - L1) < Beta)) + { + imgpel L2 = *(SrcPtrP - inc_dim2); + imgpel R2 = *(SrcPtrQ + inc_dim2); + int RL0 = L0 + R0; + int small_gap = (iabs( R0 - L0 ) < ((Alpha >> 2) + 2)); + int aq = ( iabs( R0 - R2) < Beta ) & small_gap; + int ap = ( iabs( L0 - L2) < Beta ) & small_gap; + + if (ap) + { + imgpel L3 = *(SrcPtrP - inc_dim3); + *SrcPtrP = (imgpel) (( R1 + ((L1 + RL0) << 1) + L2 + 4) >> 3); + *(SrcPtrP -= width) = (imgpel) (( L2 + L1 + RL0 + 2) >> 2); + *(SrcPtrP - width) = (imgpel) ((((L3 + L2) <<1) + L2 + L1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrP = (imgpel) (((L1 << 1) + L0 + R1 + 2) >> 2); + } + + if (aq) + { + imgpel R3 = *(SrcPtrQ + inc_dim3); + *(SrcPtrQ ) = (imgpel) (( L1 + ((R1 + RL0) << 1) + R2 + 4) >> 3); + *(SrcPtrQ += width ) = (imgpel) (( R2 + R0 + L0 + R1 + 2) >> 2); + *(SrcPtrQ + width ) = (imgpel) ((((R3 + R2) <<1) + R2 + R1 + RL0 + 4) >> 3); + } + else + { + *SrcPtrQ = (imgpel) (((R1 << 1) + R0 + L1 + 2) >> 2); + } + } + } + } + } + else if( *Strength != 0) // normal filtering + { + int C0 = ClipTab[ *Strength ] * bitdepth_scale; + int i; + imgpel *SrcPtrP, *SrcPtrQ; + int edge_diff; + for( i= 0 ; i < BLOCK_SIZE ; ++i ) + { + SrcPtrP = imgP++; + SrcPtrQ = imgQ++; + edge_diff = *SrcPtrQ - *SrcPtrP; + + if( iabs( edge_diff ) < Alpha ) + { + imgpel *SrcPtrQ1 = SrcPtrQ + width; + imgpel *SrcPtrP1 = SrcPtrP - width; + + if ((iabs( *SrcPtrQ - *SrcPtrQ1) < Beta) && (iabs(*SrcPtrP - *SrcPtrP1) < Beta)) + { + int RL0 = (*SrcPtrP + *SrcPtrQ + 1) >> 1; + imgpel R2 = *(SrcPtrQ1 + width); + imgpel L2 = *(SrcPtrP1 - width); + + int aq = (iabs(*SrcPtrQ - R2) < Beta); + int ap = (iabs(*SrcPtrP - L2) < Beta); + + int tc0 = (C0 + ap + aq) ; + int dif = iClip3( -tc0, tc0, (((edge_diff) << 2) + (*SrcPtrP1 - *SrcPtrQ1) + 4) >> 3 ); + + if( ap ) + *SrcPtrP1 += iClip3( -C0, C0, (L2 + RL0 - (*SrcPtrP1<<1)) >> 1 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1(max_imgpel_value, *SrcPtrP + dif); + *SrcPtrQ = (imgpel) iClip1(max_imgpel_value, *SrcPtrQ - dif); + } + + if( aq ) + *SrcPtrQ1 += iClip3( -C0, C0, (R2 + RL0 - (*SrcPtrQ1<<1)) >> 1 ); + } + } + } + } + else + { + imgP += 4; + imgQ += 4; + } + Strength += 4; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters chroma block edge for Frame or Field coded pictures + ***************************************************************************************** + */ +static void EdgeLoopChromaVer(imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge, int uv) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + int xQ = edge - 1; + int yQ = 0; + PixelPos pixMB1; + + getNonAffNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_CHROMA], &pixMB1); + + if (pixMB1.available || (MbQ->DFDisableIdc == 0)) + { + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + Macroblock *MbP = &(p_Vid->mb_data[pixMB1.mb_addr]); + + // Average QP of the two blocks + int QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + if ((Alpha | Beta) != 0) + { + const int PelNum = pelnum_cr[0][p_Vid->yuv_format]; + const byte *ClipTab = CLIP_TAB[indexA]; + + int pel; + int pos_x1 = pixMB1.pos_x; + imgpel **cur_img = &Img[pixMB1.pos_y]; + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + int Strng = Strength[(PelNum == 8) ? (((pel >> 1) << 2) + (pel & 0x01)) : pel]; + + if( Strng != 0) + { + imgpel *SrcPtrP = *cur_img + pos_x1; + imgpel *SrcPtrQ = SrcPtrP + 1; + int edge_diff = *SrcPtrQ - *SrcPtrP; + + if ( iabs( edge_diff ) < Alpha ) + { + imgpel R1 = *(SrcPtrQ + 1); + if ( iabs(*SrcPtrQ - R1) < Beta ) + { + imgpel L1 = *(SrcPtrP - 1); + if ( iabs(*SrcPtrP - L1) < Beta ) + { + if( Strng == 4 ) // INTRA strong filtering + { + *SrcPtrP = (imgpel) ( ((L1 << 1) + *SrcPtrP + R1 + 2) >> 2 ); + *SrcPtrQ = (imgpel) ( ((R1 << 1) + *SrcPtrQ + L1 + 2) >> 2 ); + } + else + { + int tc0 = ClipTab[ Strng ] * bitdepth_scale + 1; + int dif = iClip3( -tc0, tc0, ( ((edge_diff) << 2) + (L1 - R1) + 4) >> 3 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrP + dif ); + *SrcPtrQ = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrQ - dif ); + } + } + } + } + } + } + cur_img++; + } + } + } +} + + +/*! + ***************************************************************************************** + * \brief + * Filters chroma block edge for Frame or Field coded pictures + ***************************************************************************************** + */ +static void EdgeLoopChromaHor(imgpel** Img, byte Strength[16], Macroblock *MbQ, int edge, int width, int uv) +{ + VideoParameters *p_Vid = MbQ->p_Vid; + + int xQ = 0; + int yQ = (edge < 16 ? edge - 1: 0); + PixelPos pixMB1; + + getNonAffNeighbour(MbQ, xQ, yQ, p_Vid->mb_size[IS_CHROMA], &pixMB1); + + if (pixMB1.available || (MbQ->DFDisableIdc == 0)) + { + int bitdepth_scale = p_Vid->bitdepth_scale[IS_CHROMA]; + int max_imgpel_value = p_Vid->max_pel_value_comp[uv + 1]; + + int AlphaC0Offset = MbQ->DFAlphaC0Offset; + int BetaOffset = MbQ->DFBetaOffset; + Macroblock *MbP = &(p_Vid->mb_data[pixMB1.mb_addr]); + + // Average QP of the two blocks + int QP = (MbP->qpc[uv] + MbQ->qpc[uv] + 1) >> 1; + + int indexA = iClip3(0, MAX_QP, QP + AlphaC0Offset); + int indexB = iClip3(0, MAX_QP, QP + BetaOffset); + + int Alpha = ALPHA_TABLE[indexA] * bitdepth_scale; + int Beta = BETA_TABLE [indexB] * bitdepth_scale; + if ((Alpha | Beta) != 0) + { + const int PelNum = pelnum_cr[1][p_Vid->yuv_format]; + const byte *ClipTab = CLIP_TAB[indexA]; + + int pel; + + imgpel *imgP = &Img[pixMB1.pos_y ][pixMB1.pos_x]; + imgpel *imgQ = imgP + width ; + + for( pel = 0 ; pel < PelNum ; ++pel ) + { + int Strng = Strength[(PelNum == 8) ? (((pel >> 1) << 2) + (pel & 0x01)) : pel]; + + if( Strng != 0) + { + imgpel *SrcPtrP = imgP; + imgpel *SrcPtrQ = imgQ; + int edge_diff = *imgQ - *imgP; + + if ( iabs( edge_diff ) < Alpha ) + { + imgpel R1 = *(SrcPtrQ + width); + if ( iabs(*SrcPtrQ - R1) < Beta ) + { + imgpel L1 = *(SrcPtrP - width); + if ( iabs(*SrcPtrP - L1) < Beta ) + { + if( Strng == 4 ) // INTRA strong filtering + { + *SrcPtrP = (imgpel) ( ((L1 << 1) + *SrcPtrP + R1 + 2) >> 2 ); + *SrcPtrQ = (imgpel) ( ((R1 << 1) + *SrcPtrQ + L1 + 2) >> 2 ); + } + else + { + int tc0 = ClipTab[ Strng ] * bitdepth_scale + 1; + int dif = iClip3( -tc0, tc0, ( ((edge_diff) << 2) + (L1 - R1) + 4) >> 3 ); + + if (dif != 0) + { + *SrcPtrP = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrP + dif ); + *SrcPtrQ = (imgpel) iClip1 ( max_imgpel_value, *SrcPtrQ - dif ); + } + } + } + } + } + } + imgP++; + imgQ++; + } + } + } +} + diff --git a/lencod/src/macroblock.c b/lencod/src/macroblock.c new file mode 100644 index 0000000..7e1f71a --- /dev/null +++ b/lencod/src/macroblock.c @@ -0,0 +1,4882 @@ +/*! + ************************************************************************************* + * \file macroblock.c + * + * \brief + * Process one macroblock + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langoy + * - Rickard Sjoberg + * - Jani Lainema + * - Sebastian Purreiter + * - Detlev Marpe + * - Thomas Wedi + * - Ragip Kurceren + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "enc_statistics.h" + +#include "block.h" +#include "elements.h" +#include "macroblock.h" +#include "memalloc.h" +#include "blk_prediction.h" +#include "mc_prediction.h" +#include "fmo.h" +#include "vlc.h" +#include "image.h" +#include "mb_access.h" +#include "ratectl.h" // header file for rate control +#include "cabac.h" +#include "biariencode.h" +#include "me_fullsearch.h" +#include "me_fullfast.h" +#include "symbol.h" +#include "conformance.h" +#include "md_common.h" +#include "mv_prediction.h" +#include "rdopt.h" +#include "transform.h" + + +#if TRACE +#define TRACE_SE(trace,str) snprintf(trace,TRACESTRING_SIZE,str) +#else +#define TRACE_SE(trace,str) +#endif + + +static int slice_too_big (Slice *currSlice, int rlc_bits); +static int write_chroma_intra_pred_mode (Macroblock* currMB); +static int write_chroma_coeff (Macroblock* currMB); +static int write_CBP_and_Dquant (Macroblock* currMB); + + /*! + ************************************************************************ + * \brief + * updates the coordinates for the next macroblock to be processed + * + * \param currSlice + * current slice pointer + * \param currMB + * macroblock structure to be set + ************************************************************************ + */ +void set_MB_parameters (Slice *currSlice, Macroblock *currMB) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + int mb_addr = currMB->mbAddrX; + p_Vid->current_mb_nr = mb_addr; + + p_Vid->get_mb_block_pos(p_Vid->PicPos, currMB->mbAddrX, &currMB->mb_x, &currMB->mb_y); + + currMB->block_x = currMB->mb_x << 2; + currMB->block_y = currMB->mb_y << 2; + + currMB->pix_x = currMB->block_x << 2; + currMB->pix_y = currMB->block_y << 2; + + if (currSlice->mb_aff_frame_flag) + { + if (currMB->mb_field) + { + p_Vid->pCurImg = (mb_addr & 0x01) ? p_Vid->imgData.bot_data[0] : p_Vid->imgData.top_data[0]; + p_Vid->pImgOrg[0] = p_Vid->pCurImg; + + if ((p_Vid->yuv_format != YUV400) && (p_Inp->separate_colour_plane_flag == 0)) + { + if (mb_addr & 0x01) + { + p_Vid->pImgOrg[1] = p_Vid->imgData.bot_data[1]; + p_Vid->pImgOrg[2] = p_Vid->imgData.bot_data[2]; + } + else + { + p_Vid->pImgOrg[1] = p_Vid->imgData.top_data[1]; + p_Vid->pImgOrg[2] = p_Vid->imgData.top_data[2]; + } + } + + currMB->opix_y = (currMB->mb_y >> 1 ) << 4; + currMB->list_offset = (mb_addr & 0x01) ? 4 : 2; + } + else + { + p_Vid->pCurImg = p_Vid->imgData.frm_data[0]; + p_Vid->pImgOrg[0] = p_Vid->imgData.frm_data[0]; + + if ((p_Vid->yuv_format != YUV400) && (p_Inp->separate_colour_plane_flag == 0)) + { + p_Vid->pImgOrg[1] = p_Vid->imgData.frm_data[1]; + p_Vid->pImgOrg[2] = p_Vid->imgData.frm_data[2]; + } + + currMB->opix_y = currMB->block_y << 2; + currMB->list_offset = 0; + } + } + else + { + currMB->opix_y = currMB->block_y << 2; + currMB->list_offset = 0; + } + + if (p_Vid->yuv_format != YUV400) + { + currMB->pix_c_x = (p_Vid->mb_cr_size_x * currMB->pix_x) >> 4; + currMB->pix_c_y = (p_Vid->mb_cr_size_y * currMB->pix_y) >> 4; + + currMB->opix_c_y = (p_Vid->mb_cr_size_y * currMB->opix_y) >> 4; + } + + // printf ("set_MB_parameters: mb %d, mb_x %d, mb_y %d\n", mb_addr, currMB->mb_x, currMB->mb_y); +} + + +/*! + ************************************************************************ + * \brief + * updates the coordinates and statistics parameter for the + * next macroblock + ************************************************************************ + */ +void next_macroblock(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + int slice_type = currSlice->slice_type; + BitCounter *mbBits = &currMB->bits; + int i; + StatParameters *cur_stats = &p_Vid->enc_picture->stats; + + if (mbBits->mb_total > p_Vid->max_bitCount) + printf("Warning!!! Number of bits (%d) of macroblock_layer() data seems to exceed defined limit (%d).\n", mbBits->mb_total,p_Vid->max_bitCount); + + // Update the statistics + cur_stats->bit_use_mb_type[slice_type] += mbBits->mb_mode; + cur_stats->tmp_bit_use_cbp[slice_type] += mbBits->mb_cbp; + cur_stats->bit_use_coeffC[slice_type] += mbBits->mb_uv_coeff; + cur_stats->bit_use_coeff[0][slice_type] += mbBits->mb_y_coeff; + cur_stats->bit_use_coeff[1][slice_type] += mbBits->mb_cb_coeff; + cur_stats->bit_use_coeff[2][slice_type] += mbBits->mb_cr_coeff; + cur_stats->bit_use_delta_quant[slice_type] += mbBits->mb_delta_quant; + cur_stats->bit_use_stuffing_bits[slice_type] += mbBits->mb_stuffing; + + if (IS_INTRA(currMB)) + { + ++cur_stats->intra_chroma_mode[ (short) currMB->c_ipred_mode]; + + + if ((currMB->cbp&15) != 0) + { + ++cur_stats->mode_use_transform[slice_type][currMB->mb_type][currMB->luma_transform_size_8x8_flag]; + } + } + + ++cur_stats->mode_use[slice_type][currMB->mb_type]; + cur_stats->bit_use_mode[slice_type][currMB->mb_type] += mbBits->mb_inter; + + if (slice_type != I_SLICE) + { + if (currMB->mb_type == P8x8) + { + for(i=0;i<4;++i) + { + if (currMB->b8x8[i].mode > 0) + ++cur_stats->mode_use[slice_type][(short) currMB->b8x8[i].mode]; + else + ++cur_stats->b8_mode_0_use[slice_type][currMB->luma_transform_size_8x8_flag]; + + if (currMB->b8x8[i].mode ==4) + { + if ((currMB->luma_transform_size_8x8_flag && (currMB->cbp&15) != 0) || p_Inp->Transform8x8Mode == 2) + ++cur_stats->mode_use_transform[slice_type][4][1]; + else + ++cur_stats->mode_use_transform[slice_type][4][0]; + } + } + } + else if (currMB->mb_type >= 0 && currMB->mb_type <=3 && ((currMB->cbp&15) != 0)) + { + ++cur_stats->mode_use_transform[slice_type][currMB->mb_type][currMB->luma_transform_size_8x8_flag]; + } + } + + // Statistics + cur_stats->quant[slice_type] += currMB->qp; + ++cur_stats->num_macroblocks[slice_type]; +} + +static void set_chroma_qp(Macroblock* currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int i; + for (i = 0; i <= 1; ++i) + { + currMB->qpc[i] = (short) iClip3 ( -currSlice->bitdepth_chroma_qp_scale, 51, currMB->qp + p_Vid->chroma_qp_offset[i] ); + currMB->qpc[i] = (short) (currMB->qpc[i] < 0 ? currMB->qpc[i] : QP_SCALE_CR[currMB->qpc[i]]); + currMB->qp_scaled[i + 1] = (short) (currMB->qpc[i] + currSlice->bitdepth_chroma_qp_scale); + } +} + +/*! +************************************************************************ +* \brief +* updates chroma QP according to luma QP and bit depth +************************************************************************ +*/ +void update_qp(Macroblock *currMB) +{ + currMB->qp_scaled[PLANE_Y] = (short) (currMB->qp + currMB->p_Slice->bitdepth_luma_qp_scale); + set_chroma_qp(currMB); + + select_transform(currMB); +} + +/*! + ************************************************************************ + * \brief + * resets info for the current macroblock + * + * \param currMB + * current macroblock + ************************************************************************ + */ +void reset_macroblock(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + PicMotionParams *p_motion; + int j, i; + + // Reset vectors and reference indices + for (j=currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; ++j) + { + for (i = currMB->block_x; i < currMB->block_x + BLOCK_MULTIPLE; ++i) + { + p_motion = &motion[j][i]; + p_motion->ref_pic[LIST_0] = NULL; + p_motion->ref_pic[LIST_1] = NULL; + p_motion->mv [LIST_0] = zero_mv; + p_motion->mv [LIST_1] = zero_mv; + p_motion->ref_idx[LIST_0] = -1; + p_motion->ref_idx[LIST_1] = -1; + } + } + + + // Reset syntax element entries in MB struct + currMB->mb_type = 0; + currMB->cbp_blk = 0; + currMB->cbp = 0; + currMB->c_ipred_mode = DC_PRED_8; + + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = currSlice->curr_cbp[0] = currSlice->curr_cbp[1] = 0; + + memset(currMB->cbp_bits , 0, 3 * sizeof(int64)); + memset(currMB->cbp_bits_8x8, 0, 3 * sizeof(int64)); + + memset (currMB->mvd, 0, BLOCK_CONTEXT * sizeof(short)); + memset (currMB->intra_pred_modes, DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); // changing this to char would allow us to use memset + memset (currMB->intra_pred_modes8x8, DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + + currMB->b8x8[0].bipred = 0; + currMB->b8x8[1].bipred = 0; + currMB->b8x8[2].bipred = 0; + currMB->b8x8[3].bipred = 0; + + currMB->write_mb = FALSE; + + //initialize the whole MB as INTRA coded + //Blocks are set to notINTRA in write_macroblock + if (p_Inp->UseConstrainedIntraPred) + { + p_Vid->intra_block[currMB->mbAddrX] = 1; + } + + // Initialize bitcounters for this macroblock + memset(&currMB->bits, 0, sizeof(BitCounter)); + + currMB->min_rdcost = DISTBLK_MAX; + currMB->min_dcost = DISTBLK_MAX; + currMB->min_rate = DISTBLK_MAX; + + currMB->best_mode = 0; + currMB->best_c_imode = 0; + currMB->best_i16offset = 0; + currMB->best_cbp = 0; +} + + +/*! + ************************************************************************ + * \brief + * initializes the current macroblock + * + * \param currSlice + * current slice + * \param currMB + * current macroblock + * \param mb_addr + * current macroblock address + * \param mb_field + * true for field macroblock coding + ************************************************************************ + */ +void start_macroblock(Slice *currSlice, Macroblock **currMB, int mb_addr, Boolean mb_field) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int i, mb_qp; + int use_bitstream_backing = (p_Inp->slice_mode == FIXED_RATE || p_Inp->slice_mode == CALL_BACK); + + static Macroblock *last_coded_mb = NULL; // used to find whether this is recoding an MB + + DataPartition *dataPart; + Bitstream *currStream; + int prev_mb; + + *currMB = &p_Vid->mb_data[mb_addr]; + (*currMB)->p_Slice = currSlice; + (*currMB)->p_Vid = p_Vid; + (*currMB)->p_Inp = p_Inp; + + (*currMB)->mbAddrX = mb_addr; + + (*currMB)->is_intra_block = (currSlice->slice_type == I_SLICE || currSlice->slice_type == SI_SLICE) ? TRUE : FALSE; + + (*currMB)->mb_field = (byte) mb_field; + p_Vid->enc_picture->motion.mb_field[mb_addr] = (byte) mb_field; + + (*currMB)->is_field_mode = (byte) (p_Vid->field_picture || ( currSlice->mb_aff_frame_flag && (*currMB)->mb_field)); + (*currMB)->prev_recode_mb = FALSE; + (*currMB)->DeblockCall = FALSE; + //set buffer; + (*currMB)->intra4x4_pred = (*currMB)->intra4x4_pred_buf[p_Vid->dpb_layer_id]; + (*currMB)->intra8x8_pred = (*currMB)->intra8x8_pred_buf[p_Vid->dpb_layer_id]; + (*currMB)->intra16x16_pred = (*currMB)->intra16x16_pred_buf[p_Vid->dpb_layer_id]; + + set_MB_parameters (currSlice, *currMB); + + prev_mb = FmoGetPreviousMBNr(p_Vid, mb_addr); + + if(use_bitstream_backing) + { + if ((!p_Inp->MbInterlace)||((mb_addr & 0x01)==0)) // KS: MB AFF -> store stream positions for 1st MB only + { + // Keep the current state of the bitstreams + if(!p_Vid->cod_counter) + { + for (i=0; imax_part_nr; ++i) + { + dataPart = &(currSlice->partArr[i]); + currStream = dataPart->bitstream; + currStream->stored_bits_to_go = currStream->bits_to_go; + currStream->stored_byte_pos = currStream->byte_pos; + currStream->stored_byte_buf = currStream->byte_buf; + p_Vid->p_Stats->stored_bit_slice = p_Vid->p_Stats->bit_slice; + + if (currSlice->symbol_mode ==CABAC) + { + dataPart->ee_recode = dataPart->ee_cabac; + } + } + } + } + } + + // Save the slice number of this macroblock. When the macroblock below + // is coded it will use this to decide if prediction for above is possible + (*currMB)->slice_nr = currSlice->slice_nr; + + // Initialize delta qp change from last macroblock. Feature may be used for future rate control + // Rate control + (*currMB)->qpsp = (short) p_Vid->qpsp; + + if (prev_mb > -1 && (p_Vid->mb_data[prev_mb].slice_nr == currSlice->slice_nr)) + { + (*currMB)->PrevMB = &p_Vid->mb_data[prev_mb]; + (*currMB)->prev_qp = (*currMB)->PrevMB->qp; + (*currMB)->prev_dqp = (*currMB)->prev_qp - (*currMB)->PrevMB->prev_qp; + } + else + { + prev_mb = - 1; + (*currMB)->PrevMB = NULL; + (*currMB)->prev_qp = (short) currSlice->qp; + (*currMB)->prev_dqp = 0; + } + + if(p_Inp->RCEnable && (last_coded_mb != *currMB)) //!< avoid decreasing the NumberofbasicUnit for the same MB twice + { + mb_qp = rc_handle_mb( *currMB, prev_mb); + } + else + { + mb_qp = p_Vid->qp; + } + + last_coded_mb = *currMB; // save the address of the last coded MB + + if ((*currMB)->mbAddrX == 0) + p_Vid->BasicUnitQP = mb_qp; + + mb_qp = iClip3(-currSlice->bitdepth_luma_qp_scale, 51, mb_qp); + (*currMB)->qp = (short) mb_qp; + p_Vid->qp = mb_qp; + + update_qp (*currMB); + + + // deblocking filter parameter + if (p_Vid->active_pps->deblocking_filter_control_present_flag) + { + (*currMB)->DFDisableIdc = currSlice->DFDisableIdc; + (*currMB)->DFAlphaC0Offset = currSlice->DFAlphaC0Offset; + (*currMB)->DFBetaOffset = currSlice->DFBetaOffset; + } + else + { + (*currMB)->DFDisableIdc = 0; + (*currMB)->DFAlphaC0Offset = 0; + (*currMB)->DFBetaOffset = 0; + } + (*currMB)->min_rdcost = DISTBLK_MAX; + (*currMB)->min_dcost = DISTBLK_MAX; + (*currMB)->min_rate = DISTBLK_MAX; + + (*currMB)->i16mode = 0; + (*currMB)->best_mode = 10; + + if ((p_Vid->yuv_format!=0) && (p_Vid->yuv_format!=3)) + { + (*currMB)->cbp_linfo_intra = cbp_linfo_intra_normal; + (*currMB)->cbp_linfo_inter = cbp_linfo_inter_normal; + } + else + { + (*currMB)->cbp_linfo_intra = cbp_linfo_intra_other; + (*currMB)->cbp_linfo_inter = cbp_linfo_inter_other; + } + + // Select appropriate MV predictor function + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + init_motion_vector_prediction(*currMB, currSlice->mb_aff_frame_flag); + init_ME_engine(*currMB); + } + + // If MB is next to a slice boundary, mark neighboring blocks unavailable for prediction + CheckAvailabilityOfNeighbors(*currMB); + + if (currSlice->symbol_mode == CABAC) + CheckAvailabilityOfNeighborsCABAC(*currMB); + + reset_macroblock(*currMB); + + if ((p_Inp->SearchMode[p_Vid->view_id] == FAST_FULL_SEARCH) && (!p_Inp->IntraProfile)) + reset_fast_full_search (p_Vid); + + // disable writing of trace file +#if TRACE + for (i=0; imax_part_nr; ++i ) + { + currSlice->partArr[i].bitstream->trace_enabled = FALSE; + } +#endif +} + +/*! + ************************************************************************ + * \brief + * terminates processing of the current macroblock depending + * on the chosen slice mode + ************************************************************************ + */ +void end_macroblock(Macroblock *currMB, //!< Current Macroblock + Boolean *end_of_slice, //!< returns true for last macroblock of a slice, otherwise false + Boolean *recode_macroblock //!< returns true if max. slice size is exceeded an macroblock must be recoded in next slice + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + int i; + SyntaxElement se; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition *dataPart; + Bitstream *currStream; + int rlc_bits=0; + int use_bitstream_backing = (p_Inp->slice_mode == FIXED_RATE || p_Inp->slice_mode == CALL_BACK); + int skip = FALSE; + int new_slice = 0; + + // if previous mb in the same slice group has different slice number as the current, it's the + // the start of new slice + if ((currMB->mbAddrX == 0) || currMB->PrevMB == NULL || ( currMB->PrevMB->slice_nr != currSlice->slice_nr )) + new_slice=1; + + *recode_macroblock=FALSE; + + switch(p_Inp->slice_mode) + { + case NO_SLICES: + ++currSlice->num_mb; + *recode_macroblock = FALSE; + if ((currSlice->num_mb) == (int)p_Vid->PicSizeInMbs) // maximum number of MBs reached + *end_of_slice = TRUE; + + // if it's end of current slice group, slice ends too + *end_of_slice = (Boolean) (*end_of_slice | (currMB->mbAddrX == FmoGetLastCodedMBOfSliceGroup (p_Vid, FmoMB2SliceGroup (p_Vid, currMB->mbAddrX)))); + + break; + case FIXED_MB: + // For slice mode one, check if a new slice boundary follows + ++currSlice->num_mb; + *recode_macroblock = FALSE; + //! Check end-of-slice group condition first + *end_of_slice = (Boolean) (currMB->mbAddrX == FmoGetLastCodedMBOfSliceGroup (p_Vid, FmoMB2SliceGroup (p_Vid, currMB->mbAddrX))); + //! Now check maximum # of MBs in slice + *end_of_slice = (Boolean) (*end_of_slice | (currSlice->num_mb >= p_Inp->slice_argument)); + + break; + + // For slice modes two and three, check if coding of this macroblock + // resulted in too many bits for this slice. If so, indicate slice + // boundary before this macroblock and code the macroblock again + case FIXED_RATE: + // in case of skip MBs check if there is a slice boundary + // only for CAVLC (p_Vid->cod_counter is always 0 in case of CABAC) + if(p_Vid->cod_counter) + { + // write out the skip MBs to know how many bits we need for the RLC + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; + dataPart = &(currSlice->partArr[partMap[se.type]]); + + TRACE_SE (se.tracestring, "mb_skip_run"); + writeSE_UVLC(&se, dataPart); + rlc_bits=se.len; + + for (i=0; imax_part_nr; ++i) + { + dataPart = &(currSlice->partArr[i]); + currStream = dataPart->bitstream; + // save the bitstream as it would be if we write the skip MBs + currStream->bits_to_go_skip = currStream->bits_to_go; + currStream->byte_pos_skip = currStream->byte_pos; + currStream->byte_buf_skip = currStream->byte_buf; + // restore the bitstream + currStream->bits_to_go = currStream->stored_bits_to_go; + currStream->byte_pos = currStream->stored_byte_pos; + currStream->byte_buf = currStream->stored_byte_buf; + } + skip = TRUE; + } + //! Check if the last coded macroblock fits into the size of the slice + //! But only if this is not the first macroblock of this slice + if (!new_slice) + { + if(slice_too_big(currSlice, rlc_bits)) + { + *recode_macroblock = TRUE; + *end_of_slice = TRUE; + } + else if(!p_Vid->cod_counter) + skip = FALSE; + } + // maximum number of MBs + + // check if current slice group is finished + if ((*recode_macroblock == FALSE) && (currMB->mbAddrX == FmoGetLastCodedMBOfSliceGroup (p_Vid, FmoMB2SliceGroup (p_Vid, currMB->mbAddrX)))) + { + *end_of_slice = TRUE; + if(!p_Vid->cod_counter) + skip = FALSE; + } + + //! (first MB OR first MB in a slice) AND bigger that maximum size of slice + if (new_slice && slice_too_big(currSlice, rlc_bits)) + { + *end_of_slice = TRUE; + if(!p_Vid->cod_counter) + skip = FALSE; + } + if (!*recode_macroblock) + ++currSlice->num_mb; + break; + + case CALL_BACK: + if (currMB->mbAddrX > 0 && !new_slice) + { + if (currSlice->slice_too_big(rlc_bits)) + { + *recode_macroblock = TRUE; + *end_of_slice = TRUE; + } + } + + if ( (*recode_macroblock == FALSE) && (currMB->mbAddrX == FmoGetLastCodedMBOfSliceGroup (p_Vid, FmoMB2SliceGroup (p_Vid, currMB->mbAddrX)))) + *end_of_slice = TRUE; + break; + + default: + snprintf(errortext, ET_SIZE, "Slice Mode %d not supported", p_Inp->slice_mode); + error(errortext, 600); + } + + if (*recode_macroblock == TRUE) + { + // Restore everything + for (i=0; imax_part_nr; ++i) + { + dataPart = &(currSlice->partArr[i]); + currStream = dataPart->bitstream; + currStream->bits_to_go = currStream->stored_bits_to_go; + currStream->byte_pos = currStream->stored_byte_pos; + currStream->byte_buf = currStream->stored_byte_buf; + p_Vid->p_Stats->bit_slice = p_Vid->p_Stats->stored_bit_slice; + + if (currSlice->symbol_mode == CABAC) + { + dataPart->ee_cabac = dataPart->ee_recode; + } + } + } + + if (currSlice->symbol_mode == CAVLC) + { + // Skip MBs at the end of this slice + dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + if(*end_of_slice == TRUE && skip == TRUE) + { + // only for Slice Mode 2 or 3 + // If we still have to write the skip, let's do it! + if(p_Vid->cod_counter && *recode_macroblock == TRUE) // MB that did not fit in this slice + { + // If recoding is true and we have had skip, + // we have to reduce the counter in case of recoding + p_Vid->cod_counter--; + if(p_Vid->cod_counter) + { + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "Final MB runlength = %3d",p_Vid->cod_counter); +#endif + writeSE_UVLC(&se, dataPart); + rlc_bits=se.len; + currMB->bits.mb_mode = currMB->bits.mb_mode + (unsigned short) rlc_bits; + p_Vid->cod_counter = 0; + } + } + else //! MB that did not fit in this slice anymore is not a Skip MB + { + for (i=0; imax_part_nr; ++i) + { + dataPart = &(currSlice->partArr[i]); + currStream = dataPart->bitstream; + // update the bitstream + currStream->bits_to_go = currStream->bits_to_go_skip; + currStream->byte_pos = currStream->byte_pos_skip; + currStream->byte_buf = currStream->byte_buf_skip; + } + // update the statistics + p_Vid->cod_counter = 0; + skip = FALSE; + } + } + + // Skip MBs at the end of this slice for Slice Mode 0 or 1 + if(*end_of_slice == TRUE && p_Vid->cod_counter && !use_bitstream_backing) + { + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE (se.tracestring, "mb_skip_run"); + writeSE_UVLC(&se, dataPart); + + rlc_bits=se.len; + currMB->bits.mb_mode = currMB->bits.mb_mode + (unsigned short) rlc_bits; + p_Vid->cod_counter = 0; + } + } +} + +/*! + ***************************************************************************** + * + * \brief + * For Slice Mode 2: Checks if one partition of one slice exceeds the + * allowed size + * + * \return + * FALSE if all Partitions of this slice are smaller than the allowed size + * TRUE is at least one Partition exceeds the limit + * + * \par Side effects + * none + * + * \date + * 4 November 2001 + * + * \author + * Tobias Oelbaum drehvial@gmx.net + *****************************************************************************/ + +int slice_too_big(Slice *currSlice, int rlc_bits) +{ + InputParameters *p_Inp = currSlice->p_Inp; + DataPartition *dataPart; + Bitstream *currStream; + EncodingEnvironmentPtr eep; + int i; + int size_in_bytes; + + //! CAVLC + if (currSlice->symbol_mode == CAVLC) + { + for (i = 0; i < currSlice->max_part_nr; ++i) + { + dataPart = &(currSlice->partArr[i]); + currStream = dataPart->bitstream; + size_in_bytes = currStream->byte_pos /*- currStream->tmp_byte_pos*/; + + if (currStream->bits_to_go < 8) + ++size_in_bytes; + if (currStream->bits_to_go < rlc_bits) + ++size_in_bytes; + if(size_in_bytes > p_Inp->slice_argument) + return TRUE; + } + } + else //! CABAC + { + for (i=0; imax_part_nr; ++i) + { + dataPart= &(currSlice->partArr[i]); + eep = &(dataPart->ee_cabac); + + if( arienco_bits_written(eep) > (p_Inp->slice_argument*8)) + return TRUE; + } + } + + return FALSE; +} + +/* +The purpose of the actions performed in this function is to prevent that single or 'expensive' coefficients are coded. +With 4x4 transform there is larger chance that a single coefficient in a 8x8 or 16x16 block may be nonzero. +A single small (level=1) coefficient in a 8x8 block will cost: 3 or more bits for the coefficient, +4 bits for EOBs for the 4x4 blocks,possibly also more bits for CBP. Hence the total 'cost' of that single +coefficient will typically be 10-12 bits which in a RD consideration is too much to justify the distortion improvement. +The action below is to watch such 'single' coefficients and set the reconstructed block equal to the prediction according +to a given criterium. The action is taken only for inter luma blocks. + +Notice that this is a pure encoder issue and hence does not have any implication on the standard. +coeff_cost is a parameter set in residual_transform_quant_luma_4x4() and accumulated for each 8x8 block. If level=1 for a coefficient, +coeff_cost is increased by a number depending on RUN for that coefficient.The numbers are (see also residual_transform_quant_luma_4x4()): 3,2,2,1,1,1,0,0,... +when RUN equals 0,1,2,3,4,5,6, etc. +If level >1 coeff_cost is increased by 9 (or any number above 3). The threshold is set to 3. This means for example: +1: If there is one coefficient with (RUN,level)=(0,1) in a 8x8 block this coefficient is discarded. +2: If there are two coefficients with (RUN,level)=(1,1) and (4,1) the coefficients are also discarded +sum_cnt_nonz is the accumulation of coeff_cost over a whole macro block. If sum_cnt_nonz is 5 or less for the whole MB, +all nonzero coefficients are discarded for the MB and the reconstructed block is set equal to the prediction. +*/ +int reset_block(Macroblock* currMB, int *cbp, int64 *cbp_blk, int block8x8) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int i, j; + int mb_y = (block8x8 >> 1) << 3; + int mb_x = (block8x8 & 0x01) << 3; + int cbp_mask = 1 << block8x8; + + (*cbp) &= (63 - cbp_mask); + (*cbp_blk) &= ~(51 << (4 * block8x8 - 2 * (block8x8 & 0x01))); + + memset( currSlice->cofAC[block8x8][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + copy_image_data_8x8(&p_Vid->enc_picture->imgY[currMB->pix_y + mb_y], &currSlice->mb_pred[0][mb_y], currMB->pix_x + mb_x, mb_x); + + if (currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + for (i = mb_x; i < mb_x + BLOCK_SIZE_8x8; i += BLOCK_SIZE) + for (j = mb_y; j < mb_y + BLOCK_SIZE_8x8; j += BLOCK_SIZE) + copyblock_sp(currMB, PLANE_Y, i, j); + } + + return 0; +} + +/*! + ************************************************************************ + * \brief + * Residual Coding of an 8x8 Luma block (not for intra) + * + * \return + * coefficient cost + ************************************************************************ + */ +int luma_residual_coding_16x16 (Macroblock* currMB, //!< Current Macroblock to be coded + int block8x8, //!< block number of 8x8 block + int list_mode[2] //!< list prediction mode (1-7, 0=DIRECT) +) +{ + + int *cbp = &(currMB->cbp); + int64 *cbp_blk = &(currMB->cbp_blk); + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int nonzero = 0, cbp_blk_mask; + int coeff_cost = 0; + int mb_y = (block8x8 >> 1) << 3; + int mb_x = (block8x8 & 0x01) << 3; + int cbp_mask = 1 << block8x8; + + int skipped = (list_mode[0] == 0 && list_mode[1] == 0 && (currSlice->slice_type != B_SLICE)); + + //memset( currSlice->cofAC[block8x8][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + //===== loop over 4x4 blocks ===== + if(!currMB->luma_transform_size_8x8_flag) + { + //===== forward transform, Quantization, inverse Quantization, inverse transform, Reconstruction ===== + if (!skipped && ( (currSlice->NoResidueDirect != 1) || (currMB->qp_scaled[PLANE_Y] == 0 && p_Vid->active_sps->lossless_qpprime_flag == 1) )) + { + int block_y, block_x; + + for (block_y=mb_y; block_yresidual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &coeff_cost, 0); + + if (nonzero) + { + cbp_blk_mask = (block_x >> 2) + block_y; + (*cbp_blk) |= (int64) 1 << cbp_blk_mask; // one bit for every 4x4 block + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + } + } + } + else + { + if (currSlice->NoResidueDirect != 1 && !skipped) + { + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, block8x8, &coeff_cost, 0); + + if (nonzero) + { + (*cbp_blk) |= 51 << (4*block8x8 - 2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + } + + if (currSlice->NoResidueDirect != 1 && !skipped && coeff_cost <= _LUMA_COEFF_COST_ && + ((currMB->qp_scaled[PLANE_Y])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0)) + { + coeff_cost = reset_block(currMB, cbp, cbp_blk, block8x8); + } + + return coeff_cost; +} + +/*! + ************************************************************************ + * \brief + * Residual Coding of an 8x8 Luma block (not for intra) + * + * \return + * coefficient cost + ************************************************************************ + */ +int luma_residual_coding_8x8 (Macroblock* currMB, //!< Current Macroblock to be coded + int *cbp, //!< Output: cbp (updated according to processed 8x8 luminance block) + int64 *cbp_blk, //!< Output: block cbp (updated according to processed 8x8 luminance block) + int block8x8, //!< block number of 8x8 block + short p_dir, //!< prediction direction + int list_mode[2], //!< list0 prediction mode (1-7, 0=DIRECT) + char *ref_idx) //!< reference pictures for each list +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int block_y, block_x, pic_pix_x, nonzero = 0, cbp_blk_mask; + int coeff_cost = 0; + int mb_y = (block8x8 >> 1) << 3; + int mb_x = (block8x8 & 0x01) << 3; + int cbp_mask = 1 << block8x8; + int skipped = (list_mode[0] == 0 && list_mode[1] == 0 && (currSlice->slice_type != B_SLICE)); + Boolean direct_inference = (list_mode[0] == 0 && list_mode[1] == 0 && currSlice->slice_type == B_SLICE && p_Vid->active_sps->direct_8x8_inference_flag == 0); + + char bipred_me = currMB->b8x8[block8x8].bipred; + currSlice->coeff_cost_cr[1] = currSlice->coeff_cost_cr[2] = 0; + + //memset( currSlice->cofAC[block8x8][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + //===== loop over 4x4 blocks ===== + if(!currMB->luma_transform_size_8x8_flag) + { + int bxx, byy; // indexing curr_blk + if (!direct_inference && (((p_dir == 0 || p_dir == 2 )&& list_mode[0] < 5) || ((p_dir == 1 || p_dir == 2 ) && list_mode[1] < 5))) + { + p_Dpb->pf_luma_prediction (currMB, mb_x, mb_y, 8, 8, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pCurImg[currMB->opix_y + mb_y], &currSlice->mb_pred[0][mb_y], &currSlice->mb_ores[0][mb_y], mb_x, currMB->pix_x + mb_x, 8, 8); + } + + for (byy=0, block_y=mb_y; block_ypix_x + block_x; + cbp_blk_mask = (block_x >> 2) + block_y; + + //===== prediction of 4x4 block ===== + if (direct_inference || !(((p_dir == 0 || p_dir == 2 )&& list_mode[0] < 5) || ((p_dir == 1 || p_dir == 2 ) && list_mode[1] < 5))) + { + p_Dpb->pf_luma_prediction (currMB, block_x, block_y, 4, 4, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue(&p_Vid->pCurImg[currMB->opix_y + block_y], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], block_x, pic_pix_x, 4, 4); + } + + //===== forward transform, Quantization, inverse Quantization, inverse transform, Reconstruction ===== + if (!skipped && ( (currSlice->NoResidueDirect != 1) || (currMB->qp_scaled[PLANE_Y] == 0 && p_Vid->active_sps->lossless_qpprime_flag == 1) )) + { + //===== forward transform, Quantization, inverse Quantization, inverse transform, Reconstruction ===== + nonzero = currMB->residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &coeff_cost, 0); + + if (nonzero) + { + (*cbp_blk) |= (int64)1 << cbp_blk_mask; // one bit for every 4x4 block + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + } + } + } + else + { + block_y = mb_y; + block_x = mb_x; + pic_pix_x = currMB->pix_x + block_x; + + cbp_blk_mask = (block_x>>2) + block_y; + + //===== prediction of 4x4 block ===== + p_Dpb->pf_luma_prediction (currMB, block_x, block_y, 8, 8, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pCurImg[currMB->opix_y + block_y], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], block_x, pic_pix_x, 8, 8); + + if (currSlice->NoResidueDirect != 1 && !skipped) + { + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, block8x8, &coeff_cost, 0); + + if (nonzero) + { + (*cbp_blk) |= 51 << (4*block8x8 - 2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + } + + if (currSlice->NoResidueDirect != 1 && !skipped && coeff_cost <= _LUMA_COEFF_COST_ && + ((currMB->qp_scaled[PLANE_Y])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0)) + { + coeff_cost = reset_block(currMB, cbp, cbp_blk, block8x8); + } + + return coeff_cost; +} + +/*! + ************************************************************************ + * \brief + * Set mode parameters and reference frames for an 8x8 block + ************************************************************************ + */ +void set_modes_and_reframe (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int j = 2*(b8>>1); + int i = 2*(b8 & 0x01); + + list_mode[0] = list_mode[1] = list_ref_idx[0] = list_ref_idx[1] = -1; + + *p_dir = currMB->b8x8[b8].pdir; + + if (currSlice->slice_type != B_SLICE) + { + list_ref_idx[0] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + list_ref_idx[1] = 0; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = 0; + } + else + { + if (*p_dir == -1) + { + list_ref_idx[0] = -1; + list_ref_idx[1] = -1; + list_mode[0] = 0; + list_mode[1] = 0; + } + else if (*p_dir == 0) + { + list_ref_idx[0] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + list_ref_idx[1] = 0; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = 0; + } + else if (*p_dir == 1) + { + list_ref_idx[0] = 0; + list_ref_idx[1] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + list_mode[0] = 0; + list_mode[1] = currMB->b8x8[b8].mode; + } + else + { + list_ref_idx[0] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + list_ref_idx[1] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = currMB->b8x8[b8].mode; + } + } +} + + +/*! + ************************************************************************ + * \brief + * Set mode parameters and reference frames for an 8x8 block + ************************************************************************ + */ +void set_modes_and_reframe_i_slice (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx) +{ + *p_dir = currMB->b8x8[b8].pdir; + + list_ref_idx[0] = -1; + list_ref_idx[1] = 0; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = 0; +} + +/*! + ************************************************************************ + * \brief + * Set mode parameters and reference frames for an 8x8 block + ************************************************************************ + */ +void set_modes_and_reframe_p_slice (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx) +{ + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int j = 2*(b8>>1); + int i = 2*(b8 & 0x01); + + *p_dir = currMB->b8x8[b8].pdir; + + list_ref_idx[0] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + list_ref_idx[1] = 0; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = 0; +} + + + +/*! + ************************************************************************ + * \brief + * Set mode parameters and reference frames for an 8x8 block + ************************************************************************ + */ +void set_modes_and_reframe_b_slice (Macroblock* currMB, int b8, short* p_dir, int list_mode[2], char *list_ref_idx) +{ + *p_dir = currMB->b8x8[b8].pdir; + + if (*p_dir == -1) + { + list_ref_idx[0] = -1; + list_ref_idx[1] = -1; + list_mode[0] = 0; + list_mode[1] = 0; + } + else if (*p_dir == 0) + { + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int j = 2*(b8>>1); + int i = 2*(b8 & 0x01); + + list_ref_idx[0] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + list_ref_idx[1] = 0; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = 0; + } + else if (*p_dir == 1) + { + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int j = 2*(b8>>1); + int i = 2*(b8 & 0x01); + + list_ref_idx[0] = 0; + list_ref_idx[1] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + list_mode[0] = 0; + list_mode[1] = currMB->b8x8[b8].mode; + } + else + { + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int j = 2*(b8>>1); + int i = 2*(b8 & 0x01); + + list_ref_idx[0] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + list_ref_idx[1] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + list_mode[0] = currMB->b8x8[b8].mode; + list_mode[1] = currMB->b8x8[b8].mode; + } +} + + +/*! + ************************************************************************ + * \brief + * Residual Coding of a Luma macroblock (not for intra) + ************************************************************************ + */ +void luma_residual_coding (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + int block8x8; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir = 0; + + int is_skip = currSlice->slice_type == P_SLICE && currMB->mb_type == PSKIP; + + currMB->cbp = 0; + currMB->cbp_blk = 0; + // the following parameters are not useful and should be removed for profiles < P444 + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + currSlice->cur_cbp_blk[1] = currSlice->cur_cbp_blk[2] = 0; + + if (is_skip) + { + for (block8x8=0; block8x8<4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + } + + //===== luma prediction ====== + p_Dpb->pf_luma_prediction (currMB, 0, 0, 16, 16, p_dir, list_mode, list_ref_idx, currMB->b8x8[0].bipred); + + //===== compute prediction residual ====== + // We should not need to compute this for skip mode, but currently computed for "debugging" purposes + compute_residue (&p_Vid->pCurImg[currMB->opix_y], *currSlice->mb_pred, *currSlice->mb_ores, 0, currMB->pix_x, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], *currSlice->mb_pred, currMB->pix_x, 0); + } + else + { + int sum_cnt_nonz = 0; + if (currMB->mb_type == P16x16) + { + for (block8x8 = 0; block8x8 < 4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + } + //===== luma prediction ====== + p_Dpb->pf_luma_prediction (currMB, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE, p_dir, list_mode, list_ref_idx, currMB->b8x8[0].bipred); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pCurImg[currMB->opix_y], *currSlice->mb_pred, *currSlice->mb_ores, 0, currMB->pix_x, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + // Luma residual coding (16x16 mode) + for (block8x8 = 0; block8x8 < 4; ++block8x8) + { + sum_cnt_nonz += luma_residual_coding_16x16 (currMB, block8x8, list_mode); + } + } + else + { + for (block8x8 = 0; block8x8 < 4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + sum_cnt_nonz += currSlice->luma_residual_coding_8x8 (currMB, &(currMB->cbp), &(currMB->cbp_blk), block8x8, p_dir, list_mode, list_ref_idx); + } + } + + // reset information (coefficient thresholding) + if (sum_cnt_nonz <= _LUMA_MB_COEFF_COST_ && ((currMB->qp_scaled[PLANE_Y])!=0 || p_Vid->active_sps->lossless_qpprime_flag == 0)) + { + currMB->cbp &= 0xfffff0 ; + currMB->cbp_blk &= 0xff0000 ; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], currSlice->mb_pred[0], currMB->pix_x, 0); + //memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + } + } +} + + +/*! + ************************************************************************ + * \brief + * Residual Coding of a Luma macroblock (not for intra) + ************************************************************************ + */ +void luma_residual_coding_sp (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + int i, j, block8x8, b8_x, b8_y; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir = 0; + int sum_cnt_nonz = 0; + + int is_skip = currSlice->slice_type == P_SLICE && currMB->mb_type == PSKIP; + + currMB->cbp = 0; + currMB->cbp_blk = 0; + // the following parameters are not useful and should be removed for profiles < P444 + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + currSlice->cur_cbp_blk[1] = currSlice->cur_cbp_blk[2] = 0; + + if (is_skip || currMB->mb_type == 1) + { + for (block8x8=0; block8x8<4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + } + + //===== luma prediction ====== + p_Dpb->pf_luma_prediction (currMB, 0, 0, 16, 16, p_dir, list_mode, list_ref_idx, currMB->b8x8[0].bipred); + + //===== compute prediction residual ====== + // We should not need to compute this for skip mode, but currently computed for "debugging" purposes + compute_residue (&p_Vid->pCurImg[currMB->opix_y], &currSlice->mb_pred[0][0], &currSlice->mb_ores[0][0], 0, currMB->pix_x, 16, 16); + + // Luma residual coding (16x16 mode) + if (!is_skip) + { + for (block8x8=0; block8x8<4; ++block8x8) + { + sum_cnt_nonz += luma_residual_coding_16x16 (currMB, block8x8, list_mode); + } + } + } + else + { + for (block8x8=0; block8x8<4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + sum_cnt_nonz += currSlice->luma_residual_coding_8x8 (currMB, &(currMB->cbp), &(currMB->cbp_blk), block8x8, p_dir, list_mode, list_ref_idx); + } + } + + // reset information (coefficient thresholding) + + if ((is_skip || + (sum_cnt_nonz <= _LUMA_MB_COEFF_COST_ && ((currMB->qp_scaled[PLANE_Y])!=0 || p_Vid->active_sps->lossless_qpprime_flag == 0))))// modif ES added last set of conditions + { + currMB->cbp &= 0xfffff0 ; + currMB->cbp_blk &= 0xff0000 ; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], currSlice->mb_pred[0], currMB->pix_x, 0); + + //memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + for(block8x8 = 0;block8x8 < 4; ++block8x8) + { + b8_x=(block8x8&1)<<3; + b8_y=(block8x8&2)<<2; + for (i = b8_x; i < b8_x + BLOCK_SIZE_8x8; i += 4) + for (j = b8_y; j < b8_y + BLOCK_SIZE_8x8;j += 4) + copyblock_sp(currMB, PLANE_Y, i, j); + } + } +} + +/*! + ************************************************************************ + * \brief + * RDOff decision between 4x4 and 8x8 transform + ************************************************************************ + */ +byte transform_decision (Macroblock *currMB, int block_check, distblk *cost) +{ + if(currMB->p_Inp->Transform8x8Mode == 2) //always allow 8x8 transform + { + return 1; + } + else + { + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int pic_pix_y, pic_pix_x, i, j; + int mb_y, mb_x, block8x8; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir; + int num_blks; + distblk cost8x8=0, cost4x4=0; + char bipred_me; + imgpel **mb_pred = currSlice->mb_pred[0]; + short diff16[4][16]; + short diff64[64]; + int index; + + if(block_check == -1) + { + block8x8 = 0; + num_blks = 4; + } + else + { + block8x8 = block_check; + num_blks = block_check + 1; + } + + for (; block8x8set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + bipred_me = currMB->b8x8[block8x8].bipred; + mb_y = (block8x8 >> 1) << 3; + mb_x = (block8x8 & 0x01) << 3; + + //===== prediction of 8x8 block ===== + p_Dpb->pf_luma_prediction (currMB, mb_x, mb_y, 8, 8, p_dir, list_mode, list_ref_idx, bipred_me); + + //===== loop over 8x8 blocks ===== + pic_pix_y = currMB->opix_y; + pic_pix_x = currMB->pix_x; + //===== get displaced frame difference ====== + for (j = mb_y; j < 8 + mb_y; j++) + { + for (i = mb_x; i < 8 + mb_x; i++) + { + index = 2 * ((j - mb_y)> 3) + ((i - mb_x)> 3); + *tmp64++ = *(tmp16[index])++ = (short) (p_Vid->pCurImg[pic_pix_y + j][pic_pix_x + i] - mb_pred[j][i]); + } + } + + cost4x4 += p_Vid->distortion4x4 (diff16[0], DISTBLK_MAX); + cost4x4 += p_Vid->distortion4x4 (diff16[1], DISTBLK_MAX); + cost4x4 += p_Vid->distortion4x4 (diff16[2], DISTBLK_MAX); + cost4x4 += p_Vid->distortion4x4 (diff16[3], DISTBLK_MAX); + cost8x8 += p_Vid->distortion8x8 (diff64 , DISTBLK_MAX); + } + + + if(cost8x8 < cost4x4) + { + return 1; + } + else + { + *cost += (cost4x4 - cost8x8); + return 0; + } + } +} + +/*! + ************************************************************************ + * \brief + * Chroma residual coding for an macroblock + ************************************************************************ + */ +void chroma_residual_coding (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + int chroma_cbp = 0; + int uv, block_y, block_x; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir; + int skipped = (currMB->mb_type == 0 && (currSlice->slice_type == P_SLICE)); + int yuv = p_Vid->yuv_format - 1; + + for (uv = 0; uv < 2; ++uv) + { + //===== prediction of chrominance blocks ===d== + // Intra modes + if (currMB->mb_type > P8x8) + { + for (block_y=0; block_y < p_Vid->mb_cr_size_y; block_y += BLOCK_SIZE) + { + for (block_x=0; block_x < p_Vid->mb_cr_size_x; block_x += BLOCK_SIZE) + { + int block8 = block8x8_idx[yuv][block_y>>2][block_x>>2]; + currSlice->set_modes_and_reframe (currMB, block8, &p_dir, list_mode, list_ref_idx); + IntraChromaPrediction4x4 (currMB, uv + 1, block_x, block_y); + } + } + } + else + { + for (block_y = 0; block_y < p_Vid->mb_cr_size_y; block_y += BLOCK_SIZE) + { + for (block_x = 0; block_x < p_Vid->mb_cr_size_x; block_x += BLOCK_SIZE) + { + int block8 = block8x8_idx[yuv][block_y>>2][block_x>>2]; + char bipred_me = currMB->b8x8[block8].bipred; + currSlice->set_modes_and_reframe (currMB, block8, &p_dir, list_mode, list_ref_idx); + + chroma_prediction_4x4 (currMB, uv, block_x, block_y, p_dir, list_mode[0], list_mode[1], list_ref_idx[0], list_ref_idx[1], bipred_me); + } + } + } + + // ==== set chroma residue to zero for skip Mode in SP frames + if (currSlice->NoResidueDirect) + { + copy_image_data(&p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y], currSlice->mb_pred[ uv + 1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + else if (skipped) + { + copy_image_data(&p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y], currSlice->mb_pred[ uv + 1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + else + { + compute_residue(&p_Vid->pImgOrg[uv + 1][currMB->opix_c_y ], currSlice->mb_pred[ uv + 1], currSlice->mb_ores[uv + 1], 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + + //===== forward transform, Quantization, inverse Quantization, inverse transform, and Reconstruction ===== + chroma_cbp = currMB->residual_transform_quant_chroma_4x4[uv] (currMB, uv, chroma_cbp); + } + } + + //===== update currMB->cbp ===== + currMB->cbp += ((chroma_cbp) << 4); +} + +/*! + ************************************************************************ + * \brief + * Chroma residual coding for an macroblock + ************************************************************************ + */ +void chroma_residual_coding_si (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + int chroma_cbp = 0; + int uv, block_y, block_x; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir; + int yuv = p_Vid->yuv_format - 1; + + for (uv = 0; uv < 2; ++uv) + { + //===== prediction of chrominance blocks ===d== + for (block_y=0; block_y < p_Vid->mb_cr_size_y; block_y+=4) + { + for (block_x=0; block_x < p_Vid->mb_cr_size_x; block_x+=4) + { + int block8 = block8x8_idx[yuv][block_y>>2][block_x>>2]; + currSlice->set_modes_and_reframe (currMB, block8, &p_dir, list_mode, list_ref_idx); + IntraChromaPrediction4x4 (currMB, uv + 1, block_x, block_y); + } + } + + compute_residue(&p_Vid->pImgOrg[uv + 1][currMB->opix_c_y ], currSlice->mb_pred[ uv + 1], currSlice->mb_ores[uv + 1], 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + + //===== forward transform, Quantization, inverse Quantization, inverse transform, and Reconstruction ===== + if (currMB->mb_type==I16MB || currMB->mb_type == I4MB) + { + chroma_cbp = residual_transform_quant_chroma_4x4(currMB, uv, chroma_cbp); + } + else + { + chroma_cbp = residual_transform_quant_chroma_4x4_sp2(currMB, uv, chroma_cbp); + } + } + + //===== update currMB->cbp ===== + currMB->cbp += ((chroma_cbp) << 4); +} + + +/*! + ************************************************************************ + * \brief + * Chroma residual coding for an macroblock + ************************************************************************ + */ +void chroma_residual_coding_sp (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + int chroma_cbp; + int uv, block_y, block_x, j; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir; + int skipped = (currMB->mb_type == 0); + int yuv = p_Vid->yuv_format - 1; + + + for (chroma_cbp = 0, uv=0; uv<2; ++uv) + { + //===== prediction of chrominance blocks ===d== + // Intra modes + if (currMB->mb_type > P8x8) + { + for (block_y=0; block_y < p_Vid->mb_cr_size_y; block_y += BLOCK_SIZE) + { + for (block_x=0; block_x < p_Vid->mb_cr_size_x; block_x += BLOCK_SIZE) + { + int block8 = block8x8_idx[yuv][block_y>>2][block_x>>2]; + currSlice->set_modes_and_reframe (currMB, block8, &p_dir, list_mode, list_ref_idx); + IntraChromaPrediction4x4 (currMB, uv + 1, block_x, block_y); + } + } + } + else + { + for (block_y=0; block_y < p_Vid->mb_cr_size_y; block_y += BLOCK_SIZE) + { + for (block_x=0; block_x < p_Vid->mb_cr_size_x; block_x += BLOCK_SIZE) + { + int block8 = block8x8_idx[yuv][block_y>>2][block_x>>2]; + char bipred_me = currMB->b8x8[block8].bipred; + currSlice->set_modes_and_reframe (currMB, block8, &p_dir, list_mode, list_ref_idx); + + chroma_prediction_4x4 (currMB, uv, block_x, block_y, p_dir, list_mode[0], list_mode[1], list_ref_idx[0], list_ref_idx[1], bipred_me); + } + } + } + + // ==== set chroma residue to zero for skip Mode in SP frames + if (currSlice->NoResidueDirect) + { + copy_image_data(&p_Vid->enc_picture->imgUV[uv][currMB->pix_c_y], currSlice->mb_pred[ uv + 1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + else if (skipped) + { + for (j=0; jmb_cr_size_y; ++j) + memset(currSlice->mb_ores[uv + 1][j], 0 , p_Vid->mb_cr_size_x * sizeof(int)); + for (j=0; jmb_cr_size_y; ++j) + memset(currSlice->mb_rres[uv + 1][j], 0 , p_Vid->mb_cr_size_x * sizeof(int)); + } + else + { + compute_residue(&p_Vid->pImgOrg[uv + 1][currMB->opix_c_y ], &currSlice->mb_pred[ uv + 1][0], &currSlice->mb_ores[uv + 1][0], 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + //===== forward transform, Quantization, inverse Quantization, inverse transform, and Reconstruction ===== + //===== Call function for skip mode in SP frames to properly process frame ==== + + if (skipped) + { + if(p_Vid->sp2_frame_indicator) + chroma_cbp = residual_transform_quant_chroma_4x4_sp2(currMB, uv, chroma_cbp); + else + chroma_cbp = residual_transform_quant_chroma_4x4_sp(currMB, uv, chroma_cbp); + } + else + { + if (!currSlice->NoResidueDirect && !skipped) + { + if (currMB->mb_type==I16MB || currMB->mb_type == I4MB) + { + chroma_cbp = residual_transform_quant_chroma_4x4(currMB, uv,chroma_cbp); + } + else + { + if(p_Vid->sp2_frame_indicator) + chroma_cbp = residual_transform_quant_chroma_4x4_sp2(currMB, uv, chroma_cbp);// switching SP frames + else + chroma_cbp=residual_transform_quant_chroma_4x4_sp(currMB, uv, chroma_cbp); + } + } + } + } + + //===== update currMB->cbp ===== + currMB->cbp += ((chroma_cbp)<<4); +} + +/*! + ************************************************************************ + * \brief + * Check if all reference frames for a macroblock are zero + ************************************************************************ + */ +int ZeroRef (Macroblock* currMB) +{ + PicMotionParams **motion = currMB->p_Vid->enc_picture->mv_info; + int i,j; + + for (j=currMB->block_y; jblock_y + BLOCK_MULTIPLE; ++j) + { + for (i=currMB->block_x; iblock_x + BLOCK_MULTIPLE; ++i) + { + if (motion[j][i].ref_idx[LIST_0] != 0) + return 0; + } + } + return 1; +} + + +/*! + ************************************************************************ + * \brief + * Converts macroblock type to coding value + ************************************************************************ + */ +int MBType2Value (Macroblock* currMB) +{ + Slice *currSlice = currMB->p_Slice; + static const int dir1offset[3] = { 1, 2, 3}; + static const int dir2offset[3][3] = {{ 0, 4, 8}, // 1. block forward + { 6, 2, 10}, // 1. block backward + {12, 14, 16}}; // 1. block bi-directional + + int si_slice = (currSlice->slice_type == SI_SLICE) ? 1 : 0; + + if (currSlice->slice_type != B_SLICE) + { + switch( currMB->mb_type ) + { + case I8MB: + case I4MB: + return ((currSlice->slice_type == I_SLICE || si_slice) ? (0 + si_slice) : 6); + break; + case SI4MB: + return 0; + break; + case I16MB: + return ((currSlice->slice_type == I_SLICE || si_slice) ? (0 + si_slice) : 6) + currMB->i16offset; + break; + case IPCM: + return ((currSlice->slice_type == I_SLICE || si_slice ) ? (25 + si_slice) : 31); + break; + case P8x8: + { + if (currSlice->symbol_mode==CAVLC && ZeroRef (currMB)) + return 5; + else + return 4; + } + break; + default: + return currMB->mb_type; + break; + } + } + else + { + switch( currMB->mb_type ) + { + case 0: + return 0; + break; + case I4MB: + case I8MB: + return 23; + break; + case I16MB: + return 23 + currMB->i16offset; + break; + case IPCM: + return 48; + break; + case P8x8: + return 22; + break; + case 1: + { + int pdir0 = currMB->b8x8[0].pdir; + return dir1offset[pdir0]; + } + break; + case 2: + { + int pdir0 = currMB->b8x8[0].pdir; + int pdir1 = currMB->b8x8[3].pdir; + + return 4 + dir2offset[pdir0][pdir1]; + } + break; + default: + { + int pdir0 = currMB->b8x8[0].pdir; + int pdir1 = currMB->b8x8[3].pdir; + return 5 + dir2offset[pdir0][pdir1]; + } + break; + } + } +} + +/*! +************************************************************************ +* \brief +* Writes 4x4 intra prediction modes for a macroblock +************************************************************************ +*/ +static int writeIntra4x4Modes(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + int i; + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition *dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + int rate = 0; + + currMB->IntraChromaPredModeFlag = 1; + + for(i = 0; i < 16; ++i) + { + se.context = i; + se.value1 = currMB->intra_pred_modes[i]; + se.value2 = 0; + +#if TRACE + if (se.value1 < 0 ) + snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 4x4 mode = predicted (context: %d)",se.context); + else + snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 4x4 mode = %3d (context: %d)",se.value1,se.context); +#endif + + // set symbol type and function pointers + se.type = SE_INTRAPREDMODE; + + // encode and update rate + currSlice->writeIntraPredMode (&se, dataPart); + + rate += se.len; + } + + mbBits->mb_mode += rate; + + return rate; +} + +/*! +************************************************************************ +* \brief +* Writes 8x8 intra prediction modes for a macroblock +************************************************************************ +*/ +static int writeIntra8x8Modes(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + int block8x8; + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition *dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + int rate = 0; + + currMB->IntraChromaPredModeFlag = 1; + + for(block8x8 = 0; block8x8 < 16; block8x8 += 4) + { + + se.context = block8x8; + se.value1 = currMB->intra_pred_modes8x8[block8x8]; + se.value2 = 0; + +#if TRACE + if (se.value1 < 0 ) + snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 8x8 mode = predicted (context: %d)",se.context); + else + snprintf(se.tracestring, TRACESTRING_SIZE, "Intra 8x8 mode = %3d (context: %d)",se.value1,se.context); +#endif + + // set symbol type and function pointers + se.type = SE_INTRAPREDMODE; + + // encode and update rate + currSlice->writeIntraPredMode (&se, dataPart); + + rate += se.len; + } + mbBits->mb_mode += rate; + + return rate; +} + +static int writeIntraModes(Macroblock *currMB) +{ + switch (currMB->mb_type) + { + case I4MB: + return writeIntra4x4Modes(currMB); + break; + case I8MB: + return writeIntra8x8Modes(currMB); + break; + default: + return 0; + break; + } +} + +/*! + ************************************************************************ + * \brief + * Converts 8x8 block type to coding value + ************************************************************************ + */ +int B8Mode2Value (Slice *currSlice, short b8mode, short b8pdir) +{ + static const int b8start[8] = {0,0,0,0, 1, 4, 5, 10}; + static const int b8inc [8] = {0,0,0,0, 1, 2, 2, 1}; + + return (currSlice->slice_type!=B_SLICE) ? (b8mode - 4) : b8start[b8mode] + b8inc[b8mode] * b8pdir; +} + +static int writeIPCMLuma (Macroblock *currMB, imgpel **imgY, Bitstream *currStream, SyntaxElement *se, int *bitCount) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int i, j; + int bit_size = MB_BLOCK_SIZE * MB_BLOCK_SIZE * p_Vid->bitdepth_luma; + + *bitCount += bit_size; + se->len = p_Vid->bitdepth_luma; + se->type = SE_MBTYPE; + + for (j = currMB->pix_y; j < currMB->pix_y + MB_BLOCK_SIZE; ++j) + { + for (i = currMB->pix_x; i < currMB->pix_x + MB_BLOCK_SIZE; ++i) + { + se->bitpattern = imax(p_Vid->min_IPCM_value, imgY[j][i]); + se->value1 = se->bitpattern; +#if TRACE + snprintf(se->tracestring, TRACESTRING_SIZE, "pcm_sample_luma (%d %d) = %d", j, i, se->bitpattern); +#endif + writeSE_Fix(se, currStream); + } + } + return bit_size; +} + +static int writeIPCMChroma (Macroblock *currMB, imgpel **imgUV, Bitstream *currStream, SyntaxElement *se, int *bitCount) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int i, j; + int bit_size = p_Vid->mb_cr_size_y * p_Vid->mb_cr_size_x * p_Vid->bitdepth_luma; + *bitCount += bit_size; + + se->len = p_Vid->bitdepth_chroma; + se->type = SE_MBTYPE; + + for (j = currMB->pix_c_y; j < currMB->pix_c_y + p_Vid->mb_cr_size_y; ++j) + { + for (i = currMB->pix_c_x; i < currMB->pix_c_x + p_Vid->mb_cr_size_x; ++i) + { + se->bitpattern = imax(p_Vid->min_IPCM_value, imgUV[j][i]); + se->value1 = se->bitpattern; +#if TRACE + //snprintf(se.tracestring, TRACESTRING_SIZE, "pcm_sample_chroma (%s) (%d %d) = %d", uv?"v":"u", j,i,se->bitpattern); + snprintf(se->tracestring, TRACESTRING_SIZE, "pcm_sample_chroma (%d %d) = %d", j, i, se->bitpattern); +#endif + writeSE_Fix(se, currStream); + } + } + return bit_size; +} + +static int writeIPCMByteAlign(Bitstream *currStream, SyntaxElement *se, int *bitCount) +{ + if (currStream->bits_to_go < 8) + { + // This will only happen in the CAVLC case, CABAC is already padded + se->type = SE_MBTYPE; + se->len = currStream->bits_to_go; + *bitCount += se->len; + se->bitpattern = 0; +#if TRACE + snprintf(se->tracestring, TRACESTRING_SIZE, "pcm_alignment_zero_bits = %d", se->len); +#endif + writeSE_Fix(se, currStream); + + return se->len; + } + else + return 0; +} + +/*! +************************************************************************ +* \brief +* Codes IPCM data +************************************************************************ +*/ +static int writeIPCMData(Macroblock *currMB, DataPartition* dataPart) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + int no_bits = 0; + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + + if (currSlice->symbol_mode == CABAC) + { + int len; + EncodingEnvironmentPtr eep = &dataPart->ee_cabac; + len = arienco_bits_written(eep); + arienco_done_encoding(currMB, eep); // This pads to byte + len = arienco_bits_written(eep) - len; + no_bits += len; + // Now restart the encoder + arienco_start_encoding(eep, dataPart->bitstream->streamBuffer, &(dataPart->bitstream->byte_pos)); + } + + writeIPCMByteAlign(dataPart->bitstream, &se, &(currMB->bits.mb_y_coeff)); + + no_bits += writeIPCMLuma (currMB, p_Vid->enc_picture->imgY, dataPart->bitstream, &se, &mbBits->mb_y_coeff); + + if ((p_Vid->active_sps->chroma_format_idc != YUV400) && (p_Inp->separate_colour_plane_flag == 0)) + { + int uv; + for (uv = 0; uv < 2; ++uv ) + { + no_bits += writeIPCMChroma (currMB, p_Vid->enc_picture->imgUV[uv], dataPart->bitstream, &se, &mbBits->mb_uv_coeff); + } + } + return no_bits; +} + +/*! +************************************************************************ +* \brief +* Codes macroblock header +* \param currMB +* current macroblock +* \param rdopt +* true for calls during RD-optimization +* \param coeff_rate +* bitrate of Luma and Chroma coeff +************************************************************************ +*/ +int write_b_slice_MB_layer (Macroblock *currMB, int rdopt, int *coeff_rate) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int i; + int mb_nr = currMB->mbAddrX; + Macroblock *prevMB = currMB->PrevMB; + int prev_mb_nr = (NULL == prevMB) ? -1 : prevMB->mbAddrX; + + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + // choose the appropriate data partition + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + Bitstream *currStream; + + int no_bits = 0; + int skip = currMB->mb_type ? 0 : !currMB->cbp; + int prevMbSkipped = 0; + int WriteFrameFieldMBInHeader = 0; + + if (currSlice->mb_aff_frame_flag) + { + if ((mb_nr & 0x01) == 0) + { + WriteFrameFieldMBInHeader = 1; // top field + + prevMbSkipped = 0; + } + else + { + if (prevMB->mb_type ? 0: !prevMB->cbp) + { + WriteFrameFieldMBInHeader = 1; // bottom, if top was skipped + } + + prevMbSkipped = p_Vid->mb_data[prev_mb_nr].skip_flag; + } + } + currMB->IntraChromaPredModeFlag = (char) IS_INTRA(currMB); + + if (currSlice->symbol_mode == CABAC) + { + int mb_type = MBType2Value (currMB); + if (currSlice->mb_aff_frame_flag && ((currMB->mbAddrX & 0x01) == 0 || prevMbSkipped)) + { + byte mb_field_tmp = currMB->mb_field; + currMB->mb_field = field_flag_inference(currMB); + CheckAvailabilityOfNeighborsCABAC(currMB); + currMB->mb_field = mb_field_tmp; + } + + //========= write mb_skip_flag (CABAC) ========= + se.value1 = mb_type; + se.value2 = currMB->cbp; + se.type = SE_MBTYPE; + + TRACE_SE (se.tracestring, "mb_skip_flag"); + currSlice->writeMB_Skip(currMB, &se, dataPart); + + no_bits += se.len; + + CheckAvailabilityOfNeighborsCABAC(currMB); + + //========= write mb_aff (CABAC) ========= + if(currSlice->mb_aff_frame_flag && !skip) // check for copy mode + { + if(WriteFrameFieldMBInHeader) + { + se.value1 = currMB->mb_field; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE(se.tracestring, "mb_field_decoding_flag"); + currSlice->writeFieldModeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + } + + //========= write mb_type (CABAC) ========= + if (currMB->mb_type != 0 || ((currMB->cbp != 0 || currSlice->cmp_cbp[1] !=0 || currSlice->cmp_cbp[2]!=0 ))) + { + se.value1 = mb_type; + se.value2 = 0; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "mb_type (B_SLICE) (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, currMB->mb_type); +#endif + currSlice->writeMB_typeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + } + // VLC not intra + else if (currMB->mb_type != 0 || ((currMB->cbp != 0 || currSlice->cmp_cbp[1] != 0 || currSlice->cmp_cbp[2]!=0 ))) + { + //===== Run Length Coding: Non-Skipped macroblock ===== + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE (se.tracestring, "mb_skip_run"); + writeSE_UVLC(&se, dataPart); + + no_bits += se.len; + + // store position after skip_run when re-encoding can occur (slices with fixed number of bytes) + if ( (p_Vid->cod_counter) && (p_Inp->slice_mode == FIXED_RATE) && (!rdopt)) + { + for (i=0; imax_part_nr; ++i) + { + currStream = currSlice->partArr[i].bitstream; + currStream->stored_bits_to_go = currStream->bits_to_go; + currStream->stored_byte_pos = currStream->byte_pos; + currStream->stored_byte_buf = currStream->byte_buf; + } + p_Vid->p_Stats->stored_bit_slice = p_Vid->p_Stats->bit_slice; + } + + // Reset cod counter + p_Vid->cod_counter = 0; + + // write mb_aff + if(currSlice->mb_aff_frame_flag && !skip) // check for copy mode + { + if(WriteFrameFieldMBInHeader) + { + se.value1 = currMB->mb_field; + se.type = SE_MBTYPE; + + TRACE_SE(se.tracestring, "mb_field_decoding_flag"); + writeSE_Flag (&se, dataPart); + + no_bits += se.len; + } + } + // Put out mb mode + se.value1 = MBType2Value (currMB); + + se.type = SE_MBTYPE; + se.value2 = 0; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "mb_type (B_SLICE) (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, currMB->mb_type); +#endif + + currSlice->writeMB_typeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + else + { + //Run Length Coding: Skipped macroblock + ++(p_Vid->cod_counter); + + currMB->skip_flag = 1; + // CAVLC + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + + if(FmoGetNextMBNr(p_Vid, currMB->mbAddrX) == -1 && p_Vid->cod_counter > 0) + { + // Put out run + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE(se.tracestring, "mb_skip_run"); + writeSE_UVLC(&se, dataPart); + + no_bits += se.len; + + // Reset cod counter + p_Vid->cod_counter = 0; + } + } + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) no_bits;; + + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = (currMB->mb_type == 0 && !(p_Vid->active_sps->direct_8x8_inference_flag))? FALSE : TRUE; + + if (currMB->mb_type == IPCM) + { + no_bits += writeIPCMData(currMB, &(currSlice->partArr[partMap[SE_LUM_DC_INTRA]])); + return no_bits; + } + + dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + //===== BITS FOR 8x8 SUB-PARTITION MODES ===== + if (currMB->mb_type == P8x8) + { + for (i=0; i<4; ++i) + { + se.value1 = B8Mode2Value (currSlice, currMB->b8x8[i].mode, currMB->b8x8[i].pdir); + se.value2 = 0; + se.type = SE_MBTYPE; +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d", i, currMB->b8x8[i].mode, currMB->b8x8[i].pdir); +#endif + currSlice->writeB8_typeInfo (&se, dataPart); + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) se.len;; + no_bits += se.len; + + //set NoMbPartLessThan8x8Flag for P8x8 mode + currMB->NoMbPartLessThan8x8Flag &= (Boolean) ((currMB->b8x8[i].mode == 0 && p_Vid->active_sps->direct_8x8_inference_flag) + || (currMB->b8x8[i].mode == 4)); + } + + no_bits += currSlice->writeMotionInfo2NAL (currMB); + } + + //============= Transform size flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + if ((currMB->mb_type == I8MB || currMB->mb_type == I4MB) && p_Inp->Transform8x8Mode) + { + se.value1 = currMB->luma_transform_size_8x8_flag; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "transform_size_8x8_flag = %3d", currMB->luma_transform_size_8x8_flag); +#endif + currSlice->writeMB_transform_size(currMB, &se, dataPart); + + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) se.len;; + no_bits += se.len; + } + + //===== BITS FOR INTRA PREDICTION MODES ==== + no_bits += writeIntraModes(currMB); + //===== BITS FOR CHROMA INTRA PREDICTION MODE ==== + if (currMB->IntraChromaPredModeFlag && ((p_Vid->active_sps->chroma_format_idc != YUV400) && (p_Vid->active_sps->chroma_format_idc != YUV444))) + no_bits += write_chroma_intra_pred_mode(currMB); + else if(!rdopt) //GB CHROMA !!!!! + { + currMB->c_ipred_mode = DC_PRED_8; + } + //setting c_ipred_mode to default is not the right place here + //resetting in rdopt.c (but where ??) + //with cabac and bframes maybe it could crash without this default + //since cabac needs the right neighborhood for the later MBs + + //----- motion information ----- + if (currMB->mb_type !=0 && currMB->mb_type != P8x8 && (!IS_INTRA(currMB))) + { + no_bits += currSlice->writeMotionInfo2NAL (currMB); + } + + if ((currMB->mb_type!=0) || ((currMB->cbp!=0 || currSlice->cmp_cbp[1]!=0 || currSlice->cmp_cbp[2]!=0))) + { + *coeff_rate = write_CBP_and_Dquant (currMB); + *coeff_rate += currSlice->writeCoeff16x16 (currMB, PLANE_Y); + + if ((p_Vid->active_sps->chroma_format_idc != YUV400) && ((p_Inp->separate_colour_plane_flag == 0))) + { + if(p_Vid->active_sps->chroma_format_idc == YUV444) + { + *coeff_rate += currSlice->writeCoeff16x16(currMB, PLANE_U); + *coeff_rate += currSlice->writeCoeff16x16(currMB, PLANE_V); + } + else + *coeff_rate += write_chroma_coeff (currMB); + } + no_bits += *coeff_rate; + } + + return no_bits; +} + +/*! +************************************************************************ +* \brief +* Codes macroblock header +* \param currMB +* current macroblock +* \param rdopt +* true for calls during RD-optimization +* \param coeff_rate +* bitrate of Luma and Chroma coeff +************************************************************************ +*/ +int write_p_slice_MB_layer (Macroblock *currMB, int rdopt, int *coeff_rate) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int i; + int mb_nr = currMB->mbAddrX; + Macroblock *prevMB = currMB->PrevMB; + int prev_mb_nr = (NULL == prevMB) ? -1 : prevMB->mbAddrX; + + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + // choose the appropriate data partition + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + Bitstream *currStream; + + int no_bits = 0; + int skip = currMB->mb_type ? 0 : 1; + int prevMbSkipped = 0; + int WriteFrameFieldMBInHeader = 0; + + if (currSlice->mb_aff_frame_flag) + { + if ((mb_nr & 0x01) == 0) + { + WriteFrameFieldMBInHeader = 1; // top field + + prevMbSkipped = 0; + } + else + { + if (prevMB->mb_type ? 0 : 1) + { + WriteFrameFieldMBInHeader = 1; // bottom, if top was skipped + } + + prevMbSkipped = p_Vid->mb_data[prev_mb_nr].skip_flag; + } + } + currMB->IntraChromaPredModeFlag = (char) IS_INTRA(currMB); + + if (currSlice->symbol_mode == CABAC) + { + int mb_type = MBType2Value (currMB); + if (currSlice->mb_aff_frame_flag && ((currMB->mbAddrX & 0x01) == 0 || prevMbSkipped)) + { + byte mb_field_tmp = currMB->mb_field; + currMB->mb_field = field_flag_inference(currMB); + CheckAvailabilityOfNeighborsCABAC(currMB); + currMB->mb_field = mb_field_tmp; + } + + //========= write mb_skip_flag (CABAC) ========= + se.value1 = mb_type; + se.value2 = currMB->cbp; + se.type = SE_MBTYPE; + + TRACE_SE (se.tracestring, "mb_skip_flag"); + currSlice->writeMB_Skip(currMB, &se, dataPart); + + no_bits += se.len; + + CheckAvailabilityOfNeighborsCABAC(currMB); + + //========= write mb_aff (CABAC) ========= + if(currSlice->mb_aff_frame_flag && !skip) // check for copy mode + { + if(WriteFrameFieldMBInHeader) + { + se.value1 = currMB->mb_field; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE(se.tracestring, "mb_field_decoding_flag"); + currSlice->writeFieldModeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + } + + //========= write mb_type (CABAC) ========= + if (currMB->mb_type != 0) + { + se.value1 = mb_type; + se.value2 = 0; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "mb_type (P_SLICE) (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, currMB->mb_type); +#endif + currSlice->writeMB_typeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + } + // VLC not intra + else if (currMB->mb_type != 0) + { + //===== Run Length Coding: Non-Skipped macroblock ===== + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE (se.tracestring, "mb_skip_run"); + writeSE_UVLC(&se, dataPart); + + no_bits += se.len; + + // store position after skip_run when re-encoding can occur (slices with fixed number of bytes) + if ( (p_Vid->cod_counter) && (p_Inp->slice_mode == FIXED_RATE) && (!rdopt)) + { + for (i=0; imax_part_nr; ++i) + { + currStream = currSlice->partArr[i].bitstream; + currStream->stored_bits_to_go = currStream->bits_to_go; + currStream->stored_byte_pos = currStream->byte_pos; + currStream->stored_byte_buf = currStream->byte_buf; + p_Vid->p_Stats->stored_bit_slice = p_Vid->p_Stats->bit_slice; + } + } + // Reset cod counter + p_Vid->cod_counter = 0; + + // write mb_aff + if(currSlice->mb_aff_frame_flag && !skip) // check for copy mode + { + if(WriteFrameFieldMBInHeader) + { + se.value1 = currMB->mb_field; + se.type = SE_MBTYPE; + + TRACE_SE(se.tracestring, "mb_field_decoding_flag"); + writeSE_Flag (&se, dataPart); + + no_bits += se.len; + } + } + // Put out mb mode + se.value1 = MBType2Value (currMB); + se.value1--; + + se.type = SE_MBTYPE; + se.value2 = 0; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "mb_type (P_SLICE) (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, currMB->mb_type); +#endif + + currSlice->writeMB_typeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + else + { + //Run Length Coding: Skipped macroblock + ++(p_Vid->cod_counter); + + currMB->skip_flag = 1; + // CAVLC + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + + if(FmoGetNextMBNr(p_Vid, currMB->mbAddrX) == -1 && p_Vid->cod_counter > 0) + { + // Put out run + se.value1 = p_Vid->cod_counter; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE(se.tracestring, "mb_skip_run"); + writeSE_UVLC(&se, dataPart); + + no_bits += se.len; + + // Reset cod counter + p_Vid->cod_counter = 0; + } + } + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) no_bits;; + + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + if (currMB->mb_type == IPCM) + { + no_bits += writeIPCMData(currMB, &(currSlice->partArr[partMap[SE_LUM_DC_INTRA]])); + return no_bits; + } + + dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + //===== BITS FOR 8x8 SUB-PARTITION MODES ===== + if (currMB->mb_type == P8x8) + { + for (i=0; i<4; ++i) + { + se.value1 = B8Mode2Value (currSlice, currMB->b8x8[i].mode, currMB->b8x8[i].pdir); + se.value2 = 0; + se.type = SE_MBTYPE; +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d", i, currMB->b8x8[i].mode, currMB->b8x8[i].pdir); +#endif + currSlice->writeB8_typeInfo (&se, dataPart); + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) se.len;; + no_bits += se.len; + + //set NoMbPartLessThan8x8Flag for P8x8 mode + currMB->NoMbPartLessThan8x8Flag &= (Boolean) ((currMB->b8x8[i].mode == 0 && p_Vid->active_sps->direct_8x8_inference_flag) + || (currMB->b8x8[i].mode ==4)); + } + + no_bits += currSlice->writeMotionInfo2NAL (currMB); + } + + //============= Transform size flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + if ((currMB->mb_type == I8MB || currMB->mb_type == I4MB) && p_Inp->Transform8x8Mode) + { + se.value1 = currMB->luma_transform_size_8x8_flag; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "transform_size_8x8_flag = %3d", currMB->luma_transform_size_8x8_flag); +#endif + currSlice->writeMB_transform_size(currMB, &se, dataPart); + + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) se.len;; + no_bits += se.len; + } + + //===== BITS FOR INTRA PREDICTION MODES ==== + no_bits += writeIntraModes(currMB); + //===== BITS FOR CHROMA INTRA PREDICTION MODE ==== + if (currMB->IntraChromaPredModeFlag && ((p_Vid->active_sps->chroma_format_idc != YUV400) && (p_Vid->active_sps->chroma_format_idc != YUV444))) + no_bits += write_chroma_intra_pred_mode(currMB); + else if(!rdopt) //GB CHROMA !!!!! + { + currMB->c_ipred_mode = DC_PRED_8; + } + //setting c_ipred_mode to default is not the right place here + //resetting in rdopt.c (but where ??) + //with cabac and bframes maybe it could crash without this default + //since cabac needs the right neighborhood for the later MBs + + //----- motion information ----- + if (currMB->mb_type !=0 && currMB->mb_type != P8x8 && (!IS_INTRA(currMB))) + { + no_bits += currSlice->writeMotionInfo2NAL (currMB); + } + + if (currMB->mb_type!=0) + { + *coeff_rate = write_CBP_and_Dquant (currMB); + *coeff_rate += currSlice->writeCoeff16x16 (currMB, PLANE_Y); + + if ((p_Vid->active_sps->chroma_format_idc != YUV400) && ((p_Inp->separate_colour_plane_flag == 0))) + { + if(p_Vid->active_sps->chroma_format_idc == YUV444) + { + *coeff_rate += currSlice->writeCoeff16x16(currMB, PLANE_U); + *coeff_rate += currSlice->writeCoeff16x16(currMB, PLANE_V); + } + else + *coeff_rate += write_chroma_coeff (currMB); + } + no_bits += *coeff_rate; + } + + return no_bits; +} + + +int write_i_slice_MB_layer (Macroblock *currMB, int rdopt, int *coeff_rate) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int mb_nr = currMB->mbAddrX; + Macroblock *prevMB = currMB->PrevMB; + + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + // choose the appropriate data partition + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + int no_bits = 0; + int WriteFrameFieldMBInHeader = 0; + + if (currSlice->mb_aff_frame_flag) + { + if ((mb_nr & 0x01) == 0) + { + WriteFrameFieldMBInHeader = 1; // top field + } + else + { + if (prevMB->mb_type ? 0: 1) + { + WriteFrameFieldMBInHeader = 1; // bottom, if top was skipped + } + } + + //========= write mb_aff (I_SLICE) ========= + if(WriteFrameFieldMBInHeader) + { + se.value1 = currMB->mb_field; + se.value2 = 0; + se.type = SE_MBTYPE; + + TRACE_SE (se.tracestring, "mb_field_decoding_flag"); + currSlice->writeFieldModeInfo(currMB, &se, dataPart); + + no_bits += se.len; + } + } + currMB->IntraChromaPredModeFlag = (char) IS_INTRA(currMB); + + + //========= write mb_type (I_SLICE) ========= + se.value1 = MBType2Value (currMB); + se.value2 = 0; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "mb_type (I_SLICE) (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, currMB->mb_type); +#endif + + currSlice->writeMB_typeInfo (currMB, &se, dataPart); + + no_bits += se.len; + + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) no_bits; + + //init NoMbPartLessThan8x8Flag + currMB->NoMbPartLessThan8x8Flag = TRUE; + + if (currMB->mb_type == IPCM) + { + no_bits += writeIPCMData(currMB, &(currSlice->partArr[partMap[SE_LUM_DC_INTRA]])); + return no_bits; + } + + dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + //============= Transform size flag for INTRA MBs ============= + //------------------------------------------------------------- + //transform size flag for INTRA_4x4 and INTRA_8x8 modes + if ((currMB->mb_type == I8MB || currMB->mb_type == I4MB) && p_Inp->Transform8x8Mode) + { + se.value1 = currMB->luma_transform_size_8x8_flag; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "transform_size_8x8_flag = %3d", currMB->luma_transform_size_8x8_flag); +#endif + currSlice->writeMB_transform_size(currMB, &se, dataPart); + + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) se.len;; + no_bits += se.len; + } + + //===== BITS FOR INTRA PREDICTION MODES ==== + no_bits += writeIntraModes(currMB); + //===== BITS FOR CHROMA INTRA PREDICTION MODE ==== + if (currMB->IntraChromaPredModeFlag && ((p_Vid->active_sps->chroma_format_idc != YUV400) && (p_Vid->active_sps->chroma_format_idc != YUV444))) + no_bits += write_chroma_intra_pred_mode(currMB); + else if(!rdopt) //GB CHROMA !!!!! + { + currMB->c_ipred_mode = DC_PRED_8; + } + //setting c_ipred_mode to default is not the right place here + //resetting in rdopt.c (but where ??) + //with cabac and bframes maybe it could crash without this default + //since cabac needs the right neighborhood for the later MBs + + *coeff_rate = write_CBP_and_Dquant (currMB); + *coeff_rate += currSlice->writeCoeff16x16 (currMB, PLANE_Y); + + if ((p_Vid->active_sps->chroma_format_idc != YUV400) && ((p_Inp->separate_colour_plane_flag == 0))) + { + if(p_Vid->active_sps->chroma_format_idc == YUV444) + { + *coeff_rate += currSlice->writeCoeff16x16(currMB, PLANE_U); + *coeff_rate += currSlice->writeCoeff16x16(currMB, PLANE_V); + } + else + *coeff_rate += write_chroma_coeff (currMB); + } + + no_bits += *coeff_rate; + + return no_bits; +} + +void write_terminating_bit (Slice *currSlice, int bit) +{ + const int* partMap = assignSE2partition[currSlice->partition_mode]; + //--- write non-slice termination symbol if the macroblock is not the first one in its slice --- + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + dataPart->bitstream->write_flag = 1; + + biari_encode_symbol_final(&(dataPart->ee_cabac), bit); +#if TRACE + fprintf (p_Enc->p_trace, " CABAC terminating bit = %d\n",bit); +#endif +} + + +/*! + ************************************************************************ + * \brief + * Write chroma intra prediction mode. + ************************************************************************ + */ +int write_chroma_intra_pred_mode(Macroblock* currMB) +{ + Slice* currSlice = currMB->p_Slice; + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + int rate = 0; + + + //===== BITS FOR CHROMA INTRA PREDICTION MODES + + se.value1 = currMB->c_ipred_mode; + se.value2 = 0; + se.type = SE_INTRAPREDMODE; + + TRACE_SE(se.tracestring, "intra_chroma_pred_mode"); + currSlice->writeCIPredMode(currMB, &se, dataPart); + + currMB->bits.mb_uv_coeff += se.len; + rate += se.len; + + return rate; +} + + +#if (MVC_EXTENSION_ENABLE) +int is_interview_mb(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + struct storable_picture **pList = currSlice->listX[0]; + int i,j, iRefIdx=-1, k; + int interview_in_l0 = 1; + int step_h0 = (block_size[(currMB->mb_type == P8x8) ? 4 : currMB->mb_type][0] >> 2); + int step_v0 = (block_size[(currMB->mb_type == P8x8) ? 4 : currMB->mb_type][1] >> 2); + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + for(i=0; ilistXsize[LIST_0]; i++) + { + if(pList[i]->view_id==0) + { + iRefIdx = i; + break; + } + } + if(iRefIdx == -1 && currSlice->slice_type == B_SLICE) + { + interview_in_l0 = 0; + pList = currSlice->listX[LIST_1]; + for(i=0; ilistXsize[LIST_1]; i++) + { + if(pList[i]->view_id==0) + { + iRefIdx = i; + break; + } + } + } + + if(iRefIdx<0) + { + return 0; + } + if(currMB->mb_type == PSKIP && currSlice->slice_type==P_SLICE) + { + return (iRefIdx==0); + } + for (j=0; j<4; j+=step_v0) + { + for (i=0; i<4; i +=step_h0) + { + k = j + (i >> 1); + if (interview_in_l0 && (currMB->b8x8[k].pdir == 0 || currMB->b8x8[k].pdir == 2))//has forward vector + { + if(motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0] == iRefIdx) + return 1; + } + else if (!interview_in_l0 && (currMB->b8x8[k].pdir == 1 || currMB->b8x8[k].pdir == 2))//has forward vector + { + if(motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1] == iRefIdx) + return 1; + } + } + } + + return 0; +} +#endif +/*! + ************************************************************************ + * \brief + * Passes the chosen syntax elements to the NAL + ************************************************************************ + */ +void write_macroblock (Macroblock* currMB, int eos_bit) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + BitCounter *mbBits = &currMB->bits; + int i; + + // enable writing of trace file +#if TRACE + if ( currMB->prev_recode_mb == FALSE ) + { + for (i=0; imax_part_nr; ++i) + { + currSlice->partArr[i].bitstream->trace_enabled = TRUE; + } + } +#endif + + //--- constrain intra prediction --- + if(p_Inp->UseConstrainedIntraPred && (currSlice->slice_type==P_SLICE || currSlice->slice_type==B_SLICE)) + { + p_Vid->intra_block[currMB->mbAddrX] = IS_INTRA(currMB); + } + + //===== init and update number of intra macroblocks ===== + if (currMB->mbAddrX == 0) + { + p_Vid->intras = 0; + p_Vid->iInterViewMBs =0; + } + + if (IS_INTRA(currMB)) + ++p_Vid->intras; +#if (MVC_EXTENSION_ENABLE) + else if(p_Vid->num_of_layers==2 && p_Vid->dpb_layer_id==1) + { + int is_interview = is_interview_mb(currMB); + + if(is_interview) + p_Vid->iInterViewMBs++; //p_Vid->enc_picture->mv_info + + } +#endif + //--- write non-slice termination symbol if the macroblock is not the first one in its slice --- + if (currSlice->symbol_mode==CABAC && currMB->mbAddrX != currSlice->start_mb_nr && eos_bit) + { + write_terminating_bit (currSlice, 0); + } + +#if TRACE + // trace: write macroblock header + if (p_Enc->p_trace) + { + fprintf(p_Enc->p_trace, "\n*********** Pic: %i (I/P) MB: %i Slice: %i **********\n\n", p_Vid->frame_no, currMB->mbAddrX, currSlice->slice_nr); + } +#endif + + p_Vid->cabac_encoding = 1; + + currMB->write_mb = TRUE; + //--- write macroblock --- + currSlice->write_MB_layer (currMB, 0, &i); // i is temporary + + if (!((currMB->mb_type !=0 ) || ((currSlice->slice_type==B_SLICE) && currMB->cbp != 0) )) + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); // CAVLC + } + + //--- set total bit-counter --- + mbBits->mb_total = mbBits->mb_mode + + mbBits->mb_y_coeff + + mbBits->mb_inter + + mbBits->mb_cbp + + mbBits->mb_delta_quant + + mbBits->mb_uv_coeff + + mbBits->mb_cb_coeff + + mbBits->mb_cr_coeff; + + if ( p_Inp->RCEnable ) + rc_update_mb_stats(currMB); + + /*record the total number of MBs*/ + ++(p_Vid->NumberofCodedMacroBlocks); + + p_Vid->p_Stats->bit_slice += mbBits->mb_total; + + p_Vid->cabac_encoding = 0; +} + + +/*! + ************************************************************************ + * \brief + * Codes the reference frame + ************************************************************************ + */ +int writeReferenceFrame (Macroblock* currMB, int i, int j, int list_idx, int ref) +{ + BitCounter *mbBits = &currMB->bits; + Slice *currSlice = currMB->p_Slice; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_REFFRAME]]); + int list = list_idx + currMB->list_offset; + SyntaxElement se; + + se.value1 = ref; + se.type = SE_REFFRAME; + se.value2 = list_idx; + + currMB->subblock_x = (short) (i << 2); // position used for context determination + currMB->subblock_y = (short) (j << 2); // position used for context determination + +#if TRACE + if (!list_idx) + snprintf(se.tracestring, TRACESTRING_SIZE, "ref_idx_l0 = %d", se.value1); + else + snprintf(se.tracestring, TRACESTRING_SIZE, "ref_idx_l1 = %d", se.value1); +#endif + + currSlice->writeRefFrame[list](currMB, &se, dataPart); + + mbBits->mb_inter = mbBits->mb_inter + (unsigned short) se.len; + + return (se.len); +} + + +/*! + ************************************************************************ + * \brief + * Writes motion vectors of an 8x8 block + ************************************************************************ + */ +int writeMotionVector8x8 (Macroblock *currMB, + int i0, + int j0, + int i1, + int j1, + int refframe, + int list_idx, + int mv_mode, + short bipred_me + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + PixelPos block[4]; + int i, j, k, l, m; + int curr_mvd; + + int rate = 0; + int step_h = part_size[mv_mode][0]; + int step_v = part_size[mv_mode][1]; + SyntaxElement se; + BitCounter *mbBits = &currMB->bits; + + const int* partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_MVD]]); + int refindex = refframe; + + MotionVector **all_mv = currSlice->all_mv[list_idx][refindex][mv_mode]; + MotionVector *cur_mv; + MotionVector predMV; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + //MotionVector **final_mv = &motion->mv[list_idx][currMB->block_y]; + short mvd[2]; + short (*currMB_mvd)[4][2] = currMB->mvd[list_idx]; + se.type = SE_MVD; + + if (bipred_me && is_bipred_enabled(p_Vid, mv_mode) && refindex == 0) + all_mv = currSlice->bipred_mv[bipred_me - 1][list_idx][refindex][mv_mode]; + + for (j = j0; j < j1; j += step_v) + { + currMB->subblock_y = (short) (j << 2); // position used for context determination + for (i = i0; i < i1; i += step_h) + { + currMB->subblock_x = (short) (i << 2); // position used for context determination + // When writing mv, let us use final mv instead of all_mv structure + if (currMB->write_mb) + cur_mv = &motion[currMB->block_y + j][currMB->block_x + i].mv[list_idx]; + else + cur_mv = &all_mv[j][i]; + + // Lets recompute MV predictor. This should avoid any problems with alterations of the motion vectors after ME + get_neighbors(currMB, block, i<<2, j<<2, step_h<<2); + currMB->GetMVPredictor (currMB, block, &predMV, (short) refindex, p_Vid->enc_picture->mv_info, list_idx, (i<<2), (j<<2), step_h<<2, step_v<<2); + //test_clip_mvs(p_Vid, cur_mv, currMB->write_mb); + mvd[0] = cur_mv->mv_x - predMV.mv_x; + mvd[1] = cur_mv->mv_y - predMV.mv_y; + + for (k=0; k<2; ++k) + { + curr_mvd = mvd[k]; + + //--- store (oversampled) mvd --- + for (l = j; l < j + step_v; ++l) + { + for (m = i; m < i + step_h; ++m) + { + currMB_mvd[l][m][k] = (short) curr_mvd; + } + } + + se.value1 = curr_mvd; + se.value2 = (k << 1) + list_idx; // identifies the component and the direction; only used for context determination +#if TRACE + if (k == 0) + snprintf(se.tracestring, TRACESTRING_SIZE, "mvd_l%d (%d) = %3d (org_mv %3d pred_mv %3d)",list_idx, k, curr_mvd, cur_mv->mv_x, predMV.mv_x); + else + snprintf(se.tracestring, TRACESTRING_SIZE, "mvd_l%d (%d) = %3d (org_mv %3d pred_mv %3d)",list_idx, k, curr_mvd, cur_mv->mv_y, predMV.mv_y); +#endif + currSlice->writeMVD (currMB, &se, dataPart); + + rate += se.len; + } + } + } + + mbBits->mb_inter = mbBits->mb_inter + (unsigned short) rate; + return rate; +} + + +/*! + ************************************************************************ + * \brief + * Writes motion info (b slice) + ************************************************************************ + */ +int write_b_slice_motion_info_to_NAL (Macroblock* currMB) +{ + int no_bits = 0; + //=== If multiple ref. frames, write reference frame for the MB === + if (currMB->mb_type != I4MB && currMB->mb_type != I16MB && currMB->mb_type != I8MB && currMB->mb_type != 0) + { + Slice* currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int k, j0, i0; + + int step_h0 = (block_size[(currMB->mb_type == P8x8) ? 4 : currMB->mb_type][0] >> 2); + int step_v0 = (block_size[(currMB->mb_type == P8x8) ? 4 : currMB->mb_type][1] >> 2); + + // Disable for now so we can check MBAFF + //if (currSlice->listXsize[0] > 1) + { + for (j0 = 0; j0 < 4; j0 += step_v0) + { + for (i0 = 0; i0 < 4; i0 += step_h0) + { + k = j0 + (i0 >> 1); + if (currMB->b8x8[k].mode !=0 && (currMB->b8x8[k].pdir == 0 || currMB->b8x8[k].pdir == 2))//has forward vector + { + no_bits += writeReferenceFrame (currMB, i0, j0, LIST_0, motion[currMB->block_y + j0][currMB->block_x + i0].ref_idx[LIST_0]); + } + } + } + } + + //if (currSlice->listXsize[1] > 1) + { + for (j0 = 0; j0 < 4; j0 += step_v0) + { + for (i0 = 0; i0 < 4; i0 += step_h0) + { + k = j0 + (i0 >> 1); + if (currMB->b8x8[k].mode !=0 && (currMB->b8x8[k].pdir == 1 || currMB->b8x8[k].pdir == 2))//has backward vector + { + no_bits += writeReferenceFrame (currMB, i0, j0, LIST_1, motion[currMB->block_y + j0][currMB->block_x + i0].ref_idx[LIST_1]); + } + } + } + } + + //===== write forward motion vectors ===== + for (j0=0; j0<4; j0+=step_v0) + { + for (i0=0; i0<4; i0+=step_h0) + { + k = j0 + (i0 >> 1); + if (currMB->b8x8[k].mode !=0 && (currMB->b8x8[k].pdir == 0 || currMB->b8x8[k].pdir == 2))//has forward vector + { + + no_bits += writeMotionVector8x8 (currMB, i0, j0, i0 + step_h0, j0 + step_v0, motion[currMB->block_y + j0][currMB->block_x + i0].ref_idx[LIST_0], + LIST_0, currMB->b8x8[k].mode, currMB->b8x8[k].bipred); + } + } + } + + //===== write backward motion vectors ===== + + for (j0=0; j0<4; j0+=step_v0) + { + for (i0 = 0; i0 < 4; i0 += step_h0) + { + k=j0+(i0 >> 1); + if (currMB->b8x8[k].mode !=0 && (currMB->b8x8[k].pdir == 1 || currMB->b8x8[k].pdir == 2))//has backward vector + { + no_bits += writeMotionVector8x8 (currMB, i0, j0, i0+step_h0, j0+step_v0, motion[currMB->block_y + j0][currMB->block_x + i0].ref_idx[LIST_1], + LIST_1, currMB->b8x8[k].mode, currMB->b8x8[k].bipred); + } + } + } + } + + return no_bits; +} + + +/*! + ************************************************************************ + * \brief + * Writes motion info (p slice) + ************************************************************************ + */ +int write_p_slice_motion_info_to_NAL (Macroblock* currMB) +{ + int no_bits = 0; + //=== If multiple ref. frames, write reference frame for the MB === + if (currMB->mb_type != I4MB && currMB->mb_type != I16MB && currMB->mb_type != I8MB && currMB->mb_type != 0) + { + Slice* currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int k, j0, i0; + int step_h0 = (block_size[(currMB->mb_type == P8x8) ? 4 : currMB->mb_type][0] >> 2); + int step_v0 = (block_size[(currMB->mb_type == P8x8) ? 4 : currMB->mb_type][1] >> 2); + + // if CAVLC is turned on, a 8x8 macroblock with all ref=0 in a P-frame is signalled in macroblock mode + if ((currMB->mb_type != P8x8) || !ZeroRef (currMB) || currSlice->symbol_mode==CABAC) + { + for (j0 = 0; j0 < 4; j0 += step_v0) + { + for (i0 = 0; i0 < 4; i0 += step_h0) + { + k = j0 + (i0 >> 1); + if (currMB->b8x8[k].mode !=0 && (currMB->b8x8[k].pdir == 0 || currMB->b8x8[k].pdir == 2)) + { + no_bits += writeReferenceFrame (currMB, i0, j0, LIST_0, motion[currMB->block_y + j0][currMB->block_x + i0].ref_idx[LIST_0]); + } + } + } + } + + //===== write forward motion vectors ===== + for (j0=0; j0<4; j0+=step_v0) + { + for (i0=0; i0<4; i0+=step_h0) + { + k = j0 + (i0 >> 1); + if (currMB->b8x8[k].mode !=0 && (currMB->b8x8[k].pdir == 0 || currMB->b8x8[k].pdir == 2))//has forward vector + { + no_bits += writeMotionVector8x8 (currMB, i0, j0, i0 + step_h0, j0 + step_v0, motion[currMB->block_y + j0][currMB->block_x + i0].ref_idx[LIST_0], + LIST_0, currMB->b8x8[k].mode, currMB->b8x8[k].bipred); + } + } + } + } + + return no_bits; +} + + +/*! + ************************************************************************ + * \brief + * Writes chrominance coefficients + ************************************************************************ + */ +static int write_chroma_coeff (Macroblock* currMB) +{ + Slice* currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + + int rate = 0; + int block_rate = 0; + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + int cbp = currMB->cbp; + DataPartition* dataPart; + + int level; + int k, uv; + int b8, b4; + int* ACLevel; + int* ACRun; + int* DCLevel; + int* DCRun; + + static const int chroma_dc_context[3]= + { + CHROMA_DC, CHROMA_DC_2x4, CHROMA_DC_4x4 + }; + + static const unsigned char chroma_ac_param[3][8][4] = + { + {{ 4, 20, 5, 21}, + {36, 52, 37, 53}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}}, + {{ 4, 20, 5, 21}, + { 6, 22, 7, 23}, + {36, 52, 37, 53}, + {38, 54, 39, 55}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}}, + {{ 4, 20, 5, 21}, + {36, 52, 37, 53}, + { 6, 22, 7, 23}, + {38, 54, 39, 55}, + { 8, 24, 9, 25}, + {40, 56, 41, 57}, + {10, 26, 11, 27}, + {42, 58, 43, 59}} + }; + + int yuv = p_Vid->yuv_format - 1; + //===== + //===== D C - C O E F F I C I E N T S + //===== + if (cbp > 15) // check if any chroma bits in coded block pattern is set + { + if (currSlice->symbol_mode == CAVLC) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CHROMA_DC, 0, 0, 0); //PLANE_U + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CHROMA_DC, 0, 0, 1); //PLANE_V + } + else + { + currMB->is_intra_block = (byte) IS_INTRA(currMB); + se.type = (currMB->is_intra_block ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER); + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + se.context = chroma_dc_context[yuv]; + + for (uv=0; uv < 2; ++uv) + { + p_Vid->is_v_block = uv; + + DCLevel = currSlice->cofDC[uv+1][0]; + DCRun = currSlice->cofDC[uv+1][1]; + + level = 1; + for (k=0; k <= p_Vid->num_cdc_coeff && level != 0; ++k) + { + level = se.value1 = DCLevel[k]; // level + se.value2 = DCRun [k]; // run + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "DC Chroma %2d: level =%3d run =%2d",k, level, se.value2); +#endif + writeRunLevel_CABAC(currMB, &se, dataPart); + + block_rate += se.len; + } + } + currMB->bits.mb_uv_coeff += block_rate; + rate += block_rate; + } + } + + //===== + //===== A C - C O E F F I C I E N T S + //===== + uv=-1; + if (cbp >> 4 == 2) // check if chroma bits in coded block pattern = 10b + { + if (currSlice->symbol_mode == CAVLC) + { + for (b8=4; b8 < (4 + p_Vid->num_blk8x8_uv); b8++) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CHROMA_AC, b8, 0, chroma_ac_param[yuv][b8 - 4][0]); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CHROMA_AC, b8, 1, chroma_ac_param[yuv][b8 - 4][1]); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CHROMA_AC, b8, 2, chroma_ac_param[yuv][b8 - 4][2]); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CHROMA_AC, b8, 3, chroma_ac_param[yuv][b8 - 4][3]); + } + } + else + { + block_rate = 0; + currMB->is_intra_block = (byte) IS_INTRA(currMB); + se.context = CHROMA_AC; + se.type = (currMB->is_intra_block ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER); + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + + for (b8=4; b8 < (4+p_Vid->num_blk8x8_uv); b8++) + { + for (b4=0; b4 < 4; b4++) + { + ACLevel = currSlice->cofAC[b8][b4][0]; + ACRun = currSlice->cofAC[b8][b4][1]; + + level=1; + uv++; + p_Vid->is_v_block = (uv >= (p_Vid->num_blk8x8_uv << 1)); + + currMB->subblock_y = subblk_offset_y[yuv][b8 - 4][b4]; + currMB->subblock_x = subblk_offset_x[yuv][b8 - 4][b4]; + + for (k=0; k < 16 && level != 0; k++) + { + level = se.value1 = ACLevel[k]; // level + se.value2 = ACRun [k]; // run + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "AC Chroma %2d: level =%3d run =%2d",k, level, se.value2); +#endif + writeRunLevel_CABAC(currMB, &se, dataPart); + block_rate += se.len; + } + } + } + currMB->bits.mb_uv_coeff += block_rate; + rate += block_rate; + } + } + + return rate; +} + +#if TRACE +static inline void trace_coeff(SyntaxElement *se, int plane, char *type, int k, int level, int run) +{ + if (plane == 0) + snprintf(se->tracestring, TRACESTRING_SIZE, "Luma%s sng(%2d) level =%3d run =%2d", type, k, level,run); + else if (plane == 1) + snprintf(se->tracestring, TRACESTRING_SIZE, "Cb%s sng(%2d) level =%3d run =%2d", type, k, level,run); + else + snprintf(se->tracestring, TRACESTRING_SIZE, "Cr%s sng(%2d) level =%3d run =%2d", type, k, level,run); +} +#endif + +/*! + ************************************************************************ + * \brief + * Writes Coeffs of an 4x4 block + ************************************************************************ + */ +int writeCoeff4x4_CABAC (Macroblock* currMB, ColorPlane plane, int b8, int b4, int intra4x4mode) +{ + Slice* currSlice = currMB->p_Slice; + + int rate = 0; + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition* dataPart; + + int level; + int k; + int pl_off=plane<<2; + + int *mb_bits_coeff = ((plane==0) ? &currMB->bits.mb_y_coeff : ((plane==1) ? &currMB->bits.mb_cb_coeff : &currMB->bits.mb_cr_coeff)); + int* ACLevel = currSlice->cofAC[b8+pl_off][b4][0]; + int* ACRun = currSlice->cofAC[b8+pl_off][b4][1]; + + currMB->subblock_x = ((b8&0x1)==0) ? (((b4&0x1)==0)? 0: 4) : (((b4&0x1)==0)? 8: 12); // horiz. position for coeff_count context + currMB->subblock_y = (b8<2) ? ((b4<2) ? 0: 4) : ((b4<2) ? 8: 12); // vert. position for coeff_count context + currMB->is_intra_block = (byte) intra4x4mode; + se.context = ((plane == 0) ? (LUMA_4x4) : ((plane==1) ? CB_4x4 : CR_4x4)); + + // DC + se.type = (intra4x4mode ? SE_LUM_DC_INTRA : SE_LUM_DC_INTER); + + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + + level = se.value1 = ACLevel[0]; // level + se.value2 = ACRun [0]; // run + +#if TRACE + trace_coeff(&se, plane, "4x4", 0, level, se.value2); +#endif + + writeRunLevel_CABAC(currMB, &se, dataPart); + rate += se.len; + + // AC Coefficients + se.type = (intra4x4mode ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER); + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + + for(k = 1; k <= 16 && level != 0; k++) + { + level = se.value1 = ACLevel[k]; // level + se.value2 = ACRun [k]; // run +#if TRACE + trace_coeff(&se, plane, "4x4", k, level, se.value2); +#endif + writeRunLevel_CABAC(currMB, &se, dataPart); + + rate += se.len; + } + + *mb_bits_coeff += rate; + + return rate; +} + +/*! +************************************************************************ +* \brief +* Writes coefficients of an 8x8 block (CABAC) +************************************************************************ +*/ +int writeCoeff8x8_CABAC (Macroblock* currMB, ColorPlane plane, int b8, int intra_mode) +{ + Slice* currSlice = currMB->p_Slice; + + int rate = 0; + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition* dataPart; + + int level; + int k; + + int pl_off = plane<<2; + int *mb_bits_coeff = ((plane==0) ? &currMB->bits.mb_y_coeff : ((plane==1) ? &currMB->bits.mb_cb_coeff : &currMB->bits.mb_cr_coeff)); + int* ACLevel = currSlice->cofAC[b8+pl_off][0][0]; + int* ACRun = currSlice->cofAC[b8+pl_off][0][1]; + + currMB->subblock_x = ((b8&0x1) == 0) ? 0 : 8; // horiz. position for coeff_count context + currMB->subblock_y = (b8 < 2) ? 0 : 8; // vert. position for coeff_count context + currMB->is_intra_block = (byte) intra_mode; + + se.context = ((plane==0) ? (LUMA_8x8) : ((plane == 1)? CB_8x8 : CR_8x8)); + + // DC + level = se.value1 = ACLevel[0]; // level + se.value2 = ACRun [0]; // run + + se.type = (intra_mode ? SE_LUM_DC_INTRA : SE_LUM_DC_INTER); + + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[currSlice->slice_type != B_SLICE ? se.type : SE_BFRAME]]); + +#if TRACE + trace_coeff(&se, plane, "8x8", 0, level, se.value2); +#endif + + writeRunLevel_CABAC(currMB, &se, dataPart); + rate += se.len; + + // AC + se.type = (intra_mode ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER); + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[currSlice->slice_type != B_SLICE ? se.type : SE_BFRAME]]); + + for(k=1; k<=64 && level !=0; k++) + { + level = se.value1 = ACLevel[k]; // level + se.value2 = ACRun [k]; // run + +#if TRACE + trace_coeff(&se, plane, "8x8", k, level, se.value2); +#endif + + writeRunLevel_CABAC(currMB, &se, dataPart); + rate += se.len; + } + + *mb_bits_coeff += rate; + return rate; +} + +/*! +************************************************************************ +* \brief +* Writes Luma Coeff of an 8x8 block +************************************************************************ +*/ +int writeCoeff8x8 (Macroblock* currMB, ColorPlane pl, int block8x8, int block_mode, int transform_size_flag) +{ + Slice* currSlice = currMB->p_Slice; + int rate = 0; + int is_intra = (block_mode == IBLOCK) || (block_mode == I8MB); + + //if (block_mode == I8MB) + //assert(transform_size_flag == 1); + + if (currSlice->symbol_mode == CAVLC ) + { + int block_color_type = ((pl == 0) ? LUMA : ((pl == 1) ? CB : CR)); + + rate += currSlice->writeCoeff4x4_CAVLC (currMB, block_color_type, block8x8, 0, is_intra); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, block_color_type, block8x8, 1, is_intra); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, block_color_type, block8x8, 2, is_intra); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, block_color_type, block8x8, 3, is_intra); + } + else // CABAC + { + if(transform_size_flag) // 8x8 + rate += writeCoeff8x8_CABAC (currMB, pl, block8x8, is_intra); + else + { + rate += writeCoeff4x4_CABAC (currMB, pl, block8x8, 0, is_intra); + rate += writeCoeff4x4_CABAC (currMB, pl, block8x8, 1, is_intra); + rate += writeCoeff4x4_CABAC (currMB, pl, block8x8, 2, is_intra); + rate += writeCoeff4x4_CABAC (currMB, pl, block8x8, 3, is_intra); + } + } + + return rate; +} + +/*! + ************************************************************************ + * \brief + * Writes CBP, DQUANT of an macroblock + ************************************************************************ + */ +int write_CBP_and_Dquant (Macroblock* currMB) +{ + Slice* currSlice = currMB->p_Slice; + + int rate = 0; + BitCounter *mbBits = &currMB->bits; + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + int cbp = currMB->cbp; + DataPartition* dataPart; + + se.value2 = 0; // Initialize value2 to avoid problems + + if (currMB->mb_type != I16MB) + { + VideoParameters *p_Vid = currMB->p_Vid; + int need_transform_size_flag; //ADD-VG-24062004 + //===== C B P ===== + //--------------------- + se.value1 = cbp; + se.type = SE_CBP; + + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "CBP (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, cbp); +#endif + currSlice->writeCBP (currMB, &se, dataPart); + + currMB->bits.mb_cbp = currMB->bits.mb_cbp + (unsigned short) se.len; + rate += se.len; + + //============= Transform Size Flag for INTER MBs ============= + //------------------------------------------------------------- + need_transform_size_flag = (((currMB->mb_type >= 1 && currMB->mb_type <= 3)|| + (currSlice->slice_type == B_SLICE && currMB->mb_type == 0 && p_Vid->active_sps->direct_8x8_inference_flag) || + (currMB->NoMbPartLessThan8x8Flag)) + && currMB->mb_type != I8MB && currMB->mb_type != I4MB + && (currMB->cbp&15 || currSlice->cmp_cbp[1]&15 || currSlice->cmp_cbp[2] & 15) + && currSlice->p_Inp->Transform8x8Mode); + + if (need_transform_size_flag) + { + se.value1 = currMB->luma_transform_size_8x8_flag; + se.type = SE_MBTYPE; + +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "transform_size_8x8_flag = %3d", currMB->luma_transform_size_8x8_flag); +#endif + currSlice->writeMB_transform_size(currMB, &se, dataPart); + + mbBits->mb_mode = mbBits->mb_mode + (unsigned short) se.len; + rate += se.len; + } + } + + //===== DQUANT ===== + //---------------------- + if (cbp!=0 || (currMB->mb_type == I16MB)) + { + se.value1 = currMB->qp - currMB->prev_qp; + se.type = SE_DELTA_QUANT; + + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); +#if TRACE + snprintf(se.tracestring, TRACESTRING_SIZE, "Delta QP (%2d,%2d) = %3d",currMB->mb_x, currMB->mb_y, se.value1); +#endif + currSlice->writeDquant (currMB, &se, dataPart); + currMB->bits.mb_delta_quant = currMB->bits.mb_delta_quant + (unsigned short) se.len; + rate += se.len; + } + + return rate; +} + +/*! +************************************************************************ +* \brief +* Write Luma Coeffcients, as well as Cb and Cr Coefficients in the +* case of 444 common mode, of an macroblock +************************************************************************ +*/ +int writeCoeff16x16_CAVLC (Macroblock* currMB, ColorPlane plane) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int cbp = currMB->cbp; + + int i, k; + int rate = 0; + + int b8, data_type; + int *mb_bits_coeff = ((plane==0) ? &currMB->bits.mb_y_coeff : ((plane==1) ? &currMB->bits.mb_cb_coeff : &currMB->bits.mb_cr_coeff)); + + if (currSlice->P444_joined) + { + for (i=0; i < 4; i++) + for (k=4*plane; k<4*(plane+1); k++) + p_Vid->nz_coeff [currMB->mbAddrX][i][k] = 0; + } + else + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + } + + + if (currMB->mb_type != I16MB) + { + //===== L U M I N A N C E ===== + //-------------------------------- + for (i=0; i<4; i++) + { + if (cbp & (1<b8x8[i].mode, currMB->luma_transform_size_8x8_flag); + } + } + } + else + { + //===== L U M I N A N C E f o r 1 6 x 1 6 ===== + //---------------------------------------------------- + // DC coeffs + switch (plane) + { + case 0: + default: + data_type = LUMA_INTRA16x16DC; + break; + case 1: + data_type = CB_INTRA16x16DC; + break; + case 2: + data_type = CR_INTRA16x16DC; + break; + } + rate += currSlice->writeCoeff4x4_CAVLC (currMB, data_type, 0, 0, 0); // CAVLC + + + // AC coeffs + if (cbp & 15) + { + switch (plane) + { + case 0: + default: + data_type = LUMA_INTRA16x16AC; + break; + case 1: + data_type = CB_INTRA16x16AC; + break; + case 2: + data_type = CR_INTRA16x16AC; + break; + } + + for (b8 = 0; b8 < 4; b8 ++) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, data_type, b8, 0, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, data_type, b8, 1, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, data_type, b8, 2, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, data_type, b8, 3, 0); + } + } + } + mb_bits_coeff += rate; + return rate; +} + + +/*! +************************************************************************ +* \brief +* Write Luma Coeffcients, as well as Cb and Cr Coefficients in the +* case of 444 common mode, of an macroblock +************************************************************************ +*/ +int writeCoeff16x16_CABAC (Macroblock* currMB, ColorPlane plane) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + + int cbp = currMB->cbp; + + int mb_x, mb_y, i, j, k; + int level; + int rate = 0; + int block_rate = 0; + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + int pl_off = plane<<2; + DataPartition* dataPart; + + int b8, b4; + int* DCLevel = currSlice->cofDC[plane][0]; + int* DCRun = currSlice->cofDC[plane][1]; + int* ACLevel; + int* ACRun; + int data_type; + int* mb_bits_coeff = ((plane==0) ? &currMB->bits.mb_y_coeff : ((plane==1) ? &currMB->bits.mb_cb_coeff : &currMB->bits.mb_cr_coeff)); + + if (currSlice->P444_joined) + { + for (i=0; i < 4; i++) + for (k=4*plane; k<4*(plane+1); k++) + p_Vid->nz_coeff [currMB->mbAddrX][i][k] = 0; + } + else + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + } + + + if (currMB->mb_type != I16MB) + { + //===== L U M I N A N C E ===== + //-------------------------------- + if (cbp != 0) + { + for (i=0; i<4; i++) + { + if (cbp & (1<b8x8[i].mode, currMB->luma_transform_size_8x8_flag); + } + } + } + } + else + { + //===== L U M I N A N C E f o r 1 6 x 1 6 ===== + //---------------------------------------------------- + // DC coeffs + currMB->is_intra_block = TRUE; + switch (plane) + { + case 0: + default: + data_type = LUMA_16DC; + break; + case 1: + data_type = CB_16DC; + break; + case 2: + data_type = CR_16DC; + break; + } + + se.context = data_type; + se.type = SE_LUM_DC_INTRA; // element is of type DC + + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + + level = 1; // get inside loop + for (k=0; k<=16 && level!=0; k++) + { + level = se.value1 = DCLevel[k]; // level + se.value2 = DCRun [k]; // run +#if TRACE + trace_coeff(&se, plane, "16x16 DC", k, level, se.value2); +#endif + writeRunLevel_CABAC(currMB, &se, dataPart); + block_rate += se.len; + } + *mb_bits_coeff += block_rate; + rate += block_rate; + + // AC coeffs + if (cbp & 15) + { + switch (plane) + { + case 0: + default: + data_type = LUMA_16AC; + break; + case 1: + data_type = CB_16AC; + break; + case 2: + data_type = CR_16AC; + break; + } + + se.context = data_type; + se.type = SE_LUM_AC_INTRA; // element is of type AC + + // choose the appropriate data partition + dataPart = &(currSlice->partArr[partMap[se.type]]); + block_rate = 0; + + for (mb_y = 0; mb_y < 4; mb_y += 2) + { + for (mb_x = 0; mb_x < 4; mb_x += 2) + { + for (j = mb_y; j < mb_y + 2; j++) + { + int j1 = 2*(j >> 1); + int j2 = 2*(j & 0x01); + currMB->subblock_y = (short) (j << 2); + + for (i=mb_x; i < mb_x+2; i++) + { + currMB->subblock_x = (short) (i << 2); + b8 = j1 + (i >> 1) + pl_off; + b4 = j2 + (i & 0x01); + + ACLevel = currSlice->cofAC[b8][b4][0]; + ACRun = currSlice->cofAC[b8][b4][1]; + + level=1; // get inside loop + + for (k=0; k < 16 && level !=0; k++) + { + level = se.value1 = ACLevel[k]; // level + se.value2 = ACRun [k]; // run +#if TRACE + trace_coeff(&se, plane, "16x16 AC", k, level, se.value2); +#endif + writeRunLevel_CABAC(currMB, &se, dataPart); + block_rate += se.len; + } + } + } + } + } + + rate += block_rate; + *mb_bits_coeff += block_rate; + } + } + + return rate; +} + +/*! + ************************************************************************ + * \brief + * Get the Prediction from the Neighboring Blocks for Number of Nonzero Coefficients + * + * Luma Blocks + ************************************************************************ + */ +int predict_nnz(Macroblock *currMB, int block_type, int i,int j) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos pix; + + int pred_nnz = 0; + int cnt = 0; + + // left block + get4x4Neighbour(currMB, (i << 2) - 1, (j << 2), p_Vid->mb_size[IS_LUMA], &pix); + + if (IS_INTRA(currMB) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && ((currSlice->partition_mode != 0) && !currSlice->idr_flag)) + { + pix.available &= p_Vid->intra_block[pix.mb_addr]; + if (!pix.available) + cnt++; + } + + if (pix.available) + { + switch (block_type) + { + case LUMA: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][pix.x][pix.y]; + cnt++; + break; + case CB: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][pix.x][4+pix.y]; + cnt++; + break; + case CR: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][pix.x][8+pix.y]; + cnt++; + break; + default: + error("writeCoeff4x4_CAVLC: Invalid block type", 600); + break; + } + } + + // top block + get4x4Neighbour(currMB, (i<<2), (j<<2) - 1, p_Vid->mb_size[IS_LUMA], &pix); + + if (IS_INTRA(currMB) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && ((currSlice->partition_mode != 0) && !currSlice->idr_flag)) + { + pix.available &= p_Vid->intra_block[pix.mb_addr]; + if (!pix.available) + cnt++; + } + + if (pix.available) + { + switch (block_type) + { + case LUMA: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][pix.x][pix.y]; + cnt++; + break; + case CB: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][pix.x][4+pix.y]; + cnt++; + break; + case CR: + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][pix.x][8+pix.y]; + cnt++; + break; + default: + error("writeCoeff4x4_CAVLC: Invalid block type", 600); + break; + } + } + + if (cnt==2) + { + pred_nnz++; + pred_nnz>>=1; + } + + return pred_nnz; +} + + +/*! + ************************************************************************ + * \brief + * Get the Prediction from the Neighboring Blocks for Number of Nonzero Coefficients + * + * Chroma Blocks + ************************************************************************ + */ +int predict_nnz_chroma(Macroblock *currMB, int i,int j) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PixelPos pix; + + int pred_nnz = 0; + int cnt = 0; + + if (p_Vid->yuv_format != YUV444) + { + //YUV420 and YUV422 + // left block + get4x4Neighbour(currMB, ((i & 0x01)<<2) - 1, ((j-4)<<2), p_Vid->mb_size[IS_CHROMA], &pix); + + if (IS_INTRA(currMB) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && ((currSlice->partition_mode != 0) && !currSlice->idr_flag)) + { + pix.available &= p_Vid->intra_block[pix.mb_addr]; + if (!pix.available) + cnt++; + } + + if (pix.available) + { + pred_nnz = p_Vid->nz_coeff [pix.mb_addr ][2 * (i >> 1) + pix.x][4 + pix.y]; + cnt++; + } + + // top block + get4x4Neighbour(currMB, ((i & 0x01)<<2), ((j-4)<<2) -1, p_Vid->mb_size[IS_CHROMA], &pix); + + if (IS_INTRA(currMB) && pix.available && p_Vid->active_pps->constrained_intra_pred_flag && ((currSlice->partition_mode != 0) && !currSlice->idr_flag)) + { + pix.available &= p_Vid->intra_block[pix.mb_addr]; + if (!pix.available) + cnt++; + } + + if (pix.available) + { + pred_nnz += p_Vid->nz_coeff [pix.mb_addr ][2 * (i >> 1) + pix.x][4 + pix.y]; + cnt++; + } + } + + + if (cnt==2) + { + pred_nnz++; + pred_nnz>>=1; + } + + return pred_nnz; +} + +/*! + ************************************************************************ + * \brief + * Writes coeff of an 4x4 block (CAVLC) + * + * \author + * Karl Lillevold + * contributions by James Au + ************************************************************************ + */ +int writeCoeff4x4_CAVLC_normal (Macroblock* currMB, int block_type, int b8, int b4, int param) +{ + Slice* currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + int no_bits = 0; + SyntaxElement se; + DataPartition *dataPart; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + + int k,level = 1,run = 0, vlcnum; + int numcoeff = 0, lastcoeff = 0, numtrailingones = 0; + int numones = 0, totzeros = 0, zerosleft, numcoef; + int numcoeff_vlc; + int code, level_two_or_higher; + int dptype = 0; + int nnz, max_coeff_num = 0, cdc = 0, cac = 0; + int subblock_x, subblock_y; + int *mb_bits_coeff = &currMB->bits.mb_y_coeff; +#if TRACE + char type[15]; +#endif + + static const int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6 + + + int* pLevel = NULL; + int* pRun = NULL; + + switch (block_type) + { + case LUMA: + max_coeff_num = 16; + + pLevel = currSlice->cofAC[b8][b4][0]; + pRun = currSlice->cofAC[b8][b4][1]; +#if TRACE + sprintf(type, "%s", "Luma"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + break; + + case CHROMA_AC: + max_coeff_num = 15; + mb_bits_coeff = &currMB->bits.mb_uv_coeff; + cac = 1; + + pLevel = currSlice->cofAC[b8][b4][0]; + pRun = currSlice->cofAC[b8][b4][1]; +#if TRACE + sprintf(type, "%s", "ChrAC"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER; + break; + + case CHROMA_DC: + max_coeff_num = p_Vid->num_cdc_coeff; + mb_bits_coeff = &currMB->bits.mb_uv_coeff; + cdc = 1; + + pLevel = currSlice->cofDC[param + 1][0]; + pRun = currSlice->cofDC[param + 1][1]; +#if TRACE + sprintf(type, "%s", "ChrDC"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER; + break; + + case LUMA_INTRA16x16AC: + max_coeff_num = 15; + + pLevel = currSlice->cofAC[b8][b4][0]; + pRun = currSlice->cofAC[b8][b4][1]; +#if TRACE + sprintf(type, "%s", "Lum16AC"); +#endif + dptype = SE_LUM_AC_INTRA; + break; + + case LUMA_INTRA16x16DC: + max_coeff_num = 16; + + pLevel = currSlice->cofDC[0][0]; + pRun = currSlice->cofDC[0][1]; +#if TRACE + sprintf(type, "%s", "Lum16DC"); +#endif + dptype = SE_LUM_DC_INTRA; + break; + + + default: + error("writeCoeff4x4_CAVLC: Invalid block type", 600); + break; + } + + dataPart = &(currSlice->partArr[partMap[dptype]]); + + for(k = 0; (k <= ((cdc) ? p_Vid->num_cdc_coeff : 16)) && level != 0; k++) + { + level = pLevel[k]; // level + run = pRun[k]; // run + + if (level) + { + + totzeros += run; + if (iabs(level) == 1) + { + numones ++; + numtrailingones ++; + numtrailingones = imin(numtrailingones, 3); // clip to 3 + } + else + { + numtrailingones = 0; + } + numcoeff ++; + lastcoeff = k; + } + } + + if (!cdc) + { + if (!cac) + { + // luma + subblock_x = ((b8 & 0x1) == 0) ? (((b4 & 0x1) == 0) ? 0 : 1) : (((b4 & 0x1) == 0) ? 2 : 3); + // horiz. position for coeff_count context + subblock_y = (b8 < 2) ? ((b4 < 2) ? 0 : 1) : ((b4 < 2) ? 2 : 3); + // vert. position for coeff_count context + nnz = predict_nnz(currMB, LUMA, subblock_x,subblock_y); + } + else + { + // chroma AC + subblock_x = param >> 4; + subblock_y = param & 15; + nnz = predict_nnz_chroma(currMB, subblock_x, subblock_y); + } + p_Vid->nz_coeff [currMB->mbAddrX ][subblock_x][subblock_y] = numcoeff; + + numcoeff_vlc = (nnz < 2) ? 0 : ((nnz < 4) ? 1 : ((nnz < 8) ? 2 : 3)); + } + else + { + // chroma DC (has its own VLC) + // numcoeff_vlc not relevant + numcoeff_vlc = 0; + + subblock_x = param; + subblock_y = param; + } + + se.type = dptype; + + se.value1 = numcoeff; + se.value2 = numtrailingones; + se.len = numcoeff_vlc; /* use len to pass vlcnum */ + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s # c & tr.1s(%d,%d) vlc=%d #c=%d #t1=%d", + type, subblock_x, subblock_y, numcoeff_vlc, numcoeff, numtrailingones); +#endif + + if (!cdc) + writeSyntaxElement_NumCoeffTrailingOnes(&se, dataPart); + else + writeSyntaxElement_NumCoeffTrailingOnesChromaDC(p_Vid, &se, dataPart); + + *mb_bits_coeff += se.len; + no_bits += se.len; + + if (!numcoeff) + return no_bits; + + if (numcoeff) + { + code = 0; + for (k = lastcoeff; k > lastcoeff - numtrailingones; k--) + { + level = pLevel[k]; // level +#ifdef _DEBUG + if (iabs(level) > 1) + { + printf("ERROR: level > 1\n"); + exit(-1); + } +#endif + code <<= 1; + + code |= (level < 0); + } + + if (numtrailingones) + { + se.type = dptype; + + se.value2 = numtrailingones; + se.value1 = code; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s trailing ones sign (%d,%d)", + type, subblock_x, subblock_y); +#endif + + writeSyntaxElement_VLC (&se, dataPart); + *mb_bits_coeff += se.len; + no_bits += se.len; + + } + + // encode levels + level_two_or_higher = (numcoeff > 3 && numtrailingones == 3) ? 0 : 1; + + vlcnum = (numcoeff > 10 && numtrailingones < 3) ? 1 : 0; + + for (k = lastcoeff - numtrailingones; k >= 0; k--) + { + level = pLevel[k]; // level + + se.value1 = level; + se.type = dptype; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s lev (%d,%d) k=%d vlc=%d lev=%3d", + type, subblock_x, subblock_y, k, vlcnum, level); +#endif + + if (level_two_or_higher) + { + level_two_or_higher = 0; + + if (se.value1 > 0) + se.value1 --; + else + se.value1 ++; + } + + // encode level + + if (vlcnum == 0) + writeSyntaxElement_Level_VLC1(&se, dataPart, p_Vid->active_sps->profile_idc); + else + writeSyntaxElement_Level_VLCN(&se, vlcnum, dataPart, p_Vid->active_sps->profile_idc); + + // update VLC table + if (iabs(level) > incVlc[vlcnum]) + vlcnum++; + + if ((k == lastcoeff - numtrailingones) && iabs(level) > 3) + vlcnum = 2; + + *mb_bits_coeff += se.len; + no_bits += se.len; + } + + // encode total zeroes + if (numcoeff < max_coeff_num) + { + + se.type = dptype; + se.value1 = totzeros; + + vlcnum = numcoeff - 1; + + se.len = vlcnum; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s totalrun (%d,%d) vlc=%d totzeros=%3d", + type, subblock_x, subblock_y, vlcnum, totzeros); +#endif + if (!cdc) + writeSyntaxElement_TotalZeros(&se, dataPart); + else + writeSyntaxElement_TotalZerosChromaDC(p_Vid, &se, dataPart); + + *mb_bits_coeff += se.len; + no_bits += se.len; + } + + // encode run before each coefficient + zerosleft = totzeros; + numcoef = numcoeff; + for (k = lastcoeff; k >= 0; k--) + { + run = pRun[k]; // run + + se.value1 = run; + se.type = dptype; + + // for last coeff, run is remaining totzeros + // when zerosleft is zero, remaining coeffs have 0 run + if ((!zerosleft) || (numcoeff <= 1 )) + break; + + if (numcoef > 1 && zerosleft) + { + vlcnum = imin(zerosleft - 1, RUNBEFORE_NUM_M1); + se.len = vlcnum; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s run (%d,%d) k=%d vlc=%d run=%2d", + type, subblock_x, subblock_y, k, vlcnum, run); +#endif + + writeSyntaxElement_Run(&se, dataPart); + + *mb_bits_coeff += se.len; + no_bits += se.len; + + zerosleft -= run; + numcoef --; + } + } + } + + return no_bits; +} + +/*! + ************************************************************************ + * \brief + * Writes coeff of an 4x4 block (CAVLC) + * + * \author + * Karl Lillevold + * contributions by James Au + ************************************************************************ + */ +int writeCoeff4x4_CAVLC_444 (Macroblock* currMB, int block_type, int b8, int b4, int param) +{ + Slice* currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + int no_bits = 0; + SyntaxElement se; + DataPartition *dataPart; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + + int k,level = 1,run = 0, vlcnum; + int numcoeff = 0, lastcoeff = 0, numtrailingones = 0; + int numones = 0, totzeros = 0, zerosleft, numcoef; + int numcoeff_vlc; + int code, level_two_or_higher; + int dptype = 0; + int nnz, max_coeff_num = 0, cdc = 0, cac = 0; + int subblock_x, subblock_y; + int *mb_bits_coeff = &currMB->bits.mb_y_coeff; +#if TRACE + char type[15]; +#endif + + static const int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6 + + int* pLevel = NULL; + int* pRun = NULL; + + switch (block_type) + { + case LUMA: + max_coeff_num = 16; + + pLevel = currSlice->cofAC[b8][b4][0]; + pRun = currSlice->cofAC[b8][b4][1]; +#if TRACE + sprintf(type, "%s", "Luma"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + break; + case LUMA_INTRA16x16DC: + max_coeff_num = 16; + + pLevel = currSlice->cofDC[0][0]; + pRun = currSlice->cofDC[0][1]; +#if TRACE + sprintf(type, "%s", "Lum16DC"); +#endif + dptype = SE_LUM_DC_INTRA; + break; + case LUMA_INTRA16x16AC: + max_coeff_num = 15; + + pLevel = currSlice->cofAC[b8][b4][0]; + pRun = currSlice->cofAC[b8][b4][1]; +#if TRACE + sprintf(type, "%s", "Lum16AC"); +#endif + dptype = SE_LUM_AC_INTRA; + break; + case CB: + max_coeff_num = 16; + mb_bits_coeff = &currMB->bits.mb_cb_coeff; + + pLevel = currSlice->cofAC[4+b8][b4][0]; + pRun = currSlice->cofAC[4+b8][b4][1]; +#if TRACE + sprintf(type, "%s", "CB"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + break; + case CB_INTRA16x16DC: + max_coeff_num = 16; + mb_bits_coeff = &currMB->bits.mb_cb_coeff; + + pLevel = currSlice->cofDC[1][0]; + pRun = currSlice->cofDC[1][1]; +#if TRACE + sprintf(type, "%s", "CB_16DC"); +#endif + dptype = SE_LUM_DC_INTRA; + break; + case CB_INTRA16x16AC: + max_coeff_num = 15; + mb_bits_coeff = &currMB->bits.mb_cb_coeff; + + pLevel = currSlice->cofAC[4+b8][b4][0]; + pRun = currSlice->cofAC[4+b8][b4][1]; +#if TRACE + sprintf(type, "%s", "CB_16AC"); +#endif + dptype = SE_LUM_AC_INTRA; + break; + + case CR: + max_coeff_num = 16; + mb_bits_coeff = &currMB->bits.mb_cr_coeff; + + pLevel = currSlice->cofAC[8+b8][b4][0]; + pRun = currSlice->cofAC[8+b8][b4][1]; +#if TRACE + sprintf(type, "%s", "CR"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER; + break; + case CR_INTRA16x16DC: + max_coeff_num = 16; + mb_bits_coeff = &currMB->bits.mb_cr_coeff; + + pLevel = currSlice->cofDC[2][0]; + pRun = currSlice->cofDC[2][1]; +#if TRACE + sprintf(type, "%s", "CR_16DC"); +#endif + dptype = SE_LUM_DC_INTRA; + break; + case CR_INTRA16x16AC: + max_coeff_num = 15; + mb_bits_coeff = &currMB->bits.mb_cr_coeff; + + pLevel = currSlice->cofAC[8+b8][b4][0]; + pRun = currSlice->cofAC[8+b8][b4][1]; +#if TRACE + sprintf(type, "%s", "CR_16AC"); +#endif + dptype = SE_LUM_AC_INTRA; + break; + + case CHROMA_DC: + max_coeff_num = p_Vid->num_cdc_coeff; + mb_bits_coeff = &currMB->bits.mb_uv_coeff; + cdc = 1; + + pLevel = currSlice->cofDC[param+1][0]; + pRun = currSlice->cofDC[param+1][1]; +#if TRACE + sprintf(type, "%s", "ChrDC"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_CHR_DC_INTRA : SE_CHR_DC_INTER; + break; + case CHROMA_AC: + max_coeff_num = 15; + mb_bits_coeff = &currMB->bits.mb_uv_coeff; + cac = 1; + + pLevel = currSlice->cofAC[b8][b4][0]; + pRun = currSlice->cofAC[b8][b4][1]; +#if TRACE + sprintf(type, "%s", "ChrAC"); +#endif + dptype = (IS_INTRA (currMB)) ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER; + break; + default: + error("writeCoeff4x4_CAVLC: Invalid block type", 600); + break; + } + + dataPart = &(currSlice->partArr[partMap[dptype]]); + + for(k = 0; (k <= ((cdc) ? p_Vid->num_cdc_coeff : 16)) && level != 0; k++) + { + level = pLevel[k]; // level + run = pRun[k]; // run + + if (level) + { + + totzeros += run; // lets add run always (even if zero) to avoid conditional + if (iabs(level) == 1) + { + numones ++; + numtrailingones ++; + numtrailingones = imin(numtrailingones, 3); // clip to 3 + } + else + { + numtrailingones = 0; + } + numcoeff ++; + lastcoeff = k; + } + } + + if (!cdc) + { + if(block_type==LUMA || block_type==LUMA_INTRA16x16DC || block_type==LUMA_INTRA16x16AC + ||block_type==CHROMA_AC) + { + if (!cac) + { + // luma + subblock_x = ((b8 & 0x1) == 0) ? (((b4 & 0x1) == 0) ? 0 : 1) : (((b4 & 0x1) == 0) ? 2 : 3); + // horiz. position for coeff_count context + subblock_y = (b8 < 2) ? ((b4 < 2) ? 0 : 1) : ((b4 < 2) ? 2 : 3); + // vert. position for coeff_count context + nnz = predict_nnz(currMB, LUMA, subblock_x,subblock_y); + } + else + { + // chroma AC + subblock_x = param >> 4; + subblock_y = param & 15; + nnz = predict_nnz_chroma(currMB, subblock_x, subblock_y); + } + p_Vid->nz_coeff [currMB->mbAddrX ][subblock_x][subblock_y] = numcoeff; + } + else if (block_type==CB || block_type==CB_INTRA16x16DC + || block_type==CB_INTRA16x16AC) + { //CB in the common mode in 4:4:4 profiles + subblock_x = ((b8 & 0x1) == 0)?(((b4 & 0x1) == 0) ? 0 : 1):(((b4 & 0x1) == 0) ? 2 : 3); + // horiz. position for coeff_count context + subblock_y = (b8 < 2) ? ((b4 < 2) ? 0 : 1) : ((b4 < 2) ? 2 : 3); + // vert. position for coeff_count context + nnz = predict_nnz(currMB, CB, subblock_x,subblock_y); + p_Vid->nz_coeff [currMB->mbAddrX ][subblock_x][4+subblock_y] = numcoeff; + } + else + { //CR in the common mode in 4:4:4 profiles + subblock_x = ((b8 & 0x1) == 0)?(((b4 & 0x1) == 0) ? 0 : 1) : (((b4 & 0x1) == 0) ? 2 : 3); + // horiz. position for coeff_count context + subblock_y = (b8 < 2) ? ((b4 < 2) ? 0 : 1) : ((b4 < 2) ? 2 : 3); + // vert. position for coeff_count context + nnz = predict_nnz(currMB, CR, subblock_x,subblock_y); + p_Vid->nz_coeff [currMB->mbAddrX ][subblock_x][8+subblock_y] = numcoeff; + } + + numcoeff_vlc = (nnz < 2) ? 0 : ((nnz < 4) ? 1 : ((nnz < 8) ? 2 : 3)); + } + else + { + // chroma DC (has its own VLC) + // numcoeff_vlc not relevant + numcoeff_vlc = 0; + + subblock_x = param; + subblock_y = param; + } + + se.type = dptype; + + se.value1 = numcoeff; + se.value2 = numtrailingones; + se.len = numcoeff_vlc; /* use len to pass vlcnum */ + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s # c & tr.1s(%d,%d) vlc=%d #c=%d #t1=%d", + type, subblock_x, subblock_y, numcoeff_vlc, numcoeff, numtrailingones); +#endif + + if (!cdc) + writeSyntaxElement_NumCoeffTrailingOnes(&se, dataPart); + else + writeSyntaxElement_NumCoeffTrailingOnesChromaDC(p_Vid, &se, dataPart); + + *mb_bits_coeff += se.len; + no_bits += se.len; + + if (!numcoeff) + return no_bits; + + if (numcoeff) + { + code = 0; + for (k = lastcoeff; k > lastcoeff - numtrailingones; k--) + { + level = pLevel[k]; // level + + if (iabs(level) > 1) + { + printf("ERROR: level > 1\n"); + exit(-1); + } + + code <<= 1; + + if (level < 0) + { + code |= 0x1; + } + } + + if (numtrailingones) + { + se.type = dptype; + + se.value2 = numtrailingones; + se.value1 = code; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s trailing ones sign (%d,%d)", + type, subblock_x, subblock_y); +#endif + + writeSyntaxElement_VLC (&se, dataPart); + *mb_bits_coeff += se.len; + no_bits += se.len; + + } + + // encode levels + level_two_or_higher = (numcoeff > 3 && numtrailingones == 3) ? 0 : 1; + + vlcnum = (numcoeff > 10 && numtrailingones < 3) ? 1 : 0; + + for (k = lastcoeff - numtrailingones; k >= 0; k--) + { + level = pLevel[k]; // level + + se.value1 = level; + se.type = dptype; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s lev (%d,%d) k=%d vlc=%d lev=%3d", + type, subblock_x, subblock_y, k, vlcnum, level); +#endif + + if (level_two_or_higher) + { + level_two_or_higher = 0; + + if (se.value1 > 0) + se.value1 --; + else + se.value1 ++; + } + + // encode level + + if (vlcnum == 0) + writeSyntaxElement_Level_VLC1(&se, dataPart, p_Vid->active_sps->profile_idc); + else + writeSyntaxElement_Level_VLCN(&se, vlcnum, dataPart, p_Vid->active_sps->profile_idc); + + // update VLC table + if (iabs(level) > incVlc[vlcnum]) + vlcnum++; + + if ((k == lastcoeff - numtrailingones) && iabs(level) > 3) + vlcnum = 2; + + *mb_bits_coeff += se.len; + no_bits += se.len; + } + + // encode total zeroes + if (numcoeff < max_coeff_num) + { + + se.type = dptype; + se.value1 = totzeros; + + vlcnum = numcoeff - 1; + + se.len = vlcnum; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s totalrun (%d,%d) vlc=%d totzeros=%3d", + type, subblock_x, subblock_y, vlcnum, totzeros); +#endif + if (!cdc) + writeSyntaxElement_TotalZeros(&se, dataPart); + else + writeSyntaxElement_TotalZerosChromaDC(p_Vid, &se, dataPart); + + *mb_bits_coeff += se.len; + no_bits += se.len; + } + + // encode run before each coefficient + zerosleft = totzeros; + numcoef = numcoeff; + for (k = lastcoeff; k >= 0; k--) + { + run = pRun[k]; // run + + se.value1 = run; + se.type = dptype; + + // for last coeff, run is remaining totzeros + // when zerosleft is zero, remaining coeffs have 0 run + if ((!zerosleft) || (numcoeff <= 1 )) + break; + + if (numcoef > 1 && zerosleft) + { + vlcnum = imin(zerosleft - 1, RUNBEFORE_NUM_M1); + se.len = vlcnum; + +#if TRACE + snprintf(se.tracestring, + TRACESTRING_SIZE, "%s run (%d,%d) k=%d vlc=%d run=%2d", + type, subblock_x, subblock_y, k, vlcnum, run); +#endif + + writeSyntaxElement_Run(&se, dataPart); + + *mb_bits_coeff += se.len; + no_bits += se.len; + + zerosleft -= run; + numcoef --; + } + } + } + + return no_bits; +} +/*! + ************************************************************************ + * \brief + * Change color plane for 4:4:4 Independent Mode + * + * \par Input: + * plane number + ************************************************************************/ +void change_plane_JV( VideoParameters *p_Vid, int nplane ) +{ + p_Vid->colour_plane_id = (char) nplane; + p_Vid->mb_data = p_Vid->mb_data_JV[nplane]; + p_Vid->enc_picture = p_Vid->enc_frame_picture_JV[nplane]; + p_Vid->pCurImg = p_Vid->imgData.frm_data[nplane]; +} + +/*! + ************************************************************************ + * \brief + * Make one frame picture from 4:4:4 plane + ************************************************************************/ +void make_frame_picture_JV(VideoParameters *p_Vid) +{ + int uv, line; + int nsize; + + p_Vid->enc_frame_picture[0] = p_Vid->enc_frame_picture_JV[0]; + + //copy; + if(p_Vid->currentSlice->nal_reference_idc) + { + nsize = (p_Vid->enc_frame_picture_JV[0]->size_y/BLOCK_SIZE)*(p_Vid->enc_frame_picture_JV[0]->size_x/BLOCK_SIZE)*sizeof(PicMotionParams); + memcpy( &(p_Vid->enc_frame_picture[0]->JVmv_info[PLANE_Y][0][0]), &(p_Vid->enc_frame_picture_JV[PLANE_Y]->mv_info[0][0]), nsize); + memcpy( &(p_Vid->enc_frame_picture[0]->JVmv_info[PLANE_U][0][0]), &(p_Vid->enc_frame_picture_JV[PLANE_U]->mv_info[0][0]), nsize); + memcpy( &(p_Vid->enc_frame_picture[0]->JVmv_info[PLANE_V][0][0]), &(p_Vid->enc_frame_picture_JV[PLANE_V]->mv_info[0][0]), nsize); + } + + for( uv=0; uv<2; uv++ ) + { + for( line=0; lineheight; line++ ) + { + nsize = sizeof(imgpel) * p_Vid->width; + memcpy( p_Vid->enc_frame_picture[0]->imgUV[uv][line], p_Vid->enc_frame_picture_JV[uv+1]->imgY[line], nsize ); + } + free_storable_picture(p_Vid, p_Vid->enc_frame_picture_JV[uv+1]); + } + +} + +Macroblock *alloc_mbs(VideoParameters *p_Vid, int mb_num, int layers) +{ + int i, j; + Macroblock *pMBs = (Macroblock *)calloc(mb_num, sizeof(Macroblock)), *pMB; + if(!pMBs) + return NULL; + for(i=0; iintra4x4_pred_buf[j], 3, 17); + get_mem2Dpel(&pMB->intra8x8_pred_buf[j], 3, 25); + get_mem2Dpel(&pMB->intra16x16_pred_buf[j], 3, 33); + } + pMB->intra4x4_pred = pMB->intra4x4_pred_buf[0]; + pMB->intra8x8_pred = pMB->intra8x8_pred_buf[0]; + pMB->intra16x16_pred = pMB->intra16x16_pred_buf[0]; + } + return pMBs; +} + +void setup_mbs(Macroblock *pMBs, int mb_num, int layer_id) +{ + int i; + Macroblock *pMB; + for(i=0; iintra4x4_pred = pMB->intra4x4_pred_buf[layer_id]; + pMB->intra8x8_pred = pMB->intra8x8_pred_buf[layer_id]; + pMB->intra16x16_pred = pMB->intra16x16_pred_buf[layer_id]; + } +} + +void free_mbs(Macroblock *pMBs, int mb_num) +{ + int i, j; + Macroblock *pMB; + if(!pMBs) + return; + for(i=0; iintra4x4_pred_buf[j]); + free_mem2Dpel(pMB->intra8x8_pred_buf[j]); + free_mem2Dpel(pMB->intra16x16_pred_buf[j]); + } + pMB->intra4x4_pred = NULL; + pMB->intra8x8_pred = NULL; + pMB->intra16x16_pred = NULL; + } + free(pMBs); +} diff --git a/lencod/src/macroblock_P444.c b/lencod/src/macroblock_P444.c new file mode 100644 index 0000000..83e0333 --- /dev/null +++ b/lencod/src/macroblock_P444.c @@ -0,0 +1,467 @@ +/*! + ************************************************************************************* + * \file macroblock_P444.c + * + * \brief + * Process one macroblock functions (P444 mode) + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + ************************************************************************************* + */ + +#include "contributors.h" +#include "global.h" +#include "blk_prediction.h" +#include "mc_prediction.h" +#include "md_common.h" +#include "rdopt.h" +#include "macroblock.h" + + +/*! + ************************************************************************ + * \brief + * Residual Coding of an 8x8 Luma block (not for intra) + * + * \return + * coefficient cost + ************************************************************************ + */ +int luma_residual_coding_p444_16x16 (Macroblock* currMB, //!< Current Macroblock to be coded + int block8x8, //!< block number of 8x8 block + short p_dir, //!< prediction direction + int list_mode[2], //!< list0 prediction mode (1-7, 0=DIRECT) + char *ref_idx) //!< reference pictures for each list +{ + + int *cbp = &(currMB->cbp); + int64 *cbp_blk = &(currMB->cbp_blk); + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int i, j, nonzero = 0, cbp_blk_mask; + int coeff_cost = 0; + int mb_y = (block8x8 >> 1) << 3; + int mb_x = (block8x8 & 0x01) << 3; + int cbp_mask = 1 << block8x8; + + int skipped = (list_mode[0] == 0 && list_mode[1] == 0 && (currSlice->slice_type != B_SLICE)); + ColorPlane uv; + + char bipred_me = currMB->b8x8[block8x8].bipred; + currSlice->coeff_cost_cr[1] = currSlice->coeff_cost_cr[2] = 0; + + //memset( currSlice->cofAC[block8x8][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + //===== luma prediction ====== + p_Dpb->pf_luma_prediction (currMB, mb_x, mb_y, 8, 8, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pCurImg[currMB->opix_y + mb_y], &currSlice->mb_pred[0][mb_y], &currSlice->mb_ores[0][mb_y], mb_x, currMB->pix_x + mb_x, 8, 8); + + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, uv); + p_Dpb->pf_chroma_prediction (currMB, uv - 1, mb_x, mb_y, 8, 8, p_dir, list_mode[0], list_mode[1], ref_idx[0], ref_idx[1], bipred_me); + + //===== compute prediction residual ====== + compute_residue(&p_Vid->pImgOrg[uv][currMB->opix_y + mb_y], &currSlice->mb_pred[uv][mb_y], &currSlice->mb_ores[uv][mb_y], mb_x, currMB->pix_x + mb_x, 8, 8); + } + select_plane(p_Vid, PLANE_Y); + + //===== loop over 4x4 blocks ===== + if(!currMB->luma_transform_size_8x8_flag) + { + //===== forward transform, Quantization, inverse Quantization, inverse transform, Reconstruction ===== + if (!skipped && ( (currSlice->NoResidueDirect != 1) || (currMB->qp_scaled[0] == 0 && p_Vid->active_sps->lossless_qpprime_flag == 1) )) + { + int block_y, block_x; + + for (block_y=mb_y; block_yresidual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &coeff_cost, 0); + + if (nonzero) + { + cbp_blk_mask = (block_x >> 2) + block_y; + (*cbp_blk) |= (int64) 1 << cbp_blk_mask; // one bit for every 4x4 block + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + { + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, (ColorPlane) uv); + nonzero = currMB->residual_transform_quant_luma_4x4( currMB, (ColorPlane) uv, block_x, block_y, &currSlice->coeff_cost_cr[uv], 0); + if (nonzero) + { + cbp_blk_mask = (block_x >> 2) + block_y; + (currSlice->cur_cbp_blk[uv]) |= (int64) 1 << cbp_blk_mask; // one bit for every 4x4 block + (currSlice->cmp_cbp[uv]) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + select_plane(p_Vid, PLANE_Y); + } + else + { + assert(currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE); //SP_SLICE not implemented for FREXT_AD444 + } + } + } + } + } + else + { + if (currSlice->NoResidueDirect != 1 && !skipped) + { + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, block8x8, &coeff_cost, 0); + + if (nonzero) + { + (*cbp_blk) |= 51 << (4*block8x8 - 2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + { + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, (ColorPlane) uv); + nonzero = currMB->residual_transform_quant_luma_8x8( currMB, (ColorPlane) uv, block8x8, &currSlice->coeff_cost_cr[uv], 0); + if (nonzero) + { + (currSlice->cur_cbp_blk[uv]) |= 51 << (4*block8x8-2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + (currSlice->cmp_cbp[uv]) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + select_plane(p_Vid, PLANE_Y); + } + } + } + + if (currSlice->NoResidueDirect != 1 && !skipped && coeff_cost <= _LUMA_COEFF_COST_ && + ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0)&& + !(currSlice->slice_type == SI_SLICE || (currSlice->slice_type == SP_SLICE && p_Vid->sp2_frame_indicator == TRUE )))// last set of conditions + // cannot skip when perfect reconstruction is as in switching pictures or SI pictures + { + coeff_cost = 0; + (*cbp) &= (63 - cbp_mask); + (*cbp_blk) &= ~(51 << (4 * block8x8 - 2 * (block8x8 & 0x01))); + + memset( currSlice->cofAC[block8x8][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + copy_image_data_8x8(&p_Vid->enc_picture->imgY[currMB->pix_y + mb_y], &currSlice->mb_pred[0][mb_y], currMB->pix_x + mb_x, mb_x); + + if (currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + for (i = mb_x; i < mb_x + BLOCK_SIZE_8x8; i += BLOCK_SIZE) + for (j = mb_y; j < mb_y + BLOCK_SIZE_8x8; j += BLOCK_SIZE) + copyblock_sp(currMB, PLANE_Y, i, j); + } + } + + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + if (currSlice->NoResidueDirect != 1 && !skipped && currSlice->coeff_cost_cr[uv] <= _LUMA_COEFF_COST_ && + (currMB->qp_scaled[uv]!=0 || p_Vid->active_sps->lossless_qpprime_flag==0))// last set of conditions + { + currSlice->coeff_cost_cr[uv] = 0; + currSlice->cmp_cbp[uv] &= (63 - cbp_mask); + currSlice->cur_cbp_blk[uv] &= ~(51 << (4*block8x8-2*(block8x8 & 0x01))); + + memset( currSlice->cofAC[block8x8 + 4 * uv][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[uv - 1][currMB->pix_y + mb_y], &currSlice->mb_pred[uv][mb_y], currMB->pix_x + mb_x, mb_x); + } + } + + return coeff_cost; +} + + +/*! + ************************************************************************ + * \brief + * Residual Coding of an 8x8 Luma block (not for intra) + * + * \return + * coefficient cost + ************************************************************************ + */ +int luma_residual_coding_p444_8x8 (Macroblock* currMB, //!< Current Macroblock to be coded + int *cbp, //!< Output: cbp (updated according to processed 8x8 luminance block) + int64 *cbp_blk, //!< Output: block cbp (updated according to processed 8x8 luminance block) + int block8x8, //!< block number of 8x8 block + short p_dir, //!< prediction direction + int list_mode[2], //!< list prediction mode (1-7, 0=DIRECT) + char *ref_idx) //!< reference pictures for each list +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int block_y, block_x, pic_pix_x, nonzero = 0, cbp_blk_mask; + int coeff_cost = 0; + int mb_y = (block8x8 >> 1) << 3; + int mb_x = (block8x8 & 0x01) << 3; + int cbp_mask = 1 << block8x8; + int bxx, byy; // indexing curr_blk + int skipped = (list_mode[0] == 0 && list_mode[1] == 0 && (currSlice->slice_type != B_SLICE)); + ColorPlane uv; + + char bipred_me = currMB->b8x8[block8x8].bipred; + currSlice->coeff_cost_cr[1] = currSlice->coeff_cost_cr[2] = 0; + + //memset( currSlice->cofAC[block8x8][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + //===== loop over 4x4 blocks ===== + if(!currMB->luma_transform_size_8x8_flag) + { + if (((p_dir == 0 || p_dir == 2 )&& list_mode[0] < 5) || ((p_dir == 1 || p_dir == 2 ) && list_mode[1] < 5)) + { + p_Dpb->pf_luma_prediction (currMB, mb_x, mb_y, 8, 8, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pCurImg[currMB->opix_y + mb_y], &currSlice->mb_pred[0][mb_y], &currSlice->mb_ores[0][mb_y], mb_x, currMB->pix_x + mb_x, 8, 8); + } + + for (byy=0, block_y=mb_y; block_ypix_x + block_x; + cbp_blk_mask = (block_x >> 2) + block_y; + + //===== prediction of 4x4 block ===== + if (!(((p_dir == 0 || p_dir == 2 )&& list_mode[0] < 5) || ((p_dir == 1 || p_dir == 2 ) && list_mode[1] < 5))) + { + p_Dpb->pf_luma_prediction (currMB, block_x, block_y, 4, 4, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue(&p_Vid->pCurImg[currMB->opix_y + block_y], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], block_x, pic_pix_x, 4, 4); + } + + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, uv); + p_Dpb->pf_chroma_prediction (currMB, uv - 1, block_x, block_y, 4, 4, p_dir, list_mode[0], list_mode[1], ref_idx[0], ref_idx[1], bipred_me); + + //===== compute prediction residual ====== + compute_residue(&p_Vid->pImgOrg[uv][currMB->opix_y + block_y], &currSlice->mb_pred[uv][block_y], &currSlice->mb_ores[uv][block_y], block_x, pic_pix_x, 4, 4); + } + select_plane(p_Vid, PLANE_Y); + + //===== forward transform, Quantization, inverse Quantization, inverse transform, Reconstruction ===== + if (!skipped && ( (currSlice->NoResidueDirect != 1) || (currMB->qp_scaled[0] == 0 && p_Vid->active_sps->lossless_qpprime_flag == 1) )) + { + //===== forward transform, Quantization, inverse Quantization, inverse transform, Reconstruction ===== + nonzero = currMB->residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &coeff_cost, 0); + + if (nonzero) + { + (*cbp_blk) |= (int64)1 << cbp_blk_mask; // one bit for every 4x4 block + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + { + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, (ColorPlane) uv); + nonzero = currMB->residual_transform_quant_luma_4x4( currMB, (ColorPlane) uv, block_x, block_y, &currSlice->coeff_cost_cr[uv], 0); + if (nonzero) + { + (currSlice->cur_cbp_blk[uv]) |= (int64) 1 << cbp_blk_mask; // one bit for every 4x4 block + (currSlice->cmp_cbp[uv]) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + select_plane(p_Vid, PLANE_Y); + } + else + { + assert(currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE); //SP_SLICE not implementd for FREXT_AD444 + } + } + } + } + } + else + { + block_y = mb_y; + block_x = mb_x; + + pic_pix_x = currMB->pix_x + block_x; + + cbp_blk_mask = (block_x>>2) + block_y; + + //===== prediction of 4x4 block ===== + p_Dpb->pf_luma_prediction (currMB, block_x, block_y, 8, 8, p_dir, list_mode, ref_idx, bipred_me); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pCurImg[currMB->opix_y + block_y], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], block_x, pic_pix_x, 8, 8); + + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, (ColorPlane) uv); + p_Dpb->pf_chroma_prediction (currMB, uv - 1, block_x, block_y, 8, 8, p_dir, list_mode[0], list_mode[1], ref_idx[0], ref_idx[1], bipred_me); + + //===== compute prediction residual ====== + compute_residue (&p_Vid->pImgOrg[uv][currMB->opix_y + block_y], &currSlice->mb_pred[uv][block_y], &currSlice->mb_ores[uv][block_y], block_x, pic_pix_x, 8, 8); + } + select_plane(p_Vid, PLANE_Y); + + if (currSlice->NoResidueDirect != 1 && !skipped) + { + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, block8x8, &coeff_cost, 0); + + if (nonzero) + { + (*cbp_blk) |= 51 << (4*block8x8 - 2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + (*cbp) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + + if (currSlice->slice_type != SP_SLICE && currSlice->slice_type != SI_SLICE) + { + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + select_plane(p_Vid, (ColorPlane) uv); + nonzero = currMB->residual_transform_quant_luma_8x8( currMB, (ColorPlane) uv, block8x8, &currSlice->coeff_cost_cr[uv], 0); + if (nonzero) + { + (currSlice->cur_cbp_blk[uv]) |= 51 << (4*block8x8-2*(block8x8 & 0x01)); // corresponds to 110011, as if all four 4x4 blocks contain coeff, shifted to block position + (currSlice->cmp_cbp[uv]) |= cbp_mask; // one bit for the 4x4 blocks of an 8x8 block + } + } + select_plane(p_Vid, PLANE_Y); + } + } + } + + if (currSlice->NoResidueDirect != 1 && !skipped && coeff_cost <= _LUMA_COEFF_COST_ && + ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0)&& + !(currSlice->slice_type == SI_SLICE || (currSlice->slice_type == SP_SLICE && p_Vid->sp2_frame_indicator == TRUE )))// last set of conditions + // cannot skip when perfect reconstruction is as in switching pictures or SI pictures + { + coeff_cost = reset_block(currMB, cbp, cbp_blk, block8x8); + } + + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + if (currSlice->NoResidueDirect != 1 && !skipped && currSlice->coeff_cost_cr[uv] <= _LUMA_COEFF_COST_ && + (currMB->qp_scaled[uv]!=0 || p_Vid->active_sps->lossless_qpprime_flag==0))// last set of conditions + { + currSlice->coeff_cost_cr[uv] = 0; + currSlice->cmp_cbp[uv] &= (63 - cbp_mask); + currSlice->cur_cbp_blk[uv] &= ~(51 << (4*block8x8-2*(block8x8 & 0x01))); + + memset( currSlice->cofAC[block8x8 + 4 * uv][0][0], 0, 4 * 2 * 65 * sizeof(int)); + + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[uv - 1][currMB->pix_y + mb_y], &currSlice->mb_pred[uv][mb_y], currMB->pix_x + mb_x, mb_x); + } + } + + return coeff_cost; +} + + +/*! + ************************************************************************ + * \brief + * Residual Coding of a Luma macroblock (not for intra) + ************************************************************************ + */ +void luma_residual_coding_p444 (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int uv, i,j,block8x8,b8_x,b8_y; + int list_mode[2]; + char list_ref_idx[2]; + short p_dir; + int sum_cnt_nonz[3] = {0 ,0, 0}; + int is_skip = currSlice->slice_type == P_SLICE && currMB->mb_type == PSKIP; + + currMB->cbp = 0; + currMB->cbp_blk = 0; + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + currSlice->cur_cbp_blk[1] = currSlice->cur_cbp_blk[2] = 0; + + if (is_skip || currMB->mb_type == 1) + { + + for (block8x8=0; block8x8<4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + + sum_cnt_nonz[0] += luma_residual_coding_p444_16x16 (currMB, block8x8, p_dir, list_mode, list_ref_idx); + sum_cnt_nonz[1] += currSlice->coeff_cost_cr[1]; + sum_cnt_nonz[2] += currSlice->coeff_cost_cr[2]; + } + } + else + { + for (block8x8=0; block8x8<4; ++block8x8) + { + currSlice->set_modes_and_reframe (currMB, block8x8, &p_dir, list_mode, list_ref_idx); + + sum_cnt_nonz[0] += luma_residual_coding_p444_8x8 (currMB, &(currMB->cbp), &(currMB->cbp_blk), block8x8, p_dir, list_mode, list_ref_idx); + + if(p_Vid->P444_joined) + { + sum_cnt_nonz[1] += currSlice->coeff_cost_cr[1]; + sum_cnt_nonz[2] += currSlice->coeff_cost_cr[2]; + } + } + } + + if ((is_skip || + (sum_cnt_nonz[0] <= _LUMA_MB_COEFF_COST_ && ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0))) && + !(currSlice->slice_type == SI_SLICE || (currSlice->slice_type == SP_SLICE && p_Vid->sp2_frame_indicator == TRUE )))// last set of conditions + //cannot skip if SI or switching SP frame perfect reconstruction is needed + { + currMB->cbp &= 0xfffff0 ; + currMB->cbp_blk &= 0xff0000 ; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], currSlice->mb_pred[0], currMB->pix_x, 0); + + memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + if (currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + for(block8x8=0;block8x8<4; ++block8x8) + { + b8_x=(block8x8&1)<<3; + b8_y=(block8x8&2)<<2; + for (i = b8_x; i < b8_x + BLOCK_SIZE_8x8; i += 4) + for (j = b8_y; j < b8_y + BLOCK_SIZE_8x8;j += 4) + copyblock_sp(currMB, PLANE_Y, i, j); + } + } + } + + for (uv = PLANE_U; uv <= PLANE_V; ++uv) + { + if(is_skip || (sum_cnt_nonz[uv] <= _LUMA_MB_COEFF_COST_ && + ((currMB->qp_scaled[uv])!=0 ||p_Vid->active_sps->lossless_qpprime_flag==0))) + { + currSlice->cmp_cbp[uv] &= 0xfffff0 ; + currSlice->cur_cbp_blk[uv] &= 0xff0000 ; + + copy_image_data_16x16(&p_Vid->enc_picture->p_img[uv][currMB->pix_y], currSlice->mb_pred[uv], currMB->pix_x, 0); + + memset( currSlice->cofAC[4 * uv][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + } + currMB->cbp |= currSlice->cmp_cbp[uv]; + } +} + + + diff --git a/lencod/src/mb_access.c b/lencod/src/mb_access.c new file mode 100644 index 0000000..476658c --- /dev/null +++ b/lencod/src/mb_access.c @@ -0,0 +1,575 @@ + +/*! + ************************************************************************************* + * \file mb_access.c + * + * \brief + * Functions for macroblock neighborhoods + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + ************************************************************************************* + */ + +#include "global.h" +#include "mb_access.h" + +/*! + ************************************************************************ + * \brief + * returns 1 if the macroblock at the given address is available + ************************************************************************ + */ +Boolean mb_is_available(int mbAddr, Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + if ((mbAddr < 0) || (mbAddr > ((int)p_Vid->PicSizeInMbs - 1))) + return FALSE; + + // the following line checks both: slice number and if the mb has been decoded + if (!currMB->DeblockCall) + { + if (p_Vid->mb_data[mbAddr].slice_nr != currMB->slice_nr) + return FALSE; + } + + return TRUE; +} + + +/*! + ************************************************************************ + * \brief + * Checks the availability of neighboring macroblocks of + * the current macroblock for prediction and context determination; + ************************************************************************ + */ +void CheckAvailabilityOfNeighbors(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + const int mb_nr = currMB->mbAddrX; + BlockPos *PicPos = p_Vid->PicPos; + + // mark all neighbors as unavailable + currMB->mb_up = NULL; + currMB->mb_left = NULL; + + if (p_Vid->mb_aff_frame_flag) + { + int cur_mb_pair = mb_nr >> 1; + currMB->mbAddrA = 2 * (cur_mb_pair - 1); + currMB->mbAddrB = 2 * (cur_mb_pair - p_Vid->PicWidthInMbs); + currMB->mbAddrC = 2 * (cur_mb_pair - p_Vid->PicWidthInMbs + 1); + currMB->mbAddrD = 2 * (cur_mb_pair - p_Vid->PicWidthInMbs - 1); + + currMB->mbAvailA = (byte) (mb_is_available(currMB->mbAddrA, currMB) && ((PicPos[cur_mb_pair ].x)!=0)); + currMB->mbAvailB = (byte) (mb_is_available(currMB->mbAddrB, currMB)); + currMB->mbAvailC = (byte) (mb_is_available(currMB->mbAddrC, currMB) && ((PicPos[cur_mb_pair + 1].x)!=0)); + currMB->mbAvailD = (byte) (mb_is_available(currMB->mbAddrD, currMB) && ((PicPos[cur_mb_pair ].x)!=0)); + } + else + { + currMB->mbAddrA = mb_nr - 1; + currMB->mbAddrB = mb_nr - p_Vid->PicWidthInMbs; + currMB->mbAddrC = mb_nr - p_Vid->PicWidthInMbs + 1; + currMB->mbAddrD = mb_nr - p_Vid->PicWidthInMbs - 1; + + currMB->mbAvailA = (byte) (mb_is_available(currMB->mbAddrA, currMB) && ((PicPos[mb_nr ].x)!=0)); + currMB->mbAvailB = (byte) (mb_is_available(currMB->mbAddrB, currMB)); + currMB->mbAvailC = (byte) (mb_is_available(currMB->mbAddrC, currMB) && ((PicPos[mb_nr + 1].x)!=0)); + currMB->mbAvailD = (byte) (mb_is_available(currMB->mbAddrD, currMB) && ((PicPos[mb_nr ].x)!=0)); + } + + if (currMB->mbAvailA) currMB->mb_left = &(p_Vid->mb_data[currMB->mbAddrA]); + if (currMB->mbAvailB) currMB->mb_up = &(p_Vid->mb_data[currMB->mbAddrB]); +} + + +/*! + ************************************************************************ + * \brief + * returns the x and y macroblock coordinates for a given MbAddress + ************************************************************************ + */ +void get_mb_block_pos_normal (BlockPos *PicPos, int mb_addr, short *x, short *y) +{ + *x = (short) PicPos[ mb_addr ].x; + *y = (short) PicPos[ mb_addr ].y; +} + +/*! + ************************************************************************ + * \brief + * returns the x and y macroblock coordinates for a given MbAddress + * for mbaff type slices + ************************************************************************ + */ +void get_mb_block_pos_mbaff (BlockPos *PicPos, int mb_addr, short *x, short *y) +{ + *x = (short) PicPos[mb_addr>>1].x; + *y = (short) ((PicPos[mb_addr>>1].y << 1) + (mb_addr & 0x01)); +} + +/*! + ************************************************************************ + * \brief + * returns the x and y sample coordinates for a given MbAddress + ************************************************************************ + */ +void get_mb_pos (VideoParameters *p_Vid, int mb_addr, int mb_size[2], short *x, short *y) +{ + p_Vid->get_mb_block_pos(p_Vid->PicPos, mb_addr, x, y); + + (*x) = (short) ((*x) * mb_size[0]); + (*y) = (short) ((*y) * mb_size[1]); +} + + +/*! + ************************************************************************ + * \brief + * get neighbouring positions for non-aff coding + * \param currMB + * current macroblock + * \param xN + * input x position + * \param yN + * input y position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void getNonAffNeighbour(Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix) +{ + BlockPos *PicPos = currMB->p_Vid->PicPos; + if (xN < 0) + { + if (yN < 0) + { + pix->mb_addr = currMB->mbAddrD; + pix->available = currMB->mbAvailD; + } + else if ((yN >= 0)&&(yN < mb_size[1])) + { + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + } + else + { + pix->available = FALSE; + } + } + else if ((xN >= 0)&&(xN < mb_size[0])) + { + if (yN<0) + { + pix->mb_addr = currMB->mbAddrB; + pix->available = currMB->mbAvailB; + } + else if (((yN >= 0)&&(yN < mb_size[1]))) + { + pix->mb_addr = currMB->mbAddrX; + pix->available = TRUE; + } + else + { + pix->available = FALSE; + } + } + else if ((xN >= mb_size[0])&&(yN < 0)) + { + pix->mb_addr = currMB->mbAddrC; + pix->available = currMB->mbAvailC; + } + else + { + pix->available = FALSE; + } + + if (pix->available || currMB->DeblockCall) + { + pix->x = (short) (xN & (mb_size[0] - 1)); + pix->y = (short) (yN & (mb_size[1] - 1)); + pix->pos_x = (short) (pix->x + PicPos[ pix->mb_addr ].x * mb_size[0]); + pix->pos_y = (short) (pix->y + PicPos[ pix->mb_addr ].y * mb_size[1]); + } +} + +/*! + ************************************************************************ + * \brief + * get neighboring positions for aff coding + * \param currMB + * current macroblock + * \param xN + * input x position + * \param yN + * input y position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void getAffNeighbour(Macroblock *currMB, int xN, int yN, int mb_size[2], PixelPos *pix) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int maxW, maxH; + int yM = -1; + + maxW = mb_size[0]; + maxH = mb_size[1]; + + // initialize to "not available" + pix->available = FALSE; + + if(yN > (maxH - 1)) + { + return; + } + if (xN > (maxW - 1) && yN >= 0 && yN < maxH) + { + return; + } + + if (xN < 0) + { + if (yN < 0) + { + if(!currMB->mb_field) + { + // frame + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrD + 1; + pix->available = currMB->mbAvailD; + yM = yN; + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + yM = yN; + } + else + { + (pix->mb_addr)++; + yM = (yN + maxH) >> 1; + } + } + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrD; + pix->available = currMB->mbAvailD; + if (currMB->mbAvailD) + { + if(!p_Vid->mb_data[currMB->mbAddrD].mb_field) + { + (pix->mb_addr)++; + yM = 2 * yN; + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrD+1; + pix->available = currMB->mbAvailD; + yM = yN; + } + } + } + else + { // xN < 0 && yN >= 0 + if (yN >= 0 && yN mb_field) + { + // frame + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + yM = yN; + } + else + { + (pix->mb_addr)+= ((yN & 0x01) != 0); + yM = yN >> 1; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + (pix->mb_addr)++; + yM = yN; + } + else + { + (pix->mb_addr)+= ((yN & 0x01) != 0); + yM = (yN + maxH) >> 1; + } + } + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + if (yN < (maxH >> 1)) + { + yM = yN << 1; + } + else + { + (pix->mb_addr)++; + yM = (yN << 1 ) - maxH; + } + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrA; + pix->available = currMB->mbAvailA; + if (currMB->mbAvailA) + { + if(!p_Vid->mb_data[currMB->mbAddrA].mb_field) + { + if (yN < (maxH >> 1)) + { + yM = (yN << 1) + 1; + } + else + { + (pix->mb_addr)++; + yM = (yN << 1 ) + 1 - maxH; + } + } + else + { + (pix->mb_addr)++; + yM = yN; + } + } + } + } + } + } + } + else + { // xN >= 0 + if (xN >= 0 && xN < maxW) + { + if (yN<0) + { + if (!currMB->mb_field) + { + //frame + if ((currMB->mbAddrX & 0x01) == 0) + { + //top + pix->mb_addr = currMB->mbAddrB; + // for the deblocker if the current MB is a frame and the one above is a field + // then the neighbor is the top MB of the pair + if (currMB->mbAvailB) + { + if (!(currMB->DeblockCall == 1 && (p_Vid->mb_data[currMB->mbAddrB]).mb_field)) + pix->mb_addr += 1; + } + + pix->available = currMB->mbAvailB; + yM = yN; + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrX - 1; + pix->available = TRUE; + yM = yN; + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrB; + pix->available = currMB->mbAvailB; + if (currMB->mbAvailB) + { + if(!p_Vid->mb_data[currMB->mbAddrB].mb_field) + { + (pix->mb_addr)++; + yM = 2 * yN; + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrB + 1; + pix->available = currMB->mbAvailB; + yM = yN; + } + } + } + else + { + // yN >=0 + // for the deblocker if this is the extra edge then do this special stuff + if (yN == 0 && currMB->DeblockCall == 2) + { + pix->mb_addr = currMB->mbAddrB + 1; + pix->available = TRUE; + yM = yN - 1; + } + + else if ((yN >= 0) && (yN mb_addr = currMB->mbAddrX; + pix->available = TRUE; + yM = yN; + } + } + } + else + { // xN >= maxW + if(yN < 0) + { + if (!currMB->mb_field) + { + // frame + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrC + 1; + pix->available = currMB->mbAvailC; + yM = yN; + } + else + { + // bottom + pix->available = FALSE; + } + } + else + { + // field + if ((currMB->mbAddrX & 0x01) == 0) + { + // top + pix->mb_addr = currMB->mbAddrC; + pix->available = currMB->mbAvailC; + if (currMB->mbAvailC) + { + if(!p_Vid->mb_data[currMB->mbAddrC].mb_field) + { + (pix->mb_addr)++; + yM = 2* yN; + } + else + { + yM = yN; + } + } + } + else + { + // bottom + pix->mb_addr = currMB->mbAddrC + 1; + pix->available = currMB->mbAvailC; + yM = yN; + } + } + } + } + } + if (pix->available || currMB->DeblockCall) + { + pix->x = (short) (xN & (maxW - 1)); + pix->y = (short) (yM & (maxH - 1)); + get_mb_pos(p_Vid, pix->mb_addr, mb_size, &(pix->pos_x), &(pix->pos_y)); + pix->pos_x = pix->pos_x + pix->x; + pix->pos_y = pix->pos_y + pix->y; + } +} + + +/*! + ************************************************************************ + * \brief + * get neighboring 4x4 block + * \param currMB + * current macroblock + * \param block_x + * input x block position + * \param block_y + * input y block position + * \param mb_size + * Macroblock size in pixel (according to luma or chroma MB access) + * \param pix + * returns position informations + ************************************************************************ + */ +void get4x4Neighbour (Macroblock *currMB, int block_x, int block_y, int mb_size[2], PixelPos *pix) +{ + currMB->p_Vid->getNeighbour(currMB, block_x, block_y, mb_size, pix); + + if (pix->available) + { + pix->x >>= 2; + pix->y >>= 2; + pix->pos_x >>= 2; + pix->pos_y >>= 2; + } +} diff --git a/lencod/src/mbuffer.c b/lencod/src/mbuffer.c new file mode 100644 index 0000000..2dd6652 --- /dev/null +++ b/lencod/src/mbuffer.c @@ -0,0 +1,3407 @@ + +/*! + *********************************************************************** + * \file + * mbuffer.c + * + * \brief + * Frame buffer functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Tourapis + *********************************************************************** + */ + +#include + +#include "global.h" +#include "mbuffer.h" +#include "mbuffer_common.h" +#include "memalloc.h" +#include "output.h" +#include "image.h" +#include "nalucommon.h" +#include "img_luma.h" +#include "img_chroma.h" +#include "errdo.h" + +extern void SbSMuxBasic(ImageData *imgOut, ImageData *imgIn0, ImageData *imgIn1, int offset); +extern void init_stats (InputParameters *p_Inp, StatParameters *stats); +static void insert_picture_in_dpb (VideoParameters *p_Vid, FrameStore* fs, StorablePicture* p); +static void output_one_frame_from_dpb (DecodedPictureBuffer *p_Dpb, FrameFormat *output); +static void gen_field_ref_ids (StorablePicture *p); +static int flush_unused_frame_from_dpb (DecodedPictureBuffer *p_Dpb); +static void process_picture_in_dpb_s(VideoParameters *p_Vid, StorablePicture *p_pic); +static StorablePicture * clone_storable_picture( VideoParameters *p_Vid, StorablePicture *p_pic ); + +#define MAX_LIST_SIZE 33 + +extern void free_mem2Duint16(uint16 **array2D); +extern void free_mem3Duint16(uint16 ***array3D); + +/*! + ************************************************************************ + * \brief + * Print out list of pictures in DPB. Used for debug purposes. + ************************************************************************ + */ +void dump_dpb(DecodedPictureBuffer *p_Dpb) +{ +#if DUMP_DPB + unsigned i; + + for (i=0; iused_size;i++) + { + printf("("); + printf("fn=%d ", p_Dpb->fs[i]->frame_num); + if (p_Dpb->fs[i]->is_used & 1) + { + if (p_Dpb->fs[i]->top_field) + printf("T: poc=%d ", p_Dpb->fs[i]->top_field->poc); + else + printf("T: poc=%d ", p_Dpb->fs[i]->frame->top_poc); + } + if (p_Dpb->fs[i]->is_used & 2) + { + if (p_Dpb->fs[i]->bottom_field) + printf("B: poc=%d ", p_Dpb->fs[i]->bottom_field->poc); + else + printf("B: poc=%d ", p_Dpb->fs[i]->frame->bottom_poc); + } + if (p_Dpb->fs[i]->is_used == 3) + printf("F: poc=%d ", p_Dpb->fs[i]->frame->poc); + printf("G: poc=%d) ", p_Dpb->fs[i]->poc); + if (p_Dpb->fs[i]->is_reference) printf ("ref (%d) ", p_Dpb->fs[i]->is_reference); + if (p_Dpb->fs[i]->is_long_term) printf ("lt_ref (%d) ", p_Dpb->fs[i]->is_reference); + if (p_Dpb->fs[i]->is_output) printf ("out "); + if (p_Dpb->fs[i]->is_used == 3) + { + if (p_Dpb->fs[i]->frame->non_existing) printf ("ne "); + } +#if (MVC_EXTENSION_ENABLE) + if(p_Dpb->p_Inp->num_of_views==2) + printf ("view_id=%d ", p_Dpb->fs[i]->view_id); +#endif + printf ("\n"); + } +#endif +} + +/*! + ************************************************************************ + * \brief + * Returns the size of the dpb depending on level and picture size + * + * + ************************************************************************ + */ +int getDpbSize(VideoParameters *p_Vid, seq_parameter_set_rbsp_t *active_sps) +{ + int pic_size = (active_sps->pic_width_in_mbs_minus1 + 1) * (active_sps->pic_height_in_map_units_minus1 + 1) * (active_sps->frame_mbs_only_flag?1:2) * 384; + + int size = 0; + + switch (active_sps->level_idc) + { + case 9: + size = 152064; + break; + case 10: + size = 152064; + break; + case 11: + if (!is_FREXT_profile(active_sps->profile_idc) && (active_sps->constrained_set3_flag == 1)) + size = 152064; + else + size = 345600; + break; + case 12: + size = 912384; + break; + case 13: + size = 912384; + break; + case 20: + size = 912384; + break; + case 21: + size = 1824768; + break; + case 22: + size = 3110400; + break; + case 30: + size = 3110400; + break; + case 31: + size = 6912000; + break; + case 32: + size = 7864320; + break; + case 40: + size = 12582912; + break; + case 41: + size = 12582912; + break; + case 42: + size = 13369344; + break; + case 50: + size = 42393600; + break; + case 51: + size = 70778880; + break; + default: + error ("undefined level", 500); + break; + } + + size /= pic_size; + if(is_MVC_profile(p_Vid->p_Inp->ProfileIDC)) + { + int num_views = p_Vid->p_Inp->num_of_views; + size = imin(2*size, imax(1, RoundLog2(num_views))*16)/num_views; + } + else + size = imin( size, 16); + + if (active_sps->vui_parameters_present_flag && active_sps->vui_seq_parameters.bitstream_restriction_flag) + { + if ((int)active_sps->vui_seq_parameters.max_dec_frame_buffering > size) + { + error ("max_dec_frame_buffering larger than MaxDpbSize", 500); + } + size = imax (1, active_sps->vui_seq_parameters.max_dec_frame_buffering); + } + + return size; +} + +/*! + ************************************************************************ + * \brief + * Check then number of frames marked "used for reference" and break + * if maximum is exceeded + * + ************************************************************************ + */ +void check_num_ref(DecodedPictureBuffer *p_Dpb) +{ + if ((int)(p_Dpb->ltref_frames_in_buffer + p_Dpb->ref_frames_in_buffer ) > imax(1, p_Dpb->num_ref_frames)) + { + error ("Max. number of reference frames exceeded. Invalid stream.", 500); + } +} + + +/*! + ************************************************************************ + * \brief + * Allocate memory for decoded picture buffer and initialize with sane values. + * + ************************************************************************ + */ +void init_dpb(VideoParameters *p_Vid, DecodedPictureBuffer *p_Dpb) +{ + unsigned i; + + p_Dpb->p_Vid = p_Vid; + p_Dpb->p_Inp = p_Vid->p_Inp; + p_Dpb->num_ref_frames = p_Vid->num_ref_frames; + + if (p_Dpb->init_done) + { + free_dpb(p_Dpb); + } + + p_Dpb->size = getDpbSize(p_Vid, p_Vid->sps[p_Dpb->layer_id]); + + + if (p_Dpb->size < (unsigned int) (p_Vid->p_Inp)->num_ref_frames) + { + error ("DPB size at specified level is smaller than the specified number of reference frames. This is not allowed.\n", 1000); + } + + p_Dpb->used_size = 0; + p_Dpb->last_picture = NULL; + + p_Dpb->ref_frames_in_buffer = 0; + p_Dpb->ltref_frames_in_buffer = 0; + + p_Dpb->fs = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs) + no_mem_exit("init_dpb: p_Dpb->fs"); + + p_Dpb->fs_ref = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ref) + no_mem_exit("init_dpb: p_Dpb->fs_ref"); + + p_Dpb->fs_ltref = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ltref) + no_mem_exit("init_dpb: p_Dpb->fs_ltref"); + + for (i = 0; i < p_Dpb->size; i++) + { + p_Dpb->fs[i] = alloc_frame_store(); + p_Dpb->fs_ref[i] = NULL; + p_Dpb->fs_ltref[i] = NULL; + } + p_Dpb->fs_ilref = calloc(1, sizeof (FrameStore*)); + if (NULL==p_Dpb->fs_ilref) + no_mem_exit("init_dpb: p_Dpb->fs_ilref"); + + if(p_Dpb->layer_id == 0) + { + p_Dpb->fs_ilref[0] = NULL; + } + else if(p_Dpb->layer_id == 1) + { + p_Dpb->fs_ilref[0] = alloc_frame_store(); + } + + p_Dpb->last_output_poc = INT_MIN; + +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = 0; +#endif + + p_Vid->last_has_mmco_5 = 0; + + p_Dpb->init_done = 1; + +} + + +/*! + ************************************************************************ + * \brief + * Free memory for decoded picture buffer. + ************************************************************************ + */ +void free_dpb(DecodedPictureBuffer *p_Dpb) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + if (p_Dpb->fs) + { + for (i=0; isize; i++) + { + free_frame_store(p_Vid, p_Dpb->fs[i]); + } + free (p_Dpb->fs); + p_Dpb->fs=NULL; + } + + if (p_Dpb->fs_ref) + { + free (p_Dpb->fs_ref); + } + if (p_Dpb->fs_ltref) + { + free (p_Dpb->fs_ltref); + } + if(p_Dpb->fs_ilref) + { + if(p_Dpb->fs_ilref[0]) + { + free_frame_store(p_Vid, p_Dpb->fs_ilref[0]); + p_Dpb->fs_ilref[0] = NULL; + } + free(p_Dpb->fs_ilref); + } + p_Dpb->last_output_poc = INT_MIN; + +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = 0; +#endif + + p_Dpb->init_done = 0; +} + + +/*! + ************************************************************************ + * \brief + * Allocate memory for decoded picture buffer frame stores and initialize with sane values. + * + * \return + * the allocated FrameStore structure + ************************************************************************ + */ +FrameStore* alloc_frame_store(void) +{ + FrameStore *f; + + f = calloc (1, sizeof(FrameStore)); + if (NULL==f) + no_mem_exit("alloc_frame_store: f"); + + f->is_used = 0; + f->is_reference = 0; + f->is_long_term = 0; + f->is_orig_reference = 0; + + f->is_output = 0; + + f->frame = NULL;; + f->top_field = NULL; + f->bottom_field = NULL; + +#if (MVC_EXTENSION_ENABLE) + f->view_id = -1; + f->inter_view_flag[0] = 0; + f->inter_view_flag[1] = 0; + f->anchor_pic_flag[0] = 0; + f->anchor_pic_flag[1] = 0; +#endif + + return f; +} + +void alloc_pic_motion(PicMotionParamsOld *motion, int size_y, int size_x) +{ + motion->mb_field = calloc (size_y * size_x, sizeof(byte)); + if (motion->mb_field == NULL) + no_mem_exit("alloc_storable_picture: motion->mb_field"); +} + +/*! + ************************************************************************ + * \brief + * Allocate memory for a stored picture. + * + * \param p_Vid + * VideoParameters + * \param structure + * picture structure + * \param size_x + * horizontal luma size + * \param size_y + * vertical luma size + * \param size_x_cr + * horizontal chroma size + * \param size_y_cr + * vertical chroma size + * + * \return + * the allocated StorablePicture structure + ************************************************************************ + */ +StorablePicture* alloc_storable_picture(VideoParameters *p_Vid, PictureStructure structure, int size_x, int size_y, int size_x_cr, int size_y_cr) +{ + StorablePicture *s; + int nplane; + InputParameters *p_Inp = p_Vid->p_Inp; + + //printf ("Allocating (%s) picture (x=%d, y=%d, x_cr=%d, y_cr=%d)\n", (type == FRAME)?"FRAME":(type == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", size_x, size_y, size_x_cr, size_y_cr); + + s = calloc (1, sizeof(StorablePicture)); + if (NULL==s) + no_mem_exit("alloc_storable_picture: s"); + + s->imgY = NULL; + s->imgUV = NULL; + s->imgY_sub = NULL; + s->imgUV_sub = NULL; + + s->p_img_sub[0] = NULL; + s->p_img_sub[1] = NULL; + s->p_img_sub[2] = NULL; + + s->de_mem = NULL; + +#if (MVC_EXTENSION_ENABLE) + if ((p_Vid->nal_reference_idc != NALU_PRIORITY_DISPOSABLE) || ((p_Inp->num_of_views == 2) && p_Vid->view_id == 0)) //p_Vid->inter_view_flag[structure?structure-1: structure])) +#else + if (p_Vid->nal_reference_idc != NALU_PRIORITY_DISPOSABLE) +#endif + { + if (!p_Inp->OnTheFlyFractMCP) // JLT : on-the-fly flag + { + get_mem4Dpel_pad(&(s->imgY_sub), 4, 4, size_y, size_x, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + s->imgY = s->imgY_sub[0][0]; + + if ( p_Inp->ChromaMCBuffer || p_Vid->P444_joined || (p_Inp->yuv_format==YUV444 && !p_Vid->P444_joined)) + { + // UV components + if ( p_Vid->yuv_format != YUV400 ) + { + if ( p_Vid->yuv_format == YUV420 ) + { + get_mem5Dpel_pad(&(s->imgUV_sub), 2, 8, 8, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + else if ( p_Vid->yuv_format == YUV422 ) + { + get_mem5Dpel_pad(&(s->imgUV_sub), 2, 4, 8, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + else + { // YUV444 + get_mem5Dpel_pad(&(s->imgUV_sub), 2, 4, 4, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + s->p_img_sub[1] = s->imgUV_sub[0]; + s->p_img_sub[2] = s->imgUV_sub[1]; + s->imgUV = (imgpel ***)malloc(2*sizeof(imgpel**)); + s->imgUV[0] = s->imgUV_sub[0][0][0]; + s->imgUV[1] = s->imgUV_sub[1][0][0]; + } + } + else + { + get_mem3Dpel_pad(&(s->imgUV), 2, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + } + else if ( p_Inp->OnTheFlyFractMCP == OTF_L1 ) // OTF L1 + { + get_mem4Dpel_pad(&(s->imgY_sub), 2, 2, size_y, size_x, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + s->imgY = s->imgY_sub[0][0]; + + if ( p_Inp->ChromaMCBuffer || p_Vid->P444_joined || (p_Inp->yuv_format==YUV444 && !p_Vid->P444_joined)) + { + // UV components + if ( p_Vid->yuv_format != YUV400 ) + { + if ( p_Vid->yuv_format == YUV420 ) + { + get_mem5Dpel_pad(&(s->imgUV_sub), 2, 4, 4, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + else if ( p_Vid->yuv_format == YUV422 ) + { + get_mem5Dpel_pad(&(s->imgUV_sub), 2, 2, 4, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + else + { // YUV444 + get_mem5Dpel_pad(&(s->imgUV_sub), 2, 2, 2, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + s->p_img_sub[1] = s->imgUV_sub[0]; + s->p_img_sub[2] = s->imgUV_sub[1]; + s->imgUV = (imgpel ***)malloc(2*sizeof(imgpel**)); + s->imgUV[0] = s->imgUV_sub[0][0][0]; + s->imgUV[1] = s->imgUV_sub[1][0][0]; + } + } + else + { + get_mem3Dpel_pad(&(s->imgUV), 2, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + } + else // OTF_L2 + { + get_mem2Dpel_pad(&(s->imgY), size_y, size_x, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + get_mem3Dpel_pad(&(s->imgUV), 2, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + } + else + { + get_mem2Dpel_pad(&(s->imgY), size_y, size_x, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + get_mem3Dpel_pad(&(s->imgUV), 2, size_y_cr, size_x_cr, p_Vid->pad_size_uv_y, p_Vid->pad_size_uv_x); + } + + s->p_img[0] = s->imgY; + s->p_curr_img = s->p_img[0]; + s->p_curr_img_sub = s->p_img_sub[0]; + + if (p_Vid->yuv_format != YUV400) + { + //get_mem3Dpel (&(s->imgUV), 2, size_y_cr, size_x_cr); + s->p_img[1] = s->imgUV[0]; + s->p_img[2] = s->imgUV[1]; + } + + get_mem2Dmp (&s->mv_info, (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + alloc_pic_motion(&s->motion, (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplaneJVmv_info[nplane], (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + alloc_pic_motion(&s->JVmotion[nplane], (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + } + } + + if (p_Inp->rdopt == 3) + { + errdo_alloc_storable_picture(s, p_Vid, p_Inp, size_x, size_y, size_x_cr, size_y_cr); + } + + s->pic_num=0; + s->frame_num=0; + s->long_term_frame_idx=0; + s->long_term_pic_num=0; + s->used_for_reference=0; + s->is_long_term=0; + s->non_existing=0; + s->is_output = 0; + + s->structure=structure; + s->size_x = size_x; + s->size_y = size_y; + s->size_x_padded = size_x + 2 * IMG_PAD_SIZE_X; + s->size_y_padded = size_y + 2 * IMG_PAD_SIZE_Y; + s->size_x_pad = size_x + 2 * IMG_PAD_SIZE_X - 1 - MB_BLOCK_SIZE -IMG_PAD_SIZE_X; + s->size_y_pad = size_y + 2 * IMG_PAD_SIZE_Y - 1 - MB_BLOCK_SIZE -IMG_PAD_SIZE_Y; + s->size_x_cr = size_x_cr; + s->size_y_cr = size_y_cr; + s->size_x_cr_pad = (int) (size_x_cr - 1) + (p_Vid->pad_size_uv_x << 1) - (p_Vid->mb_cr_size_x) - p_Vid->pad_size_uv_x; + s->size_y_cr_pad = (int) (size_y_cr - 1) + (p_Vid->pad_size_uv_y << 1) - (p_Vid->mb_cr_size_y) - p_Vid->pad_size_uv_y; + s->pad_size_uv_x = p_Vid->pad_size_uv_x; + s->pad_size_uv_y = p_Vid->pad_size_uv_y; + + s->top_field = NULL; + s->bottom_field = NULL; + s->frame = NULL; + + s->coded_frame = 0; + s->mb_aff_frame_flag = 0; + + memset(s->ref_pic_na, 0xff, sizeof(int)*6); + + init_stats(p_Inp, &s->stats); + return s; +} + + +/*! + ************************************************************************ + * \brief + * Free frame store memory. + * + * \param p_Vid + * VideoParameters + * \param f + * FrameStore to be freed + * + ************************************************************************ + */ +void free_frame_store(VideoParameters *p_Vid, FrameStore* f) +{ + if (f) + { + if (f->frame) + { + free_storable_picture(p_Vid, f->frame); + f->frame=NULL; + } + if (f->top_field) + { + free_storable_picture(p_Vid, f->top_field); + f->top_field=NULL; + } + if (f->bottom_field) + { + free_storable_picture(p_Vid, f->bottom_field); + f->bottom_field=NULL; + } + free(f); + } +} + +void free_pic_motion(PicMotionParamsOld *motion) +{ + if (motion->mb_field) + { + free(motion->mb_field); + motion->mb_field = NULL; + } +} + +static void free_frame_data_memory(StorablePicture *picture, int bFreeImage) +{ + if(picture) + { + if (picture->imgY_sub) + { + if(bFreeImage) + { + picture->imgY = NULL; + if( picture->otf_flag == OTF_L1 ) // JLT : on-the-fly mode + { + free_mem4Dpel_pad(picture->imgY_sub, 4, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + } + else + { + free_mem4Dpel_pad(picture->imgY_sub, 16, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + } + picture->imgY_sub=NULL; + } + else + { + int k; + int K = (picture->otf_flag==OTF_L1) ? (4):(16) ; + for(k = 1; k < K; k++) + { + if(picture->imgY_sub[k>>2][k&3]) + { + free_mem2Dpel_pad(picture->imgY_sub[k>>2][k&3], IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + picture->imgY_sub[k>>2][k&3] = NULL; + } + } + } + } + + if (picture->imgUV_sub) + { + int iUVResX = 4*(picture->size_x/picture->size_x_cr); + int iUVResY = 4*(picture->size_y/picture->size_y_cr); + + if ( picture->otf_flag == OTF_L1 ) // JLT : on-the-fly mode + { + iUVResX >>= 1 ; + iUVResY >>= 1 ; + } + + if(bFreeImage) + { + if(picture->imgUV) + { + free(picture->imgUV); + picture->imgUV = NULL; + } + free_mem5Dpel_pad(picture->imgUV_sub, 2*iUVResY*iUVResX, picture->pad_size_uv_y, picture->pad_size_uv_x); + picture->imgUV_sub = NULL; + } + else + { + int i, j, k; + for(k=1; kimgUV_sub[0][j][i]) + { + free_mem2Dpel_pad(picture->imgUV_sub[0][j][i], picture->pad_size_uv_y, picture->pad_size_uv_x); + picture->imgUV_sub[0][j][i] = NULL; + } + if(picture->imgUV_sub[1][j][i]) + { + free_mem2Dpel_pad(picture->imgUV_sub[1][j][i], picture->pad_size_uv_y, picture->pad_size_uv_x); + picture->imgUV_sub[1][j][i] = NULL; + } + } + } + } + + if (picture->mv_info) + { + free_mem2Dmp(picture->mv_info); + picture->mv_info = NULL; + } + + free_pic_motion(&picture->motion); + } +} + +/*! + ************************************************************************ + * \brief + * Free picture memory. + * + * \param p_Vid + * VideoParameters + * \param p + * Picture to be freed + * + ************************************************************************ + */ +void free_storable_picture(VideoParameters *p_Vid, StorablePicture* p) +{ + if (p) + { + InputParameters *p_Inp = p_Vid->p_Inp; + + if(p->imgY && !p->imgY_sub) + { + free_mem2Dpel_pad(p->imgY, IMG_PAD_SIZE_Y, IMG_PAD_SIZE_X); + p->imgY=NULL; + } + + if (p->imgUV && !p->imgUV_sub) + { + free_mem3Dpel_pad(p->imgUV, 2, p->pad_size_uv_y, p->pad_size_uv_x); + p->imgUV=NULL; + } + + free_frame_data_memory(p, 1); + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + int nplane; + for( nplane=0; nplaneJVmv_info[nplane]) + { + free_mem2Dmp(p->JVmv_info[nplane]); + p->JVmv_info[nplane] = NULL; + } + free_pic_motion(&p->JVmotion[nplane]); + } + p->p_curr_img = NULL; + p->p_curr_img_sub = NULL; + p->p_img[0] = NULL; + p->p_img[1] = NULL; + p->p_img[2] = NULL; + p->p_img_sub[0] = NULL; + p->p_img_sub[1] = NULL; + p->p_img_sub[2] = NULL; + } + + if (p_Inp->rdopt == 3) + { + errdo_free_storable_picture(p); + } + + free(p); + p = NULL; + } +} + +/*! + ************************************************************************ + * \brief + * mark FrameStore unused for reference + * + ************************************************************************ + */ +void unmark_for_reference(FrameStore* fs) +{ + if (fs->is_used & 1) + { + if (fs->top_field) + { + fs->top_field->used_for_reference = 0; + } + } + if (fs->is_used & 2) + { + if (fs->bottom_field) + { + fs->bottom_field->used_for_reference = 0; + } + } + if (fs->is_used == 3) + { + if (fs->top_field && fs->bottom_field) + { + fs->top_field->used_for_reference = 0; + fs->bottom_field->used_for_reference = 0; + } + fs->frame->used_for_reference = 0; + } + + fs->is_reference = 0; + + free_frame_data_memory(fs->frame, 0); + free_frame_data_memory(fs->top_field, 0); + free_frame_data_memory(fs->bottom_field, 0); +} + + +/*! + ************************************************************************ + * \brief + * mark FrameStore unused for reference and reset long term flags + * + ************************************************************************ + */ +void unmark_for_long_term_reference(FrameStore* fs) +{ + if (fs->is_used & 1) + { + if (fs->top_field) + { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + } + } + if (fs->is_used & 2) + { + if (fs->bottom_field) + { + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + } + if (fs->is_used == 3) + { + if (fs->top_field && fs->bottom_field) + { + fs->top_field->used_for_reference = 0; + fs->top_field->is_long_term = 0; + fs->bottom_field->used_for_reference = 0; + fs->bottom_field->is_long_term = 0; + } + fs->frame->used_for_reference = 0; + fs->frame->is_long_term = 0; + } + + free_frame_data_memory(fs->frame, 0); + free_frame_data_memory(fs->top_field, 0); + free_frame_data_memory(fs->bottom_field, 0); + + fs->is_reference = 0; + fs->is_long_term = 0; +} + + + +void update_pic_num(Slice *currSlice) +{ + unsigned int i; + //VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + int add_top = 0, add_bottom = 0; + + int max_frame_num = currSlice->max_frame_num; + + + if (currSlice->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if ( p_Dpb->fs_ref[i]->is_used==3 ) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if( p_Dpb->fs_ref[i]->frame_num > currSlice->frame_num ) + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num - max_frame_num; + } + else + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num; + } + p_Dpb->fs_ref[i]->frame->pic_num = p_Dpb->fs_ref[i]->frame_num_wrap; + } + } + } + // update long_term_pic_num + for (i = 0; i < p_Dpb->ltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + p_Dpb->fs_ltref[i]->frame->long_term_pic_num = p_Dpb->fs_ltref[i]->frame->long_term_frame_idx; + } + } + } + } + else + { + if (currSlice->structure == TOP_FIELD) + { + add_top = 1; + add_bottom = 0; + } + else + { + add_top = 0; + add_bottom = 1; + } + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference) + { + if( p_Dpb->fs_ref[i]->frame_num > currSlice->frame_num ) + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num - max_frame_num; + } + else + { + p_Dpb->fs_ref[i]->frame_num_wrap = p_Dpb->fs_ref[i]->frame_num; + } + if (p_Dpb->fs_ref[i]->is_reference & 1) + { + p_Dpb->fs_ref[i]->top_field->pic_num = (2 * p_Dpb->fs_ref[i]->frame_num_wrap) + add_top; + } + if (p_Dpb->fs_ref[i]->is_reference & 2) + { + p_Dpb->fs_ref[i]->bottom_field->pic_num = (2 * p_Dpb->fs_ref[i]->frame_num_wrap) + add_bottom; + } + } + } + // update long_term_pic_num + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_long_term & 1) + { + p_Dpb->fs_ltref[i]->top_field->long_term_pic_num = 2 * p_Dpb->fs_ltref[i]->top_field->long_term_frame_idx + add_top; + } + if (p_Dpb->fs_ltref[i]->is_long_term & 2) + { + p_Dpb->fs_ltref[i]->bottom_field->long_term_pic_num = 2 * p_Dpb->fs_ltref[i]->bottom_field->long_term_frame_idx + add_bottom; + } + } + } +} +/*! + ************************************************************************ + * \brief + * Initialize reference lists depending on current slice type + * + ************************************************************************ + */ +void init_lists_i_slice(Slice *currSlice) +{ + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; +} + + + +/*! + ************************************************************************ + * \brief + * Initialize reference lists for a P Slice + * + ************************************************************************ + */ +void init_lists_p_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i, j; + + int list0idx = 0; + int listltidx = 0; + +#if (MVC_EXTENSION_ENABLE) + InputParameters *p_Inp = currSlice->p_Inp; + int interview_pos = 0; +#endif + + FrameStore **fs_list0; + FrameStore **fs_listlt; + + for (i = 0; i < 6; i++) + { + currSlice->listX[i] = calloc(MAX_LIST_SIZE, sizeof (StorablePicture*)); // +1 for reordering + if (NULL == currSlice->listX[i]) + no_mem_exit("init_dpb: currSlice->listX[i]"); + } + + for (j = 0; j < 6; j++) + { + for (i = 0; i < MAX_LIST_SIZE; i++) + { + currSlice->listX[j][i] = NULL; + } + currSlice->listXsize[j]=0; + } + + // Calculate FrameNumWrap and PicNum + if (currSlice->structure == FRAME) + { + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + // order list 0 by PicNum + qsort((void *)currSlice->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc); + currSlice->listXsize[0] = (char) list0idx; + //printf("listX[0] (PicNum): "); for (i=0; ilistX[0][i]->pic_num);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = (char) list0idx; + } + else + { + fs_list0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list0) + no_mem_exit("init_lists: fs_list0"); + fs_listlt = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_listlt) + no_mem_exit("init_lists: fs_listlt"); + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_reference) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + + qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_frame_num_desc); + + //printf("fs_list0 (FrameNum): "); for (i=0; iframe_num_wrap);} printf("\n"); + + currSlice->listXsize[0] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, list0idx, currSlice->listX[0], &currSlice->listXsize[0], 0); + + //printf("listX[0] (PicNum): "); for (i=0; i < currSlice->listXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->pic_num);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + fs_listlt[listltidx++]=p_Dpb->fs_ltref[i]; + } + + qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[0], &currSlice->listXsize[0], 1); + + free(fs_list0); + free(fs_listlt); + } + currSlice->listXsize[1] = 0; + + +#if (MVC_EXTENSION_ENABLE && !SIMULCAST_ENABLE) + // MVC interview pictures list + if(p_Inp->num_of_views == 2 && p_Vid->view_id == 1) + { + StorablePicture *base_ref; + if(currSlice->structure == FRAME) + { + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + list0idx = currSlice->listXsize[0]; + /* + interview_pos = p_Dpb->used_size - 1; + base_ref = p_Dpb->fs[interview_pos]->frame; + */ + interview_pos = 0; + base_ref = p_Dpb->fs_ilref[interview_pos]->frame; + //assert(base_ref->proc_flag); + if (base_ref->used_for_reference || base_ref->inter_view_flag[0]) + { + //p_Dpb->fs[interview_pos]->frame_num_wrap = -99; + p_Dpb->fs_ilref[interview_pos]->frame_num_wrap = -99; + currSlice->listX[0][list0idx++] = base_ref; + currSlice->listXsize[0] = (char) list0idx; + } + } + else //FIELD + { + int cur_inter_view_flag = currSlice->structure != BOTTOM_FIELD ? 0 : 1; + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + list0idx = currSlice->listXsize[0]; + /* + interview_pos = (currSlice->structure != BOTTOM_FIELD) ? p_Dpb->used_size - 1: p_Dpb->used_size - 2; // top field is at the last position + base_ref = currSlice->structure!=BOTTOM_FIELD?p_Dpb->fs[interview_pos]->top_field:p_Dpb->fs[interview_pos]->bottom_field; + */ + interview_pos = 0; + base_ref = currSlice->structure!=BOTTOM_FIELD? p_Dpb->fs_ilref[interview_pos]->top_field:p_Dpb->fs_ilref[interview_pos]->bottom_field; + if (base_ref->used_for_reference || base_ref->inter_view_flag[cur_inter_view_flag]) + { + //p_Dpb->fs[interview_pos]->frame_num_wrap = -99; + p_Dpb->fs_ilref[interview_pos]->frame_num_wrap = -99; + currSlice->listX[0][list0idx++] = base_ref; + currSlice->listXsize[0] = (char) list0idx; + } + } + } +#endif + + // set max size +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2 && p_Inp->MVCInterViewReorder && p_Vid->view_id == 1) + { + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0] + 1); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + } + else +#endif + { + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + } + + // set the unused list entries to NULL + for (i=currSlice->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[0][i] = NULL; + } + for (i=currSlice->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[1][i] = NULL; + } + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if(p_Inp->num_of_views==2 && p_Vid->current_slice_nr==0) + { + if(currSlice->listXsize[0]>0) + { + printf("\n"); + printf(" ** (CurViewID:%d) %s Ref Pic List 0 ****\n", p_Vid->view_id, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + } +#endif +#endif +} + + +/*! + ************************************************************************ + * \brief + * Initialize reference lists for a B Slice + * + ************************************************************************ + */ +void init_lists_b_slice(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + unsigned int i; + int j; + + int list0idx = 0; + int list0idx_1 = 0; + int listltidx = 0; + +#if (MVC_EXTENSION_ENABLE) + InputParameters *p_Inp = currSlice->p_Inp; + int list1idx = 0; + int interview_pos = 0; +#endif + + FrameStore **fs_list0; + FrameStore **fs_list1; + FrameStore **fs_listlt; + + + for (i = 0; i < 6; i++) + { + currSlice->listX[i] = calloc(MAX_LIST_SIZE, sizeof (StorablePicture*)); // +1 for reordering + if (NULL == currSlice->listX[i]) + no_mem_exit("init_dpb: currSlice->listX[i]"); + } + + for (j = 0; j < 6; j++) + { + for (i = 0; i < MAX_LIST_SIZE; i++) + { + currSlice->listX[j][i] = NULL; + } + currSlice->listXsize[j]=0; + } + + { + // B-Slice + if (currSlice->structure == FRAME) + { + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if (currSlice->framepoc > p_Dpb->fs_ref[i]->frame->poc) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + } + qsort((void *)currSlice->listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_poc_desc); + + //get the backward reference picture (POC>current POC) in list0; + list0idx_1 = list0idx; + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used==3) + { + if ((p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + if (currSlice->framepoc < p_Dpb->fs_ref[i]->frame->poc) + { + currSlice->listX[0][list0idx++] = p_Dpb->fs_ref[i]->frame; + } + } + } + } + qsort((void *)&currSlice->listX[0][list0idx_1], list0idx-list0idx_1, sizeof(StorablePicture*), compare_pic_by_poc_asc); + + for (j=0; jlistX[1][list0idx-list0idx_1+j]=currSlice->listX[0][j]; + } + for (j=list0idx_1; jlistX[1][j-list0idx_1]=currSlice->listX[0][j]; + } + + currSlice->listXsize[0] = currSlice->listXsize[1] = (char) list0idx; + + // printf("currSlice->listX[0] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->poc);} printf("\n"); + // printf("currSlice->listX[1] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->poc);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ltref[i]->is_used==3) + { + if (p_Dpb->fs_ltref[i]->frame->is_long_term) + { + currSlice->listX[0][list0idx] = p_Dpb->fs_ltref[i]->frame; + currSlice->listX[1][list0idx++] = p_Dpb->fs_ltref[i]->frame; + } + } + } + qsort((void *)&currSlice->listX[0][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + qsort((void *)&currSlice->listX[1][(short) currSlice->listXsize[0]], list0idx - currSlice->listXsize[0], sizeof(StorablePicture*), compare_pic_by_lt_pic_num_asc); + currSlice->listXsize[0] = currSlice->listXsize[1] = (char) list0idx; + } + else + { + fs_list0 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list0) + no_mem_exit("init_lists: fs_list0"); + fs_list1 = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_list1) + no_mem_exit("init_lists: fs_list1"); + fs_listlt = calloc(p_Dpb->size, sizeof (FrameStore*)); + if (NULL==fs_listlt) + no_mem_exit("init_lists: fs_listlt"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 1; + + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used) + { + if (currSlice->ThisPOC >= p_Dpb->fs_ref[i]->poc) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)fs_list0, list0idx, sizeof(FrameStore*), compare_fs_by_poc_desc); + list0idx_1 = list0idx; + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->is_used) + { + if (currSlice->ThisPOC < p_Dpb->fs_ref[i]->poc) + { + fs_list0[list0idx++] = p_Dpb->fs_ref[i]; + } + } + } + qsort((void *)&fs_list0[list0idx_1], list0idx-list0idx_1, sizeof(FrameStore*), compare_fs_by_poc_asc); + + for (j=0; jThisPOC); for (i=0; ipoc);} printf("\n"); + // printf("fs_list1 currPoc=%d (Poc): ", currSlice->ThisPOC); for (i=0; ipoc);} printf("\n"); + + currSlice->listXsize[0] = 0; + currSlice->listXsize[1] = 0; + gen_pic_list_from_frame_list(currSlice->structure, fs_list0, list0idx, currSlice->listX[0], &currSlice->listXsize[0], 0); + gen_pic_list_from_frame_list(currSlice->structure, fs_list1, list0idx, currSlice->listX[1], &currSlice->listXsize[1], 0); + + // printf("currSlice->listX[0] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[0]; i++){printf ("%d ", currSlice->listX[0][i]->poc);} printf("\n"); + // printf("currSlice->listX[1] currPoc=%d (Poc): ", currSlice->framepoc); for (i=0; ilistXsize[1]; i++){printf ("%d ", currSlice->listX[1][i]->poc);} printf("\n"); + + // long term handling + for (i=0; iltref_frames_in_buffer; i++) + { + fs_listlt[listltidx++]=p_Dpb->fs_ltref[i]; + } + + qsort((void *)fs_listlt, listltidx, sizeof(FrameStore*), compare_fs_by_lt_pic_idx_asc); + + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[0], &currSlice->listXsize[0], 1); + gen_pic_list_from_frame_list(currSlice->structure, fs_listlt, listltidx, currSlice->listX[1], &currSlice->listXsize[1], 1); + + free(fs_list0); + free(fs_list1); + free(fs_listlt); + } + } + + if ((currSlice->listXsize[0] == currSlice->listXsize[1]) && (currSlice->listXsize[0] > 1)) + { + // check if lists are identical, if yes swap first two elements of currSlice->listX[1] + int diff=0; + for (j = 0; j< currSlice->listXsize[0]; j++) + { + if (currSlice->listX[0][j] != currSlice->listX[1][j]) + { + diff = 1; + break; + } + } + if (!diff) + { + StorablePicture *tmp_s = currSlice->listX[1][0]; + currSlice->listX[1][0]=currSlice->listX[1][1]; + currSlice->listX[1][1]=tmp_s; + } + } + +#if (MVC_EXTENSION_ENABLE && !SIMULCAST_ENABLE) + // MVC interview pictures list + if(p_Inp->num_of_views == 2 && p_Vid->view_id == 1) + { + StorablePicture *base_ref; + if(currSlice->structure == FRAME) + { + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + list0idx = currSlice->listXsize[0]; + list1idx = currSlice->listXsize[1]; + /* + interview_pos = p_Dpb->used_size-1; + base_ref = p_Dpb->fs[interview_pos]->frame; + */ + interview_pos = 0; + base_ref = p_Dpb->fs_ilref[interview_pos]->frame; + + if (base_ref->used_for_reference || base_ref->inter_view_flag[0]) + { + //p_Dpb->fs[interview_pos]->frame_num_wrap = -99; + p_Dpb->fs_ilref[interview_pos]->frame_num_wrap = -99; + currSlice->listX[0][list0idx++] = base_ref; + currSlice->listX[1][list1idx++] = base_ref; + currSlice->listXsize[0] = (char) list0idx; + currSlice->listXsize[1] = (char) list1idx; + } + } + else //FIELD + { + int cur_inter_view_flag = currSlice->structure != BOTTOM_FIELD ? 0 : 1; + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + list0idx = currSlice->listXsize[0]; + list1idx = currSlice->listXsize[1]; + /* + interview_pos = currSlice->structure!=BOTTOM_FIELD ? p_Dpb->used_size - 1: p_Dpb->used_size - 2; // top field is at the last position + base_ref = currSlice->structure != BOTTOM_FIELD ? p_Dpb->fs[interview_pos]->top_field:p_Dpb->fs[interview_pos]->bottom_field; + */ + interview_pos = 0; + base_ref = currSlice->structure != BOTTOM_FIELD ? p_Dpb->fs_ilref[interview_pos]->top_field:p_Dpb->fs_ilref[interview_pos]->bottom_field; + if (base_ref->used_for_reference || base_ref->inter_view_flag[cur_inter_view_flag]) + { + //p_Dpb->fs[interview_pos]->frame_num_wrap = -99; + p_Dpb->fs_ilref[interview_pos]->frame_num_wrap = -99; + currSlice->listX[0][list0idx++] = base_ref; + currSlice->listX[1][list1idx++] = base_ref; + currSlice->listXsize[0] = (char) list0idx; + currSlice->listXsize[1] = (char) list1idx; + } + } + } +#endif + + // set max size +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2 && p_Inp->MVCInterViewReorder && p_Vid->view_id == 1) + { + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0] + 1); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + } + else +#endif + { + currSlice->listXsize[0] = (char) imin (currSlice->listXsize[0], currSlice->num_ref_idx_active[LIST_0]); + currSlice->listXsize[1] = (char) imin (currSlice->listXsize[1], currSlice->num_ref_idx_active[LIST_1]); + } + + // set the unused list entries to NULL + for (i=currSlice->listXsize[0]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[0][i] = NULL; + } + for (i=currSlice->listXsize[1]; i< (MAX_LIST_SIZE) ; i++) + { + currSlice->listX[1][i] = NULL; + } + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + // print out for debug purpose + if(p_Inp->num_of_views==2 && p_Vid->current_slice_nr==0) + { + if((currSlice->listXsize[0]>0) || (currSlice->listXsize[1]>0)) + printf("\n"); + if(currSlice->listXsize[0]>0) + { + printf(" ** (CurViewID:%d) %s Ref Pic List 0 ****\n", p_Vid->view_id, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[0][i]->poc, currSlice->listX[0][i]->pic_num, currSlice->listX[0][i]->view_id); + } + } + if(currSlice->listXsize[1]>0) + { + printf(" ** (CurViewID:%d) %s Ref Pic List 1 ****\n", p_Vid->view_id, currSlice->structure==FRAME ? "FRM":(currSlice->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(unsigned int)(currSlice->listXsize[1]); i++) //ref list 1 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, currSlice->listX[1][i]->poc, currSlice->listX[1][i]->pic_num, currSlice->listX[1][i]->view_id); + } + } + } +#endif +#endif +} + +/*! + ************************************************************************ + * \brief + * Initialize listX[2..5] from lists 0 and 1 + * listX[2]: list0 for current_field==top + * listX[3]: list1 for current_field==top + * listX[4]: list0 for current_field==bottom + * listX[5]: list1 for current_field==bottom + * + ************************************************************************ + */ +void init_mbaff_lists(Slice *currSlice) +{ + unsigned j; + int i; + + for (i=2;i<6;i++) + { + if(currSlice->listX[i]) + { + for (j=0; jlistX[i][j] = NULL; + } + } + currSlice->listXsize[i]=0; + } + + for (i = 0; i < currSlice->listXsize[0]; i++) + { + currSlice->listX[2][2*i ] = currSlice->listX[0][i]->top_field; + currSlice->listX[2][2*i+1] = currSlice->listX[0][i]->bottom_field; + currSlice->listX[4][2*i ] = currSlice->listX[0][i]->bottom_field; + currSlice->listX[4][2*i+1] = currSlice->listX[0][i]->top_field; + } + currSlice->listXsize[2] = currSlice->listXsize[4] = currSlice->listXsize[0] * 2; + + for (i = 0; i < currSlice->listXsize[1]; i++) + { + currSlice->listX[3][2*i ] = currSlice->listX[1][i]->top_field; + currSlice->listX[3][2*i+1] = currSlice->listX[1][i]->bottom_field; + currSlice->listX[5][2*i ] = currSlice->listX[1][i]->bottom_field; + currSlice->listX[5][2*i+1] = currSlice->listX[1][i]->top_field; + } + currSlice->listXsize[3] = currSlice->listXsize[5] = currSlice->listXsize[1] * 2; +} + + /*! + ************************************************************************ + * \brief + * Returns short term pic with given picNum + * + ************************************************************************ + */ +StorablePicture *get_short_term_pic(Slice *currSlice, DecodedPictureBuffer *p_Dpb, int picNum) +{ + unsigned i; + + for (i = 0; i < p_Dpb->ref_frames_in_buffer; i++) + { + if (currSlice->structure == FRAME) + { + if (p_Dpb->fs_ref[i]->is_reference == 3) + if ((!p_Dpb->fs_ref[i]->frame->is_long_term)&&(p_Dpb->fs_ref[i]->frame->pic_num == picNum)) + return p_Dpb->fs_ref[i]->frame; + } + else + { + if (p_Dpb->fs_ref[i]->is_reference & 1) + if ((!p_Dpb->fs_ref[i]->top_field->is_long_term)&&(p_Dpb->fs_ref[i]->top_field->pic_num == picNum)) + return p_Dpb->fs_ref[i]->top_field; + if (p_Dpb->fs_ref[i]->is_reference & 2) + if ((!p_Dpb->fs_ref[i]->bottom_field->is_long_term)&&(p_Dpb->fs_ref[i]->bottom_field->pic_num == picNum)) + return p_Dpb->fs_ref[i]->bottom_field; + } + } + return NULL; +} + + +/*! + ************************************************************************ + * \brief + * Reordering process for short-term reference pictures + * + ************************************************************************ + */ +void reorder_short_term(Slice *currSlice, DecodedPictureBuffer *p_Dpb, int cur_list, int picNumLX, int *refIdxLX) +{ + StorablePicture **RefPicListX = currSlice->listX[cur_list]; + int cIdx, nIdx; + + StorablePicture *picLX; + + picLX = get_short_term_pic(currSlice, p_Dpb, picNumLX); + + for( cIdx = currSlice->num_ref_idx_active[cur_list]; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= currSlice->num_ref_idx_active[cur_list]; cIdx++ ) + { + if (RefPicListX[ cIdx ]) + if( (RefPicListX[ cIdx ]->is_long_term ) || (RefPicListX[ cIdx ]->pic_num != picNumLX )) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; + } +} + + +/*! + ************************************************************************ + * \brief + * Reordering process for long-term reference pictures + * + ************************************************************************ + */ +static void reorder_long_term(Slice *currSlice, DecodedPictureBuffer *p_Dpb, StorablePicture **RefPicListX, int cur_list, int frame_no, int *refIdxLX) +{ + int cIdx, nIdx; + int LongTermPicNum = currSlice->long_term_pic_idx[cur_list][frame_no]; + + StorablePicture *picLX; + + picLX = get_long_term_pic(currSlice, p_Dpb, LongTermPicNum); + + for( cIdx = currSlice->num_ref_idx_active[cur_list]; cIdx > *refIdxLX; cIdx-- ) + RefPicListX[ cIdx ] = RefPicListX[ cIdx - 1]; + + RefPicListX[ (*refIdxLX)++ ] = picLX; + + nIdx = *refIdxLX; + + for( cIdx = *refIdxLX; cIdx <= currSlice->num_ref_idx_active[cur_list]; cIdx++ ) + if( (!RefPicListX[ cIdx ]->is_long_term ) || (RefPicListX[ cIdx ]->long_term_pic_num != LongTermPicNum )) + RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]; +} + + + +/*! + ************************************************************************ + * \brief + * Reordering process for reference picture lists + * + ************************************************************************ + */ +void reorder_ref_pic_list(Slice *currSlice, int cur_list) +{ + int *modification_of_pic_nums_idc = currSlice->modification_of_pic_nums_idc[cur_list]; + int *abs_diff_pic_num_minus1 = currSlice->abs_diff_pic_num_minus1[cur_list]; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + int i; + + int maxPicNum, currPicNum, picNumLXNoWrap, picNumLXPred, picNumLX; + int refIdxLX = 0; + + if (currSlice->structure==FRAME) + { + maxPicNum = currSlice->max_frame_num; + currPicNum = currSlice->frame_num; + } + else + { + maxPicNum = 2 * currSlice->max_frame_num; + currPicNum = 2 * currSlice->frame_num + 1; + } + + picNumLXPred = currPicNum; + + for (i=0; modification_of_pic_nums_idc[i]!=3; i++) + { + if (modification_of_pic_nums_idc[i] > 3) + error ("Invalid modification_of_pic_nums_idc command", 500); + + if (modification_of_pic_nums_idc[i] < 2) + { + if (modification_of_pic_nums_idc[i] == 0) + { + if( picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) < 0 ) + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ) + maxPicNum; + else + picNumLXNoWrap = picNumLXPred - ( abs_diff_pic_num_minus1[i] + 1 ); + } + else // (modification_of_pic_nums_idc[i] == 1) + { + if( picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) >= maxPicNum ) + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ) - maxPicNum; + else + picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1[i] + 1 ); + } + picNumLXPred = picNumLXNoWrap; + + if( picNumLXNoWrap > currPicNum ) + picNumLX = picNumLXNoWrap - maxPicNum; + else + picNumLX = picNumLXNoWrap; + + reorder_short_term(currSlice, p_Dpb, cur_list, picNumLX, &refIdxLX); + } + else //(modification_of_pic_nums_idc[i] == 2) + { + reorder_long_term (currSlice, p_Dpb, currSlice->listX[cur_list], cur_list, i, &refIdxLX); + } + } + + // that's a definition + currSlice->listXsize[cur_list] = currSlice->num_ref_idx_active[cur_list]; +} + + + + +/*! + ************************************************************************ + * \brief + * Perform Memory management for idr pictures + * + ************************************************************************ + */ +static void idr_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output) +{ + unsigned i; + VideoParameters *p_Vid = p_Dpb->p_Vid; + + assert (p_Vid->currentPicture->idr_flag); + + if (p_Vid->no_output_of_prior_pics_flag) + { + // free all stored pictures + for (i=0; iused_size; i++) + { + // reset all reference settings + free_frame_store(p_Vid, p_Dpb->fs[i]); + p_Dpb->fs[i] = alloc_frame_store(); + } + for (i=0; iref_frames_in_buffer; i++) + { + p_Dpb->fs_ref[i]=NULL; + } + for (i=0; iltref_frames_in_buffer; i++) + { + p_Dpb->fs_ltref[i]=NULL; + } + p_Dpb->used_size=0; + } + else + { + flush_dpb(p_Dpb, output); + } + p_Dpb->last_picture = NULL; + + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + p_Dpb->last_output_poc = INT_MIN; +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = 0; +#endif + + if (p_Vid->long_term_reference_flag) + { + p_Dpb->max_long_term_pic_idx = 0; + p->is_long_term = 1; + p->long_term_frame_idx = 0; + } + else + { + p_Dpb->max_long_term_pic_idx = -1; + p->is_long_term = 0; + } +} + +/*! + ************************************************************************ + * \brief + * Perform Sliding window decoded reference picture marking process + * + ************************************************************************ + */ +static void sliding_window_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + + // if this is a reference pic with sliding sliding window, unmark first ref frame + if (p_Dpb->ref_frames_in_buffer == imax(1, p_Vid->active_sps->num_ref_frames) - p_Dpb->ltref_frames_in_buffer) + { + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term))) + { + unmark_for_reference(p_Dpb->fs[i]); + update_ref_list(p_Dpb); + break; + } + } + } + + p->is_long_term = 0; +} + + + + + + +/*! + ************************************************************************ + * \brief + * Perform Adaptive memory control decoded reference picture marking process + ************************************************************************ + */ +static void adaptive_memory_management(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output) +{ + DecRefPicMarking_t *tmp_drpm; + VideoParameters *p_Vid = p_Dpb->p_Vid; + + p_Vid->last_has_mmco_5 = 0; + + assert (!p_Vid->currentPicture->idr_flag); + assert (p_Vid->adaptive_ref_pic_buffering_flag); + + while (p_Vid->dec_ref_pic_marking_buffer) + { + tmp_drpm = p_Vid->dec_ref_pic_marking_buffer; + switch (tmp_drpm->memory_management_control_operation) + { + case 0: + if (tmp_drpm->Next != NULL) + { + error ("memory_management_control_operation = 0 not last operation in buffer", 500); + } + break; + case 1: + mm_unmark_short_term_for_reference(p_Dpb, p, tmp_drpm->difference_of_pic_nums_minus1); + update_ref_list(p_Dpb); + break; + case 2: + mm_unmark_long_term_for_reference(p_Dpb, p, tmp_drpm->long_term_pic_num); + update_ltref_list(p_Dpb); + break; + case 3: + mm_assign_long_term_frame_idx(p_Dpb, p, tmp_drpm->difference_of_pic_nums_minus1, tmp_drpm->long_term_frame_idx); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + break; + case 4: + mm_update_max_long_term_frame_idx (p_Dpb, tmp_drpm->max_long_term_frame_idx_plus1); + update_ltref_list(p_Dpb); + break; + case 5: + mm_unmark_all_short_term_for_reference(p_Dpb); + mm_unmark_all_long_term_for_reference(p_Dpb); + p_Vid->last_has_mmco_5 = 1; + break; + case 6: + mm_mark_current_picture_long_term(p_Dpb, p, tmp_drpm->long_term_frame_idx); + check_num_ref(p_Dpb); + break; + default: + error ("invalid memory_management_control_operation in buffer", 500); + } + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm->Next; + free (tmp_drpm); + } + if ( p_Vid->last_has_mmco_5 ) + { + p->pic_num = p->frame_num = 0; + + switch (p->structure) + { + case TOP_FIELD: + { + p->poc = p->top_poc = p_Vid->toppoc =0; + break; + } + case BOTTOM_FIELD: + { + p->poc = p->bottom_poc = p_Vid->bottompoc = 0; + break; + } + case FRAME: + { + p->top_poc -= p->poc; + p->bottom_poc -= p->poc; + + p_Vid->toppoc = p->top_poc; + p_Vid->bottompoc = p->bottom_poc; + + p->poc = imin (p->top_poc, p->bottom_poc); + p_Vid->framepoc = p->poc; + break; + } + } + p_Vid->ThisPOC = p->poc; + flush_dpb(p_Vid->p_Dpb_layer[0], output); + if(p_Vid->num_of_layers >1) + flush_dpb(p_Vid->p_Dpb_layer[1], output); + } +} + + +/*! + ************************************************************************ + * \brief + * Store a picture in DPB. This includes cheking for space in DPB and + * flushing frames. + * If we received a frame, we need to check for a new store, if we + * got a field, check if it's the second field of an already allocated + * store. + * + * \param p_Vid + * VideoParameters + * \param p + * Picture to be stored + * \param output + * FrameFormat for output + * + ************************************************************************ + */ +void store_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + int poc, pos; + + // diagnostics + //printf ("Storing (%s) non-ref pic with frame_num #%d\n", (p->type == FRAME)?"FRAME":(p->type == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", p->pic_num); + // if frame, check for new store, + assert (p!=NULL); + + p->otf_flag = p_Vid->p_Inp->OnTheFlyFractMCP ; // JLT : on-the-fly + + p->used_for_reference = (p_Vid->nal_reference_idc != NALU_PRIORITY_DISPOSABLE); + + p->type = p_Vid->type; + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views==2) + { + p->view_id = p_Vid->view_id; + + if(p->structure==FRAME) + { + p->inter_view_flag[0] = p->inter_view_flag[1] = p_Vid->inter_view_flag[0]; + p->anchor_pic_flag[0] = p->anchor_pic_flag[1] = p_Vid->anchor_pic_flag[0]; + } + else + { + if(p->structure==TOP_FIELD) + { + p->inter_view_flag[0] = p_Vid->inter_view_flag[0]; + p->anchor_pic_flag[0] = p_Vid->anchor_pic_flag[0]; + } + else // BOTTOM_FIELD + { + p->inter_view_flag[1] = p_Vid->inter_view_flag[1]; + p->anchor_pic_flag[1] = p_Vid->anchor_pic_flag[1]; + } + } + + if(p_Vid->view_id == 0) + { + process_picture_in_dpb_s(p_Vid, p); + p_Vid->proc_picture = clone_storable_picture(p_Vid, p); + } + } +#endif + + p_Vid->last_has_mmco_5 = 0; + p_Vid->last_pic_bottom_field = (p_Vid->structure == BOTTOM_FIELD); + + if (p_Vid->currentPicture->idr_flag) + { + idr_memory_management(p_Dpb, p, output); + if(p_Vid->num_of_layers > 1) + idr_memory_management(p_Vid->p_Dpb_layer[1], p, output); + } + else + { + // adaptive memory management + if (p->used_for_reference && (p_Vid->adaptive_ref_pic_buffering_flag)) + adaptive_memory_management(p_Dpb, p, output); + } + + if ((p->structure==TOP_FIELD)||(p->structure==BOTTOM_FIELD)) + { + // check for frame store with same pic_number + if (p_Dpb->last_picture) + { + if ((int)p_Dpb->last_picture->frame_num == p->pic_num) + { + if (((p->structure==TOP_FIELD)&&(p_Dpb->last_picture->is_used==2))||((p->structure==BOTTOM_FIELD)&&(p_Dpb->last_picture->is_used==1))) + { + if ((p->used_for_reference && (p_Dpb->last_picture->is_orig_reference!=0))|| + (!p->used_for_reference && (p_Dpb->last_picture->is_orig_reference==0))) + { + insert_picture_in_dpb(p_Vid, p_Dpb->last_picture, p); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); +#if (DUMP_DPB) + printf("\nstore_picture_in_dpb inserting complementary field\n"); +#endif + dump_dpb(p_Dpb); + p_Dpb->last_picture = NULL; + return; + } + } + } + } + } + + // this is a frame or a field which has no stored complementary field + + // sliding window, if necessary + if ((!p_Vid->currentPicture->idr_flag) && (p->used_for_reference && (!p_Vid->adaptive_ref_pic_buffering_flag))) + { + sliding_window_memory_management(p_Dpb, p); + } + + // first try to remove unused frames + if (p_Dpb->used_size == p_Dpb->size) + { + remove_unused_frame_from_dpb(p_Dpb); + } + + // then output frames until one can be removed + while (p_Dpb->used_size == p_Dpb->size) + { + // non-reference frames may be output directly + if (!p->used_for_reference) + { + get_smallest_poc(p_Dpb, &poc, &pos); + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views==2) + { + if (((-1==pos) || (p->poc < poc))) + { + direct_output(p_Vid, p, output, (p_Dpb->layer_id ? p_Vid->p_dec2: p_Vid->p_dec)); + return; + } + } + else +#endif + { + if ((-1==pos) || (p->poc < poc)) + { + direct_output(p_Vid, p, output, p_Vid->p_dec); + return; + } + } + } + // flush a frame + output_one_frame_from_dpb(p_Dpb, output); + } + + // check for duplicate frame number in short term reference buffer + if ((p->used_for_reference)&&(!p->is_long_term)) + { + for (i=0; iref_frames_in_buffer; i++) + { + if (p_Dpb->fs_ref[i]->frame_num == p->frame_num) + { + error("duplicate frame_num in short-term reference picture buffer", 500); + } + } + } + // store at end of buffer + insert_picture_in_dpb(p_Vid, p_Dpb->fs[p_Dpb->used_size],p); + + if (p->structure != FRAME) + { + p_Dpb->last_picture = p_Dpb->fs[p_Dpb->used_size]; + } + else + { + p_Dpb->last_picture = NULL; + } + + p_Dpb->used_size++; + + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + + check_num_ref(p_Dpb); +#if (DUMP_DPB) + printf("\nEnd of store_picture_in_dpb\n"); +#endif + dump_dpb(p_Dpb); +} + +#if (MVC_EXTENSION_ENABLE) +/*! + ************************************************************************ + * \brief + * Reference process the frame picture and insert into the buffer + * if the reference processed top field has already + * been stored + * + * \param p_Vid + * VideoParameters + * \param p + * StorablePicture to be inserted + * \param output + * FrameFormat for output + * + ************************************************************************ + */ +void replace_top_proc_pic_with_frame(DecodedPictureBuffer *p_Dpb, StorablePicture* p) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + StorablePicture *proc_picture = p_Vid->proc_picture; + FrameStore* fs = NULL; + unsigned found;//i, + + assert (p!=NULL); + assert (p->structure==FRAME); + assert (proc_picture==NULL); + assert (p_Vid->p_Inp->ProfileIDC <=STEREO_HIGH); + process_picture_in_dpb_s(p_Vid, p); + proc_picture = clone_storable_picture(p_Vid, p); + + proc_picture->used_for_reference = (p_Vid->nal_reference_idc != NALU_PRIORITY_DISPOSABLE); + proc_picture->type = p_Vid->type; + p_Vid->last_has_mmco_5=0; + p_Vid->last_pic_bottom_field = (p_Vid->structure == BOTTOM_FIELD); + + // upsample a reference picture + if( (p_Vid->p_Inp->separate_colour_plane_flag != 0) ) + { + UnifiedOneForthPix_JV(p_Vid, 0, proc_picture); + UnifiedOneForthPix_JV(p_Vid, 1, proc_picture); + UnifiedOneForthPix_JV(p_Vid, 2, proc_picture); + } + else + { + UnifiedOneForthPix(p_Vid, proc_picture); + } + + found=0; + + if(p_Dpb->fs_ilref[0] && (p_Dpb->fs_ilref[0]->frame_num == p_Vid->frame_num) && (p_Dpb->fs_ilref[0]->is_used == 1)) + { + found = 1; + fs = p_Dpb->fs_ilref[0]; + } + + if (!found) + { + printf("replace_top_proc_pic_with_frame: Warning! Reference processed field not found. Processed frame not inserted in DPB\n"); + free_storable_picture(p_Vid, proc_picture); + } + else + { + free_storable_picture(p_Vid, fs->top_field); + fs->top_field=NULL; + fs->frame=proc_picture; + fs->is_used = 3; + if (p->used_for_reference) + { + fs->is_reference = 3; + if (p->is_long_term) + { + fs->is_long_term = 3; + } + } + // generate field views + dpb_split_field(p_Vid, fs); + fs->top_field->view_id = fs->bottom_field->view_id = fs->frame->view_id; + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + } + + p_Vid->proc_picture = NULL; +} +#endif + +/*! + ************************************************************************ + * \brief + * Insert the frame picture into the buffer if the top field has already + * been stored for the coding decision + * + * \param p_Vid + * VideoParameters + * \param p + * StorablePicture to be inserted + * \param output + * FrameFormat for output + * + ************************************************************************ + */ +void replace_top_pic_with_frame(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + FrameStore* fs = NULL; + unsigned i, found; + + assert (p!=NULL); + assert (p->structure==FRAME); + + p->used_for_reference = (p_Vid->nal_reference_idc != NALU_PRIORITY_DISPOSABLE); + p->type = p_Vid->type; + // upsample a reference picture + +#if (MVC_EXTENSION_ENABLE) + if (p->used_for_reference || (p_Vid->p_Inp->num_of_views==2 && p_Vid->view_id == 0)) +#else + if (p->used_for_reference) +#endif + { + if( (p_Vid->p_Inp->separate_colour_plane_flag != 0) ) + { + UnifiedOneForthPix_JV(p_Vid, 0, p); + UnifiedOneForthPix_JV(p_Vid, 1, p); + UnifiedOneForthPix_JV(p_Vid, 2, p); + } + else + { + UnifiedOneForthPix(p_Vid, p); + } + } + + found=0; + + for (i = 0; i < p_Dpb->used_size; i++) + { + if((p_Dpb->fs[i]->frame_num == p_Vid->frame_num) && (p_Dpb->fs[i]->is_used == 1)) + { + found=1; + fs = p_Dpb->fs[i]; + break; + } + } + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views == 2) + { + if (p_Dpb->layer_id == 0) + { + replace_top_proc_pic_with_frame(p_Vid->p_Dpb_layer[1], p); + } + } +#endif + + if (!found) + { + // this should only happen for non-reference pictures when the dpb is full of reference pics +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views == 2) + { + if (p_Dpb->layer_id == 0) // view 0 + direct_output_paff(p_Vid, p, output, p_Vid->p_dec); + else // view 1 + direct_output_paff(p_Vid, p, output, p_Vid->p_dec2); + } + else +#endif + direct_output_paff(p_Vid, p, output, p_Vid->p_dec); + } + else + { + free_storable_picture(p_Vid, fs->top_field); + fs->top_field = NULL; + fs->frame = p; + fs->is_used = 3; + if (p->used_for_reference) + { + fs->is_reference = 3; + if (p->is_long_term) + { + fs->is_long_term = 3; + } + } + // generate field views + dpb_split_field(p_Vid, fs); + update_ref_list(p_Dpb); + update_ltref_list(p_Dpb); + } +#if (DUMP_DPB) + printf("\nReplace Top pic with Frame\n"); + dump_dpb(p_Dpb); +#endif +} + + +/*! + ************************************************************************ + * \brief + * Insert the picture into the DPB. A free DPB position is necessary + * for frames, . + * + * \param p_Vid + * VideoParameters + * \param fs + * FrameStore into which the picture will be inserted + * \param p + * StorablePicture to be inserted + * + ************************************************************************ + */ +static void insert_picture_in_dpb(VideoParameters *p_Vid, FrameStore* fs, StorablePicture* p) +{ + // printf ("insert (%s) pic with frame_num #%d, poc %d\n", (p->structure == FRAME)?"FRAME":(p->structure == TOP_FIELD)?"TOP_FIELD":"BOTTOM_FIELD", p->pic_num, p->poc); + assert (p!=NULL); + assert (fs!=NULL); + + // upsample a reference picture + if (p->used_for_reference) + { + if( (p_Vid->p_Inp->separate_colour_plane_flag != 0) ) + { + UnifiedOneForthPix_JV(p_Vid, 0, p); + UnifiedOneForthPix_JV(p_Vid, 1, p); + UnifiedOneForthPix_JV(p_Vid, 2, p); + } + else + { + UnifiedOneForthPix(p_Vid, p); + } + } +#if (MVC_EXTENSION_ENABLE) + else if(p_Vid->p_Inp->num_of_views==2 && p->inter_view_flag[p->structure>>1]) + { + UnifiedOneForthPix(p_Vid, p); + } +#endif + + switch (p->structure) + { + case FRAME: + fs->frame = p; + fs->is_used = 3; + if (p->used_for_reference) + { + fs->is_reference = 3; + fs->is_orig_reference = 3; + if (p->is_long_term) + { + fs->is_long_term = 3; + fs->long_term_frame_idx = p->long_term_frame_idx; + } + } + // generate field views + dpb_split_field(p_Vid, fs); +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views==2) + { + fs->anchor_pic_flag[0] = fs->anchor_pic_flag[1] = p->anchor_pic_flag[0]; + fs->inter_view_flag[0] = fs->inter_view_flag[1] = p->inter_view_flag[0]; + } + if (fs->top_field) + { + fs->top_field->view_id = p->view_id; + } + if (fs->bottom_field) + { + fs->bottom_field->view_id = p->view_id; + } +#endif + break; + case TOP_FIELD: + fs->top_field = p; + fs->is_used |= 1; + if (p->used_for_reference) + { + fs->is_reference |= 1; + fs->is_orig_reference |= 1; + if (p->is_long_term) + { + fs->is_long_term |= 1; + fs->long_term_frame_idx = p->long_term_frame_idx; + } + } + if (fs->is_used == 3) + { + // generate frame view + dpb_combine_field(p_Vid, fs); + } + else + { + fs->poc = p->poc; + gen_field_ref_ids(p); + } +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views==2) + { + fs->anchor_pic_flag[0] = p->anchor_pic_flag[0]; + fs->inter_view_flag[0] = p->inter_view_flag[0]; + } + fs->top_field->view_id = p->view_id; +#endif + break; + case BOTTOM_FIELD: + fs->bottom_field = p; + fs->is_used |= 2; + if (p->used_for_reference) + { + fs->is_reference |= 2; + fs->is_orig_reference |= 2; + if (p->is_long_term) + { + fs->is_long_term |= 2; + fs->long_term_frame_idx = p->long_term_frame_idx; + } + } + if (fs->is_used == 3) + { + // generate frame view + dpb_combine_field(p_Vid, fs); +#if (MVC_EXTENSION_ENABLE) + fs->frame->view_id = p->view_id; +#endif + } + else + { + fs->poc = p->poc; + gen_field_ref_ids(p); + } +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views==2) + { + fs->anchor_pic_flag[1] = p->anchor_pic_flag[1]; + fs->inter_view_flag[1] = p->inter_view_flag[1]; + } + fs->bottom_field->view_id = p->view_id; +#endif + break; + } + fs->frame_num = p->pic_num; + fs->is_output = p->is_output; + fs->is_inter_layer = FALSE; + +#if (MVC_EXTENSION_ENABLE) + fs->view_id = p->view_id; +#endif +} + + + +/*! + ************************************************************************ + * \brief + * remove one frame from DPB + ************************************************************************ + */ +void remove_frame_from_dpb(DecodedPictureBuffer *p_Dpb, int pos) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + FrameStore* fs = p_Dpb->fs[pos]; + FrameStore* tmp; + unsigned i; + + //printf ("remove frame with frame_num #%d\n", fs->frame_num); + switch (fs->is_used) + { + case 3: + free_storable_picture(p_Vid, fs->frame); + free_storable_picture(p_Vid, fs->top_field); + free_storable_picture(p_Vid, fs->bottom_field); + fs->frame=NULL; + fs->top_field=NULL; + fs->bottom_field=NULL; + break; + case 2: + free_storable_picture(p_Vid, fs->bottom_field); + fs->bottom_field=NULL; + break; + case 1: + free_storable_picture(p_Vid, fs->top_field); + fs->top_field=NULL; + break; + case 0: + break; + default: + error("invalid frame store type",500); + } + fs->is_used = 0; + fs->is_long_term = 0; + fs->is_reference = 0; + fs->is_orig_reference = 0; + + // move empty framestore to end of buffer + tmp = p_Dpb->fs[pos]; + + for (i=pos; iused_size-1;i++) + { + p_Dpb->fs[i] = p_Dpb->fs[i+1]; + } + p_Dpb->fs[p_Dpb->used_size-1] = tmp; + p_Dpb->used_size--; +} + + +/*! + ************************************************************************ + * \brief + * Flush a picture from DPB which is no longer needed. + ************************************************************************ + */ +static int flush_unused_frame_from_dpb(DecodedPictureBuffer *p_Dpb) +{ + unsigned i; + + // check for frames that were already output and no longer used for reference + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_output && (!is_used_for_reference(p_Dpb->fs[i]))) + { + remove_frame_from_dpb(p_Dpb, i); + return 1; + } + } + return 0; +} + + + +/*! + ************************************************************************ + * \brief + * Output one picture stored in the DPB. + ************************************************************************ + */ +static void output_one_frame_from_dpb(DecodedPictureBuffer *p_Dpb, FrameFormat *output) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + InputParameters *p_Inp = p_Dpb->p_Inp; + int poc, pos; + //diagnostics + if (p_Dpb->used_size < 1) + { + error("Cannot output frame, DPB empty.",150); + } + + // find smallest POC + get_smallest_poc(p_Dpb, &poc, &pos); + + if(pos==-1) + { + error("no frames for output available", 150); + } + + // call the output function + // printf ("output frame with frame_num #%d, poc %d (p_Dpb-> p_Dpb->size=%d, p_Dpb->used_size=%d)\n", p_Dpb->fs[pos]->frame_num, p_Dpb->fs[pos]->frame->poc, p_Dpb->size, p_Dpb->used_size); +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + { + if(p_Dpb->fs[pos]->view_id==1) + write_stored_frame(p_Vid, p_Dpb->fs[pos], output, p_Vid->p_dec2); + else + write_stored_frame(p_Vid, p_Dpb->fs[pos], output, p_Vid->p_dec); + } + else +#endif + write_stored_frame(p_Vid, p_Dpb->fs[pos], output, p_Vid->p_dec); + + // if redundant picture in use, output POC may be not in ascending order + if(p_Inp->redundant_pic_flag == 0) + { + if (p_Dpb->last_output_poc >= poc) + { + error ("output POC must be in ascending order", 150); + } + } + p_Dpb->last_output_poc = poc; + + // free frame store and move empty store to end of buffer + if (!is_used_for_reference(p_Dpb->fs[pos])) + { + remove_frame_from_dpb(p_Dpb, pos); + } +} + + + +/*! + ************************************************************************ + * \brief + * All stored picture are output. Should be called to empty the buffer + ************************************************************************ + */ +void flush_dpb(DecodedPictureBuffer *p_Dpb, FrameFormat *output) +{ + unsigned i; + + // diagnostics + // printf("Flush remaining frames from the dpb. p_Dpb->size=%d, p_Dpb->used_size=%d\n",p_Dpb->size,p_Dpb->used_size); + + // mark all frames unused + //VideoParameters *p_Vid = p_Dpb->p_Vid; + for (i=0; iused_size; i++) + { + unmark_for_reference (p_Dpb->fs[i]); + } + + while (flush_unused_frame_from_dpb(p_Dpb)) ; + + // output frames in POC order + while (p_Dpb->used_size) + { + output_one_frame_from_dpb(p_Dpb, output); + } + + p_Dpb->last_output_poc = INT_MIN; +#if (MVC_EXTENSION_ENABLE) + p_Dpb->last_output_view_id = 0; +#endif +} + + +static void gen_field_ref_ids(StorablePicture *p) +{ + int i,j; + //! Generate Frame parameters from field information. + for (i = 0; i < (p->size_x >> 2); i++) + { + for (j = 0; j < (p->size_y >> 2); j++) + { + p->mv_info[j][i].field_frame=1; + } + } +} + +/*! + ************************************************************************ + * \brief + * Extract top field from a frame + ************************************************************************ + */ +void dpb_split_field(VideoParameters *p_Vid, FrameStore *fs) +{ + int i, j, k, ii, jj, jj4; + int idiv,jdiv; + int currentmb; + + int twosz16 = 2 * (fs->frame->size_x >> 4); + StorablePicture *fs_top, *fs_btm; + StorablePicture *frame = fs->frame; + + fs->poc = frame->poc; + + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + fs_top = fs->top_field = alloc_storable_picture(p_Vid, TOP_FIELD, frame->size_x, frame->size_y >> 1, frame->size_x_cr, frame->size_y_cr >> 1); + fs_btm = fs->bottom_field = alloc_storable_picture(p_Vid, BOTTOM_FIELD, frame->size_x, frame->size_y >> 1, frame->size_x_cr, frame->size_y_cr >> 1); + + for (i = 0; i < (frame->size_y >> 1); i++) + { + memcpy(fs_top->imgY[i], frame->imgY[i*2], frame->size_x*sizeof(imgpel)); + memcpy(fs_btm->imgY[i], frame->imgY[i*2 + 1], frame->size_x*sizeof(imgpel)); + } + + for (k = 0; k < 2; k++) + { + for (i=0; i< (frame->size_y_cr >> 1); i++) + { + memcpy(fs_top->imgUV[k][i], frame->imgUV[k][i*2], frame->size_x_cr*sizeof(imgpel)); + memcpy(fs_btm->imgUV[k][i], frame->imgUV[k][i*2 + 1], frame->size_x_cr*sizeof(imgpel)); + } + } + if(frame->used_for_reference) + { + if( (p_Vid->p_Inp->separate_colour_plane_flag != 0) ) + { + UnifiedOneForthPix_JV(p_Vid, 0, fs->top_field); + UnifiedOneForthPix_JV(p_Vid, 1, fs->top_field); + UnifiedOneForthPix_JV(p_Vid, 2, fs->top_field); + UnifiedOneForthPix_JV(p_Vid, 0, fs->bottom_field); + UnifiedOneForthPix_JV(p_Vid, 1, fs->bottom_field); + UnifiedOneForthPix_JV(p_Vid, 2, fs->bottom_field); + } + else + { + UnifiedOneForthPix(p_Vid, fs->top_field); + UnifiedOneForthPix(p_Vid, fs->bottom_field); + } + } + fs->top_field->poc = frame->top_poc; + fs->bottom_field->poc = frame->bottom_poc; + + fs->top_field->frame_poc = frame->frame_poc; + + fs->top_field->bottom_poc =fs->bottom_field->bottom_poc = frame->bottom_poc; + fs->top_field->top_poc =fs->bottom_field->top_poc = frame->top_poc; + fs->bottom_field->frame_poc = frame->frame_poc; + + fs->top_field->used_for_reference = fs->bottom_field->used_for_reference + = frame->used_for_reference; + fs->top_field->is_long_term = fs->bottom_field->is_long_term + = frame->is_long_term; + fs->long_term_frame_idx = fs->top_field->long_term_frame_idx + = fs->bottom_field->long_term_frame_idx + = frame->long_term_frame_idx; + + fs->top_field->coded_frame = fs->bottom_field->coded_frame = 1; + fs->top_field->mb_aff_frame_flag = fs->bottom_field->mb_aff_frame_flag + = frame->mb_aff_frame_flag; + + frame->top_field = fs->top_field; + frame->bottom_field = fs->bottom_field; + frame->frame = frame; + fs->top_field->bottom_field = fs->bottom_field; + fs->top_field->frame = fs->frame; + fs->top_field->top_field = fs->top_field; + fs->bottom_field->top_field = fs->top_field; + fs->bottom_field->frame = frame; + fs->bottom_field->bottom_field = fs->bottom_field; + + fs->top_field->chroma_format_idc = fs->bottom_field->chroma_format_idc = frame->chroma_format_idc; + fs->top_field->chroma_mask_mv_x = fs->bottom_field->chroma_mask_mv_x = frame->chroma_mask_mv_x; + fs->top_field->chroma_mask_mv_y = fs->bottom_field->chroma_mask_mv_y = frame->chroma_mask_mv_y; + fs->top_field->chroma_shift_x = fs->bottom_field->chroma_shift_x = frame->chroma_shift_x; + fs->top_field->chroma_shift_y = fs->bottom_field->chroma_shift_y = frame->chroma_shift_y; + + // JLT : otf flag + fs->top_field->otf_flag = fs->bottom_field->otf_flag = frame->otf_flag ; + } + else + { + fs->top_field=NULL; + fs->bottom_field=NULL; + frame->top_field=NULL; + frame->bottom_field=NULL; + frame->frame = frame; + } + + + if (!p_Vid->active_sps->frame_mbs_only_flag && fs->frame->mb_aff_frame_flag) + { + for (j=0 ; j< frame->size_y >> 3; j++) + { + jj = (j >> 2)*8 + (j & 0x03); + jj4 = jj + 4; + jdiv = (j >> 1); + for (i=0 ; i < (frame->size_x >> 2); i++) + { + idiv=i >> 2; + + currentmb = twosz16*(jdiv >> 1)+ (idiv)*2 + (jdiv & 0x01); + // Assign field mvs attached to MB-Frame buffer to the proper buffer + if (fs->frame->motion.mb_field[currentmb]) + { + fs->bottom_field->mv_info[j][i].field_frame = fs->top_field->mv_info[j][i].field_frame=1; + fs->frame->mv_info[2*j][i].field_frame = fs->frame->mv_info[2*j+1][i].field_frame = 1; + + fs->bottom_field->mv_info[j][i].mv[LIST_0] = fs->frame->mv_info[jj4][i].mv[LIST_0]; + fs->bottom_field->mv_info[j][i].mv[LIST_1] = fs->frame->mv_info[jj4][i].mv[LIST_1]; + fs->bottom_field->mv_info[j][i].ref_idx[LIST_0] = fs->frame->mv_info[jj4][i].ref_idx[LIST_0]; + /* + if(fs->bottom_field->mv_info[j][i].ref_idx[LIST_0] >=0) + fs->bottom_field->mv_info[j][i].ref_pic[LIST_0] = currSlice->listX[4][(short) fs->bottom_field->mv_info[j][i].ref_idx[LIST_0]]; + else + fs->bottom_field->mv_info[j][i].ref_pic[LIST_0] = NULL; + */ + fs->bottom_field->mv_info[j][i].ref_idx[LIST_1] = fs->frame->mv_info[jj4][i].ref_idx[LIST_1]; + /* + if(fs->bottom_field->mv_info[j][i].ref_idx[LIST_1] >=0) + fs->bottom_field->mv_info[j][i].ref_pic[LIST_1] = currSlice->listX[5][(short) fs->bottom_field->mv_info[j][i].ref_idx[LIST_1]]; + else + fs->bottom_field->mv_info[j][i].ref_pic[LIST_1] = NULL; + */ + + fs->top_field->mv_info[j][i].mv[LIST_0] = fs->frame->mv_info[jj][i].mv[LIST_0]; + fs->top_field->mv_info[j][i].mv[LIST_1] = fs->frame->mv_info[jj][i].mv[LIST_1]; + fs->top_field->mv_info[j][i].ref_idx[LIST_0] = fs->frame->mv_info[jj][i].ref_idx[LIST_0]; + /* + if(fs->top_field->mv_info[j][i].ref_idx[LIST_0] >=0) + fs->top_field->mv_info[j][i].ref_pic[LIST_0] = currSlice->listX[2][(short) fs->top_field->mv_info[j][i].ref_idx[LIST_0]]; + else + fs->top_field->mv_info[j][i].ref_pic[LIST_0] = NULL; + */ + fs->top_field->mv_info[j][i].ref_idx[LIST_1] = fs->frame->mv_info[jj][i].ref_idx[LIST_1]; + /* + if(fs->top_field->mv_info[j][i].ref_idx[LIST_1] >=0) + fs->top_field->mv_info[j][i].ref_pic[LIST_1] = currSlice->listX[3][(short) fs->top_field->mv_info[j][i].ref_idx[LIST_1]]; + else + fs->top_field->mv_info[j][i].ref_pic[LIST_1] = NULL; + */ + } + } + } + } + + //! Generate field MVs from Frame MVs + if (!p_Vid->active_sps->frame_mbs_only_flag) + { + for (j=0 ; jframe->size_y >> 3 ; j++) + { + jj = 2* RSD(j); + jdiv = j >> 1; + for (i=0 ; iframe->size_x >> 2 ; i++) + { + ii = RSD(i); + idiv = i >> 2; + + currentmb = twosz16*(jdiv >> 1)+ (idiv)*2 + (jdiv & 0x01); + + if (!fs->frame->mb_aff_frame_flag || !fs->frame->motion.mb_field[currentmb]) + { + fs->frame->mv_info[2*j+1][i].field_frame = fs->frame->mv_info[2*j][i].field_frame = 0; + + fs->top_field->mv_info[j][i].field_frame = fs->bottom_field->mv_info[j][i].field_frame = 0; + + fs->top_field->mv_info[j][i].mv[LIST_0] = fs->bottom_field->mv_info[j][i].mv[LIST_0] = fs->frame->mv_info[jj][ii].mv[LIST_0]; + fs->top_field->mv_info[j][i].mv[LIST_1] = fs->bottom_field->mv_info[j][i].mv[LIST_1] = fs->frame->mv_info[jj][ii].mv[LIST_1]; + + // Scaling of references is done here since it will not affect spatial direct (2*0 =0) + if (fs->frame->mv_info[jj][ii].ref_idx[LIST_0] == -1) + fs->top_field->mv_info[j][i].ref_idx[LIST_0] = fs->bottom_field->mv_info[j][i].ref_idx[LIST_0] = - 1; + else + { + fs->top_field->mv_info[j][i].ref_idx[LIST_0] = fs->bottom_field->mv_info[j][i].ref_idx[LIST_0] = fs->frame->mv_info[jj][ii].ref_idx[LIST_0]; + //fs->top_field->mv_info[j][i].ref_pic[LIST_0] = fs->bottom_field->mv_info[j][i].ref_pic[LIST_0] = currSlice->listX[LIST_0][fs->frame->mv_info[jj][ii].ref_idx[LIST_0]]; + } + + if (fs->frame->mv_info[jj][ii].ref_idx[LIST_1] == -1) + fs->top_field->mv_info[j][i].ref_idx[LIST_1] = fs->bottom_field->mv_info[j][i].ref_idx[LIST_1] = - 1; + else + { + fs->top_field->mv_info[j][i].ref_idx[LIST_1] = fs->bottom_field->mv_info[j][i].ref_idx[LIST_1] = fs->frame->mv_info[jj][ii].ref_idx[LIST_1]; + //fs->top_field->mv_info[j][i].ref_pic[LIST_1] = fs->bottom_field->mv_info[j][i].ref_pic[LIST_1] = currSlice->listX[LIST_1][fs->frame->mv_info[jj][ii].ref_idx[LIST_1]]; + } + } + else + { + fs->frame->mv_info[2*j+1][i].field_frame = fs->frame->mv_info[2*j][i].field_frame= fs->frame->motion.mb_field[currentmb]; + } + } + } + } + else + { + for (j=0 ; jframe->size_y >> 2 ; j++) + { + for (i=0 ; iframe->size_x >> 2 ; i++) + { + frame->mv_info[j][i].field_frame = 0; + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Generate a frame from top and bottom fields, + * YUV components and display information only + ************************************************************************ + */ +void dpb_combine_field_yuv(VideoParameters *p_Vid, FrameStore *fs) +{ + int i, j; + + if (!fs->frame) + { + fs->frame = alloc_storable_picture(p_Vid, FRAME, fs->top_field->size_x, fs->top_field->size_y*2, fs->top_field->size_x_cr, fs->top_field->size_y_cr*2); + } + + for (i=0; itop_field->size_y; i++) + { + memcpy(fs->frame->imgY[i*2], fs->top_field->imgY[i] , fs->top_field->size_x * sizeof(imgpel)); // top field + memcpy(fs->frame->imgY[i*2 + 1], fs->bottom_field->imgY[i], fs->bottom_field->size_x * sizeof(imgpel)); // bottom field + } + + for (j = 0; j < 2; j++) + { + for (i=0; itop_field->size_y_cr; i++) + { + memcpy(fs->frame->imgUV[j][i*2], fs->top_field->imgUV[j][i], fs->top_field->size_x_cr*sizeof(imgpel)); + memcpy(fs->frame->imgUV[j][i*2 + 1], fs->bottom_field->imgUV[j][i], fs->bottom_field->size_x_cr*sizeof(imgpel)); + } + } + + fs->poc=fs->frame->poc =fs->frame->frame_poc = imin (fs->top_field->poc, fs->bottom_field->poc); + + fs->bottom_field->frame_poc=fs->top_field->frame_poc=fs->frame->poc; + + fs->bottom_field->top_poc=fs->frame->top_poc=fs->top_field->poc; + fs->top_field->bottom_poc=fs->frame->bottom_poc=fs->bottom_field->poc; + + fs->frame->used_for_reference = (fs->top_field->used_for_reference && fs->bottom_field->used_for_reference ); + fs->frame->is_long_term = (fs->top_field->is_long_term && fs->bottom_field->is_long_term ); + + if (fs->frame->is_long_term) + fs->frame->long_term_frame_idx = fs->long_term_frame_idx; + + fs->frame->top_field = fs->top_field; + fs->frame->bottom_field = fs->bottom_field; + fs->frame->frame = fs->frame; + + fs->frame->coded_frame = 0; + + fs->frame->chroma_format_idc = fs->top_field->chroma_format_idc; + fs->frame->chroma_mask_mv_x = fs->top_field->chroma_mask_mv_x; + fs->frame->chroma_mask_mv_y = fs->top_field->chroma_mask_mv_y; + fs->frame->chroma_shift_x = fs->top_field->chroma_shift_x; + fs->frame->chroma_shift_y = fs->top_field->chroma_shift_y; + + fs->frame->frame_cropping_flag = fs->top_field->frame_cropping_flag; + if (fs->frame->frame_cropping_flag) + { + fs->frame->frame_crop_top_offset = fs->top_field->frame_crop_top_offset; + fs->frame->frame_crop_bottom_offset = fs->top_field->frame_crop_bottom_offset; + fs->frame->frame_crop_left_offset = fs->top_field->frame_crop_left_offset; + fs->frame->frame_crop_right_offset = fs->top_field->frame_crop_right_offset; + } + + fs->top_field->frame = fs->bottom_field->frame = fs->frame; + fs->top_field->top_field = fs->top_field; + fs->top_field->bottom_field = fs->bottom_field; + fs->bottom_field->top_field = fs->top_field; + fs->bottom_field->bottom_field = fs->bottom_field; + + // otf flag + fs->frame->otf_flag = fs->top_field->otf_flag; +} + + +/*! + ************************************************************************ + * \brief + * Generate a frame from top and bottom fields + ************************************************************************ + */ +void dpb_combine_field(VideoParameters *p_Vid, FrameStore *fs) +{ + int i,j, jj, jj4; + + dpb_combine_field_yuv(p_Vid, fs); + if (fs->frame->used_for_reference) + { + if( (p_Vid->p_Inp->separate_colour_plane_flag != 0) ) + { + UnifiedOneForthPix_JV(p_Vid, 0, fs->frame); + UnifiedOneForthPix_JV(p_Vid, 1, fs->frame); + UnifiedOneForthPix_JV(p_Vid, 2, fs->frame); + } + else + { + UnifiedOneForthPix(p_Vid, fs->frame); + } + } + + //! Generate Frame parameters from field information. + for (j=0 ; jtop_field->size_y >> 2 ; j++) + { + jj = 8*(j >> 2) + (j & 0x03); + jj4 = jj + 4; + for (i=0 ; itop_field->size_x >> 2 ; i++) + { + fs->frame->mv_info[jj][i].field_frame= fs->frame->mv_info[jj4][i].field_frame = 1; + + fs->frame->mv_info[jj][i].mv[LIST_0] = fs->top_field->mv_info[j][i].mv[LIST_0]; + fs->frame->mv_info[jj][i].mv[LIST_1] = fs->top_field->mv_info[j][i].mv[LIST_1]; + + fs->frame->mv_info[jj4][i].mv[LIST_0] = fs->bottom_field->mv_info[j][i].mv[LIST_0]; + fs->frame->mv_info[jj4][i].mv[LIST_1] = fs->bottom_field->mv_info[j][i].mv[LIST_1]; + + fs->top_field->mv_info[j][i].field_frame = 1; + fs->bottom_field->mv_info[j][i].field_frame = 1; + } + } +} + + +/*! + ************************************************************************ + * \brief + * Allocate memory for buffering of reference picture reordering commands + ************************************************************************ + */ +void alloc_ref_pic_list_reordering_buffer(Slice *currSlice) +{ + free_ref_pic_list_reordering_buffer(currSlice); + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + int size = currSlice->num_ref_idx_active[LIST_0] + 1; + if ((currSlice->modification_of_pic_nums_idc[LIST_0] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: modification_of_pic_nums_idc_l0"); + if ((currSlice->abs_diff_pic_num_minus1[LIST_0] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_pic_num_minus1_l0"); + if ((currSlice->long_term_pic_idx[LIST_0] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: long_term_pic_idx_l0"); +#if (MVC_EXTENSION_ENABLE) + if ((currSlice->abs_diff_view_idx_minus1[LIST_0] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_view_idx_minus1_l0"); +#endif + } + else + { + currSlice->modification_of_pic_nums_idc[LIST_0] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_0] = NULL; + currSlice->long_term_pic_idx[LIST_0] = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->abs_diff_view_idx_minus1[LIST_0] = NULL; +#endif + } + + if (currSlice->slice_type == B_SLICE) + { + int size = currSlice->num_ref_idx_active[LIST_1] + 1; + if ((currSlice->modification_of_pic_nums_idc[LIST_1] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: modification_of_pic_nums_idc_l1"); + if ((currSlice->abs_diff_pic_num_minus1[LIST_1] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_pic_num_minus1_l1"); + if ((currSlice->long_term_pic_idx[LIST_1] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: long_term_pic_idx_l1"); +#if (MVC_EXTENSION_ENABLE) + if ((currSlice->abs_diff_view_idx_minus1[LIST_1] = calloc(size, sizeof(int)))==NULL) + no_mem_exit("alloc_ref_pic_list_reordering_buffer: abs_diff_view_idx_minus1_l1"); +#endif + } + else + { + currSlice->modification_of_pic_nums_idc[LIST_1] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_1] = NULL; + currSlice->long_term_pic_idx[LIST_1] = NULL; +#if (MVC_EXTENSION_ENABLE) + currSlice->abs_diff_view_idx_minus1[LIST_1] = NULL; +#endif + } +} + + +/*! + ************************************************************************ + * \brief + * Free memory for buffering of reference picture reordering commands + ************************************************************************ + */ +void free_ref_pic_list_reordering_buffer(Slice *currSlice) +{ + if (currSlice->modification_of_pic_nums_idc[LIST_0]) + free(currSlice->modification_of_pic_nums_idc[LIST_0]); + if (currSlice->abs_diff_pic_num_minus1[LIST_0]) + free(currSlice->abs_diff_pic_num_minus1[LIST_0]); + if (currSlice->long_term_pic_idx[LIST_0]) + free(currSlice->long_term_pic_idx[LIST_0]); + + currSlice->modification_of_pic_nums_idc[LIST_0] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_0] = NULL; + currSlice->long_term_pic_idx[LIST_0] = NULL; + + if (currSlice->modification_of_pic_nums_idc[LIST_1]) + free(currSlice->modification_of_pic_nums_idc[LIST_1]); + if (currSlice->abs_diff_pic_num_minus1[LIST_1]) + free(currSlice->abs_diff_pic_num_minus1[LIST_1]); + if (currSlice->long_term_pic_idx[LIST_1]) + free(currSlice->long_term_pic_idx[LIST_1]); + + currSlice->modification_of_pic_nums_idc[LIST_1] = NULL; + currSlice->abs_diff_pic_num_minus1[LIST_1] = NULL; + currSlice->long_term_pic_idx[LIST_1] = NULL; + +#if (MVC_EXTENSION_ENABLE) + if (currSlice->abs_diff_view_idx_minus1[LIST_0]) + free_pointer(currSlice->abs_diff_view_idx_minus1[LIST_0]); + if (currSlice->abs_diff_view_idx_minus1[LIST_1]) + free_pointer(currSlice->abs_diff_view_idx_minus1[LIST_1]); +#endif +} + +/*! + ************************************************************************ + * \brief + * Tian Dong + * June 13, 2002, Modified on July 30, 2003 + * + * If a gap in frame_num is found, try to fill the gap + * \param p_Vid + * VideoParameters structure + * \param output + * FrameFormat for ouput + * + ************************************************************************ + */ +void fill_frame_num_gap(VideoParameters *p_Vid, FrameFormat *output) +{ + int CurrFrameNum; + int UnusedShortTermFrameNum; + StorablePicture *picture = NULL; + int nal_ref_idc_bak = p_Vid->nal_reference_idc; + +// printf("A gap in frame number is found, try to fill it.\n"); + + + p_Vid->nal_reference_idc = NALU_PRIORITY_LOW; + + UnusedShortTermFrameNum = (p_Vid->pre_frame_num + 1) % p_Vid->max_frame_num; + CurrFrameNum = p_Vid->frame_num; + + while (CurrFrameNum != UnusedShortTermFrameNum) + { + picture = alloc_storable_picture (p_Vid, FRAME, p_Vid->width, p_Vid->height, p_Vid->width_cr, p_Vid->height_cr); + picture->coded_frame = 1; + picture->pic_num = UnusedShortTermFrameNum; + picture->non_existing = 1; + picture->is_output = 1; + + p_Vid->adaptive_ref_pic_buffering_flag = 0; + store_picture_in_dpb(p_Vid->p_Dpb_layer[0], picture, output); + picture=NULL; + UnusedShortTermFrameNum = (UnusedShortTermFrameNum + 1) % p_Vid->max_frame_num; + } + + p_Vid->nal_reference_idc = nal_ref_idc_bak; +} + +/*! + ************************************************************************ + * \brief + * Compute co-located motion info + * + ************************************************************************ + */ +void compute_colocated(Slice *currSlice, StorablePicture **listX[6]) +{ + int i, j; + + VideoParameters *p_Vid = currSlice->p_Vid; + + if (currSlice->direct_spatial_mv_pred_flag == 0) + { + for (j = 0; j < 2 + (currSlice->mb_aff_frame_flag * 4); j += 2) + { + for (i = 0; i < currSlice->listXsize[j];i++) + { + int prescale, iTRb, iTRp; + + if (j==0) + { + iTRb = iClip3( -128, 127, p_Vid->enc_picture->poc - listX[LIST_0 + j][i]->poc ); + } + else if (j == 2) + { + iTRb = iClip3( -128, 127, p_Vid->enc_picture->top_poc - listX[LIST_0 + j][i]->poc ); + } + else + { + iTRb = iClip3( -128, 127, p_Vid->enc_picture->bottom_poc - listX[LIST_0 + j][i]->poc ); + } + + iTRp = iClip3( -128, 127, listX[LIST_1 + j][0]->poc - listX[LIST_0 + j][i]->poc); + + if (iTRp!=0) + { + prescale = ( 16384 + iabs( iTRp / 2 ) ) / iTRp; + currSlice->mvscale[j][i] = iClip3( -1024, 1023, ( iTRb * prescale + 32 ) >> 6 ) ; + } + else + { + currSlice->mvscale[j][i] = 9999; + } + } + } + } +} + + +static void process_picture_in_dpb_s(VideoParameters *p_Vid, StorablePicture *p_pic) +{ + //InputParameters *p_Inp = p_Vid->p_Inp; + + ImageData *p_img_out = &p_Vid->tempData3; + ImageData img_in; + imgpel*** d_img; + int i; + + img_in.frm_stride[0] = p_pic->size_x_padded; + img_in.frm_stride[1] = img_in.frm_stride[2] = p_pic->size_x_cr + (p_pic->pad_size_uv_x << 1); + + if (p_pic->structure == FRAME) + { + img_in.frm_data[0] = p_pic->imgY; + img_in.frm_data[1] = p_pic->imgUV[0]; + img_in.frm_data[2] = p_pic->imgUV[1]; + img_in.top_stride[0] = img_in.bot_stride[0] = img_in.frm_stride[0] << 1; + img_in.top_stride[1] = img_in.bot_stride[1] = img_in.top_stride[2] = img_in.bot_stride[2] = img_in.frm_stride[1] << 1; + d_img = p_img_out->frm_data; + } + else //If reference picture is a field, then frm_data will actually contain field data and therefore top/bottom stride is set accordingly. + { + img_in.top_stride[0] = img_in.bot_stride[0] = img_in.frm_stride[0]; + img_in.top_stride[1] = img_in.bot_stride[1] = img_in.top_stride[2] = img_in.bot_stride[2] =img_in.frm_stride[1]; + if (p_pic->structure == TOP_FIELD) + { + img_in.top_data[0] = p_pic->imgY; + img_in.top_data[1] = p_pic->imgUV[0]; + img_in.top_data[2] = p_pic->imgUV[1]; + d_img = p_img_out->top_data; + } + else + { + img_in.bot_data[0] = p_pic->imgY; + img_in.bot_data[1] = p_pic->imgUV[0]; + img_in.bot_data[2] = p_pic->imgUV[1]; + d_img = p_img_out->bot_data; + } + } + + for(i=0; isize_y; i++) + memcpy(d_img[0][i], p_pic->imgY[i], p_pic->size_x*sizeof(imgpel)); + if (p_Vid->yuv_format != YUV400) + { + for(i=0; isize_y_cr; i++) + memcpy(d_img[1][i], p_pic->imgUV[0][i], p_pic->size_x_cr * sizeof(imgpel)); + for(i=0; isize_y_cr; i++) + memcpy(d_img[2][i], p_pic->imgUV[1][i], p_pic->size_x_cr * sizeof(imgpel)); + } +} + +/*! + ************************************************************************ + * \brief + * Copy a stored picture + ************************************************************************ + */ +static void copy_storable_picture(VideoParameters *p_Vid, StorablePicture *s, StorablePicture *d) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int nplane; + int i, j; + int size_x = s->size_x; + int size_y = s->size_y; + int size_x_cr = s->size_x_cr; + int size_y_cr = s->size_y_cr; + imgpel*** s_img; + extern void check_value(imgpel **pBufIn, int width, int height, int max); + // these ones are set in UnifiedOneForthPix + //d->imgY_sub = NULL; + //d->imgUV_sub = NULL; + //d->p_img_sub[0] = NULL; + //d->p_img_sub[1] = NULL; + //d->p_img_sub[2] = NULL; + + // store BL reconstruction + if (s->structure == FRAME) + { + s_img = p_Vid->tempData3.frm_data; + } + else if (s->structure == TOP_FIELD) + { + s_img = p_Vid->tempData3.top_data; + } + else + { + s_img = p_Vid->tempData3.bot_data; + } + + for(i=0; iimgY[i], (void *)s_img[0][i], size_x * sizeof (imgpel)); + + d->p_img[0] = d->imgY; + d->p_curr_img = d->p_img[0]; + + if (p_Vid->yuv_format != YUV400) + { + // store BL reconstruction + for(i=0; iimgUV[0][i], (void *)s_img[1][i], size_x_cr * sizeof (imgpel)); + for(i=0; iimgUV[1][i], (void *)s_img[2][i], size_x_cr * sizeof (imgpel)); + + d->p_img[1] = d->imgUV[0]; + d->p_img[2] = d->imgUV[1]; + } + + d->p_curr_img_sub = d->p_img_sub[0]; + for (j = 0; j < (size_y >> BLOCK_SHIFT); j++) + { + for (i = 0; i < (size_x >> BLOCK_SHIFT); i++) + { + d->mv_info[j][i].ref_idx[LIST_0] = -1; + d->mv_info[j][i].ref_idx[LIST_1] = -1; + d->mv_info[j][i].ref_pic[LIST_0] = NULL; + d->mv_info[j][i].ref_pic[LIST_1] = NULL; + } + } + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + for( nplane=0; nplane> BLOCK_SHIFT); j++) + { + for (i = 0; i < (size_x >> BLOCK_SHIFT); i++) + { + d->JVmv_info[nplane][j][i].ref_idx[LIST_0] = -1; + d->JVmv_info[nplane][j][i].ref_idx[LIST_1] = -1; + } + } + } + } + + d->pic_num = s->pic_num; + d->frame_num = s->frame_num; + d->long_term_frame_idx = s->long_term_frame_idx; + d->long_term_pic_num = s->long_term_pic_num; + d->used_for_reference = s->used_for_reference; + d->is_long_term = s->is_long_term; + d->non_existing = s->non_existing; + d->is_output = 1; + d->structure = s->structure; + + // these are set in insert_picture_in_dpb + d->top_field = NULL; + d->bottom_field = NULL; + d->frame = NULL; + + d->coded_frame = s->coded_frame; + d->mb_aff_frame_flag = s->mb_aff_frame_flag; + + memcpy( (void *)&d->stats, (void *)&s->stats, sizeof( StatParameters ) ); + d->stats.NumberBFrames = s->stats.NumberBFrames; +} + +/*! + ************************************************************************ + * \brief + * Clone an encoded frame picture structure + ************************************************************************ + */ +static StorablePicture * clone_storable_picture( VideoParameters *p_Vid, StorablePicture *p_pic ) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + StorablePicture *p_stored_pic; + int nal_reference_idc= p_Vid->nal_reference_idc; + p_Vid->nal_reference_idc = NALU_PRIORITY_HIGH; //NALU_PRIORITY_DISPOSABLE; + p_stored_pic = alloc_storable_picture (p_Vid, (PictureStructure) p_Vid->structure, p_pic->size_x, p_pic->size_y, p_pic->size_x_cr, p_pic->size_y_cr); + p_Vid->nal_reference_idc = nal_reference_idc; + p_stored_pic->poc = p_Vid->framepoc; + p_stored_pic->top_poc = p_Vid->toppoc; + p_stored_pic->bottom_poc = p_Vid->bottompoc; + p_stored_pic->frame_poc = p_Vid->framepoc; + p_stored_pic->pic_num = p_pic->pic_num; + p_stored_pic->frame_num = p_pic->frame_num; + p_stored_pic->coded_frame = 1; + p_stored_pic->mb_aff_frame_flag = p_Vid->mb_aff_frame_flag = (Boolean) (p_Inp->MbInterlace != FRAME_CODING); + + copy_params(p_Vid, p_stored_pic, p_Vid->active_sps); + + + copy_storable_picture(p_Vid, p_pic, p_stored_pic); +#if (MVC_EXTENSION_ENABLE) + // MVC-related parameters + p_stored_pic->inter_view_flag[0] = p_pic->inter_view_flag[0]; + p_stored_pic->inter_view_flag[1] = p_pic->inter_view_flag[1]; + p_stored_pic->anchor_pic_flag[0] = p_stored_pic->anchor_pic_flag[1] = 0; + p_stored_pic->view_id = 0; + //p_stored_pic->proc_flag = 1; +#endif + return p_stored_pic; +} + +/*! + ************************************************************************ + * \brief + * Store a processed picture in DPB. + * \param p_Vid + * VideoParameters + * \param p + * Picture to be stored + * \param output + * FrameFormat for output + ************************************************************************ + */ +#if (MVC_EXTENSION_ENABLE) +void store_proc_picture_in_dpb(DecodedPictureBuffer *p_Dpb, StorablePicture* p, FrameFormat *output) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + FrameStore *fs = p_Dpb->fs_ilref[0]; + if(p_Dpb->used_size_il>0 && fs->is_used==3) + { + //checking; +#ifdef _DEBUG + if(p->structure==FRAME) + assert(fs->frame->frame_poc != p->poc); + else if(p->structure==TOP_FIELD) + assert(fs->top_field->top_poc != p->poc); + else if(p->structure==BOTTOM_FIELD) + assert(fs->bottom_field->bottom_poc != p->poc); +#endif + if(fs->frame) + { + free_storable_picture(p_Vid, fs->frame); + fs->frame = NULL; + } + if(fs->top_field) + { + free_storable_picture(p_Vid, fs->top_field); + fs->top_field = NULL; + } + if(fs->bottom_field) + { + free_storable_picture(p_Vid, fs->bottom_field); + fs->bottom_field = NULL; + } + fs->is_used = 0; + fs->is_reference = 0; + fs->is_inter_layer = TRUE; + p_Dpb->used_size_il--; + } +#ifdef _DEBUG + if(fs->is_used>0) + { + //checking; + if(p->structure==FRAME) + assert(fs->frame == NULL); + else if(p->structure==TOP_FIELD) + assert(fs->top_field == NULL); + else if(p->structure==BOTTOM_FIELD) + assert(fs->bottom_field == NULL); + } +#endif + + insert_picture_in_dpb(p_Vid, fs, p); + if((p->structure==FRAME && fs->is_used == 3) || (p->structure!=FRAME && fs->is_used && fs->is_used <3)) + p_Dpb->used_size_il++; +} +#endif + + diff --git a/lencod/src/mc_prediction.c b/lencod/src/mc_prediction.c new file mode 100644 index 0000000..ea35276 --- /dev/null +++ b/lencod/src/mc_prediction.c @@ -0,0 +1,653 @@ +/*! + ************************************************************************************* + * \file mc_prediction.c + * + * \brief + * Motion Compensation + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include +#include +#include + +#include "global.h" +#include "block.h" + +#include "macroblock.h" +#include "mc_prediction.h" +#include "refbuf.h" +#include "image.h" +#include "mb_access.h" +#include "me_distortion.h" + +/*! + ************************************************************************ + * \brief + * Weighted BiPrediction + ************************************************************************ + */ +static inline void weighted_bi_prediction(imgpel** mb_pred, imgpel* l0pred, imgpel *l1pred, + int block_size_y, int block_x, int block_size_x, + int max_imgpel_value, + short wbp0, short wbp1, short offset, short wp_round, short weight_denom) +{ + int i, j; + int block_x4 = block_x + block_size_x; + + for (j = 0; j< block_size_y; j++) + { + for (i=block_x; i> (weight_denom)) + offset); + } +} + +/*! + ************************************************************************ + * \brief + * Weighted Prediction + ************************************************************************ + */ +static inline void weighted_mc_prediction(imgpel** mb_pred, imgpel* lpred, + int block_size_y, int block_x, int block_size_x, + int max_imgpel_value, + short wp, short offset, short wp_round, short weight_denom) +{ + int i, j; + int block_x4 = block_x + block_size_x; + + for (j = 0; j < block_size_y; j++) + { + for (i=block_x; i> weight_denom) + offset); + } +} + +/*! + ************************************************************************ + * \brief + * BiPrediction + ************************************************************************ + */ +static inline void bi_prediction(imgpel** mb_pred, imgpel* l0pred, imgpel *l1pred, + int block_size_y, int block_x, int block_size_x) +{ + int i, j; + int block_x4 = block_x + block_size_x; + + for (j = 0; j < block_size_y; j++) + { + for (i=block_x; i> 1; + } +} + +/*! + ************************************************************************ + * \brief + * BiPrediction + ************************************************************************ + */ +static inline void mc_prediction(imgpel** mb_pred, imgpel* lpred, int block_size_y, int block_x, int block_size_x) +{ + int j; + for (j = 0; j < block_size_y; j++) + { + memcpy(&(mb_pred[j][block_x]), lpred, block_size_x * sizeof(imgpel)); + lpred += block_size_x; + } +} + +/*! + ************************************************************************ + * \brief + * Predict Luma block + ************************************************************************ + */ +static inline void OneComponentLumaPrediction ( VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array of prediction values (row by row) + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical coordinate of block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *list //!< reference picture list + ) +{ + int j; + imgpel *ref_line = UMVLine4X (list, pic_pix_y, pic_pix_x); + + for (j = 0; j < block_size_y; j++) + { + memcpy(mpred, ref_line, block_size_x * sizeof(imgpel)); + ref_line += p_Vid->padded_size_x; + mpred += block_size_x; + } +} + + +/*! + ************************************************************************ + * \brief + * Predict one Luma block + ************************************************************************ + */ +void luma_prediction (Macroblock* currMB, //!< Current Macroblock + int block_x, //!< relative horizontal block coordinate of block + int block_y, //!< relative vertical block coordinate of block + int block_size_x, //!< relative horizontal block coordinate of block + int block_size_y, //!< relative vertical block coordinate of block + int p_dir, //!< prediction direction (0=list0, 1=list1, 2=bipred) + int list_mode[2], //!< list prediction mode (1-7, 0=DIRECT) + char *ref_idx, //!< reference pictures + short bipred_me //!< use bi prediction mv (0=no bipred, 1 = use set 1, 2 = use set 2) + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + + int pic_opix_x = ((currMB->pix_x + block_x) << 2); + int pic_opix_y = ((currMB->opix_y + block_y) << 2); + int bx = block_x >> 2; + int by = block_y >> 2; + MotionVector ***** mv_array = currSlice->all_mv; + MotionVector *curr_mv = NULL; + imgpel **mb_pred = currSlice->mb_pred[0]; + + int apply_weights = ( (currSlice->weighted_prediction == 1) || (currSlice->weighted_prediction == 2 && p_dir == 2) ); + + if (bipred_me && ref_idx[0] == 0 && ref_idx[1] == 0 && p_dir == 2 && is_bipred_enabled(p_Vid, list_mode[0]) && is_bipred_enabled(p_Vid, list_mode[1])) + mv_array = currSlice->bipred_mv[bipred_me - 1]; + + switch (p_dir) + { + case 0: + curr_mv = &mv_array[LIST_0][(short) ref_idx[LIST_0]][list_mode[LIST_0]][by][bx]; + OneComponentLumaPrediction (p_Vid, l0_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_0 + currMB->list_offset][(short) ref_idx[LIST_0]]); + break; + case 1: + curr_mv = &mv_array[LIST_1][(short) ref_idx[LIST_1]][list_mode[LIST_1]][by][bx]; + OneComponentLumaPrediction (p_Vid, l1_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_1 + currMB->list_offset][(short)ref_idx[LIST_1]]); + break; + case 2: + curr_mv = &mv_array[LIST_0][(short) ref_idx[LIST_0]][list_mode[LIST_0]][by][bx]; + OneComponentLumaPrediction (p_Vid, l0_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_0 + currMB->list_offset][(short)ref_idx[LIST_0]]); + curr_mv = &mv_array[LIST_1][(short) ref_idx[LIST_1]][list_mode[LIST_1]][by][bx]; + OneComponentLumaPrediction (p_Vid, l1_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_1 + currMB->list_offset][(short)ref_idx[LIST_1]]); + break; + default: + break; + } + + if (apply_weights) + { + if (p_dir==2) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_imgpel_value, + currSlice->wbp_weight[0][(short)ref_idx[0]][(short)ref_idx[1]][0], currSlice->wbp_weight[1][(short)ref_idx[0]][(short)ref_idx[1]][0], + (currSlice->wp_offset[0][(short)ref_idx[0]][0] + currSlice->wp_offset[1][(short)ref_idx[1]][0] + 1)>>1, + (currSlice->wp_luma_round << 1), currSlice->luma_log_weight_denom + 1); + } + else if (p_dir==0) + { + weighted_mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_x, block_size_x, + p_Vid->max_imgpel_value, + currSlice->wp_weight[0][(short)ref_idx[0]][0], currSlice->wp_offset[0][(short)ref_idx[0]][0], currSlice->wp_luma_round, currSlice->luma_log_weight_denom); + } + else // (p_dir==1) + { + weighted_mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_imgpel_value, + currSlice->wp_weight[1][(short)ref_idx[1]][0], currSlice->wp_offset[1][(short)ref_idx[1]][0], currSlice->wp_luma_round, currSlice->luma_log_weight_denom); + } + } + else + { + if (p_dir==2) + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x); + } + else if (p_dir==0) + { + mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_x, block_size_x); + } + else // (p_dir==1) + { + mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_x, block_size_x); + } + } +} + +/*! + ************************************************************************ + * \brief + * Predict one Luma block + ************************************************************************ + */ +void luma_prediction_bi (Macroblock* currMB, //!< Current Macroblock + int block_x, //!< relative horizontal block coordinate of 4x4 block + int block_y, //!< relative vertical block coordinate of 4x4 block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + int l0_mode, //!< list0 prediction mode (1-7, 0=DIRECT if l1_mode=0) + int l1_mode, //!< list1 prediction mode (1-7, 0=DIRECT if l0_mode=0) + short l0_ref_idx, //!< reference frame for list0 prediction (-1: Intra4x4 pred. with l0_mode) + short l1_ref_idx, //!< reference frame for list1 prediction + int list //!< current list for prediction. + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + int pic_opix_x = ((currMB->pix_x + block_x) << 2); + int pic_opix_y = ((currMB->opix_y + block_y) << 2); + int bx = block_x >> 2; + int by = block_y >> 2; + + int apply_weights = ( currSlice->weighted_prediction != 0 ); + + MotionVector *****mv_array = currSlice->bipred_mv[list]; + MotionVector *mv_arrayl0 = &mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx]; + MotionVector *mv_arrayl1 = &mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx]; + imgpel **mb_pred = currSlice->mb_pred[0]; + + OneComponentLumaPrediction (p_Vid, l0_pred, pic_opix_x + mv_arrayl0->mv_x, pic_opix_y + mv_arrayl0->mv_y, block_size_x, block_size_y, currSlice->listX[0+currMB->list_offset][l0_ref_idx]); + OneComponentLumaPrediction (p_Vid, l1_pred, pic_opix_x + mv_arrayl1->mv_x, pic_opix_y + mv_arrayl1->mv_y, block_size_x, block_size_y, currSlice->listX[1+currMB->list_offset][l1_ref_idx]); + + if (apply_weights) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_imgpel_value, + currSlice->wbp_weight[0][l0_ref_idx][l1_ref_idx][0], currSlice->wbp_weight[1][l0_ref_idx][l1_ref_idx][0], + (currSlice->wp_offset[0][l0_ref_idx][0] + currSlice->wp_offset[1][l1_ref_idx][0] + 1)>>1, + (currSlice->wp_luma_round << 1), currSlice->luma_log_weight_denom + 1); + } + else + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x); + } +} + + +/*! + ************************************************************************ + * \brief + * Predict (on-the-fly) one component of a chroma 4x4 block + ************************************************************************ + */ +void OneComponentChromaPrediction4x4_regenerate ( + Macroblock *currMB, //!< Current Macroblock + imgpel* mpred, //!< array to store prediction values + int block_c_x, //!< horizontal pixel coordinate of 4x4 block + int block_c_y, //!< vertical pixel coordinate of 4x4 block + MotionVector **mv, //!< motion vector array + StorablePicture *list, //!< image components (color planes) + int uv) //!< chroma component +{ + VideoParameters *p_Vid = currMB->p_Vid; + int i, j, ii, jj, ii0, jj0, ii1, jj1, if0, if1, jf0, jf1; + MotionVector *mvb; + + int f1_x = 64/p_Vid->mb_cr_size_x; + int f2_x=f1_x-1; + + int f1_y = 64/p_Vid->mb_cr_size_y; + int f2_y=f1_y-1; + + int f3=f1_x*f1_y, f4=f3>>1; + int list_offset = p_Vid->mb_data[currMB->mbAddrX].list_offset; + int max_y_cr = (int) (list_offset ? (p_Vid->height_cr >> 1) - 1 : p_Vid->height_cr - 1); + int max_x_cr = (int) (p_Vid->width_cr - 1); + int jjx, iix; + int mb_cr_y_div4 = p_Vid->mb_cr_size_y>>2; + int mb_cr_x_div4 = p_Vid->mb_cr_size_x>>2; + int jpos; + + imgpel** refimage = list->imgUV[uv]; + + for (j=block_c_y; j < block_c_y + BLOCK_SIZE; j++) + { + jjx = j/mb_cr_y_div4; + jpos = (j + currMB->opix_c_y)*f1_y; + + for (i=block_c_x; i < block_c_x + BLOCK_SIZE; i++) + { + iix = i/mb_cr_x_div4; + mvb = &mv [jjx][iix]; + + ii = (i + currMB->pix_c_x)*f1_x + mvb->mv_x; + jj = jpos + mvb->mv_y; + + if (p_Vid->active_sps->chroma_format_idc == 1) + jj += list->chroma_vector_adjustment; + + ii0 = iClip3 (0, max_x_cr, ii/f1_x); + jj0 = iClip3 (0, max_y_cr, jj/f1_y); + ii1 = iClip3 (0, max_x_cr, (ii+f2_x)/f1_x); + jj1 = iClip3 (0, max_y_cr, (jj+f2_y)/f1_y); + + if1 = (ii&f2_x); if0 = f1_x-if1; + jf1 = (jj&f2_y); jf0 = f1_y-jf1; + + *mpred++ = (imgpel) ( + (if0 * jf0 * refimage[jj0][ii0] + + if1 * jf0 * refimage[jj0][ii1] + + if0 * jf1 * refimage[jj1][ii0] + + if1 * jf1 * refimage[jj1][ii1] + f4) / f3); + } + } +} + +/*! + ************************************************************************ + * \brief + * Retrieve one component of a chroma 4x4 block from the buffer + ************************************************************************ + */ +void OneComponentChromaPrediction4x4_retrieve ( + Macroblock *currMB, //!< Current Macroblock + imgpel* mpred, //!< array to store prediction values + int block_c_x, //!< horizontal pixel coordinate of 4x4 block + int block_c_y, //!< vertical pixel coordinate of 4x4 block + MotionVector **mv, //!< motion vector array + StorablePicture *list, //!< image components (color planes) + int uv) //!< chroma component +{ + VideoParameters *p_Vid = currMB->p_Vid; + int j, ii, jj; + MotionVector* mvb; + + int jjx; + int right_shift_x = 4 - p_Vid->chroma_shift_x; + int right_shift_y = 4 - p_Vid->chroma_shift_y; + int jpos; + + int pos_x1 = block_c_x >> right_shift_x; + int pos_x2 = (block_c_x + 2) >> right_shift_x; + + int ipos1 = ((block_c_x + currMB->pix_c_x ) << p_Vid->chroma_shift_x); + int ipos2 = ((block_c_x + currMB->pix_c_x + 2) << p_Vid->chroma_shift_x); + int jj_chroma = ((p_Vid->active_sps->chroma_format_idc == 1) ? list->chroma_vector_adjustment : 0); + + imgpel *line_ptr = NULL; + + for (j=block_c_y; j < block_c_y + BLOCK_SIZE; j++) + { + jjx = j >> right_shift_y; // translate into absolute block (luma) coordinates + + jpos = ( (j + currMB->opix_c_y) << p_Vid->chroma_shift_y ) + jj_chroma; + + mvb = &mv [jjx][pos_x1]; + + ii = ipos1 + mvb->mv_x; + jj = jpos + mvb->mv_y; + + line_ptr = UMVLine8X_chroma ( list, uv + 1, jj, ii); + *mpred++ = *line_ptr++; + *mpred++ = *line_ptr; + + mvb = &mv [jjx][pos_x2]; + + ii = ipos2 + mvb->mv_x; + jj = jpos + mvb->mv_y; + + line_ptr = UMVLine8X_chroma ( list, uv + 1, jj, ii); + *mpred++ = *line_ptr++; + *mpred++ = *line_ptr; + } +} + + +/*! + ************************************************************************ + * \brief + * Retrieve one component of a chroma block from the buffer + ************************************************************************ + */ +static inline +void OneComponentChromaPrediction (VideoParameters *p_Vid, //!< video encoding parameters for current picture + imgpel* mpred, //!< array to store prediction values + int pic_pix_x, //!< motion shifted horizontal coordinate of block + int pic_pix_y, //!< motion shifted vertical block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + StorablePicture *list, //!< reference picture list + int uv) //!< chroma component +{ + int j; + imgpel *ref_line = UMVLine4Xcr (list, uv + 1, pic_pix_y, pic_pix_x); + + for (j = 0; j < block_size_y; j++) + { + memcpy(mpred, ref_line, block_size_x * sizeof(imgpel)); + ref_line += p_Vid->cr_padded_size_x; + mpred += block_size_x; + } +} + +/*! + ************************************************************************ + * \brief + * Predict an intra chroma 4x4 block + ************************************************************************ + */ +void IntraChromaPrediction4x4 (Macroblock* currMB, //!< Current Macroblock + int uv, //!< color component + int block_x, //!< relative horizontal block coordinate of 4x4 block + int block_y) //!< relative vertical block coordinate of 4x4 block +{ + int j; + Slice *currSlice = currMB->p_Slice; + imgpel **mb_pred = currSlice->mb_pred[ uv ]; + imgpel **curr_mpr_16x16 = currSlice->mpr_16x16[uv][ (short) currMB->c_ipred_mode]; + + //===== prediction ===== + for (j=block_y; j intra prediction) + short l1_ref_idx, // <-- reference frame for list1 prediction + short bipred_me // <-- use bi prediction mv (0=no bipred, 1 = use set 1, 2 = use set 2) + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + + int pic_opix_x = ((currMB->pix_c_x + block_x) << 2); + int pic_opix_y = ((currMB->opix_c_y + block_y) << 2); + + int bx = block_x >> 2; + int by = block_y >> 2; + MotionVector ***** mv_array = currSlice->all_mv; + int uv_comp = uv + 1; + imgpel **mb_pred = currSlice->mb_pred[ uv_comp]; + + int apply_weights = ( (currSlice->weighted_prediction == 1) || (currSlice->weighted_prediction == 2 && p_dir == 2) ); + + if (bipred_me && l0_ref_idx == 0 && l1_ref_idx == 0 && p_dir == 2 && is_bipred_enabled(p_Vid, l0_mode) && is_bipred_enabled(p_Vid, l1_mode)) + mv_array = currSlice->bipred_mv[bipred_me - 1]; + + //===== INTER PREDICTION ===== + switch (p_dir) + { + case 0: + OneComponentChromaPrediction (p_Vid, l0_pred, pic_opix_x + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[0+currMB->list_offset][l0_ref_idx], uv); + break; + case 1: + OneComponentChromaPrediction (p_Vid, l1_pred, pic_opix_x + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[1+currMB->list_offset][l1_ref_idx], uv); + break; + case 2: + OneComponentChromaPrediction (p_Vid, l0_pred, pic_opix_x + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[0+currMB->list_offset][l0_ref_idx], uv); + OneComponentChromaPrediction (p_Vid, l1_pred, pic_opix_x + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[1+currMB->list_offset][l1_ref_idx], uv); + break; + default: + break; + } + + if (apply_weights) + { + if (p_dir==2) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_pel_value_comp[1], + currSlice->wbp_weight[0][l0_ref_idx][l1_ref_idx][uv_comp], currSlice->wbp_weight[1][l0_ref_idx][l1_ref_idx][uv_comp], + (currSlice->wp_offset[0][l0_ref_idx][uv_comp] + currSlice->wp_offset[1][l1_ref_idx][uv_comp] + 1)>>1, + (currSlice->wp_chroma_round << 1), currSlice->chroma_log_weight_denom + 1); + } + else if (p_dir==0) + { + weighted_mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_x, block_size_x, + p_Vid->max_pel_value_comp[1], + currSlice->wp_weight[0][l0_ref_idx][uv_comp], currSlice->wp_offset[0][l0_ref_idx][uv_comp], currSlice->wp_chroma_round, currSlice->chroma_log_weight_denom ); + } + else // (p_dir==1) + { + weighted_mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_pel_value_comp[1], + currSlice->wp_weight[1][l1_ref_idx][uv_comp], currSlice->wp_offset[1][l1_ref_idx][uv_comp], currSlice->wp_chroma_round, currSlice->chroma_log_weight_denom ); + } + } + else + { + if (p_dir==2) + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x); + } + else if (p_dir==0) + { + mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_x, block_size_x); + } + else // (p_dir==1) + { + mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_x, block_size_x); + } + } +} + + + +/*! + ************************************************************************ + * \brief + * Predict one chroma 4x4 block + ************************************************************************ + */ +void chroma_prediction_4x4 (Macroblock* currMB, // <-- Current Macroblock + int uv, // <-- colour component + int block_x, // <-- relative horizontal block coordinate of 4x4 block + int block_y, // <-- relative vertical block coordinate of 4x4 block + int p_dir, // <-- prediction direction (0=list0, 1=list1, 2=bipred) + int l0_mode, // <-- list0 prediction mode (1-7, 0=DIRECT if l1_mode=0) + int l1_mode, // <-- list1 prediction mode (1-7, 0=DIRECT if l0_mode=0) + short l0_ref_idx, // <-- reference frame for list0 prediction (if (<0) -> intra prediction) + short l1_ref_idx, // <-- reference frame for list1 prediction + short bipred_me // <-- use bi prediction mv (0=no bipred, 1 = use set 1, 2 = use set 2) + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + + MotionVector ***** mv_array = currSlice->all_mv; + int uv_comp = uv + 1; + imgpel **mb_pred = currSlice->mb_pred[uv_comp]; + int list_offset = currMB->list_offset; + + int apply_weights = ( (currSlice->weighted_prediction == 1) || (currSlice->weighted_prediction == 2 && p_dir == 2) ); + + if (bipred_me && l0_ref_idx == 0 && l1_ref_idx == 0 && p_dir == 2 && is_bipred_enabled(p_Vid, l0_mode) && is_bipred_enabled(p_Vid, l1_mode) ) + mv_array = currSlice->bipred_mv[bipred_me - 1]; + + //===== INTER PREDICTION ===== + switch (p_dir) + { + case 0: // LIST_0 + p_Vid->OneComponentChromaPrediction4x4 (currMB, l0_pred, block_x, block_y, mv_array[LIST_0][l0_ref_idx][l0_mode], currSlice->listX[LIST_0 + list_offset][l0_ref_idx], uv); + break; + case 1: // LIST_1 + p_Vid->OneComponentChromaPrediction4x4 (currMB, l1_pred, block_x, block_y, mv_array[LIST_1][l1_ref_idx][l1_mode], currSlice->listX[LIST_1 + list_offset][l1_ref_idx], uv); + break; + case 2: // BI_PRED + p_Vid->OneComponentChromaPrediction4x4 (currMB, l0_pred, block_x, block_y, mv_array[LIST_0][l0_ref_idx][l0_mode], currSlice->listX[LIST_0 + list_offset][l0_ref_idx], uv); + p_Vid->OneComponentChromaPrediction4x4 (currMB, l1_pred, block_x, block_y, mv_array[LIST_1][l1_ref_idx][l1_mode], currSlice->listX[LIST_1 + list_offset][l1_ref_idx], uv); + break; + default: + break; + } + + if (apply_weights) + { + if (p_dir==2) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, BLOCK_SIZE, block_x, BLOCK_SIZE, + p_Vid->max_pel_value_comp[1], + currSlice->wbp_weight[0][l0_ref_idx][l1_ref_idx][uv_comp], currSlice->wbp_weight[1][l0_ref_idx][l1_ref_idx][uv_comp], + (currSlice->wp_offset[0][l0_ref_idx][uv_comp] + currSlice->wp_offset[1][l1_ref_idx][uv_comp] + 1)>>1, + (currSlice->wp_chroma_round << 1), currSlice->chroma_log_weight_denom + 1); + + } + else if (p_dir==0) + { + weighted_mc_prediction(&mb_pred[block_y], l0_pred, BLOCK_SIZE, block_x, BLOCK_SIZE, + p_Vid->max_pel_value_comp[1], + currSlice->wp_weight[0][l0_ref_idx][uv_comp], currSlice->wp_offset[0][l0_ref_idx][uv_comp], currSlice->wp_chroma_round, currSlice->chroma_log_weight_denom ); + } + else // (p_dir==1) + { + weighted_mc_prediction(&mb_pred[block_y], l1_pred, BLOCK_SIZE, block_x, BLOCK_SIZE, + p_Vid->max_pel_value_comp[1], + currSlice->wp_weight[1][l1_ref_idx][uv_comp], currSlice->wp_offset[1][l1_ref_idx][uv_comp], currSlice->wp_chroma_round, currSlice->chroma_log_weight_denom ); + } + } + else + { + if (p_dir==2) + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, BLOCK_SIZE, block_x, BLOCK_SIZE); + } + else if (p_dir==0) + { + mc_prediction(&mb_pred[block_y], l0_pred, BLOCK_SIZE, block_x, BLOCK_SIZE); + } + else // (p_dir==1) + { + mc_prediction(&mb_pred[block_y], l1_pred, BLOCK_SIZE, block_x, BLOCK_SIZE); + } + } +} + diff --git a/lencod/src/mc_prediction_otf.c b/lencod/src/mc_prediction_otf.c new file mode 100644 index 0000000..db7b45e --- /dev/null +++ b/lencod/src/mc_prediction_otf.c @@ -0,0 +1,387 @@ +/*! + ************************************************************************************* + * \file mc_prediction_otf.c + * + * \brief + * Motion Compensation + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Julien Le Tanou + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include +#include +#include + +#include "global.h" +#include "block.h" + +#include "macroblock.h" +#include "mc_prediction.h" +#include "mc_prediction_otf.h" + +#include "refbuf.h" +#include "image.h" +#include "mb_access.h" +#include "me_distortion.h" +#include "get_block_otf.h" + +/*! + ************************************************************************ + * \brief + * block single list prediction + ************************************************************************ + */ +static void mc_prediction(imgpel** mb_pred, imgpel* lpred, int block_size_y, int block_size_x, int ioff) +{ + int j; + for (j = 0; j < block_size_y; j++) + { + memcpy(&(mb_pred[j][ioff]), lpred, block_size_x * sizeof(imgpel)); + lpred += block_size_x; + } +} + +/*! + ************************************************************************ + * \brief + * Weighted Prediction + ************************************************************************ + */ +static void weighted_mc_prediction(imgpel** mb_pred, + imgpel* lpred, + int block_size_y, + int block_size_x, + int ioff, + int max_imgpel_value, + short wp_scale, + short wp_offset, + short wp_round, + short weight_denom) +{ + int i, j; + int result; + int block_x4 = ioff + block_size_x; + + for (j = 0; j < block_size_y; j++) + { + for (i = ioff; i < block_x4; i++) + { + result = rshift_rnd((wp_scale * *lpred++), weight_denom) + wp_offset; + mb_pred[j][i] = (imgpel) iClip1( max_imgpel_value, result); + } + } +} + +/*! + ************************************************************************ + * \brief + * block biprediction + ************************************************************************ + */ +static void bi_prediction(imgpel **mb_pred, + imgpel *l0pred, + imgpel *l1pred, + int block_size_y, + int block_size_x, + int ioff) +{ + int i, j; + int block_x4 = ioff + block_size_x; + + for (j = 0; j < block_size_y; j++) + { + for (i=ioff; i> 1; + } +} + + + +/*! + ************************************************************************ + * \brief + * block weighted biprediction + ************************************************************************ + */ +static void weighted_bi_prediction(imgpel** mb_pred, + imgpel *block_l0, + imgpel *block_l1, + int block_size_y, + int block_x, + int block_size_x, + int max_imgpel_value, + int wp_scale_l0, + int wp_scale_l1, + int wp_offset, + int weight_denom) +{ + int i, j, result; + int block_x4 = block_x + block_size_x; + + for (j = 0; j< block_size_y; j++) + { + for (i=block_x; ip_Vid; + Slice *currSlice = currMB->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + int tmp_pred[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ]; // temporary pred block to compute on-the-fly interpolation + + int pic_opix_x = ((currMB->pix_x + block_x) << 2); + int pic_opix_y = ((currMB->opix_y + block_y) << 2); + int bx = block_x >> 2; + int by = block_y >> 2; + MotionVector ***** mv_array = currSlice->all_mv; + MotionVector *curr_mv = NULL; + imgpel **mb_pred = currSlice->mb_pred[0]; + int apply_weights = ( (currSlice->weighted_prediction == 1) || (currSlice->weighted_prediction == 2 && p_dir == 2) ); + + if (bipred_me && ref_idx[0] == 0 && ref_idx[1] == 0 && p_dir == 2 && is_bipred_enabled(p_Vid, list_mode[0]) && is_bipred_enabled(p_Vid, list_mode[1])) + mv_array = currSlice->bipred_mv[bipred_me - 1]; + + switch (p_dir) + { + case 0: + curr_mv = &mv_array[LIST_0][(short) ref_idx[0]][list_mode[0]][by][bx]; + p_Dpb->pf_get_block_luma (p_Vid, l0_pred, tmp_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_0 + currMB->list_offset][(short) ref_idx[0]], 0 ); + break; + case 1: + curr_mv = &mv_array[LIST_1][(short) ref_idx[1]][list_mode[1]][by][bx]; + p_Dpb->pf_get_block_luma (p_Vid, l1_pred, tmp_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_1 + currMB->list_offset][(short)ref_idx[1]], 0 ); + break; + case 2: + curr_mv = &mv_array[LIST_0][(short) ref_idx[0]][list_mode[0]][by][bx]; + p_Dpb->pf_get_block_luma (p_Vid, l0_pred, tmp_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_0 + currMB->list_offset][(short)ref_idx[0]], 0); + curr_mv = &mv_array[LIST_1][(short) ref_idx[1]][list_mode[1]][by][bx]; + p_Dpb->pf_get_block_luma (p_Vid, l1_pred, tmp_pred, pic_opix_x + curr_mv->mv_x, pic_opix_y + curr_mv->mv_y, block_size_x, block_size_y, currSlice->listX[LIST_1 + currMB->list_offset][(short)ref_idx[1]], 0); + break; + default: + break; + } + + if (apply_weights) + { + if (p_dir==2) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_imgpel_value, + currSlice->wbp_weight[0][(short)ref_idx[0]][(short)ref_idx[1]][0], currSlice->wbp_weight[1][(short)ref_idx[0]][(short)ref_idx[1]][0], + (currSlice->wp_offset[0][(short)ref_idx[0]][0] + currSlice->wp_offset[1][(short)ref_idx[1]][0] + 1)>>1, + currSlice->luma_log_weight_denom + 1); + } + else if (p_dir==0) + { + weighted_mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_size_x, block_x, + p_Vid->max_imgpel_value, + currSlice->wp_weight[0][(short)ref_idx[0]][0], currSlice->wp_offset[0][(short)ref_idx[0]][0], currSlice->wp_luma_round, currSlice->luma_log_weight_denom); + } + else // (p_dir==1) + { + weighted_mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_size_x, block_x, + p_Vid->max_imgpel_value, + currSlice->wp_weight[1][(short)ref_idx[1]][0], currSlice->wp_offset[1][(short)ref_idx[1]][0], currSlice->wp_luma_round, currSlice->luma_log_weight_denom); + } + } + else + { + if (p_dir==2) + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_size_x, block_x); + } + else if (p_dir==0) + { + mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_size_x, block_x); + } + else // (p_dir==1) + { + mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_size_x, block_x); + } + } +} + +/*! + ************************************************************************ + * \brief + * Predict one Luma block on-the-fly + ************************************************************************ + */ +void luma_prediction_bi_otf ( Macroblock* currMB, //!< Current Macroblock + int block_x, //!< relative horizontal block coordinate of 4x4 block + int block_y, //!< relative vertical block coordinate of 4x4 block + int block_size_x, //!< horizontal block size + int block_size_y, //!< vertical block size + int l0_mode, //!< list0 prediction mode (1-7, 0=DIRECT if l1_mode=0) + int l1_mode, //!< list1 prediction mode (1-7, 0=DIRECT if l0_mode=0) + short l0_ref_idx, //!< reference frame for list0 prediction (-1: Intra4x4 pred. with l0_mode) + short l1_ref_idx, //!< reference frame for list1 prediction + int list //!< current list for prediction. + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + + int tmp_pred[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ]; // temporary pred block for on-the-fly interpolation calculation + int pic_opix_x = ((currMB->pix_x + block_x) << 2); + int pic_opix_y = ((currMB->opix_y + block_y) << 2); + int bx = block_x >> 2; + int by = block_y >> 2; + + int apply_weights = ( currSlice->weighted_prediction != 0 ); + + MotionVector *****mv_array = currSlice->bipred_mv[list]; + MotionVector *mv_arrayl0 = &mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx]; + MotionVector *mv_arrayl1 = &mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx]; + imgpel **mb_pred = currSlice->mb_pred[0]; + + p_Dpb->pf_get_block_luma(p_Vid, l0_pred, tmp_pred, pic_opix_x + mv_arrayl0->mv_x, pic_opix_y + mv_arrayl0->mv_y, block_size_x, block_size_y, currSlice->listX[0+currMB->list_offset][l0_ref_idx], 0); + p_Dpb->pf_get_block_luma(p_Vid, l1_pred, tmp_pred, pic_opix_x + mv_arrayl1->mv_x, pic_opix_y + mv_arrayl1->mv_y, block_size_x, block_size_y, currSlice->listX[1+currMB->list_offset][l1_ref_idx], 0); + + if (apply_weights) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_imgpel_value, + currSlice->wbp_weight[0][l0_ref_idx][l1_ref_idx][0], currSlice->wbp_weight[1][l0_ref_idx][l1_ref_idx][0], + (currSlice->wp_offset[0][l0_ref_idx][0] + currSlice->wp_offset[1][l1_ref_idx][0] + 1)>>1, + currSlice->luma_log_weight_denom + 1); + } + else + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_size_x, block_x); + } +} + +/*! + ************************************************************************ + * \brief + * Predict one chroma block on-the-fly + ************************************************************************ + */ +void chroma_prediction_otf ( Macroblock* currMB, // <-- Current Macroblock + int uv, // <-- colour component + int block_x, // <-- relative horizontal block coordinate of block + int block_y, // <-- relative vertical block coordinate of block + int block_size_x, // <-- relative horizontal block coordinate of block + int block_size_y, // <-- relative vertical block coordinate of block + int p_dir, // <-- prediction direction (0=list0, 1=list1, 2=bipred) + int l0_mode, // <-- list0 prediction mode (1-7, 0=DIRECT if l1_mode=0) + int l1_mode, // <-- list1 prediction mode (1-7, 0=DIRECT if l0_mode=0) + short l0_ref_idx, // <-- reference frame for list0 prediction (if (<0) -> intra prediction) + short l1_ref_idx, // <-- reference frame for list1 prediction + short bipred_me // <-- use bi prediction mv (0=no bipred, 1 = use set 1, 2 = use set 2) + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + imgpel l0_pred[MB_PIXELS]; + imgpel l1_pred[MB_PIXELS]; + int tmp_pred[(MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5)]; + + int pic_opix_x = ((currMB->pix_c_x + block_x) << 2); + int pic_opix_y = ((currMB->opix_c_y + block_y) << 2); + + int bx = block_x >> 2; + int by = block_y >> 2; + MotionVector ***** mv_array = currSlice->all_mv; + int uv_comp = uv + 1; + imgpel **mb_pred = currSlice->mb_pred[ uv_comp]; + + int apply_weights = ( (currSlice->weighted_prediction == 1) || (currSlice->weighted_prediction == 2 && p_dir == 2) ); + + if (bipred_me && l0_ref_idx == 0 && l1_ref_idx == 0 && p_dir == 2 && is_bipred_enabled(p_Vid, l0_mode) && is_bipred_enabled(p_Vid, l1_mode)) + mv_array = currSlice->bipred_mv[bipred_me - 1]; + + //===== INTER PREDICTION ===== + switch (p_dir) + { + case 0: + p_Dpb->pf_get_block_chroma[OTF_MC] (p_Vid, l0_pred, tmp_pred, pic_opix_x + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[0+currMB->list_offset][l0_ref_idx], uv+1 ); + break; + case 1: + p_Dpb->pf_get_block_chroma[OTF_MC] (p_Vid, l1_pred, tmp_pred, pic_opix_x + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[1+currMB->list_offset][l1_ref_idx], uv+1 ); + break; + case 2: + p_Dpb->pf_get_block_chroma[OTF_MC] (p_Vid, l0_pred, tmp_pred, pic_opix_x + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_0][l0_ref_idx][l0_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[0+currMB->list_offset][l0_ref_idx], uv+1 ); + p_Dpb->pf_get_block_chroma[OTF_MC] (p_Vid, l1_pred, tmp_pred, pic_opix_x + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_x, pic_opix_y + mv_array[LIST_1][l1_ref_idx][l1_mode][by][bx].mv_y, block_size_x, block_size_y, currSlice->listX[1+currMB->list_offset][l1_ref_idx], uv+1 ); + break; + default: + break; + } + + if (apply_weights) + { + if (p_dir==2) + { + weighted_bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_x, block_size_x, + p_Vid->max_pel_value_comp[1], + currSlice->wbp_weight[0][l0_ref_idx][l1_ref_idx][uv_comp], currSlice->wbp_weight[1][l0_ref_idx][l1_ref_idx][uv_comp], + (currSlice->wp_offset[0][l0_ref_idx][uv_comp] + currSlice->wp_offset[1][l1_ref_idx][uv_comp] + 1)>>1, + currSlice->chroma_log_weight_denom + 1); + } + else if (p_dir==0) + { + weighted_mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_size_x, block_x, + p_Vid->max_pel_value_comp[1], + currSlice->wp_weight[0][l0_ref_idx][uv_comp], currSlice->wp_offset[0][l0_ref_idx][uv_comp], currSlice->wp_chroma_round, currSlice->chroma_log_weight_denom ); + } + else // (p_dir==1) + { + weighted_mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_size_x, block_x, + p_Vid->max_pel_value_comp[1], + currSlice->wp_weight[1][l1_ref_idx][uv_comp], currSlice->wp_offset[1][l1_ref_idx][uv_comp], currSlice->wp_chroma_round, currSlice->chroma_log_weight_denom ); + } + } + else + { + if (p_dir==2) + { + bi_prediction(&mb_pred[block_y], l0_pred, l1_pred, block_size_y, block_size_x, block_x); + } + else if (p_dir==0) + { + mc_prediction(&mb_pred[block_y], l0_pred, block_size_y, block_size_x, block_x); + } + else // (p_dir==1) + { + mc_prediction(&mb_pred[block_y], l1_pred, block_size_y, block_size_x, block_x); + } + } +} \ No newline at end of file diff --git a/lencod/src/md_common.c b/lencod/src/md_common.c new file mode 100644 index 0000000..3bf72e4 --- /dev/null +++ b/lencod/src/md_common.c @@ -0,0 +1,594 @@ +/*! + *************************************************************************** + * \file md_common.c + * + * \brief + * Mode Decision common functions + * + * \author + * - Alexis Michael Tourapis + * \date + * 04. October 2008 + ************************************************************************** + */ + +#include +#include "global.h" +#include "image.h" +#include "macroblock.h" +#include "mc_prediction.h" + + +/*! + ************************************************************************************* + * \brief + * Initialize the best variable + ************************************************************************************* + */ +Info8x8 init_best (void) +{ + Info8x8 best; + best.pdir = 0; + best.bipred = 0; + best.ref[LIST_0] = 0; + best.ref[LIST_1] = -1; + return best; +} + +/*! + ************************************************************************************* + * \brief + * Copy rdo mv info to 16xN picture mv buffer + ************************************************************************************* + */ +static inline void CopyMVBlock16(PicMotionParams **mv_info, MotionVector **rdo_mv, int list, int block_x, int block_y, int start, int end) +{ + int j, i; + for (j = start; j < end; j++) + { + for (i = 0; i < BLOCK_MULTIPLE; i++) + { + mv_info[block_y + j][block_x + i].mv[list] = rdo_mv[j][i]; + } + } +} + +/*! + ************************************************************************************* + * \brief + * Reset corresponding 16xN block picture mv buffer + ************************************************************************************* + */ +static inline void ResetMotionBlock16(PicMotionParams **mv_info, int list, int block_x, int block_y, int start, int end) +{ + int j, i; + for (j = block_y + start; j < block_y + end; j++) + { + for (i = block_x; i < block_x + BLOCK_MULTIPLE; i++) + { + mv_info[j][i].mv[list] = zero_mv; + mv_info[j][i].ref_idx[list] = -1; + mv_info[j][i].ref_pic[list] = NULL; + } + } +} + +/*! + ************************************************************************************* + * \brief + * Reset corresponding 16xN block picture mv buffer + ************************************************************************************* + */ +static inline void ResetMVBlock16(PicMotionParams **mv_info, int list, int block_x, int block_y, int start, int end) +{ + int j, i; + for (j = block_y + start; j < block_y + end; j++) + { + for (i = block_x; i < block_x + BLOCK_MULTIPLE; i++) + mv_info[j][i].mv[list] = zero_mv; + } +} + +/*! + ************************************************************************************* + * \brief + * Reset corresponding 16xN block picture ref buffer (intra) + ************************************************************************************* + */ +static inline void ResetRefBlock16(PicMotionParams **mv_info, int list, int block_x, int block_y, int start, int end) +{ + int j, i; + for (j = block_y + start; j < block_y + end; j++) + { + for (i = block_x; i < block_x + BLOCK_MULTIPLE; ++i) + { + mv_info[j][i].ref_idx[list] = -1; + mv_info[j][i].ref_pic[list] = NULL; + } + } +} + +/*! + ************************************************************************************* + * \brief + * Copy rdo mv info to 8xN picture mv buffer + ************************************************************************************* + */ +static inline void CopyMVBlock8(PicMotionParams **mv_info, MotionVector **rdo_mv, int list, int block_x, int start, int end, int offset) +{ + int j; + for (j = start; j < end; j++) + { + mv_info[j][block_x ].mv[list] = rdo_mv[j][offset]; + mv_info[j][block_x + 1].mv[list] = rdo_mv[j][offset + 1]; + } +} + +/*! + ************************************************************************************* + * \brief + * Reset corresponding 8xN block picture mv buffer + ************************************************************************************* + */ +static inline void ResetMotionBlock8(PicMotionParams **mv_info, int list, int block_x, int start, int end) +{ + int j; + + for (j = start; j < end; j++) + { + mv_info[j][block_x ].mv[list] = zero_mv; + mv_info[j][block_x ].ref_idx[list] = -1; + mv_info[j][block_x ].ref_pic[list] = NULL; + mv_info[j][block_x + 1].mv[list] = zero_mv; + mv_info[j][block_x + 1].ref_idx[list] = -1; + mv_info[j][block_x + 1].ref_pic[list] = NULL; + } +} + +/*! + ************************************************************************************* + * \brief + * Reset corresponding 8xN block picture mv buffer + ************************************************************************************* + */ +static inline void ResetMVBlock8(PicMotionParams **mv_info, int list, int block_x, int start, int end) +{ + int j; + + for (j = start; j < end; j++) + { + mv_info[j][block_x ].mv[list] = zero_mv; + mv_info[j][block_x + 1].mv[list] = zero_mv; + } +} + +/*! + ************************************************************************************* + * \brief + * Reset corresponding 8xN block picture ref buffer (intra) + ************************************************************************************* + */ +static inline void ResetRefBlock8(PicMotionParams **mv_info, int list, int block_x, int start, int end) +{ + int j; + for (j = start; j < end; j++) + { + mv_info[j][block_x ].ref_idx[list] = -1; + mv_info[j][block_x ].ref_pic[list] = NULL; + mv_info[j][block_x + 1].ref_idx[list] = -1; + mv_info[j][block_x + 1].ref_pic[list] = NULL; + } +} + +/*! + ************************************************************************************* + * \brief + * Sets motion vectors for a macroblock in a P Slice + ************************************************************************************* + */ +void SetMotionVectorsMBPSlice (Macroblock* currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + + RD_DATA *rdopt = currSlice->rddata; + MotionVector ****all_mv = currSlice->all_mv[LIST_0]; + int l0_ref, mode8; + + if (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1)) + { + memcpy(&rdopt->all_mv[LIST_0][0][0][0][0], &all_mv[0][0][0][0], p_Vid->max_num_references * 9 * MB_BLOCK_PARTITIONS * sizeof(MotionVector)); + } + + if (currMB->mb_type == PSKIP) // Skip mode + { + CopyMVBlock16(mv_info, all_mv[0][PSKIP], LIST_0, currMB->block_x, currMB->block_y, 0, 4); + } + else if (currMB->mb_type == P16x16) // 16x16 + { + l0_ref = mv_info[currMB->block_y][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16(mv_info, all_mv[l0_ref][P16x16], LIST_0, currMB->block_x, currMB->block_y, 0, 4); + } + else if (currMB->mb_type == P16x8) // 16x8 + { + l0_ref = mv_info[currMB->block_y][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16(mv_info, all_mv[l0_ref][P16x8], LIST_0, currMB->block_x, currMB->block_y, 0, 2); + + l0_ref = mv_info[currMB->block_y + 2][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16(mv_info, all_mv[l0_ref][P16x8], LIST_0, currMB->block_x, currMB->block_y, 2, 4); + } + else if (currMB->mb_type == P8x16) // 8x16 + { + l0_ref = mv_info[currMB->block_y][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock8(&mv_info[currMB->block_y], all_mv[l0_ref][P8x16], LIST_0, currMB->block_x , 0, 4, 0); + + l0_ref = mv_info[currMB->block_y][currMB->block_x + 2].ref_idx[LIST_0]; + CopyMVBlock8(&mv_info[currMB->block_y], all_mv[l0_ref][P8x16], LIST_0, currMB->block_x + 2, 0, 4, 2); + } + else if (currMB->mb_type == P8x8) // 8x8 + { + mode8 = currMB->b8x8[0].mode; + l0_ref = mv_info[currMB->block_y ][currMB->block_x ].ref_idx[LIST_0]; + CopyMVBlock8(&mv_info[currMB->block_y], all_mv[l0_ref][mode8], LIST_0, currMB->block_x , 0, 2, 0); + + mode8 = currMB->b8x8[1].mode; + l0_ref = mv_info[currMB->block_y ][currMB->block_x + 2].ref_idx[LIST_0]; + CopyMVBlock8(&mv_info[currMB->block_y], all_mv[l0_ref][mode8], LIST_0, currMB->block_x + 2, 0, 2, 2); + + mode8 = currMB->b8x8[2].mode; + l0_ref = mv_info[currMB->block_y + 2][currMB->block_x ].ref_idx[LIST_0]; + CopyMVBlock8(&mv_info[currMB->block_y], all_mv[l0_ref][mode8], LIST_0, currMB->block_x, 2, 4, 0); + + mode8 = currMB->b8x8[3].mode; + l0_ref = mv_info[currMB->block_y + 2][currMB->block_x + 2].ref_idx[LIST_0]; + CopyMVBlock8(&mv_info[currMB->block_y], all_mv[l0_ref][mode8], LIST_0, currMB->block_x + 2, 2, 4, 2); + } + else // Intra modes + { + ResetMotionBlock16 (mv_info, LIST_0, currMB->block_x, currMB->block_y, 0, 4); + } +} + +/*! + ************************************************************************************* + * \brief + * Sets motion vectors for a 16x8 partition in a B Slice + ************************************************************************************* + */ +static void SetMVBSlice16x8(Slice *currSlice, PicMotionParams **motion, Macroblock* currMB, int pos) +{ + int l0_ref, l1_ref; + int pdir = currMB->b8x8[pos].pdir; + if (pdir == LIST_0) + { + l0_ref = motion[currMB->block_y + pos][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16(motion, currSlice->all_mv [LIST_0][l0_ref][P16x8], LIST_0, currMB->block_x, currMB->block_y, pos, pos + 2); + ResetMotionBlock16 (motion, LIST_1, currMB->block_x, currMB->block_y, pos, pos + 2); + } + else if (pdir == LIST_1) + { + ResetMotionBlock16 (motion, LIST_0, currMB->block_x, currMB->block_y, pos, pos + 2); + l1_ref = motion[currMB->block_y + pos][currMB->block_x].ref_idx[LIST_1]; + CopyMVBlock16 (motion, currSlice->all_mv [LIST_1][l1_ref][P16x8], LIST_1, currMB->block_x, currMB->block_y, pos, pos + 2); + } + else + { + int bipred_me = currMB->b8x8[pos].bipred; + MotionVector *****all_mv = bipred_me ? currSlice->bipred_mv[bipred_me - 1]: currSlice->all_mv; + l0_ref = motion[currMB->block_y + pos][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16 (motion, all_mv [LIST_0][l0_ref][P16x8], LIST_0, currMB->block_x, currMB->block_y, pos, pos + 2); + + l1_ref = motion[currMB->block_y + pos][currMB->block_x].ref_idx[LIST_1]; + CopyMVBlock16 (motion, all_mv [LIST_1][l1_ref][P16x8], LIST_1, currMB->block_x, currMB->block_y, pos, pos + 2); + + if (bipred_me && (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1))) + { + memcpy(currSlice->rddata->all_mv [LIST_0][l0_ref][P16x8][pos], all_mv [LIST_0][l0_ref][P16x8][pos], 2 * BLOCK_MULTIPLE * sizeof(MotionVector)); + memcpy(currSlice->rddata->all_mv [LIST_1][l1_ref][P16x8][pos], all_mv [LIST_1][l1_ref][P16x8][pos], 2 * BLOCK_MULTIPLE * sizeof(MotionVector)); + } + } +} + +/*! + ************************************************************************************* + * \brief + * Sets motion vectors for a 8x16 partition in a B Slice + ************************************************************************************* + */ +static void SetMVBSlice8x16(Slice *currSlice, PicMotionParams **motion, Macroblock* currMB, int pos) +{ + int l0_ref, l1_ref; + int pdir = currMB->b8x8[pos >> 1].pdir; + if (pdir == LIST_0) + { + l0_ref = motion[currMB->block_y][currMB->block_x + pos].ref_idx[LIST_0]; + CopyMVBlock8 (&motion[currMB->block_y], currSlice->all_mv [LIST_0][l0_ref][P8x16], LIST_0, currMB->block_x + pos, 0, 4, pos); + ResetMotionBlock8(&motion[currMB->block_y], LIST_1, currMB->block_x + pos, 0, 4); + } + else if (pdir == LIST_1) + { + ResetMotionBlock8(&motion[currMB->block_y], LIST_0, currMB->block_x + pos, 0, 4); + l1_ref = motion[currMB->block_y][currMB->block_x + pos].ref_idx[LIST_1]; + CopyMVBlock8 (&motion[currMB->block_y], currSlice->all_mv [LIST_1][l1_ref][P8x16], LIST_1, currMB->block_x + pos, 0, 4, pos); + } + else + { + int bipred_me = currMB->b8x8[pos >> 1].bipred; + MotionVector *****all_mv = bipred_me ? currSlice->bipred_mv[bipred_me - 1]: currSlice->all_mv; + + l0_ref = motion[currMB->block_y][currMB->block_x + pos].ref_idx[LIST_0]; + CopyMVBlock8(&motion[currMB->block_y], all_mv [LIST_0][l0_ref][P8x16], LIST_0, currMB->block_x + pos, 0, 4, pos); + l1_ref = motion[currMB->block_y][currMB->block_x + pos].ref_idx[LIST_1]; + CopyMVBlock8(&motion[currMB->block_y], all_mv [LIST_1][l1_ref][P8x16], LIST_1, currMB->block_x + pos, 0, 4, pos); + + if (bipred_me && (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1))) + { + int j; + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + memcpy(&currSlice->rddata->all_mv [LIST_0][l0_ref][P8x16][j][pos], &all_mv [LIST_0][l0_ref][P8x16][j][pos], 2 * sizeof(MotionVector)); + } + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + memcpy(&currSlice->rddata->all_mv [LIST_1][l1_ref][P8x16][j][pos], &all_mv [LIST_1][l1_ref][P8x16][j][pos], 2 * sizeof(MotionVector)); + } + } + } +} + +/*! + ************************************************************************************* + * \brief + * Sets motion vectors for a 8x8 partition in a B Slice + ************************************************************************************* + */ +static void SetMVBSlice8x8(Slice *currSlice, PicMotionParams **motion, Macroblock* currMB, int pos_y, int pos_x) +{ + int l0_ref, l1_ref; + int pos = pos_y + (pos_x >> 1); + int pdir = currMB->b8x8[pos].pdir; + int mode = currMB->b8x8[pos].mode; + int block_y = currMB->block_y + pos_y; + int block_x = currMB->block_x + pos_x; + + if (pdir == LIST_0) + { + l0_ref = motion[block_y][block_x].ref_idx[LIST_0]; + CopyMVBlock8 (&motion[currMB->block_y], currSlice->all_mv [LIST_0][l0_ref][mode], LIST_0, currMB->block_x + pos_x, pos_y, pos_y + 2, pos_x); + ResetMotionBlock8 (&motion[currMB->block_y], LIST_1, currMB->block_x + pos_x, pos_y, pos_y + 2); + } + else if (pdir == LIST_1) + { + ResetMotionBlock8(&motion[currMB->block_y], LIST_0, currMB->block_x + pos_x, pos_y, pos_y + 2); + l1_ref = motion[block_y][block_x].ref_idx[LIST_1]; + CopyMVBlock8 (&motion[currMB->block_y], currSlice->all_mv [LIST_1][l1_ref][mode], LIST_1, currMB->block_x + pos_x, pos_y, pos_y + 2, pos_x); + } + else if (pdir == BI_PRED) + { + int bipred_me = currMB->b8x8[pos].bipred; + MotionVector *****all_mv = bipred_me ? currSlice->bipred_mv[bipred_me - 1]: currSlice->all_mv; + l0_ref = motion[block_y][block_x].ref_idx[LIST_0]; + CopyMVBlock8(&motion[currMB->block_y], all_mv [LIST_0][l0_ref][mode], LIST_0, currMB->block_x + pos_x, pos_y, pos_y + 2, pos_x); + + l1_ref = motion[block_y][block_x].ref_idx[LIST_1]; + CopyMVBlock8(&motion[currMB->block_y], all_mv [LIST_1][l1_ref][mode], LIST_1, currMB->block_x + pos_x, pos_y, pos_y + 2, pos_x); + + if (bipred_me && (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1))) + { + memcpy(&currSlice->rddata->all_mv [LIST_0][l0_ref][mode][pos_y ][pos_x], &all_mv [LIST_0][l0_ref][mode][pos_y ][pos_x], 2 * sizeof(MotionVector)); + memcpy(&currSlice->rddata->all_mv [LIST_0][l0_ref][mode][pos_y + 1][pos_x], &all_mv [LIST_0][l0_ref][mode][pos_y + 1][pos_x], 2 * sizeof(MotionVector)); + memcpy(&currSlice->rddata->all_mv [LIST_1][l1_ref][mode][pos_y ][pos_x], &all_mv [LIST_1][l1_ref][mode][pos_y ][pos_x], 2 * sizeof(MotionVector)); + memcpy(&currSlice->rddata->all_mv [LIST_1][l1_ref][mode][pos_y + 1][pos_x], &all_mv [LIST_1][l1_ref][mode][pos_y + 1][pos_x], 2 * sizeof(MotionVector)); + } + } + else // Invalid direct modes (out of range mvs). Adding this here for precaution purposes. + { + ResetMotionBlock8(&motion[currMB->block_y], LIST_0, currMB->block_x + pos_x, pos_y, pos_y + 2); + ResetMotionBlock8(&motion[currMB->block_y], LIST_1, currMB->block_x + pos_x, pos_y, pos_y + 2); + } +} + +void SetMotionVectorsMBISlice (Macroblock* currMB) +{ +} + +/*! + ************************************************************************************* + * \brief + * Sets motion vectors for a macroblock in a P Slice + ************************************************************************************* + */ +void SetMotionVectorsMBBSlice (Macroblock* currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int l0_ref, l1_ref; + + // copy all the motion vectors into rdopt structure + // Can simplify this by copying the MV's of the best mode (TBD) + // Should maybe add code to check for Intra only profiles + + if (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1)) + { + memcpy(&currSlice->rddata->all_mv[LIST_0][0][0][0][0], &currSlice->all_mv[LIST_0][0][0][0][0], 2 * p_Vid->max_num_references * 9 * MB_BLOCK_PARTITIONS * sizeof(MotionVector)); + } + + if (currMB->mb_type == P16x16) // 16x16 + { + int pdir = currMB->b8x8[0].pdir; + if (pdir == LIST_0) + { + l0_ref = motion[currMB->block_y][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16 (motion, currSlice->all_mv [LIST_0][l0_ref][P16x16], LIST_0, currMB->block_x, currMB->block_y, 0, 4); + ResetMotionBlock16(motion, LIST_1, currMB->block_x, currMB->block_y, 0, 4); + } + else if (pdir == LIST_1) + { + l1_ref = motion[currMB->block_y][currMB->block_x].ref_idx[LIST_1]; + ResetMotionBlock16 (motion, LIST_0, currMB->block_x, currMB->block_y, 0, 4); + CopyMVBlock16 (motion, currSlice->all_mv [LIST_1][l1_ref][P16x16], LIST_1, currMB->block_x, currMB->block_y, 0, 4); + } + else + { + int bipred_me = currMB->b8x8[0].bipred; + MotionVector *****all_mv = bipred_me ? currSlice->bipred_mv[bipred_me - 1]: currSlice->all_mv; + l0_ref = motion[currMB->block_y][currMB->block_x].ref_idx[LIST_0]; + CopyMVBlock16 (motion, all_mv [LIST_0][l0_ref][P16x16], LIST_0, currMB->block_x, currMB->block_y, 0, 4); + l1_ref = motion[currMB->block_y][currMB->block_x].ref_idx[LIST_1]; + CopyMVBlock16 (motion, all_mv [LIST_1][l1_ref][P16x16], LIST_1, currMB->block_x, currMB->block_y, 0, 4); + + // Is this necessary here? Can this be moved somewhere else? + if (bipred_me && (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1))) + { + memcpy(&currSlice->rddata->all_mv [LIST_0][l0_ref][P16x16][0][0], &all_mv [LIST_0][l0_ref][P16x16][0][0], MB_BLOCK_PARTITIONS * sizeof(MotionVector)); + memcpy(&currSlice->rddata->all_mv [LIST_1][l1_ref][P16x16][0][0], &all_mv [LIST_1][l1_ref][P16x16][0][0], MB_BLOCK_PARTITIONS * sizeof(MotionVector)); + } + } + } + else if (currMB->mb_type == P16x8) // 16x8 + { + SetMVBSlice16x8(currSlice, motion, currMB, 0); + SetMVBSlice16x8(currSlice, motion, currMB, 2); + } + else if (currMB->mb_type == P8x16) // 16x8 + { + SetMVBSlice8x16(currSlice, motion, currMB, 0); + SetMVBSlice8x16(currSlice, motion, currMB, 2); + } + else if (currMB->mb_type == P8x8 || currMB->mb_type == BSKIP_DIRECT) // 8x8 & Direct/SKIP + { + SetMVBSlice8x8(currSlice, motion, currMB, 0, 0); + SetMVBSlice8x8(currSlice, motion, currMB, 0, 2); + SetMVBSlice8x8(currSlice, motion, currMB, 2, 0); + SetMVBSlice8x8(currSlice, motion, currMB, 2, 2); + } + else // Intra modes + { + ResetMotionBlock16 (motion, LIST_0, currMB->block_x, currMB->block_y, 0, 4); + ResetMotionBlock16 (motion, LIST_1, currMB->block_x, currMB->block_y, 0, 4); + } +} + +/*! + ************************************************************************************* + * \brief + * Copy ImgPel Data from one structure to another (16x16) + ************************************************************************************* + */ +void copy_image_data_16x16(imgpel **imgBuf1, imgpel **imgBuf2, int off1, int off2) +{ + int j; + for(j=0; jgiRDOpt_B8OnlyFlag = TRUE; + + rd_data->mb_p8x8_cost = 0; + rd_data->cbp8x8 = 0; + rd_data->cbp_blk8x8 = 0; + rd_data->cnt_nonz_8x8 = 0; + + for (block = 0; block < 4; block++) + { + rd_data->smb_p8x8_cost[block] = DISTBLK_MAX; + rd_data->smb_p8x8_rdcost[block] = DISTBLK_MAX; + rd_data->part[block].mode = -1; + } +} + +/*! +************************************************************************************* +* \brief +* set the range of chroma prediction mode +************************************************************************************* +*/ +void set_chroma_pred_mode(Macroblock *currMB, RD_PARAMS enc_mb, int *mb_available, char chroma_pred_mode_range[2]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + if ((p_Vid->yuv_format != YUV400) && (p_Inp->separate_colour_plane_flag == 0)) + { + Slice *currSlice = currMB->p_Slice; + // precompute all new chroma intra prediction modes + currSlice->intra_chroma_prediction(currMB, &mb_available[0], &mb_available[1], &mb_available[2]); + + if (p_Inp->FastCrIntraDecision) + { + currSlice->intra_chroma_RD_decision(currMB, &enc_mb); + + chroma_pred_mode_range[0] = currMB->c_ipred_mode; + chroma_pred_mode_range[1] = currMB->c_ipred_mode; + } + else + { + chroma_pred_mode_range[0] = DC_PRED_8; + chroma_pred_mode_range[1] = PLANE_8; + } + } + else + { + chroma_pred_mode_range[0] = DC_PRED_8; + chroma_pred_mode_range[1] = DC_PRED_8; + } +} diff --git a/lencod/src/md_distortion.c b/lencod/src/md_distortion.c new file mode 100644 index 0000000..ec218d4 --- /dev/null +++ b/lencod/src/md_distortion.c @@ -0,0 +1,200 @@ + +/*! + *************************************************************************** + * \file md_distortion.c + * + * \brief + * Main macroblock mode decision functions and helpers + * + ************************************************************************** + */ + +#include +#include +#include + +#include "global.h" +#include "rdopt_coding_state.h" +#include "mb_access.h" +#include "intrarefresh.h" +#include "image.h" +#include "transform8x8.h" +#include "ratectl.h" +#include "mode_decision.h" +#include "fmo.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "macroblock.h" +#include "mv_search.h" +#include "md_distortion.h" + +void setupDistortion(Slice *currSlice) +{ + currSlice->getDistortion = distortionSSE; +} + +/*! + *********************************************************************** + * \brief + * compute generic SSE + *********************************************************************** + */ +int64 compute_SSE(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, int ySize, int xSize) +{ + int i, j; + imgpel *lineRef, *lineSrc; + int64 distortion = 0; + + for (j = 0; j < ySize; j++) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for (i = 0; i < xSize; i++) + distortion += iabs2( *lineRef++ - *lineSrc++ ); + } + return distortion; +} + +distblk compute_SSE_cr(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, int ySize, int xSize) +{ + int i, j; + imgpel *lineRef, *lineSrc; + distblk distortion = 0; + + for (j = 0; j < ySize; j++) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for (i = 0; i < xSize; i++) + distortion += iabs2( *lineRef++ - *lineSrc++ ); + } + + return dist_scale(distortion); +} + +/*! + *********************************************************************** + * \brief + * compute 16x16 SSE + *********************************************************************** + */ +distblk compute_SSE16x16(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc) +{ + int i, j; + imgpel *lineRef, *lineSrc; + distblk distortion = 0; + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for (i = 0; i < MB_BLOCK_SIZE; i++) + distortion += iabs2( *lineRef++ - *lineSrc++ ); + } + + return dist_scale(distortion); +} + +distblk compute_SSE16x16_thres(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc, distblk min_cost) +{ + int i, j; + imgpel *lineRef, *lineSrc; + distblk distortion = 0; + int imin_cost = dist_down(min_cost); + + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for (i = 0; i < MB_BLOCK_SIZE; i++) + distortion += iabs2( *lineRef++ - *lineSrc++ ); + if (distortion > imin_cost) + return (min_cost); + } + + return dist_scale(distortion); +} +/*! + *********************************************************************** + * \brief + * compute 8x8 SSE + *********************************************************************** + */ +distblk compute_SSE8x8(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc) +{ + int i, j; + imgpel *lineRef, *lineSrc; + distblk distortion = 0; + + for (j = 0; j < BLOCK_SIZE_8x8; j++) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for (i = 0; i < BLOCK_SIZE_8x8; i++) + distortion += iabs2( *lineRef++ - *lineSrc++ ); + } + + return dist_scale(distortion); +} + + +/*! + *********************************************************************** + * \brief + * compute 4x4 SSE + *********************************************************************** + */ +distblk compute_SSE4x4(imgpel **imgRef, imgpel **imgSrc, int xRef, int xSrc) +{ + int i, j; + imgpel *lineRef, *lineSrc; + distblk distortion = 0; + + for (j = 0; j < BLOCK_SIZE; j++) + { + lineRef = &imgRef[j][xRef]; + lineSrc = &imgSrc[j][xSrc]; + + for (i = 0; i < BLOCK_SIZE; i++) + distortion += iabs2( *lineRef++ - *lineSrc++ ); + } + + return dist_scale(distortion); +} + +/*! +************************************************************************************* +* \brief +* SSE distortion calculation for a macroblock +************************************************************************************* +*/ +distblk distortionSSE(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + distblk distortionY = 0; + distblk distortionCr[2] = {0, 0}; + + // LUMA + distortionY = compute_SSE16x16(&p_Vid->pCurImg[currMB->opix_y], &p_Vid->enc_picture->p_curr_img[currMB->pix_y], currMB->pix_x, currMB->pix_x); + + // CHROMA + if ((p_Vid->yuv_format != YUV400) && (p_Inp->separate_colour_plane_flag == 0)) + { + distortionCr[0] = compute_SSE_cr(&p_Vid->pImgOrg[1][currMB->opix_c_y], &p_Vid->enc_picture->imgUV[0][currMB->pix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x); + distortionCr[1] = compute_SSE_cr(&p_Vid->pImgOrg[2][currMB->opix_c_y], &p_Vid->enc_picture->imgUV[1][currMB->pix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x); + } +#if JCOST_OVERFLOWCHECK //overflow checking; + if(distortionY * p_Inp->WeightY + distortionCr[0] * p_Inp->WeightCb + distortionCr[1] * p_Inp->WeightCr > DISTBLK_MAX) + { + printf("Overflow: %s : %d \n MB: %d, Value: %lf\n", __FILE__, __LINE__, currMB->mbAddrX, (distortionY * p_Inp->WeightY + distortionCr[0] * p_Inp->WeightCb + distortionCr[1] * p_Inp->WeightCr)); + exit(-1); + } +#endif //end; + return (distblk)( distortionY * p_Inp->WeightY + distortionCr[0] * p_Inp->WeightCb + distortionCr[1] * p_Inp->WeightCr ); +} diff --git a/lencod/src/md_high.c b/lencod/src/md_high.c new file mode 100644 index 0000000..0bbac9f --- /dev/null +++ b/lencod/src/md_high.c @@ -0,0 +1,316 @@ +/*! +*************************************************************************** +* \file md_high.c +* +* \brief +* Main macroblock mode decision functions and helpers +* +************************************************************************** +*/ + +#include +#include +#include + +#include "global.h" +#include "rdopt_coding_state.h" +#include "intrarefresh.h" +#include "image.h" +#include "ratectl.h" +#include "mode_decision.h" +#include "mode_decision_p8x8.h" +#include "fmo.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "macroblock.h" +#include "md_common.h" +#include "conformance.h" +#include "vlc.h" +#include "rdopt.h" +#include "mv_search.h" + + +/*! +************************************************************************************* +* \brief +* Mode Decision for a macroblock +************************************************************************************* +*/ +void encode_one_macroblock_high (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int max_index = 9; + int block, index, mode, i, j; + RD_PARAMS enc_mb; + distblk bmcost[5] = {DISTBLK_MAX}; + distblk cost=0; + distblk min_cost = DISTBLK_MAX; + int intra1 = 0; + int mb_available[3]; + + short bslice = (short) (currSlice->slice_type == B_SLICE); + short pslice = (short) ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == SP_SLICE)); + short intra = (short) ((currSlice->slice_type == I_SLICE) || (currSlice->slice_type == SI_SLICE) || (pslice && currMB->mb_y == p_Vid->mb_y_upd && p_Vid->mb_y_upd != p_Vid->mb_y_intra)); + int lambda_mf[3]; + + imgpel **mb_pred = currSlice->mb_pred[0]; + Block8x8Info *b8x8info = p_Vid->b8x8info; + + char chroma_pred_mode_range[2]; + short inter_skip = 0; + BestMode md_best; + Info8x8 best; + + init_md_best(&md_best); + + // Init best (need to create simple function) + best = init_best(); + + intra |= RandomIntra (p_Vid, currMB->mbAddrX); // Forced Pseudo-Random Intra + + //===== Setup Macroblock encoding parameters ===== + init_enc_mb_params(currMB, &enc_mb, intra); + if (p_Inp->AdaptiveRounding) + { + reset_adaptive_rounding(p_Vid); + } + + if (currSlice->mb_aff_frame_flag) + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + } + + //===== S T O R E C O D I N G S T A T E ===== + //--------------------------------------------------- + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm); + + if (!intra) + { + //===== set skip/direct motion vectors ===== + if (enc_mb.valid[0]) + { + if (bslice) + currSlice->Get_Direct_Motion_Vectors (currMB); + else + FindSkipModeMotionVector (currMB); + } + if (p_Inp->CtxAdptLagrangeMult == 1) + { + get_initial_mb16x16_cost(currMB); + } + + //===== MOTION ESTIMATION FOR (1)16x16, (2)16x8, (3)8x16 BLOCKS ===== + for (mode = 1; mode < 4; mode++) + { + best.mode = (char) mode; + best.bipred = 0; + b8x8info->best[mode][0].bipred = 0; + + if (enc_mb.valid[mode]) + { + for (cost=0, block=0; block<(mode==1?1:2); block++) + { + update_lambda_costs(currMB, &enc_mb, lambda_mf); + PartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- set 4x4 block indices (for getting MV) --- + j = (block==1 && mode==2 ? 2 : 0); + i = (block==1 && mode==3 ? 2 : 0); + + //--- get cost and reference frame for List 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, &enc_mb, bmcost, best.ref); + + if (bslice) + { + //--- get cost and reference frame for List 1 prediction --- + bmcost[LIST_1] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_1, block, mode, &enc_mb, bmcost, best.ref); + + // Compute bipredictive cost between best list 0 and best list 1 references + list_prediction_cost(currMB, BI_PRED, block, mode, &enc_mb, bmcost, best.ref); + + // currently Bi predictive ME is only supported for modes (1)16x16, (2)16x8, (3)8x16 and ref 0 + if (is_bipred_enabled(p_Vid, mode)) + { + get_bipred_cost(currMB, mode, block, i, j, &best, &enc_mb, bmcost); + } + else + { + bmcost[BI_PRED_L0] = DISTBLK_MAX; + bmcost[BI_PRED_L1] = DISTBLK_MAX; + } + + if( p_Inp->Force_BiPredMultiview == 1 ) + { + bmcost[BI_PRED] = 0; + } + + // Determine prediction list based on mode cost + determine_prediction_list(bmcost, &best, &cost); + + } + else // if (bslice) + { + best.pdir = 0; + cost += bmcost[LIST_0]; + } + + assign_enc_picture_params(currMB, mode, &best, 2 * block); + + //----- set reference frame and direction parameters ----- + set_block8x8_info(b8x8info, mode, block, &best); + + //--- set reference frames and motion vectors --- + if (mode>1 && block == 0) + currSlice->set_ref_and_motion_vectors (currMB, motion, &best, block); + } // for (block=0; block<(mode==1?1:2); block++) + + if (cost < min_cost) + { + md_best.mode = (byte) mode; + md_best.cost = cost; + currMB->best_mode = (short) mode; + min_cost = cost; + if (p_Inp->CtxAdptLagrangeMult == 1) + { + adjust_mb16x16_cost(currMB, cost); + } + } + } // if (enc_mb.valid[mode]) + } // for (mode=1; mode<4; mode++) + + if (enc_mb.valid[P8x8]) + { + currMB->valid_8x8 = FALSE; + + if (p_Inp->Transform8x8Mode) + { + ResetRD8x8Data(p_Vid, p_RDO->tr8x8); + currMB->luma_transform_size_8x8_flag = TRUE; //switch to 8x8 transform size + //=========================================================== + // Check 8x8 partition with transform size 8x8 + //=========================================================== + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (block = 0; block < 4; block++) + { + currSlice->submacroblock_mode_decision(currMB, &enc_mb, p_RDO->tr8x8, p_RDO->cofAC8x8ts[block], block, &cost); + if(!currMB->valid_8x8) + break; + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr8x8); + } + + }// if (p_Inp->Transform8x8Mode) + + currMB->valid_4x4 = FALSE; + if (p_Inp->Transform8x8Mode != 2) + { + currMB->luma_transform_size_8x8_flag = FALSE; //switch to 8x8 transform size + ResetRD8x8Data(p_Vid, p_RDO->tr4x4); + //================================================================= + // Check 8x8, 8x4, 4x8 and 4x4 partitions with transform size 4x4 + //================================================================= + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (block = 0; block < 4; block++) + { + currSlice->submacroblock_mode_decision(currMB, &enc_mb, p_RDO->tr4x4, p_RDO->coefAC8x8[block], block, &cost); + if(!currMB->valid_4x4) + break; + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr4x4); + } + }// if (p_Inp->Transform8x8Mode != 2) + + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + p_Vid->giRDOpt_B8OnlyFlag = FALSE; + } + } + else // if (!intra) + { + min_cost = DISTBLK_MAX; + } + + // Set Chroma mode + set_chroma_pred_mode(currMB, enc_mb, mb_available, chroma_pred_mode_range); + + //========= C H O O S E B E S T M A C R O B L O C K M O D E ========= + //------------------------------------------------------------------------- + + for (currMB->c_ipred_mode = chroma_pred_mode_range[0]; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + { + // bypass if c_ipred_mode is not allowed + if ( (p_Vid->yuv_format != YUV400) && + ( ((!intra || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && currMB->c_ipred_mode!=DC_PRED_8) + || (currMB->c_ipred_mode == VERT_PRED_8 && !mb_available[0]) + || (currMB->c_ipred_mode == HOR_PRED_8 && !mb_available[1]) + || (currMB->c_ipred_mode == PLANE_8 && (!mb_available[1] || !mb_available[0] || !mb_available[2])))) + continue; + + //===== GET BEST MACROBLOCK MODE ===== + for (index=0; index < max_index; index++) + { + mode = mb_mode_table[index]; + if (enc_mb.valid[mode]) + { + if (p_Vid->yuv_format != YUV400) + { + currMB->i16mode = 0; + } + + // Skip intra modes in inter slices if best mode is inter P444_joined) + { + if (p_Inp->SkipIntraInInterSlices && !intra && mode >= I16MB + && currMB->best_mode <=3 && currMB->best_cbp == 0 && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,5))) + continue; + } + else + { + if (p_Inp->SkipIntraInInterSlices) + { + if (!intra && mode >= I4MB) + { + if (currMB->best_mode <=3 && currMB->best_cbp == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp, 5))) + { + continue; + } + else if (currMB->best_mode == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,6))) + { + continue; + } + } + } + } + + compute_mode_RD_cost(currMB, &enc_mb, (short) mode, &inter_skip); + + } + }// for (index=0; indexc_ipred_mode=DC_PRED_8; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + + restore_nz_coeff(currMB); + + intra1 = IS_INTRA(currMB); + + //===== S E T F I N A L M A C R O B L O C K P A R A M E T E R S ====== + //--------------------------------------------------------------------------- + update_qp_cbp_tmp(currMB, p_RDO->cbp); + currSlice->set_stored_mb_parameters (currMB); + + // Rate control + if(p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE) + rc_store_mad(currMB); + + + //===== Decide if this MB will restrict the reference frames ===== + if (p_Inp->RestrictRef) + update_refresh_map(currMB, intra, intra1); +} + + diff --git a/lencod/src/md_highfast.c b/lencod/src/md_highfast.c new file mode 100644 index 0000000..f57255b --- /dev/null +++ b/lencod/src/md_highfast.c @@ -0,0 +1,465 @@ +/*! +*************************************************************************** +* \file md_highfast.c +* +* \brief +* Main macroblock mode decision functions and helpers +* +************************************************************************** +*/ + +#include +#include +#include + +#include "global.h" +#include "rdopt_coding_state.h" +#include "mb_access.h" +#include "intrarefresh.h" +#include "image.h" +#include "ratectl.h" +#include "mode_decision.h" +#include "mode_decision_p8x8.h" +#include "fmo.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "macroblock.h" +#include "md_common.h" +#include "conformance.h" +#include "vlc.h" +#include "rdopt.h" +#include "mv_search.h" + +/*! +************************************************************************************* +* \brief +* Fast intra decision +************************************************************************************* +*/ + +static void fast_mode_intra_decision(Macroblock *currMB, short *intra_skip) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int i; + int mb_available_up, mb_available_left; + long SBE; + double AR = 0, ABE = 0; + PixelPos up; //!< pixel position p(0,-1) + PixelPos left[2]; //!< pixel positions p(-1, -1..0) + + p_Vid->getNeighbour(currMB, 0 , -1 , p_Vid->mb_size[IS_LUMA], &up); + p_Vid->getNeighbour(currMB, -1 , -1 , p_Vid->mb_size[IS_LUMA], &left[0]); + p_Vid->getNeighbour(currMB, -1 , 0 , p_Vid->mb_size[IS_LUMA], &left[1]); + + mb_available_up = up.available; + mb_available_left = left[1].available; + + AR=(1.0/384)*currMB->min_rate; + + SBE = 0; + + if( (currMB->mb_y != (int)p_Vid->FrameHeightInMbs-1) && (currMB->mb_x != (int)p_Vid->PicWidthInMbs-1) && mb_available_left && mb_available_up) + { + for(i = 0; i < MB_BLOCK_SIZE; i++) + { + SBE += iabs(p_Vid->pCurImg[currMB->opix_y][currMB->pix_x + i] - p_Vid->enc_picture->imgY[currMB->pix_y - 1][currMB->pix_x + i]); + SBE += iabs(p_Vid->pCurImg[currMB->opix_y + i][currMB->pix_x] - p_Vid->enc_picture->imgY[currMB->pix_y + i][currMB->pix_x - 1]); + } + + for(i = 0; i < 8; i++) + { + SBE += iabs(p_Vid->pImgOrg[1][currMB->opix_c_y][currMB->pix_c_x + i] - p_Vid->enc_picture->imgUV[0][currMB->pix_c_y - 1][currMB->pix_c_x + i]); + SBE += iabs(p_Vid->pImgOrg[1][currMB->opix_c_y+i][currMB->pix_c_x] - p_Vid->enc_picture->imgUV[0][currMB->pix_c_y + i][currMB->pix_c_x - 1]); + SBE += iabs(p_Vid->pImgOrg[2][currMB->opix_c_y][currMB->pix_c_x + i] - p_Vid->enc_picture->imgUV[1][currMB->pix_c_y - 1][currMB->pix_c_x + i]); + SBE += iabs(p_Vid->pImgOrg[2][currMB->opix_c_y+i][currMB->pix_c_x] - p_Vid->enc_picture->imgUV[1][currMB->pix_c_y + i][currMB->pix_c_x - 1]); + } + ABE = 1.0/64 * SBE; + } + else // Image boundary + { + ABE = 0; + } + + if(AR <= ABE) + { + *intra_skip = 1; + } +} + +/*! +************************************************************************************* +* \brief +* Mode Decision for a macroblock +************************************************************************************* +*/ +void encode_one_macroblock_highfast (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int max_index; + int block, index, mode, i, j; + RD_PARAMS enc_mb; + distblk max_rdcost = DISTBLK_MAX; + distblk bmcost[5] = {DISTBLK_MAX}; + distblk cost=0; + distblk min_cost = DISTBLK_MAX; + int intra1 = 0; + int mb_available[3]; + + short islice = (short) (currSlice->slice_type == I_SLICE); + short bslice = (short) (currSlice->slice_type == B_SLICE); + short pslice = (short) ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == SP_SLICE)); + short intra = (short) ((currSlice->slice_type == I_SLICE) || (currSlice->slice_type == SI_SLICE) || (pslice && currMB->mb_y == p_Vid->mb_y_upd && p_Vid->mb_y_upd != p_Vid->mb_y_intra)); + int lambda_mf[3]; + + imgpel **mb_pred = currSlice->mb_pred[0]; + Block8x8Info *b8x8info = p_Vid->b8x8info; + + char chroma_pred_mode_range[2]; + + + MotionVector *allmvs = (currSlice->slice_type == I_SLICE) ? NULL: &currSlice->all_mv[0][0][0][0][0]; + + // Fast Mode Decision + short inter_skip = 0, intra_skip = 0; + int mode16 = 0; + distblk RDCost16 = DISTBLK_MAX; + BestMode md_best; + Info8x8 best; + + init_md_best(&md_best); + + // Init best (need to create simple function) + best.pdir = 0; + best.bipred = 0; + best.ref[LIST_0] = 0; + best.ref[LIST_1] = -1; + + intra |= RandomIntra (p_Vid, currMB->mbAddrX); // Forced Pseudo-Random Intra + + //===== Setup Macroblock encoding parameters ===== + init_enc_mb_params(currMB, &enc_mb, intra); + if (p_Inp->AdaptiveRounding) + { + reset_adaptive_rounding(p_Vid); + } + + if (currSlice->mb_aff_frame_flag) + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + } + + //===== S T O R E C O D I N G S T A T E ===== + //--------------------------------------------------- + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm); + + if (!intra) + { + //===== set direct motion vectors ===== + if (bslice && enc_mb.valid[0]) + { + currSlice->Get_Direct_Motion_Vectors (currMB); + currMB->best_mode = 0; + currMB->c_ipred_mode=DC_PRED_8; + currMB->min_rdcost = max_rdcost; + compute_mode_RD_cost(currMB, &enc_mb, 0, &inter_skip); + } + if (p_Inp->CtxAdptLagrangeMult == 1) + { + get_initial_mb16x16_cost(currMB); + } + + //===== MOTION ESTIMATION FOR (1)16x16, (2)16x8, (3)8x16 BLOCKS ===== + for (mode = 1; mode < 4; mode++) + { + best.mode = (char) mode; + best.bipred = 0; + b8x8info->best[mode][0].bipred = 0; + + if (enc_mb.valid[mode] && !inter_skip) + { + for (cost=0, block=0; block<(mode==1?1:2); block++) + { + update_lambda_costs(currMB, &enc_mb, lambda_mf); + PartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- set 4x4 block indizes (for getting MV) --- + j = (block==1 && mode==2 ? 2 : 0); + i = (block==1 && mode==3 ? 2 : 0); + + //--- get cost and reference frame for List 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, &enc_mb, bmcost, best.ref); + + if (bslice) + { + //--- get cost and reference frame for List 1 prediction --- + bmcost[LIST_1] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_1, block, mode, &enc_mb, bmcost, best.ref); + + // Compute bipredictive cost between best list 0 and best list 1 references + list_prediction_cost(currMB, BI_PRED, block, mode, &enc_mb, bmcost, best.ref); + + // currently Bi predictive ME is only supported for modes (1)16x16, (2)16x8, (3)8x16 and ref 0 + if (is_bipred_enabled(p_Vid, mode)) + { + get_bipred_cost(currMB, mode, block, i, j, &best, &enc_mb, bmcost); + } + else + { + bmcost[BI_PRED_L0] = DISTBLK_MAX; + bmcost[BI_PRED_L1] = DISTBLK_MAX; + } + + // Determine prediction list based on mode cost + determine_prediction_list(bmcost, &best, &cost); + } + else // if (bslice) + { + best.pdir = 0; + cost += bmcost[LIST_0]; + } + + assign_enc_picture_params(currMB, mode, &best, 2 * block); + + //----- set reference frame and direction parameters ----- + set_block8x8_info(b8x8info, mode, block, &best); + + //--- set reference frames and motion vectors --- + if (mode>1 && block == 0) + currSlice->set_ref_and_motion_vectors (currMB, motion, &best, block); + } // for (block=0; block<(mode==1?1:2); block++) + + + if(mode == 1) + { + if(pslice) + currMB->min_rdcost = max_rdcost; + + currMB->c_ipred_mode=DC_PRED_8; + compute_mode_RD_cost(currMB, &enc_mb, (short) mode, &inter_skip); + + if(pslice) + { + // Get SKIP motion vector and compare SKIP_MV with best motion vector of 16x16 + FindSkipModeMotionVector (currMB); + + if(p_Inp->EarlySkipEnable) + { + //===== check for SKIP mode ===== + if ( currMB->cbp==0 && motion[currMB->block_y][currMB->block_x].ref_idx[LIST_0]==0 && + motion[currMB->block_y][currMB->block_x].mv[LIST_0].mv_x == allmvs->mv_x && + motion[currMB->block_y][currMB->block_x].mv[LIST_0].mv_y == allmvs->mv_y) + { + inter_skip = 1; + currMB->best_mode = 0; + } + } // if(p_Inp->EarlySkipEnable) + } + + // store variables. + RDCost16 = currMB->min_rdcost; + mode16 = currMB->best_mode; + } // if(mode == 1) + + if ((!inter_skip) && (cost < min_cost)) + { + md_best.mode = (byte) mode; + md_best.cost = cost; + currMB->best_mode = (short) mode; + min_cost = cost; + if (p_Inp->CtxAdptLagrangeMult == 1) + { + adjust_mb16x16_cost(currMB, cost); + } + } + } // if (enc_mb.valid[mode]) + } // for (mode=1; mode<4; mode++) + + if ((!inter_skip) && enc_mb.valid[P8x8]) + { + currMB->valid_8x8 = FALSE; + + if (p_Inp->Transform8x8Mode) + { + ResetRD8x8Data(p_Vid, p_RDO->tr8x8); + currMB->luma_transform_size_8x8_flag = TRUE; //switch to 8x8 transform size + //=========================================================== + // Check 8x8 partition with transform size 8x8 + //=========================================================== + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (block = 0; block < 4; block++) + { + currSlice->submacroblock_mode_decision(currMB, &enc_mb, p_RDO->tr8x8, p_RDO->cofAC8x8ts[block], block, &cost); + if(!currMB->valid_8x8) + break; + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr8x8); + } + }// if (p_Inp->Transform8x8Mode) + + currMB->valid_4x4 = FALSE; + if (p_Inp->Transform8x8Mode != 2) + { + currMB->luma_transform_size_8x8_flag = FALSE; //switch to 8x8 transform size + ResetRD8x8Data(p_Vid, p_RDO->tr4x4); + //================================================================= + // Check 8x8, 8x4, 4x8 and 4x4 partitions with transform size 4x4 + //================================================================= + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (block = 0; block < 4; block++) + { + currSlice->submacroblock_mode_decision(currMB, &enc_mb, p_RDO->tr4x4, p_RDO->coefAC8x8[block], block, &cost); + if(!currMB->valid_4x4) + break; + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr4x4); + } + }// if (p_Inp->Transform8x8Mode != 2) + + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + p_Vid->giRDOpt_B8OnlyFlag = FALSE; + } + } + else // if (!intra) + { + min_cost = DISTBLK_MAX; + } + + //========= C H O O S E B E S T M A C R O B L O C K M O D E ========= + //------------------------------------------------------------------------- + { + if (!inter_skip) + { + if(currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + currMB->min_rdcost = RDCost16; + currMB->best_mode = (short) mode16; + } + else + currMB->min_rdcost = max_rdcost; + + // if Fast High mode, compute inter modes separate process for inter/intra + max_index = ((!intra && p_Inp->SelectiveIntraEnable ) ? 5 : 9); + + // Set Chroma mode + set_chroma_pred_mode(currMB, enc_mb, mb_available, chroma_pred_mode_range); + + //========= C H O O S E B E S T M A C R O B L O C K M O D E ========= + //------------------------------------------------------------------------- + + for (currMB->c_ipred_mode = chroma_pred_mode_range[0]; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + { + // bypass if c_ipred_mode is not allowed + if ( (p_Vid->yuv_format != YUV400) && + ( ((!intra || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && currMB->c_ipred_mode!=DC_PRED_8) + || (currMB->c_ipred_mode == VERT_PRED_8 && !mb_available[0]) + || (currMB->c_ipred_mode == HOR_PRED_8 && !mb_available[1]) + || (currMB->c_ipred_mode == PLANE_8 && (!mb_available[1] || !mb_available[0] || !mb_available[2])))) + continue; + + //===== GET BEST MACROBLOCK MODE ===== + for (index=0; index < max_index; index++) + { + mode = mb_mode_table[index]; + if (mode == 1) + continue; + if (enc_mb.valid[mode]) + { + if (p_Vid->yuv_format != YUV400) + { + currMB->i16mode = 0; + } + + // Skip intra modes in inter slices if best mode is inter P444_joined) + { + if (p_Inp->SkipIntraInInterSlices && !intra && mode >= I16MB + && currMB->best_mode <=3 && currMB->best_cbp == 0 && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp, 5))) + continue; + } + else + { + if (p_Inp->SkipIntraInInterSlices && !intra && mode >= I4MB && currMB->best_mode <=3 && currMB->best_cbp == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,5))) + continue; + } + + compute_mode_RD_cost(currMB, &enc_mb, (short) mode, &inter_skip); + + } + }// for (index=0; indexc_ipred_mode=DC_PRED_8; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + + // Selective Intra Coding + if((currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) && p_Inp->SelectiveIntraEnable && !is_FREXT_profile(p_Inp->ProfileIDC)) + { + fast_mode_intra_decision(currMB, &intra_skip); + + if(!intra_skip) + { + // Set Chroma mode + set_chroma_pred_mode(currMB, enc_mb, mb_available, chroma_pred_mode_range); + + max_index = 9; + + for (currMB->c_ipred_mode=chroma_pred_mode_range[0]; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + { + + // bypass if c_ipred_mode is not allowed + if ( (p_Vid->yuv_format != YUV400) && + ( ((!intra || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && currMB->c_ipred_mode!=DC_PRED_8) + || (currMB->c_ipred_mode == VERT_PRED_8 && !mb_available[0]) + || (currMB->c_ipred_mode == HOR_PRED_8 && !mb_available[1]) + || (currMB->c_ipred_mode == PLANE_8 && (!mb_available[0] || !mb_available[1]|| !mb_available[2])))) + continue; + + //===== GET BEST MACROBLOCK MODE ===== + for (index = 5; index < max_index; index++) + { + mode = mb_mode_table[index]; + + // Skip intra modes in inter slices if best mode is inter SkipIntraInInterSlices && !intra && mode >= I4MB && currMB->best_mode <=3 && currMB->best_cbp == 0) + continue; + + if (p_Vid->yuv_format != YUV400) + { + currMB->i16mode = 0; + // RDcost of mode 1 in P-slice and mode 0, 1 in B-slice are already available + if(((bslice && mode == 0) || (!islice && mode == 1))) + continue; + } + + if (enc_mb.valid[mode]) + compute_mode_RD_cost(currMB, &enc_mb, (short) mode, &inter_skip); + } // for (index = 5; index < max_index; index++) + } + } + } + } + restore_nz_coeff(currMB); + + } + + intra1 = IS_INTRA(currMB); + + //===== S E T F I N A L M A C R O B L O C K P A R A M E T E R S ====== + //--------------------------------------------------------------------------- + update_qp_cbp_tmp(currMB, p_RDO->cbp); + currSlice->set_stored_mb_parameters (currMB); + + // Rate control + if(p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE) + rc_store_mad(currMB); + + //===== Decide if this MB will restrict the reference frames ===== + if (p_Inp->RestrictRef) + update_refresh_map(currMB, intra, intra1); + +} + + diff --git a/lencod/src/md_highloss.c b/lencod/src/md_highloss.c new file mode 100644 index 0000000..4f2fe66 --- /dev/null +++ b/lencod/src/md_highloss.c @@ -0,0 +1,318 @@ +/*! + *************************************************************************** + * \file md_highloss.c + * + * \brief + * Main macroblock mode decision functions and helpers + * + ************************************************************************** + */ + +#include +#include +#include + +#include "global.h" +#include "rdopt_coding_state.h" +#include "intrarefresh.h" +#include "image.h" +#include "ratectl.h" +#include "mode_decision.h" +#include "mode_decision_p8x8.h" +#include "fmo.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "macroblock.h" +#include "md_common.h" +#include "conformance.h" +#include "vlc.h" +#include "rdopt.h" +#include "mv_search.h" + +/*! +************************************************************************************* +* \brief +* Mode Decision for a macroblock with error resilience +************************************************************************************* +*/ +void encode_one_macroblock_highloss (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int max_index = 9; + int rerun, block, index, mode, i, j; + RD_PARAMS enc_mb; + distblk bmcost[5] = {DISTBLK_MAX}; + distblk cost=0; + distblk min_cost = DISTBLK_MAX; + int intra1 = 0; + int mb_available[3]; + + short bslice = (short) (currSlice->slice_type == B_SLICE); + short pslice = (short) ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == SP_SLICE)); + short intra = (short) ((currSlice->slice_type == I_SLICE) || (currSlice->slice_type == SI_SLICE) || (pslice && currMB->mb_y == p_Vid->mb_y_upd && p_Vid->mb_y_upd != p_Vid->mb_y_intra)); + int lambda_mf[3]; + short runs = (short) ((p_Inp->RestrictRef==1 && (pslice || (bslice && p_Vid->nal_reference_idc>0))) ? 2 : 1); + + imgpel **mb_pred = currSlice->mb_pred[0]; + Block8x8Info *b8x8info = p_Vid->b8x8info; + + char chroma_pred_mode_range[2]; + short inter_skip = 0; + BestMode md_best; + Info8x8 best; + + init_md_best(&md_best); + + // Init best (need to create simple function) + best.pdir = 0; + best.bipred = 0; + best.ref[LIST_0] = 0; + best.ref[LIST_1] = -1; + + intra |= RandomIntra (p_Vid, currMB->mbAddrX); // Forced Pseudo-Random Intra + + //===== Setup Macroblock encoding parameters ===== + init_enc_mb_params(currMB, &enc_mb, intra); + + // Perform multiple encodings if rdopt with losses is enabled + for (rerun=0; rerunrdopt= (rerun==0) ? 1 : 3; + + if (p_Inp->AdaptiveRounding) + { + reset_adaptive_rounding(p_Vid); + } + + if (currSlice->mb_aff_frame_flag) + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + } + + //===== S T O R E C O D I N G S T A T E ===== + //--------------------------------------------------- + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm); + + if (!intra) + { + //===== set skip/direct motion vectors ===== + if (enc_mb.valid[0]) + { + if (bslice) + currSlice->Get_Direct_Motion_Vectors (currMB); + else + FindSkipModeMotionVector (currMB); + } + if (p_Inp->CtxAdptLagrangeMult == 1) + { + get_initial_mb16x16_cost(currMB); + } + + //===== MOTION ESTIMATION FOR 16x16, 16x8, 8x16 BLOCKS ===== + for (mode = 1; mode < 4; mode++) + { + best.mode = (char) mode; + best.bipred = 0; + b8x8info->best[mode][0].bipred = 0; + + if (enc_mb.valid[mode]) + { + for (cost=0, block=0; block<(mode==1?1:2); block++) + { + update_lambda_costs(currMB, &enc_mb, lambda_mf); + PartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- set 4x4 block indices (for getting MV) --- + j = (block==1 && mode==2 ? 2 : 0); + i = (block==1 && mode==3 ? 2 : 0); + + //--- get cost and reference frame for List 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, &enc_mb, bmcost, best.ref); + + if (bslice) + { + //--- get cost and reference frame for List 1 prediction --- + bmcost[LIST_1] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_1, block, mode, &enc_mb, bmcost, best.ref); + + // Compute bipredictive cost between best list 0 and best list 1 references + list_prediction_cost(currMB, BI_PRED, block, mode, &enc_mb, bmcost, best.ref); + + // currently Bi predictive ME is only supported for modes 1, 2, 3 and ref 0 + if (is_bipred_enabled(p_Vid, mode)) + { + get_bipred_cost(currMB, mode, block, i, j, &best, &enc_mb, bmcost); + } + else + { + bmcost[BI_PRED_L0] = DISTBLK_MAX; + bmcost[BI_PRED_L1] = DISTBLK_MAX; + } + + // Determine prediction list based on mode cost + determine_prediction_list(bmcost, &best, &cost); + } + else // if (bslice) + { + best.pdir = 0; + cost += bmcost[LIST_0]; + } + + assign_enc_picture_params(currMB, mode, &best, 2 * block); + + //----- set reference frame and direction parameters ----- + set_block8x8_info(b8x8info, mode, block, &best); + + //--- set reference frames and motion vectors --- + if (mode>1 && block==0) + currSlice->set_ref_and_motion_vectors (currMB, motion, &best, block); + } // for (block=0; block<(mode==1?1:2); block++) + if (cost < min_cost) + { + md_best.mode = (byte) mode; + md_best.cost = cost; + currMB->best_mode = (short) mode; + min_cost = cost; + if (p_Inp->CtxAdptLagrangeMult == 1) + { + adjust_mb16x16_cost(currMB, cost); + } + } + } // if (enc_mb.valid[mode]) + } // for (mode=1; mode<4; mode++) + + if (enc_mb.valid[P8x8]) + { + currMB->valid_8x8 = FALSE; + + if (p_Inp->Transform8x8Mode) + { + ResetRD8x8Data(p_Vid, p_RDO->tr8x8); + currMB->luma_transform_size_8x8_flag = TRUE; //switch to 8x8 transform size + //=========================================================== + // Check 8x8 partition with transform size 8x8 + //=========================================================== + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (block = 0; block < 4; block++) + { + currSlice->submacroblock_mode_decision(currMB, &enc_mb, p_RDO->tr8x8, p_RDO->cofAC8x8ts[block], block, &cost); + if(!currMB->valid_8x8) + break; + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr8x8); + } + }// if (p_Inp->Transform8x8Mode) + + currMB->valid_4x4 = FALSE; + if (p_Inp->Transform8x8Mode != 2) + { + currMB->luma_transform_size_8x8_flag = FALSE; //switch to 8x8 transform size + ResetRD8x8Data(p_Vid, p_RDO->tr4x4); + //================================================================= + // Check 8x8, 8x4, 4x8 and 4x4 partitions with transform size 4x4 + //================================================================= + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (block = 0; block < 4; block++) + { + currSlice->submacroblock_mode_decision(currMB, &enc_mb, p_RDO->tr4x4, p_RDO->coefAC8x8[block], block, &cost); + if(!currMB->valid_4x4) + break; + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr4x4); + } + + }// if (p_Inp->Transform8x8Mode != 2) + + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + p_Vid->giRDOpt_B8OnlyFlag = FALSE; + } + } + else // if (!intra) + { + min_cost = DISTBLK_MAX; + } + + // Set Chroma mode + set_chroma_pred_mode(currMB, enc_mb, mb_available, chroma_pred_mode_range); + + //========= C H O O S E B E S T M A C R O B L O C K M O D E ========= + //------------------------------------------------------------------------- + for (currMB->c_ipred_mode = chroma_pred_mode_range[0]; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + { + // bypass if c_ipred_mode is not allowed + if ( (p_Vid->yuv_format != YUV400) && + ( ((!intra || !p_Inp->IntraDisableInterOnly) && p_Inp->ChromaIntraDisable == 1 && currMB->c_ipred_mode!=DC_PRED_8) + || (currMB->c_ipred_mode == VERT_PRED_8 && !mb_available[0]) + || (currMB->c_ipred_mode == HOR_PRED_8 && !mb_available[1]) + || (currMB->c_ipred_mode == PLANE_8 && (!mb_available[1] || !mb_available[0] || !mb_available[2])))) + continue; + + //===== GET BEST MACROBLOCK MODE ===== + for (index=0; index < max_index; index++) + { + mode = mb_mode_table[index]; + if (enc_mb.valid[mode]) + { + if (p_Vid->yuv_format != YUV400) + { + currMB->i16mode = 0; + } + + // Skip intra modes in inter slices if best mode is inter P444_joined) + { + if (p_Inp->SkipIntraInInterSlices && !intra && mode >= I16MB + && currMB->best_mode <=3 && currMB->best_cbp == 0 && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,5))) + continue; + } + else + { + if (p_Inp->SkipIntraInInterSlices) + { + if (!intra && mode >= I4MB) + { + if (currMB->best_mode <=3 && currMB->best_cbp == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp, 5))) + { + continue; + } + else if (currMB->best_mode == 0 && (currMB->min_rdcost < weighted_cost(enc_mb.lambda_mdfp,6))) + { + continue; + } + } + } + } + compute_mode_RD_cost(currMB, &enc_mb, (short) mode, &inter_skip); + + } + }// for (index=0; indexc_ipred_mode=DC_PRED_8; currMB->c_ipred_mode<=chroma_pred_mode_range[1]; currMB->c_ipred_mode++) + + restore_nz_coeff(currMB); + + if (rerun==0) + intra1 = IS_INTRA(currMB); + } // for (rerun=0; reruncbp); + currSlice->set_stored_mb_parameters (currMB); + + // Rate control + if(p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE) + rc_store_mad(currMB); + + //===== Decide if this MB will restrict the reference frames ===== + if (p_Inp->RestrictRef) + update_refresh_map(currMB, intra, intra1); +} + + diff --git a/lencod/src/md_low.c b/lencod/src/md_low.c new file mode 100644 index 0000000..93a95d6 --- /dev/null +++ b/lencod/src/md_low.c @@ -0,0 +1,688 @@ + +/*! + *************************************************************************** + * \file md_low.c + * + * \brief + * Main macroblock mode decision functions and helpers + * + ************************************************************************** + */ + +#include +#include +#include + +#include "global.h" +#include "rdopt_coding_state.h" +#include "mb_access.h" +#include "intrarefresh.h" +#include "image.h" +#include "transform8x8.h" +#include "ratectl.h" +#include "mode_decision.h" +#include "mode_decision_p8x8.h" +#include "fmo.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "macroblock.h" +#include "q_around.h" +#include "vlc.h" +#include "md_common.h" +#include "rdopt.h" +#include "memalloc.h" +#include "mc_prediction.h" +#include "rd_intra_jm.h" + +/*! + ************************************************************************ + * \brief + * RDOff decision between 4x4 and 8x8 transform + ************************************************************************ + */ +static int get_best_transform_8x8(Macroblock *currMB) +{ + if(currMB->p_Inp->Transform8x8Mode == 2) //always use the 8x8 transform + return 1; + else + { + VideoParameters *p_Vid = currMB->p_Vid; + RDOPTStructure *p_RDO = currMB->p_Slice->p_RDO; + + short diff16[4][16]; + short diff64[64]; + int pic_pix_y, pic_pix_x, i, j; + int mb_y, mb_x, block8x8; + distblk cost8x8=0, cost4x4=0; + + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + short *tmp64 = diff64; + short *tmp16[4]; //{diff16[0], diff16[1], diff16[2], diff16[3]}; + short source_pel, index; + + tmp16[0] = diff16[0]; + tmp16[1] = diff16[1]; + tmp16[2] = diff16[2]; + tmp16[3] = diff16[3]; + + mb_y = (block8x8 >> 1) << 3; + mb_x = (block8x8 & 0x01) << 3; + + //===== loop over 8x8 blocks ===== + pic_pix_y = currMB->opix_y; + pic_pix_x = currMB->pix_x; + //===== get displaced frame difference ====== + for (j = mb_y; j < 8 + mb_y; j++) + { + for (i = mb_x; i < 8 + mb_x; i++) + { + index = (short) (2 * ((j - mb_y)> 3) + ((i - mb_x)> 3)); + source_pel = p_Vid->pCurImg[pic_pix_y + j][pic_pix_x + i]; + *(tmp16[index])++ = (short) (source_pel - p_RDO->tr4x4->mpr8x8[j][i]); + *tmp64++ = (short) (source_pel - p_RDO->tr8x8->mpr8x8[j][i]); + } + } + + cost4x4 += p_Vid->distortion4x4 (diff16[0], DISTBLK_MAX); + cost4x4 += p_Vid->distortion4x4 (diff16[1], DISTBLK_MAX); + cost4x4 += p_Vid->distortion4x4 (diff16[2], DISTBLK_MAX); + cost4x4 += p_Vid->distortion4x4 (diff16[3], DISTBLK_MAX); + cost8x8 += p_Vid->distortion8x8 (diff64 , DISTBLK_MAX); + } + + return (cost8x8 < cost4x4); + } +} + +/*! +************************************************************************************* +* \brief +* Mode Decision for a macroblock +************************************************************************************* +*/ +void encode_one_macroblock_low (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + imgpel ***temp_img; // to temp store the Y data for 8x8 transform + + int block, mode, j; + RD_PARAMS enc_mb; + distblk bmcost[5] = {DISTBLK_MAX}; + distblk rd_cost = 0; + distblk cost = 0; + distblk min_cost = DISTBLK_MAX; + distblk cost_direct=0; + distblk cost8x8_direct = 0; + int have_direct=0; + int intra1 = 0; + int temp_cpb = 0; + byte best_transform_flag = (byte) 0; + short islice = (short) (currSlice->slice_type == I_SLICE); + short bslice = (short) (currSlice->slice_type == B_SLICE); + short pslice = (short) ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == SP_SLICE)); + short intra = (short) (islice || (currSlice->slice_type == SI_SLICE) || (pslice && currMB->mb_y == p_Vid->mb_y_upd && p_Vid->mb_y_upd!=p_Vid->mb_y_intra)); + int lambda_mf[3]; + Block8x8Info *b8x8info = p_Vid->b8x8info; + //int mb_available[3] = { 1, 1, 1}; + + char **ipredmodes = p_Vid->ipredmode; + MotionVector *allmvs = (currSlice->slice_type == I_SLICE || (currSlice->slice_type == SI_SLICE)) ? NULL: &currSlice->all_mv[0][0][0][0][0]; + int ****i4p; //for non-RD-opt. mode + imgpel **mb_pred = currSlice->mb_pred[0]; + + byte tmp_8x8_flag, tmp_no_mbpart; + + BestMode md_best; + Info8x8 best = init_info_8x8_struct(); + + init_md_best(&md_best); + + get_mem3Dpel(&temp_img, 3, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + intra |= RandomIntra (p_Vid, currMB->mbAddrX); // Forced Pseudo-Random Intra +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + intra |= (currSlice->num_ref_idx_active[LIST_0]==0 && currSlice->num_ref_idx_active[LIST_1]==0); // force intra if no ref available +#endif + + //===== Setup Macroblock encoding parameters ===== + init_enc_mb_params(currMB, &enc_mb, intra); + if (p_Inp->AdaptiveRounding) + { + reset_adaptive_rounding(p_Vid); + } + + if (currSlice->mb_aff_frame_flag) + { + reset_mb_nz_coeff(p_Vid, currMB->mbAddrX); + } + + //===== S T O R E C O D I N G S T A T E ===== + //--------------------------------------------------- + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm); + + if (!intra) + { + //===== set direct motion vectors ===== + currMB->best_mode = 10; // let us set best_mode to an intra mode to avoid possible bug with RDOQ + if (bslice && enc_mb.valid[0]) + { + currSlice->Get_Direct_Motion_Vectors (currMB); + } + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + get_initial_mb16x16_cost(currMB); + } + + //===== MOTION ESTIMATION FOR 16x16, 16x8, 8x16 BLOCKS ===== + for (mode = 1; mode < 4; mode++) + { + best.bipred = 0; + best.mode = (char) mode; + b8x8info->best[mode][0].bipred = 0; + if (enc_mb.valid[mode]) + { + for (cost=0, block=0; block<(mode==1?1:2); block++) + { + update_lambda_costs(currMB, &enc_mb, lambda_mf); + PartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- set 4x4 block indizes (for getting MV) --- + j = (block==1 && mode==2 ? 2 : 0); + + //--- get cost and reference frame for List 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, &enc_mb, bmcost, best.ref); + + if (bslice) + { + //--- get cost and reference frame for List 1 prediction --- + bmcost[LIST_1] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_1, block, mode, &enc_mb, bmcost, best.ref); + + // Compute bipredictive cost between best list 0 and best list 1 references + list_prediction_cost(currMB, BI_PRED, block, mode, &enc_mb, bmcost, best.ref); + + // currently Bi predictive ME is only supported for modes 1, 2, 3 and ref 0 + if (is_bipred_enabled(p_Vid, mode)) + { + list_prediction_cost(currMB, BI_PRED_L0, block, mode, &enc_mb, bmcost, 0); + list_prediction_cost(currMB, BI_PRED_L1, block, mode, &enc_mb, bmcost, 0); + } + else + { + bmcost[BI_PRED_L0] = DISTBLK_MAX; + bmcost[BI_PRED_L1] = DISTBLK_MAX; + } + + // Determine prediction list based on mode cost + determine_prediction_list(bmcost, &best, &cost); + } + else // if (bslice) + { + best.pdir = 0; + cost += bmcost[LIST_0]; + } + + assign_enc_picture_params(currMB, mode, &best, 2 * block); + + //----- set reference frame and direction parameters ----- + set_block8x8_info(b8x8info, mode, block, &best); + + //--- set reference frames and motion vectors --- + if (mode>1 && block==0) + currSlice->set_ref_and_motion_vectors (currMB, motion, &best, block); + } // for (block=0; block<(mode==1?1:2); block++) + + currMB->luma_transform_size_8x8_flag = FALSE; + if (p_Inp->Transform8x8Mode) //for inter rd-off, set 8x8 to do 8x8 transform + { + currSlice->set_modes_and_refs_for_blocks(currMB, (short) mode); + currMB->luma_transform_size_8x8_flag = (byte) transform_decision(currMB, -1, &cost); + } + + if (cost < min_cost) + { + currMB->best_mode = (short) mode; + min_cost = cost; + best_transform_flag = currMB->luma_transform_size_8x8_flag; + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + adjust_mb16x16_cost(currMB, cost); + } + } + } // if (enc_mb.valid[mode]) + } // for (mode=1; mode<4; mode++) + + if (enc_mb.valid[P8x8]) + { + //===== store coding state of macroblock ===== + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_mb); + memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + currMB->valid_8x8 = FALSE; + + if (p_Inp->Transform8x8Mode) + { + ResetRD8x8Data(p_Vid, p_RDO->tr8x8); + //=========================================================== + // Check 8x8 partition with transform size 8x8 + //=========================================================== + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (cost_direct = 0, block = 0; block < 4; block++) + { + submacroblock_mode_decision_low(currMB, &enc_mb, p_RDO->tr8x8, p_RDO->cofAC8x8ts[block], + &have_direct, block, &cost_direct, &cost, &cost8x8_direct, 1); + + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr8x8); + } + + currMB->luma_transform_size_8x8_flag = FALSE; //switch to 4x4 transform size + }// if (p_Inp->Transform8x8Mode) + + + if (p_Inp->Transform8x8Mode != 2) + { + ResetRD8x8Data(p_Vid, p_RDO->tr4x4); + //================================================================= + // Check 8x8, 8x4, 4x8 and 4x4 partitions with transform size 4x4 + //================================================================= + //===== LOOP OVER 8x8 SUB-PARTITIONS (Motion Estimation & Mode Decision) ===== + for (cost_direct = 0, block=0; block<4; block++) + { + submacroblock_mode_decision_low(currMB, &enc_mb, p_RDO->tr4x4, p_RDO->coefAC8x8[block], + &have_direct, block, &cost_direct, &cost, &cost8x8_direct, 0); + + set_subblock8x8_info(b8x8info, P8x8, block, p_RDO->tr4x4); + } + }// if (p_Inp->Transform8x8Mode != 2) + + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + //check cost for P8x8 for non-rdopt mode + if (((p_Inp->Transform8x8Mode < 2) && (p_RDO->tr4x4->mb_p8x8_cost < min_cost)) || + ((p_Inp->Transform8x8Mode > 0) && (p_RDO->tr8x8->mb_p8x8_cost < min_cost))) + { + currMB->best_mode = P8x8; + if (p_Inp->Transform8x8Mode == 2) + { + min_cost = p_RDO->tr8x8->mb_p8x8_cost; + currMB->luma_transform_size_8x8_flag = TRUE; + } + else if (p_Inp->Transform8x8Mode) + { + if (p_RDO->tr8x8->mb_p8x8_cost < p_RDO->tr4x4->mb_p8x8_cost) + { + min_cost = p_RDO->tr8x8->mb_p8x8_cost; + currMB->luma_transform_size_8x8_flag = TRUE; + } + else if(p_RDO->tr4x4->mb_p8x8_cost < p_RDO->tr8x8->mb_p8x8_cost) + { + min_cost = p_RDO->tr4x4->mb_p8x8_cost; + currMB->luma_transform_size_8x8_flag = FALSE; + } + else + { + if (get_best_transform_8x8(currMB) == 0) + { + min_cost = p_RDO->tr4x4->mb_p8x8_cost; + currMB->luma_transform_size_8x8_flag = FALSE; + } + else + { + min_cost = p_RDO->tr8x8->mb_p8x8_cost; + currMB->luma_transform_size_8x8_flag = TRUE; + } + } + } + else + { + min_cost = p_RDO->tr4x4->mb_p8x8_cost; + currMB->luma_transform_size_8x8_flag = FALSE; + } + }// if ((p_RDO->tr4x4->mb_p8x8_cost < min_cost || p_RDO->tr8x8->mb_p8x8_cost < min_cost)) + p_Vid->giRDOpt_B8OnlyFlag = FALSE; + } + + // Find a motion vector for the Skip mode + if(pslice) + FindSkipModeMotionVector (currMB); + } + else // if (!intra) + { + min_cost = DISTBLK_MAX; + } + + + //========= C H O O S E B E S T M A C R O B L O C K M O D E ========= + //------------------------------------------------------------------------- + tmp_8x8_flag = currMB->luma_transform_size_8x8_flag; //save 8x8_flag + tmp_no_mbpart = currMB->NoMbPartLessThan8x8Flag; //save no-part-less + if ((p_Vid->yuv_format != YUV400) && (p_Vid->yuv_format != YUV444)) + // precompute all chroma intra prediction modes + currSlice->intra_chroma_prediction(currMB, NULL, NULL, NULL); + + if (enc_mb.valid[0] && bslice) // check DIRECT MODE + { + if(have_direct) + { + switch(p_Inp->Transform8x8Mode) + { + case 1: // Mixture of 8x8 & 4x4 transform + cost = ((cost8x8_direct < cost_direct) || !(enc_mb.valid[5] && enc_mb.valid[6] && enc_mb.valid[7])) + ? cost8x8_direct : cost_direct; + break; + case 2: // 8x8 Transform only + cost = cost8x8_direct; + break; + default: // 4x4 Transform only + cost = cost_direct; + break; + } + } + else + { //!have_direct + cost = GetDirectCostMB (currMB); + } + if (cost!=DISTBLK_MAX) + { + cost -= weighted_cost(enc_mb.lambda_mdfp, 16); + } + + if (cost <= min_cost) + { + if(p_Vid->active_sps->direct_8x8_inference_flag && p_Inp->Transform8x8Mode) + { + if(p_Inp->Transform8x8Mode==2) + currMB->luma_transform_size_8x8_flag = TRUE; + else + { + if(cost8x8_direct < cost_direct) + currMB->luma_transform_size_8x8_flag = TRUE; + else + currMB->luma_transform_size_8x8_flag = FALSE; + } + } + else + currMB->luma_transform_size_8x8_flag = FALSE; + + //Rate control + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + min_cost = cost; + currMB->best_mode = 0; + tmp_8x8_flag = currMB->luma_transform_size_8x8_flag; + } + else + { + currMB->luma_transform_size_8x8_flag = tmp_8x8_flag; // restore if not best + currMB->NoMbPartLessThan8x8Flag = tmp_no_mbpart; // restore if not best + } + } + currMB->min_rdcost = min_cost; + if (enc_mb.valid[I8MB]) // check INTRA8x8 + { + currMB->luma_transform_size_8x8_flag = TRUE; // at this point cost will ALWAYS be less than min_cost + + currMB->mb_type = currMB->ar_mode = I8MB; + temp_cpb = mode_decision_for_I8x8_MB (currMB, enc_mb.lambda_mdfp, &rd_cost); + + if (rd_cost <= currMB->min_rdcost) //HYU_NOTE. bug fix. 08/15/07 + { + currMB->cbp = temp_cpb; + if (p_Vid->P444_joined) + { + currSlice->curr_cbp[0] = currSlice->cmp_cbp[1]; + currSlice->curr_cbp[1] = currSlice->cmp_cbp[2]; + } + + if(enc_mb.valid[I4MB]) + { + //coeffs + if (p_Inp->Transform8x8Mode != 2) + { + i4p = p_RDO->cofAC; + p_RDO->cofAC = currSlice->cofAC; + currSlice->cofAC = i4p; + } + } + + copy_image_data_16x16(temp_img[0], &p_Vid->enc_picture->imgY[currMB->pix_y], 0, currMB->pix_x); + + if (p_Vid->P444_joined) + { + copy_image_data_16x16(temp_img[1], &p_Vid->enc_picture->imgUV[0][currMB->pix_y], 0, currMB->pix_x); + copy_image_data_16x16(temp_img[2], &p_Vid->enc_picture->imgUV[1][currMB->pix_y], 0, currMB->pix_x); + } + + //Rate control + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + currMB->min_rdcost = rd_cost; + currMB->best_mode = I8MB; + tmp_8x8_flag = currMB->luma_transform_size_8x8_flag; + } + else + { + currMB->luma_transform_size_8x8_flag = tmp_8x8_flag; // restore if not best + if (p_Vid->P444_joined) + { + currMB->cbp |= currSlice->curr_cbp[0]; + currMB->cbp |= currSlice->curr_cbp[1]; + currSlice->cmp_cbp[1] = currMB->cbp; + currSlice->cmp_cbp[2] = currMB->cbp; + } + } + } + + if (enc_mb.valid[I4MB]) // check INTRA4x4 + { + currMB->luma_transform_size_8x8_flag = FALSE; + currMB->mb_type = currMB->ar_mode = I4MB; + temp_cpb = mode_decision_for_I4x4_MB (currMB, enc_mb.lambda_mdfp, &rd_cost); + if (rd_cost <= currMB->min_rdcost) + { + currMB->cbp = temp_cpb; + + //Rate control + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + + currMB->min_rdcost = rd_cost; + currMB->best_mode = I4MB; + tmp_8x8_flag = currMB->luma_transform_size_8x8_flag; + } + else + { + currMB->luma_transform_size_8x8_flag = tmp_8x8_flag; // restore if not best + if (p_Vid->P444_joined) + { + currMB->cbp |= currSlice->curr_cbp[0]; + currMB->cbp |= currSlice->curr_cbp[1]; + currSlice->cmp_cbp[1] = currMB->cbp; + currSlice->cmp_cbp[2] = currMB->cbp; + } + //coeffs + i4p = p_RDO->cofAC; + p_RDO->cofAC = currSlice->cofAC; + currSlice->cofAC=i4p; + } + } + if (enc_mb.valid[I16MB]) // check INTRA16x16 + { + rd_cost = find_best_mode_I16x16_MB (currMB, enc_mb.lambda_mdfp, currMB->min_rdcost); + + if (rd_cost < currMB->min_rdcost) + { + //Rate control + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, currSlice->mpr_16x16[0][(short) currMB->i16mode]); + + currMB->best_mode = I16MB; + currMB->min_rdcost = rd_cost; + currMB->cbp = currMB->residual_transform_quant_luma_16x16 (currMB, PLANE_Y); + + if (p_Vid->P444_joined) + { + select_plane(p_Vid, PLANE_U); + currSlice->cmp_cbp[1] = currMB->residual_transform_quant_luma_16x16(currMB, PLANE_U); + select_plane(p_Vid, PLANE_V); + currSlice->cmp_cbp[2] = currMB->residual_transform_quant_luma_16x16(currMB, PLANE_V); + + select_plane(p_Vid, PLANE_Y); + currMB->cbp |= currSlice->cmp_cbp[1]; + currMB->cbp |= currSlice->cmp_cbp[2]; + currSlice->cmp_cbp[1] = currMB->cbp; + currSlice->cmp_cbp[2] = currMB->cbp; + } + + } + else + { + currMB->luma_transform_size_8x8_flag = tmp_8x8_flag; // restore + currMB->NoMbPartLessThan8x8Flag = tmp_no_mbpart; // restore + } + } + + intra1 = IS_INTRA(currMB); + + //===== S E T F I N A L M A C R O B L O C K P A R A M E T E R S ====== + //--------------------------------------------------------------------------- + { + //===== set parameters for chosen mode ===== + currSlice->set_modes_and_refs_for_blocks (currMB, currMB->best_mode); + + if (currMB->best_mode == P8x8) + { + if (currMB->luma_transform_size_8x8_flag && (p_RDO->tr8x8->cbp8x8 == 0) && p_Inp->Transform8x8Mode != 2) + currMB->luma_transform_size_8x8_flag = FALSE; + + currSlice->set_coeff_and_recon_8x8 (currMB); + + memset(currMB->intra_pred_modes, DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + for (j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memset(&ipredmodes[j][currMB->block_x], DC_PRED, BLOCK_MULTIPLE * sizeof(char)); + } + else + { + //===== set parameters for chosen mode ===== + if (currMB->best_mode == I8MB) + { + memcpy(currMB->intra_pred_modes,currMB->intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memcpy(&p_Vid->ipredmode[j][currMB->block_x],&p_Vid->ipredmode8x8[j][currMB->block_x], BLOCK_MULTIPLE * sizeof(char)); + + //--- restore reconstruction for 8x8 transform --- + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], temp_img[0], currMB->pix_x, 0); + + if (p_Vid->P444_joined) + { + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], temp_img[1], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], temp_img[2], currMB->pix_x, 0); + } + } + + if ((currMB->best_mode!=I4MB)&&(currMB->best_mode != I8MB)) + { + memset(currMB->intra_pred_modes,DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memset(&ipredmodes[j][currMB->block_x],DC_PRED, BLOCK_MULTIPLE * sizeof(char)); + currMB->ar_mode = currMB->best_mode; + + if (currMB->best_mode!=I16MB) + { + if((currMB->best_mode >= 1) && (currMB->best_mode <= 3)) + currMB->luma_transform_size_8x8_flag = best_transform_flag; + + currSlice->luma_residual_coding(currMB); + if (currSlice->P444_joined) + { + if((currMB->cbp==0 && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0) &&(currMB->best_mode == 0)) + currMB->luma_transform_size_8x8_flag = FALSE; + } + else + { + if((currMB->cbp==0)&&(currMB->best_mode == 0)) + currMB->luma_transform_size_8x8_flag = FALSE; + } + + //Rate control + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, mb_pred); + } + } + } + //check luma cbp for transform size flag + if (((currMB->cbp&15) == 0) && currMB->mb_type != I4MB && currMB->mb_type != I8MB) + currMB->luma_transform_size_8x8_flag = FALSE; + + // precompute all chroma intra prediction modes + if ((p_Vid->yuv_format != YUV400) && (p_Vid->yuv_format != YUV444)) + currSlice->intra_chroma_prediction(currMB, NULL, NULL, NULL); + + currMB->i16offset = 0; + + if ((p_Vid->yuv_format != YUV400) && (p_Vid->yuv_format != YUV444)) + currSlice->chroma_residual_coding (currMB); + + if (currMB->best_mode == I16MB) + { + currMB->i16offset = I16Offset (currMB->cbp, currMB->i16mode); + } + + currSlice->set_motion_vectors_mb (currMB); + + //===== check for SKIP mode ===== + if(p_Vid->P444_joined) + { + if ((pslice) && currMB->best_mode == 1 && currMB->cbp==0 && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0 && + motion[currMB->block_y][currMB->block_x].ref_idx[LIST_0] == 0 && + motion[currMB->block_y][currMB->block_x].mv [LIST_0].mv_x == allmvs->mv_x && + motion[currMB->block_y][currMB->block_x].mv [LIST_0].mv_y == allmvs->mv_y) + { + currMB->mb_type = currMB->b8x8[0].mode = currMB->b8x8[1].mode = currMB->b8x8[2].mode = currMB->b8x8[3].mode = 0; + currMB->luma_transform_size_8x8_flag = FALSE; + } + } + else if ((pslice) && currMB->best_mode == 1 && currMB->cbp==0 && + motion[currMB->block_y][currMB->block_x].ref_idx[LIST_0] == 0 && + motion[currMB->block_y][currMB->block_x].mv [LIST_0].mv_x == allmvs->mv_x && + motion[currMB->block_y][currMB->block_x].mv [LIST_0].mv_y == allmvs->mv_y) + { + currMB->mb_type = currMB->b8x8[0].mode = currMB->b8x8[1].mode = currMB->b8x8[2].mode = currMB->b8x8[3].mode = 0; + currMB->luma_transform_size_8x8_flag = FALSE; + } + + if (currSlice->mb_aff_frame_flag || (p_Inp->UseRDOQuant && currSlice->RDOQ_QP_Num > 1)) + set_mbaff_parameters(currMB); + } + + // Rate control + if(p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE) + rc_store_mad(currMB); + + //===== Decide if this MB will restrict the reference frames ===== + if (p_Inp->RestrictRef) + update_refresh_map(currMB, intra, intra1); + + + /*update adaptive rounding offset p_Inp*/ + if (p_Vid->AdaptiveRounding) + { + update_offset_params(currMB, currMB->best_mode, currMB->luma_transform_size_8x8_flag); + } + + free_mem3Dpel(temp_img); +} + diff --git a/lencod/src/me_distortion.c b/lencod/src/me_distortion.c new file mode 100644 index 0000000..634b8f6 --- /dev/null +++ b/lencod/src/me_distortion.c @@ -0,0 +1,1565 @@ +/*! +************************************************************************************* +* \file me_distortion.c +* +* \brief +* Motion estimation error calculation functions +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "refbuf.h" +#include "mv_search.h" +#include "me_distortion.h" + + +//#define CHECKOVERFLOW(mcost) assert(mcost>=0) +#define CHECKOVERFLOW(mcost) + +/*! +*********************************************************************** +* \brief +* Calculate SAD +*********************************************************************** +*/ +distblk distortion4x4SAD(short* diff, distblk min_dist) +{ + int distortion = 0, k; + for (k = 0; k < 16; k++) + { + distortion += iabs(*diff++); + } + return (dist_scale((distblk) distortion)); +} + +/*! +*********************************************************************** +* \brief +* Calculate SSE 4x4 +*********************************************************************** +*/ +distblk distortion4x4SSE(short* diff, distblk min_dist) +{ + int distortion = 0, k; + for (k = 0; k < 16; k++) + { + distortion += iabs2(*diff++); + } + return (dist_scale((distblk) distortion)); +} + +/*! +*********************************************************************** +* \brief +* Calculate SATD +*********************************************************************** +*/ +distblk distortion4x4SATD(short* diff, distblk min_dist) +{ + distblk i64Ret = HadamardSAD4x4( diff ); + return (dist_scale(i64Ret)); +} + +/*! +*********************************************************************** +* \brief +* Calculate SAD for 8x8 (with a threshold) +*********************************************************************** +*/ +distblk distortion8x8SADthres(short* diff, distblk min_cost) +{ + int distortion = 0; + int i, j; + int imin_cost = dist_down(min_cost); + + for (j = 0; j < 8; j++) + { + for (i = 0; i < 8; i++) + { + distortion += iabs(*diff++); + } + if (distortion > imin_cost) + break; + } + + return (dist_scale((distblk) distortion)); +} + +/*! +*********************************************************************** +* \brief +* Calculate SAD for 8x8 +*********************************************************************** +*/ +distblk distortion8x8SAD(short* diff, distblk min_dist) +{ + int distortion = 0; + int k; + + for (k = 0; k < 64; k++) + { + distortion += iabs(*diff++); + } + return (dist_scale((distblk) distortion)); +} + +/*! +*********************************************************************** +* \brief +* Calculate SSE for 8x8 +*********************************************************************** +*/ +distblk distortion8x8SSE(short* diff, distblk min_dist) +{ + distblk distortion = 0; + int k; + for (k = 0; k < 64; k++) + { + distortion += iabs2(*diff++); + } + return (dist_scale(distortion)); +} + +/*! +*********************************************************************** +* \brief +* Calculate SATD for 8x8 +*********************************************************************** +*/ +distblk distortion8x8SATD(short* diff, distblk min_dist) +{ + distblk i64Ret = HadamardSAD8x8( diff ); + return (dist_scale(i64Ret)); +} + +void select_distortion(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + switch(p_Inp->ModeDecisionMetric) + { + case ERROR_SAD: + p_Vid->distortion4x4 = distortion4x4SAD; + p_Vid->distortion8x8 = distortion8x8SAD; + break; + case ERROR_SSE: + p_Vid->distortion4x4 = distortion4x4SSE; + p_Vid->distortion8x8 = distortion8x8SSE; + break; + case ERROR_SATD : + default: + p_Vid->distortion4x4 = distortion4x4SATD; + p_Vid->distortion8x8 = distortion8x8SATD; + break; + } +} + + +/*! +*********************************************************************** +* \brief +* Calculate 4x4 Hadamard-Transformed SAD +*********************************************************************** +*/ +int HadamardSAD4x4 (short* diff) +{ + int k, satd = 0; + int m[16], d[16]; + + /*===== hadamard transform =====*/ + m[ 0] = diff[ 0] + diff[12]; + m[ 1] = diff[ 1] + diff[13]; + m[ 2] = diff[ 2] + diff[14]; + m[ 3] = diff[ 3] + diff[15]; + m[ 4] = diff[ 4] + diff[ 8]; + m[ 5] = diff[ 5] + diff[ 9]; + m[ 6] = diff[ 6] + diff[10]; + m[ 7] = diff[ 7] + diff[11]; + m[ 8] = diff[ 4] - diff[ 8]; + m[ 9] = diff[ 5] - diff[ 9]; + m[10] = diff[ 6] - diff[10]; + m[11] = diff[ 7] - diff[11]; + m[12] = diff[ 0] - diff[12]; + m[13] = diff[ 1] - diff[13]; + m[14] = diff[ 2] - diff[14]; + m[15] = diff[ 3] - diff[15]; + + d[ 0] = m[ 0] + m[ 4]; + d[ 1] = m[ 1] + m[ 5]; + d[ 2] = m[ 2] + m[ 6]; + d[ 3] = m[ 3] + m[ 7]; + d[ 4] = m[ 8] + m[12]; + d[ 5] = m[ 9] + m[13]; + d[ 6] = m[10] + m[14]; + d[ 7] = m[11] + m[15]; + d[ 8] = m[ 0] - m[ 4]; + d[ 9] = m[ 1] - m[ 5]; + d[10] = m[ 2] - m[ 6]; + d[11] = m[ 3] - m[ 7]; + d[12] = m[12] - m[ 8]; + d[13] = m[13] - m[ 9]; + d[14] = m[14] - m[10]; + d[15] = m[15] - m[11]; + + m[ 0] = d[ 0] + d[ 3]; + m[ 1] = d[ 1] + d[ 2]; + m[ 2] = d[ 1] - d[ 2]; + m[ 3] = d[ 0] - d[ 3]; + m[ 4] = d[ 4] + d[ 7]; + m[ 5] = d[ 5] + d[ 6]; + m[ 6] = d[ 5] - d[ 6]; + m[ 7] = d[ 4] - d[ 7]; + m[ 8] = d[ 8] + d[11]; + m[ 9] = d[ 9] + d[10]; + m[10] = d[ 9] - d[10]; + m[11] = d[ 8] - d[11]; + m[12] = d[12] + d[15]; + m[13] = d[13] + d[14]; + m[14] = d[13] - d[14]; + m[15] = d[12] - d[15]; + + d[ 0] = m[ 0] + m[ 1]; + d[ 1] = m[ 0] - m[ 1]; + d[ 2] = m[ 2] + m[ 3]; + d[ 3] = m[ 3] - m[ 2]; + d[ 4] = m[ 4] + m[ 5]; + d[ 5] = m[ 4] - m[ 5]; + d[ 6] = m[ 6] + m[ 7]; + d[ 7] = m[ 7] - m[ 6]; + d[ 8] = m[ 8] + m[ 9]; + d[ 9] = m[ 8] - m[ 9]; + d[10] = m[10] + m[11]; + d[11] = m[11] - m[10]; + d[12] = m[12] + m[13]; + d[13] = m[12] - m[13]; + d[14] = m[14] + m[15]; + d[15] = m[15] - m[14]; + + //===== sum up ===== + // Table lookup is faster than abs macro + for (k=0; k<16; ++k) + { + satd += iabs(d [k]); + } + + + return ((satd+1)>>1); +} + +/*! +*********************************************************************** +* \brief +* Calculate 8x8 Hadamard-Transformed SAD +*********************************************************************** +*/ +int HadamardSAD8x8 (short* diff) +{ + int i, j, jj, sad=0; + + // Hadamard related arrays + int m1[8][8], m2[8][8], m3[8][8]; + + + //horizontal + for (j=0; j < 8; j++) + { + jj = j << 3; + m2[j][0] = diff[jj ] + diff[jj+4]; + m2[j][1] = diff[jj+1] + diff[jj+5]; + m2[j][2] = diff[jj+2] + diff[jj+6]; + m2[j][3] = diff[jj+3] + diff[jj+7]; + m2[j][4] = diff[jj ] - diff[jj+4]; + m2[j][5] = diff[jj+1] - diff[jj+5]; + m2[j][6] = diff[jj+2] - diff[jj+6]; + m2[j][7] = diff[jj+3] - diff[jj+7]; + + m1[j][0] = m2[j][0] + m2[j][2]; + m1[j][1] = m2[j][1] + m2[j][3]; + m1[j][2] = m2[j][0] - m2[j][2]; + m1[j][3] = m2[j][1] - m2[j][3]; + m1[j][4] = m2[j][4] + m2[j][6]; + m1[j][5] = m2[j][5] + m2[j][7]; + m1[j][6] = m2[j][4] - m2[j][6]; + m1[j][7] = m2[j][5] - m2[j][7]; + + m2[j][0] = m1[j][0] + m1[j][1]; + m2[j][1] = m1[j][0] - m1[j][1]; + m2[j][2] = m1[j][2] + m1[j][3]; + m2[j][3] = m1[j][2] - m1[j][3]; + m2[j][4] = m1[j][4] + m1[j][5]; + m2[j][5] = m1[j][4] - m1[j][5]; + m2[j][6] = m1[j][6] + m1[j][7]; + m2[j][7] = m1[j][6] - m1[j][7]; + } + + //vertical + for (i=0; i < 8; i++) + { + m3[0][i] = m2[0][i] + m2[4][i]; + m3[1][i] = m2[1][i] + m2[5][i]; + m3[2][i] = m2[2][i] + m2[6][i]; + m3[3][i] = m2[3][i] + m2[7][i]; + m3[4][i] = m2[0][i] - m2[4][i]; + m3[5][i] = m2[1][i] - m2[5][i]; + m3[6][i] = m2[2][i] - m2[6][i]; + m3[7][i] = m2[3][i] - m2[7][i]; + + m1[0][i] = m3[0][i] + m3[2][i]; + m1[1][i] = m3[1][i] + m3[3][i]; + m1[2][i] = m3[0][i] - m3[2][i]; + m1[3][i] = m3[1][i] - m3[3][i]; + m1[4][i] = m3[4][i] + m3[6][i]; + m1[5][i] = m3[5][i] + m3[7][i]; + m1[6][i] = m3[4][i] - m3[6][i]; + m1[7][i] = m3[5][i] - m3[7][i]; + + m2[0][i] = m1[0][i] + m1[1][i]; + m2[1][i] = m1[0][i] - m1[1][i]; + m2[2][i] = m1[2][i] + m1[3][i]; + m2[3][i] = m1[2][i] - m1[3][i]; + m2[4][i] = m1[4][i] + m1[5][i]; + m2[5][i] = m1[4][i] - m1[5][i]; + m2[6][i] = m1[6][i] + m1[7][i]; + m2[7][i] = m1[6][i] - m1[7][i]; + } + for (j=0; j < 8; j++) + for (i=0; i < 8; i++) + sad += iabs (m2[j][i]); + + return ((sad+2)>>2); +} + +/*! +************************************************************************ +* \brief +* SAD computation +************************************************************************ +*/ +distblk computeSAD(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand) +{ + int mcost = 0; + int imin_cost = dist_down(min_mcost); + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; +#if (JM_MEM_DISTORTION) + int *imgpel_abs = p_Vid->imgpel_abs; +#endif + + imgpel *src_line, *ref_line; + src_line = mv_block->orig_pic[0]; + ref_line = UMVLine4X (ref1, cand->mv_y, cand->mv_x); + for (y=0; y imin_cost) + return (dist_scale_f((distblk)mcost)); + ref_line += pad_size_x; + } + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; // chroma me cost + + for (k=0; k < 2; k++) + { + src_line = mv_block->orig_pic[k+1]; + ref_line = UMVLine8X_chroma ( ref1, k+1, cand->mv_y, cand->mv_x); + mcr_cost = 0; + + for (y = 0; y < blocksize_y_cr; y++) + { + for (x = 0; x < blocksize_x_cr; x += 2) + { +#if (JM_MEM_DISTORTION) + mcr_cost += imgpel_abs[ *src_line++ - *ref_line++ ]; + mcr_cost += imgpel_abs[ *src_line++ - *ref_line++ ]; +#else + mcr_cost += iabs( *src_line++ - *ref_line++ ); + mcr_cost += iabs( *src_line++ - *ref_line++ ); +#endif + } + ref_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost >imin_cost) + return (dist_scale_f((distblk)mcost)); + } + } + + CHECKOVERFLOW(mcost); + return (dist_scale((distblk)mcost)); +} + +/*! +************************************************************************ +* \brief +* SAD computation for weighted samples +************************************************************************ +*/ +distblk computeSADWP(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int mcost = 0; + int imin_cost = dist_down(min_mcost); + int y, x; + int weighted_pel; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; + int max_imgpel_value = p_Vid->max_imgpel_value; + short weight = mv_block->weight_luma; + short offset = mv_block->offset_luma; + + int wp_luma_round = currSlice->wp_luma_round; + short luma_log_weight_denom = currSlice->luma_log_weight_denom; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref_line = UMVLine4X (ref1, cand->mv_y, cand->mv_x); + + for (y=0; y> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + } + if(mcost > imin_cost) + return (dist_scale_f((distblk)mcost)); + ref_line += pad_size_x; + } + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + int wp_chroma_round = currSlice->wp_chroma_round; + short chroma_log_weight_denom = currSlice->chroma_log_weight_denom; + + for (k=0; k < 2; k++) + { + weight = mv_block->weight_cr[k]; + offset = mv_block->offset_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref_line = UMVLine8X_chroma ( ref1, k+1, cand->mv_y, cand->mv_x); + for (y=0; y> chroma_log_weight_denom) + offset); + mcr_cost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value_uv, ((weight * *ref_line++ + wp_chroma_round) >> chroma_log_weight_denom) + offset); + mcr_cost += iabs( *src_line++ - weighted_pel ); + } + ref_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost >imin_cost) + return (dist_scale_f((distblk)mcost)); + } + } + + CHECKOVERFLOW(mcost); + return (dist_scale((distblk)mcost)); +} + +/*! +************************************************************************ +* \brief +* BiPred SAD computation (no weights) +************************************************************************ +*/ +distblk computeBiPredSAD1(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; +#if (JM_MEM_DISTORTION) + int *imgpel_abs = p_Vid->imgpel_abs; +#endif + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref2_line = UMVLine4X(ref2, cand2->mv_y, cand2->mv_x); + imgpel *ref1_line = UMVLine4X(ref1, cand1->mv_y, cand1->mv_x); + + for (y = 0; y < blocksize_y; y++) + { + for (x = 0; x < blocksize_x; x+=4) + { +#if (JM_MEM_DISTORTION) + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; +#else + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); +#endif + } + if(mcost > imin_cost) + return (dist_scale_f((distblk)mcost)); + + ref2_line += pad_size_x; + ref1_line += pad_size_x; + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + + for (k=1; k<3; k++) + { + mcr_cost = 0; + src_line = mv_block->orig_pic[k]; + ref2_line = UMVLine8X_chroma ( ref2, k, cand2->mv_y, cand2->mv_x); + ref1_line = UMVLine8X_chroma ( ref1, k, cand1->mv_y, cand1->mv_x); + + for (y=0; y>1); + mcr_cost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcr_cost += iabs(bi_diff); + } + ref2_line += cr_pad_size_x; + ref1_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost > imin_cost) + return (dist_scale_f((distblk)mcost)); + } + } + + CHECKOVERFLOW(mcost); + return (dist_scale((distblk)mcost)); +} + +/*! +************************************************************************ +* \brief +* BiPred SAD computation (with weights) +************************************************************************ +*/ +distblk computeBiPredSAD2(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + int denom = currSlice->luma_log_weight_denom + 1; + int lround = 2 * currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + int y,x; + int weighted_pel, pixel1, pixel2; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + short weight1 = mv_block->weight1; + short weight2 = mv_block->weight2; + short offsetBi = mv_block->offsetBi; + + int pad_size_x = p_Vid->padded_size_x - blocksize_x; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref2_line = UMVLine4X(ref2, cand2->mv_y, cand2->mv_x); + imgpel *ref1_line = UMVLine4X(ref1, cand1->mv_y, cand1->mv_x); + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + } + + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + ref2_line += pad_size_x; + ref1_line += pad_size_x; + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + for (k=0; k<2; k++) + { + weight1 = mv_block->weight1_cr[k]; + weight2 = mv_block->weight2_cr[k]; + offsetBi = mv_block->offsetBi_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref2_line = UMVLine8X_chroma ( ref2, k+1, cand2->mv_y, cand2->mv_x); + ref1_line = UMVLine8X_chroma ( ref1, k+1, cand1->mv_y, cand1->mv_x); + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value_uv, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += iabs(bi_diff); + } + ref2_line += cr_pad_size_x; + ref1_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* SAD computation _with_ Hadamard Transform +************************************************************************ +*/ +distblk computeSATD(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int src_size_x, src_size_mul; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + imgpel *src_tmp = mv_block->orig_pic[0]; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref_line; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = blocksize_x - BLOCK_SIZE; + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_SP)) + { + for (x=0; xmv_x + (x<<2)); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + + ref_line += p_Vid->padded_size_x_m4x4; + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_8x8_SP) ) + { + for (x=0; xmv_x + (x<<2)); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + + ref_line += p_Vid->padded_size_x_m8x8; + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* SAD computation of weighted samples _with_ Hadamard Transform +************************************************************************ +*/ +distblk computeSATDWP(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int weighted_pel; + int src_size_x, src_size_mul; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + imgpel *src_tmp = mv_block->orig_pic[0]; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + short luma_log_weight_denom = currSlice->luma_log_weight_denom; + short weight = mv_block->weight_luma; + short offset = mv_block->offset_luma; + + int wp_luma_round = currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref_line; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE); + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_SP)) + { + for (x=0; xmv_x + (x<<2)); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + + ref_line += p_Vid->padded_size_x_m4x4; + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_8x8_SP) ) + { + for (x=0; xmv_x + (x<<2)); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + + ref_line += p_Vid->padded_size_x_m8x8; + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* BiPred (w/o weights) SATD computation +************************************************************************ +*/ +distblk computeBiPredSATD1(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int src_size_x, src_size_mul; + imgpel *src_tmp = mv_block->orig_pic[0]; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref1_line, *ref2_line; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE); + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y=0; y<(blocksize_y<<2); y += (BLOCK_SIZE_SP)) + { + for (x=0; xmv_y + y, cand2->mv_x + (x<<2)); + ref1_line = UMVLine4X(ref1, cand1->mv_y + y, cand1->mv_x + (x<<2)); + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + + ref1_line += p_Vid->padded_size_x_m4x4; + ref2_line += p_Vid->padded_size_x_m4x4; + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y=0; y<(blocksize_y << 2); y += BLOCK_SIZE_8x8_SP ) + { + int y_pos2 = cand2->mv_y + y; + int y_pos1 = cand1->mv_y + y; + for (x=0; xmv_x + (x<<2)); + ref1_line = UMVLine4X(ref1, y_pos1, cand1->mv_x + (x<<2)); + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + + ref1_line += p_Vid->padded_size_x_m8x8; + ref2_line += p_Vid->padded_size_x_m8x8; + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* BiPred (w/ weights) SATD computation +************************************************************************ +*/ +distblk computeBiPredSATD2(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int weighted_pel, pixel1, pixel2; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + int denom = currSlice->luma_log_weight_denom + 1; + int lround = 2 * currSlice->wp_luma_round; + short weight1 = mv_block->weight1; + short weight2 = mv_block->weight2; + short offsetBi = mv_block->offsetBi; + + + int max_imgpel_value = p_Vid->max_imgpel_value; + int src_size_x, src_size_mul; + imgpel *src_tmp = mv_block->orig_pic[0]; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref1_line, *ref2_line; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE); + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y=0; y<(blocksize_y<<2); y += BLOCK_SIZE_SP) + { + for (x=0; xmv_y + y, cand2->mv_x + (x<<2)); + ref1_line = UMVLine4X(ref1, cand1->mv_y + y, cand1->mv_x + (x<<2)); + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + // 0 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 1 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 2 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 3 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + + ref1_line += p_Vid->padded_size_x_m4x4; + ref2_line += p_Vid->padded_size_x_m4x4; + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y=0; y < (blocksize_y << 2); y += BLOCK_SIZE_8x8_SP ) + { + int y_pos2 = cand2->mv_y + y; + int y_pos1 = cand1->mv_y + y; + for (x=0; xmv_x + (x<<2)); + ref1_line = UMVLine4X(ref1, y_pos1, cand1->mv_x + (x<<2)); + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + // 0 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 1 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 2 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 3 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 4 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 5 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 6 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 7 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line) - weighted_pel); + + ref1_line += p_Vid->padded_size_x_m8x8; + ref2_line += p_Vid->padded_size_x_m8x8; + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* SSE computation +************************************************************************ +*/ +distblk computeSSE(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref_line = UMVLine4X (ref1, cand->mv_y, cand->mv_x); + + for (y=0; y imin_cost) + return dist_scale_f((distblk)mcost); + ref_line += pad_size_x; + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + + for (k=0; k<2; k++) + { + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref_line = UMVLine8X_chroma ( ref1, k+1, cand->mv_y, cand->mv_x); + for (y=0; yChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + + +/*! +************************************************************************ +* \brief +* SSE computation of weighted samples +************************************************************************ +*/ +distblk computeSSEWP(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y,x; + int weighted_pel; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + short weight = mv_block->weight_luma; + short offset = mv_block->offset_luma; + + int wp_luma_round = currSlice->wp_luma_round; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; + int max_imgpel_value = p_Vid->max_imgpel_value; + short luma_log_weight_denom = currSlice->luma_log_weight_denom; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref_line = UMVLine4X (ref1, cand->mv_y, cand->mv_x); + + for (y=0; y> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + } + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + ref_line += pad_size_x; + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + // These could be made global to reduce computations + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + int wp_chroma_round = currSlice->wp_chroma_round; + short chroma_log_weight_denom = currSlice->chroma_log_weight_denom; + + for (k=0; k<2; k++) + { + weight = mv_block->weight_cr[k]; + offset = mv_block->offset_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref_line = UMVLine8X_chroma ( ref1, k+1, cand->mv_y, cand->mv_x); + for (y=0; y> chroma_log_weight_denom) + offset); + mcr_cost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value_uv, ((weight * *ref_line++ + wp_chroma_round) >> chroma_log_weight_denom) + offset); + mcr_cost += iabs2( *src_line++ - weighted_pel ); + } + ref_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* BiPred SSE computation (no weights) +************************************************************************ +*/ +distblk computeBiPredSSE1(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref2_line = UMVLine4X(ref2, cand2->mv_y, cand2->mv_x); + imgpel *ref1_line = UMVLine4X(ref1, cand1->mv_y, cand1->mv_x); + + for (y = 0; y < blocksize_y; y++) + { + for (x = 0; x < blocksize_x; x+=4) + { + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + } + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + + ref2_line += pad_size_x; + ref1_line += pad_size_x; + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + + for (k=0; k<2; k++) + { + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref2_line = UMVLine8X_chroma ( ref2, k+1, cand2->mv_y, cand2->mv_x); + ref1_line = UMVLine8X_chroma ( ref1, k+1, cand1->mv_y, cand1->mv_x); + + for (y=0; y>1); + mcr_cost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcr_cost += iabs2(bi_diff); + } + ref2_line += cr_pad_size_x; + ref1_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + + +/*! +************************************************************************ +* \brief +* BiPred SSE computation (with weights) +************************************************************************ +*/ +distblk computeBiPredSSE2(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + int denom = currSlice->luma_log_weight_denom + 1; + int lround = 2 * currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + int y,x; + int weighted_pel, pixel1, pixel2; + short weight1 = mv_block->weight1; + short weight2 = mv_block->weight2; + short offsetBi = mv_block->offsetBi; + + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + int pad_size_x = p_Vid->padded_size_x - blocksize_x; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref2_line = UMVLine4X(ref2, cand2->mv_y, cand2->mv_x); + imgpel *ref1_line = UMVLine4X(ref1, cand1->mv_y, cand1->mv_x); + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + } + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + + ref2_line += pad_size_x; + ref1_line += pad_size_x; + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int cr_pad_size_x = p_Vid->cr_padded_size_x - blocksize_x_cr; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + for (k=0; k<2; k++) + { + weight1 = mv_block->weight1_cr[k]; + weight2 = mv_block->weight2_cr[k]; + offsetBi = mv_block->offsetBi_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref2_line = UMVLine8X_chroma ( ref2, k+1, cand2->mv_y, cand2->mv_x); + ref1_line = UMVLine8X_chroma ( ref1, k+1, cand1->mv_y, cand1->mv_x); + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value_uv, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += bi_diff * bi_diff; + } + ref2_line += cr_pad_size_x; + ref1_line += cr_pad_size_x; + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + + +void calcDifference(imgpel **origImg, int ox, int oy, imgpel **predImg, int px, int py, int width, int height, short *diff) +{ + int i, j; + imgpel *orig, *pred; + for (j = 0; j < height; j++) + { + orig = origImg[oy+j]+ox; + pred = predImg[py+j]+px; + for (i = 0; i < width; i++) + { + *diff++ = *orig++ - *pred++; + } + } +} diff --git a/lencod/src/me_distortion_otf.c b/lencod/src/me_distortion_otf.c new file mode 100644 index 0000000..2d7e2f8 --- /dev/null +++ b/lencod/src/me_distortion_otf.c @@ -0,0 +1,1273 @@ +/*! +************************************************************************************* +* \file me_distortion_otf.c +* +* \brief +* Motion estimation error calculation functions with on-the-fly interpolation +* +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "mv_search.h" +#include "me_distortion.h" +#include "me_distortion_otf.h" +#include "get_block_otf.h" + +#include "refbuf_otf.h" + + +//#define CHECKOVERFLOW(mcost) assert(mcost>=0) +#define CHECKOVERFLOW(mcost) + + +/*! +************************************************************************ +* \brief +* JLT : SAD computation (on-the-fly) +************************************************************************ +*/ +distblk computeSAD_otf(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand) +{ + int mcost = 0; + int imin_cost = dist_down(min_mcost); + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; +#if (JM_MEM_DISTORTION) + int *imgpel_abs = p_Vid->imgpel_abs; +#endif + imgpel *src_line, *ref_line ; + imgpel data[MB_PIXELS]; // local allocation could be optimized by a global instanciation + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + + src_line = mv_block->orig_pic[0]; + ref_line = data ; + // get block with interpolation on-the-fly + p_Dpb->pf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x, blocksize_y, ref1, 0 ) ; + + for (y=0; y imin_cost) + return (dist_scale_f((distblk)mcost)); + } + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; // chroma me cost + + for (k=0; k < 2; k++) + { + src_line = mv_block->orig_pic[k+1]; + ref_line = data ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + mcr_cost = 0; + + for (y = 0; y < blocksize_y_cr; y++) + { + for (x = 0; x < blocksize_x_cr; x += 2) + { +#if (JM_MEM_DISTORTION) + mcr_cost += imgpel_abs[ *src_line++ - *ref_line++ ]; + mcr_cost += imgpel_abs[ *src_line++ - *ref_line++ ]; +#else + mcr_cost += iabs( *src_line++ - *ref_line++ ); + mcr_cost += iabs( *src_line++ - *ref_line++ ); +#endif + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost >imin_cost) + return (dist_scale_f((distblk)mcost)); + } + } + + CHECKOVERFLOW(mcost); + return (dist_scale((distblk)mcost)); +} + +/*! +************************************************************************ +* \brief +* JLT : SADWP computation for weighted samples ( on-the-fly ) +************************************************************************ +*/ +distblk computeSADWP_otf(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int mcost = 0; + int imin_cost = dist_down(min_mcost); + int y, x; + int weighted_pel; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int max_imgpel_value = p_Vid->max_imgpel_value; + short weight = mv_block->weight_luma; + short offset = mv_block->offset_luma; + + int wp_luma_round = currSlice->wp_luma_round; + short luma_log_weight_denom = currSlice->luma_log_weight_denom; + + imgpel *src_line, *ref_line ; + imgpel data[MB_PIXELS]; // local allocation could be optimized by a global instanciation + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + + src_line = mv_block->orig_pic[0]; + ref_line = data ; + // get block with interpolation on-the-fly + p_Dpb->pf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y=0; y> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs( *src_line++ - weighted_pel ); + } + if(mcost > imin_cost) + return (dist_scale_f((distblk)mcost)); + } + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + int wp_chroma_round = currSlice->wp_chroma_round; + short chroma_log_weight_denom = currSlice->chroma_log_weight_denom; + + for (k=0; k < 2; k++) + { + weight = mv_block->weight_cr[k]; + offset = mv_block->offset_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref_line = data ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + + for (y=0; y> chroma_log_weight_denom) + offset); + mcr_cost += iabs( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value_uv, ((weight * *ref_line++ + wp_chroma_round) >> chroma_log_weight_denom) + offset); + mcr_cost += iabs( *src_line++ - weighted_pel ); + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost >imin_cost) + return (dist_scale_f((distblk)mcost)); + } + } + + CHECKOVERFLOW(mcost); + return (dist_scale((distblk)mcost)); +} + +/*! +************************************************************************ +* \brief +* JLT : BiPred SAD computation (no weights) ( on-the-fly ) +************************************************************************ +*/ +distblk computeBiPredSAD1_otf(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; +#if (JM_MEM_DISTORTION) + int *imgpel_abs = p_Vid->imgpel_abs; +#endif + + imgpel *src_line, *ref2_line, *ref1_line ; + imgpel data2[MB_PIXELS], data1[MB_PIXELS]; // local allocation could be optimized by a global instanciation + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + + src_line = mv_block->orig_pic[0]; + ref2_line = data2 ; + ref1_line = data1 ; + + p_Dpb->pf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x, blocksize_y, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y = 0; y < blocksize_y; y++) + { + for (x = 0; x < blocksize_x; x+=4) + { +#if (JM_MEM_DISTORTION) + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += imgpel_abs[ bi_diff ]; +#else + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs(bi_diff); +#endif + } + if(mcost > imin_cost) + return (dist_scale_f((distblk)mcost)); + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + + for (k=1; k<3; k++) + { + mcr_cost = 0; + + src_line = mv_block->orig_pic[k]; + ref2_line = data2 ; + ref1_line = data1 ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x_cr, blocksize_y_cr, ref2, k ) ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k ) ; + + for (y=0; y>1); + mcr_cost += iabs(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcr_cost += iabs(bi_diff); + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost > imin_cost) + return (dist_scale_f((distblk)mcost)); + } + } + + CHECKOVERFLOW(mcost); + return (dist_scale((distblk)mcost)); +} + +/*! +************************************************************************ +* \brief +* JLT : BiPred SAD computation (with weights) ( on-the-fly ) +************************************************************************ +*/ +distblk computeBiPredSAD2_otf(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int denom = currSlice->luma_log_weight_denom + 1; + int lround = 2 * currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + int y,x; + int weighted_pel, pixel1, pixel2; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + short weight1 = mv_block->weight1; + short weight2 = mv_block->weight2; + short offsetBi = mv_block->offsetBi; + + imgpel *src_line, *ref2_line, *ref1_line ; + imgpel data2[MB_PIXELS], data1[MB_PIXELS]; // local allocation could be optimized by a global instanciation + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + src_line = mv_block->orig_pic[0]; + ref2_line = data2 ; + ref1_line = data1 ; + + p_Dpb->pf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x, blocksize_y, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += iabs(bi_diff); + } + + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + for (k=0; k<2; k++) + { + weight1 = mv_block->weight1_cr[k]; + weight2 = mv_block->weight2_cr[k]; + offsetBi = mv_block->offsetBi_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref2_line = data2 ; + ref1_line = data1 ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x_cr, blocksize_y_cr, ref2, k+1 ) ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += iabs(bi_diff); + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value_uv, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += iabs(bi_diff); + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : SAD computation _with_ Hadamard Transform (on-the-fly) +************************************************************************ +*/ +distblk computeSATD_otf(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int src_size_x, src_size_mul; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + imgpel *src_tmp = mv_block->orig_pic[0]; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref_line, data[MB_PIXELS] ; + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = blocksize_x - BLOCK_SIZE; + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_SP)) + { + for (x=0; xpf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x + (x<<2) , y, BLOCK_SIZE, BLOCK_SIZE, ref1, 0 ); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_8x8_SP) ) + { + for (x=0; xpf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x + (x<<2) , y, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, ref1, 0 ); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + *d++ = *src_line++ - *ref_line++ ; + + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : SAD computation of weighted samples _with_ Hadamard Transform ( on-the-fly ) +************************************************************************ +*/ +distblk computeSATDWP_otf(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int weighted_pel; + int src_size_x, src_size_mul; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + imgpel *src_tmp = mv_block->orig_pic[0]; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + short luma_log_weight_denom = currSlice->luma_log_weight_denom; + short weight = mv_block->weight_luma; + short offset = mv_block->offset_luma; + + int wp_luma_round = currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref_line, data[MB_PIXELS]; + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE); + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_SP)) + { + for (x=0; xpf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x + (x<<2) , y, BLOCK_SIZE, BLOCK_SIZE, ref1, 0 ); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y = cand->mv_y; y < cand->mv_y + (blocksize_y<<2); y += (BLOCK_SIZE_8x8_SP) ) + { + for (x=0; xpf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x + (x<<2) , y, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, ref1, 0 ); + src_line = src_tmp + x; + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + *d++ = (short) (*src_line++ - weighted_pel); + + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : BiPred (w/o weights) SATD computation ( on-the-fly ) +************************************************************************ +*/ +distblk computeBiPredSATD1_otf(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int src_size_x, src_size_mul; + imgpel *src_tmp = mv_block->orig_pic[0]; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref1_line, *ref2_line, data1[MB_PIXELS], data2[MB_PIXELS] ; + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE); + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y=0; y<(blocksize_y<<2); y += (BLOCK_SIZE_SP)) + { + for (x=0; xpf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x + (x<<2) , cand2->mv_y + y, BLOCK_SIZE, BLOCK_SIZE, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x + (x<<2) , cand1->mv_y + y, BLOCK_SIZE, BLOCK_SIZE, ref1, 0 ); + + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y=0; y<(blocksize_y << 2); y += BLOCK_SIZE_8x8_SP ) + { + int y_pos2 = cand2->mv_y + y; + int y_pos1 = cand1->mv_y + y; + for (x=0; xpf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x + (x<<2) , y_pos2, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x + (x<<2) , y_pos1, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, ref1, 0 ); + + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + *d++ = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : BiPred (w/ weights) SATD computation ( on-the-fly ) +************************************************************************ +*/ +distblk computeBiPredSATD2_otf(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y, x, y4; + int weighted_pel, pixel1, pixel2; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int denom = currSlice->luma_log_weight_denom + 1; + int lround = 2 * currSlice->wp_luma_round; + short weight1 = mv_block->weight1; + short weight2 = mv_block->weight2; + short offsetBi = mv_block->offsetBi; + + + int max_imgpel_value = p_Vid->max_imgpel_value; + int src_size_x, src_size_mul; + imgpel *src_tmp = mv_block->orig_pic[0]; + short *d, diff[MB_PIXELS]; + imgpel *src_line, *ref1_line, *ref2_line, data1[MB_PIXELS], data2[MB_PIXELS] ; + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + if ( !mv_block->test8x8 ) + { // 4x4 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE); + src_size_mul = blocksize_x * BLOCK_SIZE; + for (y=0; y<(blocksize_y<<2); y += BLOCK_SIZE_SP) + { + for (x=0; xpf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x + (x<<2) , cand2->mv_y + y, BLOCK_SIZE, BLOCK_SIZE, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x + (x<<2) , cand1->mv_y + y, BLOCK_SIZE, BLOCK_SIZE, ref1, 0 ); + + for (y4 = 0; y4 < BLOCK_SIZE; y4++ ) + { + // 0 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 1 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 2 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 3 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + + src_line += src_size_x; + } + mcost += HadamardSAD4x4 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + else + { // 8x8 TRANSFORM + src_size_x = (blocksize_x - BLOCK_SIZE_8x8); + src_size_mul = blocksize_x * BLOCK_SIZE_8x8; + for (y=0; y < (blocksize_y << 2); y += BLOCK_SIZE_8x8_SP ) + { + int y_pos2 = cand2->mv_y + y; + int y_pos1 = cand1->mv_y + y; + for (x=0; xpf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x + (x<<2) , y_pos2, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x + (x<<2) , y_pos1, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, ref1, 0 ); + + for (y4 = 0; y4 < BLOCK_SIZE_8x8; y4++ ) + { + // 0 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 1 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 2 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 3 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 4 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 5 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 6 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line++) - weighted_pel); + // 7 + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + *d++ = (short) ((*src_line) - weighted_pel); + + src_line += src_size_x; + } + mcost += HadamardSAD8x8 (diff); + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + src_tmp += src_size_mul; + } + } + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : SSE computation ( on-the-fly ) +************************************************************************ +*/ +distblk computeSSE_otf(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref_line , data[MB_PIXELS] ; + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + ref_line = data; + + p_Dpb->pf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y=0; y imin_cost) + return dist_scale_f((distblk)mcost); + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + + for (k=0; k<2; k++) + { + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref_line = data ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + for (y=0; yChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : SSE computation of weighted samples ( on-the-fly ) +************************************************************************ +*/ +distblk computeSSEWP_otf(StorablePicture *ref1, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand + ) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int y,x; + int weighted_pel; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + short weight = mv_block->weight_luma; + short offset = mv_block->offset_luma; + + int wp_luma_round = currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + short luma_log_weight_denom = currSlice->luma_log_weight_denom; + + imgpel *src_line = mv_block->orig_pic[0]; + imgpel *ref_line , data[MB_PIXELS] ; + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + + ref_line = data; + p_Dpb->pf_get_block_luma( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y=0; y> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value, ((weight * *ref_line++ + wp_luma_round) >> luma_log_weight_denom) + offset); + mcost += iabs2( *src_line++ - weighted_pel ); + } + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + // These could be made global to reduce computations + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + int wp_chroma_round = currSlice->wp_chroma_round; + short chroma_log_weight_denom = currSlice->chroma_log_weight_denom; + + for (k=0; k<2; k++) + { + weight = mv_block->weight_cr[k]; + offset = mv_block->offset_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref_line = data ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref_line, tmp_line, cand->mv_x, cand->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + for (y=0; y> chroma_log_weight_denom) + offset); + mcr_cost += iabs2( *src_line++ - weighted_pel ); + weighted_pel = iClip1( max_imgpel_value_uv, ((weight * *ref_line++ + wp_chroma_round) >> chroma_log_weight_denom) + offset); + mcr_cost += iabs2( *src_line++ - weighted_pel ); + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : BiPred SSE computation (no weights) ( on-the-fly ) +************************************************************************ +*/ +distblk computeBiPredSSE1_otf(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + int y,x; + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + VideoParameters *p_Vid = mv_block->p_Vid; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + + imgpel *src_line, *ref2_line, *ref1_line ; + imgpel data2[MB_PIXELS], data1[MB_PIXELS]; // local allocation could be optimized by a global instanciation + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + src_line = mv_block->orig_pic[0]; + ref2_line = data2 ; + ref1_line = data1 ; + + p_Dpb->pf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x, blocksize_y, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y = 0; y < blocksize_y; y++) + { + for (x = 0; x < blocksize_x; x+=4) + { + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcost += iabs2(bi_diff); + } + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + + for (k=0; k<2; k++) + { + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref2_line = data2 ; + ref1_line = data1 ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x_cr, blocksize_y_cr, ref2, k+1 ) ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + + for (y=0; y>1); + mcr_cost += iabs2(bi_diff); + bi_diff = (*src_line++) - ((*ref1_line++ + *ref2_line++ + 1)>>1); + mcr_cost += iabs2(bi_diff); + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} + +/*! +************************************************************************ +* \brief +* JLT : BiPred SSE computation (with weights) ( on-the-fly ) +************************************************************************ +*/ +distblk computeBiPredSSE2_otf(StorablePicture *ref1, + StorablePicture *ref2, + MEBlock *mv_block, + distblk min_mcost, + MotionVector *cand1, + MotionVector *cand2) +{ + int imin_cost = dist_down(min_mcost); + int mcost = 0; + int bi_diff; + VideoParameters *p_Vid = mv_block->p_Vid; + Slice *currSlice = mv_block->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int denom = currSlice->luma_log_weight_denom + 1; + int lround = 2 * currSlice->wp_luma_round; + int max_imgpel_value = p_Vid->max_imgpel_value; + int y,x; + int weighted_pel, pixel1, pixel2; + short weight1 = mv_block->weight1; + short weight2 = mv_block->weight2; + short offsetBi = mv_block->offsetBi; + + short blocksize_x = mv_block->blocksize_x; + short blocksize_y = mv_block->blocksize_y; + + imgpel *src_line, *ref2_line, *ref1_line ; + imgpel data2[MB_PIXELS], data1[MB_PIXELS]; // local allocation could be optimized by a global instanciation + int tmp_line[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + src_line = mv_block->orig_pic[0]; + ref2_line = data2 ; + ref1_line = data1 ; + + p_Dpb->pf_get_block_luma( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x, blocksize_y, ref2, 0 ); + p_Dpb->pf_get_block_luma( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x, blocksize_y, ref1, 0 ); + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcost += bi_diff * bi_diff; + } + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + + if ( mv_block->ChromaMEEnable ) + { + // calculate chroma conribution to motion compensation error + int blocksize_x_cr = mv_block->blocksize_cr_x; + int blocksize_y_cr = mv_block->blocksize_cr_y; + int k; + int mcr_cost = 0; + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + for (k=0; k<2; k++) + { + weight1 = mv_block->weight1_cr[k]; + weight2 = mv_block->weight2_cr[k]; + offsetBi = mv_block->offsetBi_cr[k]; + + mcr_cost = 0; + src_line = mv_block->orig_pic[k+1]; + ref2_line = data2 ; + ref1_line = data1 ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref2_line, tmp_line, cand2->mv_x, cand2->mv_y, blocksize_x_cr, blocksize_y_cr, ref2, k+1 ) ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, ref1_line, tmp_line, cand1->mv_x, cand1->mv_y, blocksize_x_cr, blocksize_y_cr, ref1, k+1 ) ; + + for (y=0; y> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += bi_diff * bi_diff; + + pixel1 = weight1 * (*ref1_line++); + pixel2 = weight2 * (*ref2_line++); + weighted_pel = iClip1( max_imgpel_value_uv, ((pixel1 + pixel2 + lround) >> denom) + offsetBi); + bi_diff = (*src_line++) - weighted_pel; + mcr_cost += bi_diff * bi_diff; + } + } + mcost += mv_block->ChromaMEWeight * mcr_cost; + if(mcost > imin_cost) + return dist_scale_f((distblk)mcost); + } + } + + CHECKOVERFLOW(mcost); + return dist_scale((distblk)mcost); +} \ No newline at end of file diff --git a/lencod/src/me_epzs.c b/lencod/src/me_epzs.c new file mode 100644 index 0000000..9d46e35 --- /dev/null +++ b/lencod/src/me_epzs.c @@ -0,0 +1,1002 @@ + +/*! +************************************************************************************* +* \file me_epzs.c +* +* \brief +* Motion Estimation using EPZS +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "refbuf.h" +#include "macroblock.h" +#include "me_distortion.h" +#include "me_epzs.h" +#include "me_epzs_common.h" +#include "mv_search.h" + +// Functions +/*! +*********************************************************************** +* \brief +* Reset MV to integer position +* AMT/HYC +*********************************************************************** +*/ +static inline void set_integer_mv(MotionVector *mv) +{ + mv->mv_x &= 0xFFFC; + mv->mv_y &= 0xFFFC; +} + +/*! +*********************************************************************** +* \brief +* FAST Motion Estimation using EPZS +* AMT/HYC +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_motion_estimation (Macroblock * currMB, // <-- current Macroblock + MotionVector * pred_mv, // <-- motion vector predictor in sub-pel units + MEBlock * mv_block, // <-- motion vector information + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int blocktype = mv_block->blocktype; + + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + MotionVector *mv = &mv_block->mv[list]; + SearchWindow *searchRange = &mv_block->searchRange; + int mapCenter_x = searchRange->max_x - mv->mv_x; + int mapCenter_y = searchRange->max_y - mv->mv_y; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + distblk lambda_dist = weighted_cost(lambda_factor, 2); + distblk stopCriterion = p_EPZS->medthres[blocktype] + lambda_dist; + distblk *prevSad = &p_EPZS->distortion[cur_list][blocktype - 1][mv_block->pos_x2]; + + MotionVector *p_motion = NULL; + + EPZSStructure *searchPatternF = p_EPZS->searchPattern; + uint16 **EPZSMap = &p_EPZS->EPZSMap[mapCenter_y]; + uint16 *EPZSPoint = &p_EPZS->EPZSMap[searchRange->max_y][searchRange->max_x]; + + MotionVector center = pad_MVs (*mv, mv_block); + MotionVector pred = pad_MVs (*pred_mv, mv_block); + MotionVector tmp = *mv, cand = center; + + ++p_EPZS->BlkCount; + if (p_EPZS->BlkCount == 0) + ++p_EPZS->BlkCount; + + if (p_Inp->EPZSSpatialMem) + { +#if EPZSREF + p_motion = &p_EPZS->p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][mv_block->pos_x2]; +#else + p_motion = &p_EPZS->p_motion[cur_list][blocktype - 1][mv_block->block_y][mv_block->pos_x2]; +#endif + } + + // Clear EPZSMap + // memset(EPZSMap[0],FALSE,searcharray*searcharray); + // Check median candidate; + //p_EPZS->EPZSMap[0][0] = p_EPZS->BlkCount; + *EPZSPoint = p_EPZS->BlkCount; + + //--- initialize motion cost (cost for motion vector) and check --- + min_mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + //--- add residual cost to motion cost --- + min_mcost += mv_block->computePredFPel (ref_picture, mv_block, DISTBLK_MAX - min_mcost, &cand); + + // Additional threshold for ref>0 + if ((ref > 0 && currSlice->structure == FRAME) && (*prevSad < distblkmin (p_EPZS->medthres[blocktype] + lambda_dist, min_mcost))) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + //! If p_EPZS->medthres satisfied, then terminate, otherwise generate Predictors + //! Condition could be strengthened by consideration distortion of adjacent partitions. + if (min_mcost > stopCriterion) + { + SPoint *p_EPZS_point = p_EPZS->predictor->point; + Boolean checkMedian = FALSE; + distblk second_mcost = DISTBLK_MAX; + distblk mcost; + int prednum = 5; + int conditionEPZS; + MotionVector tmp2 = {0, 0}, tmv; + int pos; + short invalid_refs = 0; + + stopCriterion = EPZSDetermineStopCriterion (p_EPZS, prevSad, mv_block, lambda_dist); + + if (min_mcost < (stopCriterion >> 1)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + return min_mcost; + } + + //! Add Spatial Predictors in predictor list. + //! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little + //! in terms of performance and could be removed with little penalty if any. + invalid_refs = EPZS_spatial_predictors (p_EPZS, mv_block, + list, currMB->list_offset, ref, motion); + + if (p_Inp->EPZSSpatialMem) + EPZS_spatial_memory_predictors (p_EPZS, mv_block, cur_list, &prednum, ref_picture->size_x >> 2); + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->EPZSTemporal[currSlice->view_id] && blocktype < 5 ) +#else + // Temporal predictors + if (p_Inp->EPZSTemporal && blocktype < 5) +#endif + { + EPZS_temporal_predictors (currMB, ref_picture, p_EPZS, mv_block, &prednum, stopCriterion, min_mcost); + } + + //! Window Size Based Predictors + //! Basically replaces a Hierarchical ME concept and helps escaping local minima, or + //! determining large motion variations. + //! Following predictors can be adjusted further (i.e. removed, conditioned etc) + //! based on distortion, correlation of adjacent MVs, complexity etc. These predictors + //! and their conditioning could also be moved after all other predictors have been + //! tested. Adaptation could also be based on type of material and coding mode (i.e. + //! field/frame coding,MBAFF etc considering the higher dependency with opposite parity field + //conditionEPZS = ((min_mcost > stopCriterion) + // && (p_Inp->EPZSFixed > 1 || (p_Inp->EPZSFixed && currSlice->slice_type == P_SLICE))); + //conditionEPZS = ((ref == 0) && (blocktype < 5) && (min_mcost > stopCriterion) + //&& (p_Inp->EPZSFixed > 1 || (p_Inp->EPZSFixed && currSlice->slice_type == P_SLICE))); + //conditionEPZS = ((min_mcost > stopCriterion) && ((ref < 2 && blocktype < 4) + conditionEPZS = (p_Inp->EPZSFixed == 3 && (currMB->mb_x == 0 || currMB->mb_y == 0)) + || ((min_mcost > 3 * stopCriterion) && ((ref < 2 && blocktype < 4) || (ref < 1 && blocktype == 4) + || ((currSlice->structure != FRAME || currMB->list_offset) + && ref < 3)) + && (p_Inp->EPZSFixed > 1 || (p_Inp->EPZSFixed && currSlice->slice_type == P_SLICE))); + + if (conditionEPZS) + EPZSWindowPredictors (mv, p_EPZS->predictor, &prednum, + (blocktype < 5) && (invalid_refs > 2) && (ref < 1 + (currSlice->structure != FRAME || currMB->list_offset)) + ? p_EPZS->window_predictor_ext : p_EPZS->window_predictor); + + //! Blocktype/Reference dependent predictors. + //! Since already mvs for other blocktypes/references have been computed, we can reuse + //! them in order to easier determine the optimal point. Use of predictors could depend + //! on cost, + //conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > stopCriterion) || currSlice->structure != FRAME || currMB->list_offset); + conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > 2 * stopCriterion)); + + if (conditionEPZS && currMB->mbAddrX != 0 && p_Inp->EPZSBlockType) + EPZSBlockTypePredictorsMB (currSlice, mv_block, p_EPZS_point, &prednum); + + //! Check all predictors + for (pos = 0; pos < prednum; ++pos) + { + tmv = p_EPZS_point[pos].motion; + set_integer_mv(&tmv); + + //if (((iabs (tmv.mv_x - mv->mv_x) > searchRange->max_x || iabs (tmv.mv_y - mv->mv_y) > searchRange->max_y)) && (tmv.mv_x || tmv.mv_y)) + if ((iabs (tmv.mv_x - mv->mv_x) - searchRange->max_x <= 0) && (iabs (tmv.mv_y - mv->mv_y) - searchRange->max_y <= 0)) + { + EPZSPoint = &EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x]; + if (*EPZSPoint != p_EPZS->BlkCount) + { + *EPZSPoint = p_EPZS->BlkCount; + cand = pad_MVs (tmv, mv_block); + + //--- set motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (mcost < second_mcost) + { + mcost += mv_block->computePredFPel (ref_picture, mv_block, second_mcost - mcost, &cand); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + tmp2 = tmp; + tmp = tmv; + second_mcost = min_mcost; + min_mcost = mcost; + checkMedian = TRUE; + } + //else if (mcost < second_mcost && (tmp.mv_x != tmv.mv_x || tmp.mv_y != tmv.mv_y)) + else if (mcost < second_mcost) + { + tmp2 = tmv; + second_mcost = mcost; + checkMedian = TRUE; + } + } + } + } + } + + //! Refine using EPZS pattern if needed + //! Note that we are using a conservative threshold method. Threshold + //! could be tested after checking only a certain number of predictors + //! instead of the full set. Code could be easily modified for this task. + if (min_mcost > stopCriterion) + { + const int mv_range = 10; + int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0; + int totalCheckPts = 0, motionDirection = 0; + + //! Adapt pattern based on different conditions. + if (p_Inp->EPZSPattern != 0) + { + if ((min_mcost < stopCriterion + ((3 * p_EPZS->medthres[blocktype]) >> 1))) + { + if ((tmp.mv_x == 0 && tmp.mv_y == 0) + || (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else if (blocktype > 4 || (ref > 0 && blocktype != 1)) + searchPatternF = p_Vid->square; + else + searchPatternF = p_EPZS->searchPattern; + } + + //! center on best predictor + center = tmp; + + for (;;) + { + totalCheckPts = searchPatternF->searchPoints; + do + { + checkPts = totalCheckPts; + do + { + tmv = add_MVs (center, &(searchPatternF->point[pointNumber].motion)); + + if (((iabs (tmv.mv_x - mv->mv_x) - searchRange->max_x) <= 0) && ((iabs (tmv.mv_y - mv->mv_y) - searchRange->max_y) <= 0)) + { + EPZSPoint = &EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x]; + if (*EPZSPoint != p_EPZS->BlkCount) + { + *EPZSPoint = p_EPZS->BlkCount; + cand = pad_MVs (tmv, mv_block); + + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (mcost < min_mcost) + { + mcost += mv_block->computePredFPel (ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + tmp = tmv; + min_mcost = mcost; + motionDirection = pointNumber; + } + } + } + } + ++pointNumber; + if (pointNumber >= searchPatternF->searchPoints) + pointNumber -= searchPatternF->searchPoints; + checkPts--; + } + while (checkPts > 0); + + if (nextLast || ((tmp.mv_x == center.mv_x) && (tmp.mv_y == center.mv_y))) + { + patternStop = searchPatternF->stopSearch; + searchPatternF = searchPatternF->nextpattern; + totalCheckPts = searchPatternF->searchPoints; + nextLast = searchPatternF->nextLast; + motionDirection = 0; + pointNumber = 0; + } + else + { + totalCheckPts = searchPatternF->point[motionDirection].next_points; + pointNumber = searchPatternF->point[motionDirection].start_nmbr; + center = tmp; + } + } + while (patternStop != 1); + + if ((ref > 0) && (currSlice->structure == FRAME) + && ((4 * *prevSad < min_mcost) || ((3 * *prevSad < min_mcost) && (*prevSad <= stopCriterion)))) + { + *mv = tmp; +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + return min_mcost; + } + + //! Check Second best predictor with EPZS pattern + conditionEPZS = (checkMedian == TRUE) + && ((currSlice->slice_type == P_SLICE) || (blocktype < 5)) + && (min_mcost > stopCriterion) && (p_Inp->EPZSDual > 0); + + if (!conditionEPZS) + break; + + pointNumber = 0; + patternStop = 0; + motionDirection = 0; + nextLast = 0; + + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (tmp.mv_x == mv->mv_x && tmp.mv_y == mv->mv_y)) + { + if (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range)) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_EPZS->searchPatternD; + + //! Second best. Note that following code is identical as for best predictor. + center = tmp2; + checkMedian = FALSE; + } + } + } + + if ((ref == 0) || (*prevSad > min_mcost)) + *prevSad = min_mcost; +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + //printf("value %d %d %d %d\n", p_motion->mv_x, p_motion->mv_y, p_motion[cur_list][ref][0][0][0].mv_x, p_motion[list + list_offset][ref][0][0][0].mv_y); + //printf("xxxxx %d %d %d %d\n", p_motion->mv_x, p_motion->mv_y, p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][pic_pix_x2].mv_x, p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][pic_pix_x2].mv_y); + } + + *mv = tmp; + + return min_mcost; +} + +/*! +*********************************************************************** +* \brief +* FAST Motion Estimation using EPZS +* AMT/HYC +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_subMB_motion_estimation (Macroblock * currMB, // <-- current Macroblock + MotionVector * pred_mv, // <-- motion vector predictor in sub-pel units + MEBlock * mv_block, // <-- motion vector information + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int blocktype = mv_block->blocktype; + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + MotionVector *mv = &mv_block->mv[list]; + MotionVector center = pad_MVs (*mv, mv_block); + MotionVector cand = center; + MotionVector pred = pad_MVs (*pred_mv, mv_block); + MotionVector tmp = *mv; + SearchWindow *searchRange = &mv_block->searchRange; + int mapCenter_x = searchRange->max_x - mv->mv_x; + int mapCenter_y = searchRange->max_y - mv->mv_y; + + short pic_pix_x2 = mv_block->pos_x2; + distblk lambda_dist = weighted_cost(lambda_factor,3); + distblk stopCriterion = p_EPZS->medthres[blocktype] + lambda_dist; + distblk *prevSad = &p_EPZS->distortion[cur_list][blocktype - 1][pic_pix_x2]; + MotionVector *p_motion = NULL; + + EPZSStructure *searchPatternF = p_EPZS->searchPattern; + uint16 **EPZSMap = &p_EPZS->EPZSMap[mapCenter_y]; + + ++p_EPZS->BlkCount; + if (p_EPZS->BlkCount == 0) + ++p_EPZS->BlkCount; + + if (p_Inp->EPZSSpatialMem) + { +#if EPZSREF + p_motion = &p_EPZS->p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][pic_pix_x2]; +#else + p_motion = &p_EPZS->p_motion[cur_list][blocktype - 1][mv_block->block_y][pic_pix_x2]; +#endif + } + + // Clear p_EPZS->EPZSMap + // memset(p_EPZS->EPZSMap[0],FALSE,searcharray*searcharray); + // Check median candidate; + //p_EPZS->EPZSMap[0][0] = p_EPZS->BlkCount; + p_EPZS->EPZSMap[searchRange->max_y][searchRange->max_x] = p_EPZS->BlkCount; + + //--- initialize motion cost (cost for motion vector) and check --- + min_mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + //--- add residual cost to motion cost --- + min_mcost += mv_block->computePredFPel (ref_picture, mv_block, DISTBLK_MAX-min_mcost, &cand); + + // Additional threshold for ref>0 + if ((ref > 0 && currSlice->structure == FRAME) && + (*prevSad < distblkmin (p_EPZS->medthres[blocktype] + lambda_dist, min_mcost))) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + //! If p_EPZS->medthres satisfied, then terminate, otherwise generate Predictors + //! Condition could be strengthened by consideration distortion of adjacent partitions. + if (min_mcost > stopCriterion) + { + SPoint *p_EPZS_point = p_EPZS->predictor->point; + Boolean checkMedian = FALSE; + distblk second_mcost = DISTBLK_MAX; + distblk mcost; + int prednum = 5; + int conditionEPZS; + + MotionVector tmv, tmp2 = {0,0}; + int pos; + + stopCriterion = EPZSDetermineStopCriterion (p_EPZS, prevSad, mv_block, lambda_dist); + + if (min_mcost < (stopCriterion >> 1)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + //! Add Spatial Predictors in predictor list. + //! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little + //! in terms of performance and could be removed with little penalty if any. + EPZS_spatial_predictors (p_EPZS, mv_block/*->block*/, list, currMB->list_offset, ref, motion); + + if (p_Inp->EPZSSpatialMem) + EPZS_spatial_memory_predictors (p_EPZS, mv_block, cur_list, &prednum, ref_picture->size_x >> 2); + + //! Blocktype/Reference dependent predictors. + //! Since already mvs for other blocktypes/references have been computed, we can reuse + //! them in order to easier determine the optimal point. Use of predictors could depend + //! on cost, + conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > 2 * stopCriterion)); + + if (conditionEPZS && currMB->mbAddrX != 0 && p_Inp->EPZSBlockType) + EPZSBlockTypePredictors (currSlice, mv_block, p_EPZS_point, &prednum); + + //! Check all predictors + for (pos = 0; pos < prednum; ++pos) + { + tmv = p_EPZS_point[pos].motion; + set_integer_mv(&tmv); + + //if (((iabs (tmv.mv_x - mv->mv_x) > searchRange->max_x || iabs (tmv.mv_y - mv->mv_y) > searchRange->max_y)) && (tmv.mv_x || tmv.mv_y)) + if ((iabs (tmv.mv_x - mv->mv_x) - searchRange->max_x <= 0) && (iabs (tmv.mv_y - mv->mv_y) - searchRange->max_y <= 0)) + { + + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + + cand = pad_MVs (tmv, mv_block); + + //--- set motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (mcost < second_mcost) + { + mcost += mv_block->computePredFPel (ref_picture, mv_block, second_mcost - mcost, &cand); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + tmp2 = tmp; + tmp = tmv; + second_mcost = min_mcost; + min_mcost = mcost; + checkMedian = TRUE; + } + //else if (mcost < second_mcost && (tmp.mv_x != tmv.mv_x || tmp.mv_y != tmv.mv_y)) + else if (mcost < second_mcost) + { + tmp2 = tmv; + second_mcost = mcost; + checkMedian = TRUE; + } + } + } + } + + + // At this point, let us add an early termination criterion + // after checking each predictor. This can help speed up a lot. + if (min_mcost < ((3 * stopCriterion) >> 2)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + *mv = tmp; + return min_mcost; + } + } + + //! Refine using EPZS pattern if needed + //! Note that we are using a conservative threshold method. Threshold + //! could be tested after checking only a certain number of predictors + //! instead of the full set. Code could be easily modified for this task. + if (min_mcost > stopCriterion) + { + int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0; + int totalCheckPts = 0, motionDirection = 0; + const int mv_range = 12; + + //! Adapt pattern based on different conditions. + if (p_Inp->EPZSPattern != 0) + { + if ((min_mcost < stopCriterion + ((3 * p_EPZS->medthres[blocktype]) >> 1))) + { + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_Vid->square; + } + + //! center on best predictor + center = tmp; + for (;;) + { + totalCheckPts = searchPatternF->searchPoints; + do + { + checkPts = totalCheckPts; + do + { + tmv = add_MVs (center, &(searchPatternF->point[pointNumber].motion)); + + if ((iabs (tmv.mv_x - mv->mv_x) <= searchRange->max_x) && (iabs (tmv.mv_y - mv->mv_y) <= searchRange->max_y)) + { + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + cand = pad_MVs(tmv, mv_block); + + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + if (mcost < min_mcost) + { + + mcost += mv_block->computePredFPel (ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + tmp = tmv; + min_mcost = mcost; + motionDirection = pointNumber; + } + } + } + } + ++pointNumber; + if (pointNumber >= searchPatternF->searchPoints) + pointNumber -= searchPatternF->searchPoints; + checkPts--; + } + while (checkPts > 0); + + if (nextLast || ((tmp.mv_x == center.mv_x) && (tmp.mv_y == center.mv_y))) + { + patternStop = searchPatternF->stopSearch; + searchPatternF = searchPatternF->nextpattern; + totalCheckPts = searchPatternF->searchPoints; + nextLast = searchPatternF->nextLast; + motionDirection = 0; + pointNumber = 0; + } + else + { + totalCheckPts = searchPatternF->point[motionDirection].next_points; + pointNumber = searchPatternF->point[motionDirection].start_nmbr; + center = tmp; + } + } + while (patternStop != 1); + + if ((ref > 0) && (currSlice->structure == FRAME) + && ((4 * *prevSad < min_mcost) || ((3 * *prevSad < min_mcost) && (*prevSad <= stopCriterion)))) + { + *mv = tmp; +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + return min_mcost; + } + + //! Check Second best predictor with EPZS pattern + conditionEPZS = (checkMedian == TRUE) + && ((currSlice->slice_type == P_SLICE)) + && (min_mcost > stopCriterion) && (p_Inp->EPZSDual > 0); + + if (!conditionEPZS) + break; + + pointNumber = 0; + patternStop = 0; + motionDirection = 0; + nextLast = 0; + + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (tmp.mv_x == mv->mv_x && tmp.mv_y == mv->mv_y)) + { + if (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range)) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_EPZS->searchPatternD; + + //! Now consider second best. + center = tmp2; + checkMedian = FALSE; + } + } + } + + if ((ref == 0) || (*prevSad > min_mcost)) + *prevSad = min_mcost; + +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + *mv = tmp; + + return min_mcost; +} + +/*! +*********************************************************************** +* \brief +* FAST Motion Estimation using EPZS +* AMT/HYC +* \return +* minimum motion cost after search +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_bipred_motion_estimation (Macroblock * currMB, // <-- Current Macroblock + int list, // <-- reference list + MotionVector * pred_mv1, // <-- motion vector predictor in sub-pel units + MotionVector * pred_mv2, // <-- motion vector predictor in sub-pel units + MotionVector * mv1, // <--> in: search center (x|y) / out: motion vector (x|y) - in pel units + MotionVector * mv2, // <--> in: search center (x|y) + MEBlock * mv_block, // <-- motion vector information + int search_range, // <-- 1-d search range in pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int blocktype = mv_block->blocktype; + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture1 = currSlice->listX[list + currMB->list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[(list ^ 1) + currMB->list_offset][0]; + + int mapCenter_x = search_range - mv1->mv_x; + int mapCenter_y = search_range - mv1->mv_y; + distblk lambda_dist = weighted_cost(lambda_factor, 4); + distblk stopCriterion = p_EPZS->medthres[blocktype] + lambda_dist; + distblk *prevSad = &p_EPZS->bi_distortion[list + currMB->list_offset][blocktype - 1][mv_block->pos_x2]; + EPZSStructure *searchPatternF = p_EPZS->searchPattern; + uint16 **EPZSMap = &p_EPZS->EPZSMap[mapCenter_y]; + + MotionVector tmp = *mv1; + MotionVector center1 = pad_MVs (*mv1, mv_block); + MotionVector center2 = pad_MVs (*mv2, mv_block); + MotionVector pred1 = pad_MVs (*pred_mv1, mv_block); + MotionVector pred2 = pad_MVs (*pred_mv2, mv_block); + MotionVector cand1 = center1; + MotionVector cand2 = center2; + + ++p_EPZS->BlkCount; + if (p_EPZS->BlkCount == 0) + ++p_EPZS->BlkCount; + + + // Clear p_EPZS->EPZSMap + //memset(p_EPZS->EPZSMap[0],FALSE,searcharray*searcharray); + // Check median candidate; + //p_EPZS->EPZSMap[0][0] = p_EPZS->BlkCount; + p_EPZS->EPZSMap[search_range][search_range] = p_EPZS->BlkCount; + + //--- initialize motion cost (cost for motion vector) and check --- + min_mcost = mv_cost (p_Vid, lambda_factor, &cand1, &pred1); + min_mcost += mv_cost (p_Vid, lambda_factor, &cand2, &pred2); + + //--- add residual cost to motion cost --- + min_mcost += mv_block->computeBiPredFPel (ref_picture1, ref_picture2, mv_block, DISTBLK_MAX-min_mcost, &cand1, &cand2); + + //! If p_EPZS->medthres satisfied, then terminate, otherwise generate Predictors + if (min_mcost > stopCriterion) + { + SPoint *p_EPZS_point = p_EPZS->predictor->point; + Boolean checkMedian = FALSE; + distblk second_mcost = DISTBLK_MAX; + distblk mcost; + int prednum = 5; + MotionVector tmv, tmp2 = { 0, 0 }; + int pos; + + stopCriterion = EPZSDetermineStopCriterion (p_EPZS, prevSad, mv_block, lambda_dist); + + //! Add Spatial Predictors in predictor list. + //! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little + //! in terms of performance and could be removed with little penalty if any. + EPZS_spatial_predictors (p_EPZS, mv_block/*->block*/, list, currMB->list_offset, ref, motion); + + //! Check all predictors + for (pos = 0; pos < prednum; ++pos) + { + tmv = p_EPZS_point[pos].motion; + set_integer_mv(&tmv); + //if ((iabs (tmv.mv_x - mv1->mv_x) > search_range || iabs (tmv.mv_y - mv1->mv_y) > search_range) && (tmv.mv_x || tmv.mv_y)) + if (iabs (tmv.mv_x - mv1->mv_x) <= search_range && iabs (tmv.mv_y - mv1->mv_y) <= search_range) + { + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + + cand1 = pad_MVs (tmv, mv_block); + + //--- set motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand1, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, &cand2, &pred2); + + if (mcost >= second_mcost) + continue; + + mcost += mv_block->computeBiPredFPel (ref_picture1, ref_picture2, mv_block, second_mcost - mcost, &cand1, &cand2); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + tmp2 = tmp; + tmp = tmv; + second_mcost = min_mcost; + min_mcost = mcost; + checkMedian = TRUE; + } + //else if (mcost < second_mcost && (tmp.mv_x != tmv.mv_x || tmp.mv_y != tmv.mv_y)) + else if (mcost < second_mcost) + { + tmp2 = tmv; + second_mcost = mcost; + checkMedian = TRUE; + } + } + } + } + + //! Refine using EPZS pattern if needed + //! Note that we are using a conservative threshold method. Threshold + //! could be tested after checking only a certain number of predictors + //! instead of the full set. Code could be easily modified for this task. + if (min_mcost > stopCriterion) + { + int conditionEPZS; + int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0; + int totalCheckPts = 0, motionDirection = 0; + + const int mv_range = 12; + + //! Adapt pattern based on different conditions. + if (p_Inp->EPZSPattern != 0) + { + if ((min_mcost < stopCriterion + ((4 * p_EPZS->medthres[blocktype]) >> 1))) + { + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (iabs (tmp.mv_x - mv1->mv_x) < (mv_range) && iabs (tmp.mv_y - mv1->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else if (blocktype > 5 || (ref > 0 && blocktype != 1)) + searchPatternF = p_Vid->square; + else + searchPatternF = p_EPZS->searchPattern; + } + + //! center on best predictor + center1 = tmp; + for (;;) + { + totalCheckPts = searchPatternF->searchPoints; + do + { + checkPts = totalCheckPts; + do + { + tmv = add_MVs (center1, &(searchPatternF->point[pointNumber].motion)); + + if ((iabs (tmv.mv_x - mv1->mv_x) <= search_range) && (iabs (tmv.mv_y - mv1->mv_y) <= search_range)) + { + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + cand1 = pad_MVs (tmv, mv_block); + + mcost = mv_cost (p_Vid, lambda_factor, &cand1, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, &cand2, &pred2); + + if (mcost < min_mcost) + { + mcost += mv_block->computeBiPredFPel (ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cand1, &cand2); + + if (mcost < min_mcost) + { + tmp = tmv; + min_mcost = mcost; + motionDirection = pointNumber; + } + } + } + } + ++pointNumber; + if (pointNumber >= searchPatternF->searchPoints) + pointNumber -= searchPatternF->searchPoints; + checkPts--; + } + while (checkPts > 0); + + if (nextLast || ((tmp.mv_x == center1.mv_x) && (tmp.mv_y == center1.mv_y))) + { + patternStop = searchPatternF->stopSearch; + searchPatternF = searchPatternF->nextpattern; + totalCheckPts = searchPatternF->searchPoints; + nextLast = searchPatternF->nextLast; + motionDirection = 0; + pointNumber = 0; + } + else + { + totalCheckPts = searchPatternF->point[motionDirection].next_points; + pointNumber = searchPatternF->point[motionDirection].start_nmbr; + center1 = tmp; + } + } + while (patternStop != 1); + + //! Check Second best predictor with EPZS pattern + conditionEPZS = (checkMedian == TRUE) && (blocktype < 5) && (min_mcost > stopCriterion) && (p_Inp->EPZSDual > 0); + + if (!conditionEPZS) + break; + + pointNumber = 0; + patternStop = 0; + motionDirection = 0; + nextLast = 0; + + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (tmp.mv_x == mv1->mv_x && tmp.mv_y == mv1->mv_y)) + { + if (iabs (tmp.mv_x - mv1->mv_x) < (mv_range) && iabs (tmp.mv_y - mv1->mv_y) < (mv_range)) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_EPZS->searchPatternD; + totalCheckPts = searchPatternF->searchPoints; + + //! Second best. Note that following code is identical as for best predictor. + center1 = tmp2; + checkMedian = FALSE; + } + } + } + + if (mv_block->iteration_no == 0) + { + *prevSad = min_mcost; + } + + *mv1 = tmp; + + return min_mcost; +} + diff --git a/lencod/src/me_epzs_common.c b/lencod/src/me_epzs_common.c new file mode 100644 index 0000000..6d3ace6 --- /dev/null +++ b/lencod/src/me_epzs_common.c @@ -0,0 +1,1862 @@ + +/*! +************************************************************************************* +* \file me_epzs_common.c +* +* \brief +* Common functions for EPZS scheme +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* +************************************************************************************* +*/ + +#include + +#include "contributors.h" +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "refbuf.h" +#include "macroblock.h" +#include "me_distortion.h" +#include "me_epzs.h" +#include "me_epzs_common.h" +#include "me_epzs_int.h" +#include "me_fullsearch.h" +#include "mv_search.h" + +static const short BLOCK_PARENT[8] = { 1, 1, 1, 1, 2, 4, 4, 5 }; //!< {skip, 16x16, 16x8, 8x16, 8x8, 8x4, 4x8, 4x4} +static const int MIN_THRES_BASE[8] = { 0, 64, 32, 32, 16, 8, 8, 4 }; +static const int MED_THRES_BASE[8] = { 0, 256, 128, 128, 64, 32, 32, 16 }; +static const int MAX_THRES_BASE[8] = { 0, 768, 384, 384, 192, 96, 96, 48 }; + +// Other definitions +static const char EPZS_PATTERN[6][20] = { "Diamond", "Square", "Extended Diamond", "Large Diamond", "SBP Large Diamond", "PMVFAST" }; +static const char EPZS_DUAL_PATTERN[7][20] = +{ "Disabled", "Diamond", "Square", "Extended Diamond", "Large Diamond", "SBP Large Diamond", "PMVFAST" }; +static const char EPZS_FIXED_PREDICTORS[4][20] = { "Disabled", "All P", "All P + B", "Aggressive" }; +static const char EPZS_OTHER_PREDICTORS[2][20] = { "Disabled", "Enabled" }; +static const char EPZS_SUBPEL_METHOD[3][20] = { "Full", "Basic", "Enhanced" }; + +//! Define EPZS Refinement patterns +static const short pattern_data[7][12][4] = +{ + { // Small Diamond pattern + { 0, 4, 3, 3 }, { 4, 0, 0, 3 }, { 0, -4, 1, 3 }, { -4, 0, 2, 3 } + }, + { // Square pattern + { 0, 4, 7, 3 }, { 4, 4, 7, 5 }, { 4, 0, 1, 3 }, { 4, -4, 1, 5 }, + { 0, -4, 3, 3 }, { -4, -4, 3, 5 }, { -4, 0, 5, 3 }, { -4, 4, 5, 5 } + }, + { // Enhanced Diamond pattern + { -4, 4, 10, 5 }, { 0, 8, 10, 8 }, { 0, 4, 10, 7 }, { 4, 4, 1, 5 }, + { 8, 0, 1, 8 }, { 4, 0, 1, 7 }, { 4, -4, 4, 5 }, { 0, -8, 4, 8 }, + { 0, -4, 4, 7 }, { -4, -4, 7, 5 }, { -8, 0, 7, 8 }, { -4, 0, 7, 7 } + + }, + { // Large Diamond pattern + { 0, 8, 6, 5 }, { 4, 4, 0, 3 }, { 8, 0, 0, 5 }, { 4, -4, 2, 3 }, + { 0, -8, 2, 5 }, { -4, -4, 4, 3 }, { -8, 0, 4, 5 }, { -4, 4, 6, 3 } + }, + { // Extended Subpixel pattern + { 0, 8, 6, 12 }, { 4, 4, 0, 12 }, { 8, 0, 0, 12 }, { 4, -4, 2, 12 }, + { 0, -8, 2, 12 }, { -4, -4, 4, 12 }, { -8, 0, 4, 12 }, { -4, 4, 6, 12 }, + { 0, 2, 6, 12 }, { 2, 0, 0, 12 }, { 0, -2, 2, 12 }, { -2, 0, 4, 12 } + } +}; + +/*! +************************************************************************ +* \brief +* Allocate EPZS pattern memory +* +* \param searchpoints +* number of searchpoints to allocate +* +* \return +* the allocated EPZSStructure structure +************************************************************************ +*/ +static EPZSStructure * +allocEPZSpattern (int searchpoints) +{ + EPZSStructure *s; + s = calloc (1, sizeof (EPZSStructure)); + + if (NULL == s) + no_mem_exit ("alloc_EPZSpattern: s"); + + s->searchPoints = searchpoints; + s->point = (SPoint *) calloc (searchpoints, sizeof (SPoint)); + + return s; +} + +/*! +************************************************************************ +* \brief +* Free EPZS pattern memory. +* +* \param p +* structure to be freed +* +************************************************************************ +*/ +static void +freeEPZSpattern (EPZSStructure * p) +{ + if (p) + { + free ((SPoint *) p->point); + free (p); + p = NULL; + } +} + +/*! +************************************************************************ +* \brief +* Assign EPZS pattern +* +* +************************************************************************ +*/ +static void +assignEPZSpattern (EPZSStructure * pattern, int type, int stopSearch, int nextLast, EPZSStructure * nextpattern) +{ + int i; + + for (i = 0; i < pattern->searchPoints; ++i) + { + pattern->point[i].motion.mv_x = pattern_data[type][i][0]; + pattern->point[i].motion.mv_y = pattern_data[type][i][1]; + pattern->point[i].start_nmbr = pattern_data[type][i][2]; + pattern->point[i].next_points = pattern_data[type][i][3]; + } + pattern->stopSearch = stopSearch; + pattern->nextLast = nextLast; + pattern->nextpattern = nextpattern; +} + +/*! +************************************************************************ +* \brief +* Setup EPZS ME engine +************************************************************************ +*/ +void EPZS_setup_engine(Macroblock *currMB, InputParameters *p_Inp) +{ + currMB->IntPelME = (p_Inp->EPZSSubPelGrid) ? EPZS_integer_motion_estimation : EPZS_motion_estimation; + currMB->BiPredME = (p_Inp->EPZSSubPelGrid) ? EPZS_integer_bipred_motion_estimation : EPZS_bipred_motion_estimation; + if (p_Inp->EPZSSubPelME == 1) + currMB->SubPelME = EPZS_sub_pel_motion_estimation; + else if (p_Inp->EPZSSubPelME == 2) + currMB->SubPelME = full_sub_pel_motion_estimation; + else + currMB->SubPelME = sub_pel_motion_estimation; + if (p_Inp->EPZSSubPelMEBiPred == 1) + currMB->SubPelBiPredME = EPZS_sub_pel_bipred_motion_estimation; + else if (p_Inp->EPZSSubPelMEBiPred == 2) + currMB->SubPelBiPredME = full_sub_pel_bipred_motion_estimation; + else + currMB->SubPelBiPredME = sub_pel_bipred_motion_estimation; +} + +/*! +************************************************************************ +* \brief +* EPZS Global Initialization +************************************************************************ +*/ +int +EPZSInit (VideoParameters * p_Vid) +{ + + int memory_size = 0; + + //! Definition of pottential EPZS patterns. + //! It is possible to also define other patterns, or even use + //! resizing patterns (such as the PMVFAST scheme. These patterns + //! are only shown here as reference, while the same also holds + //! for this implementation (i.e. new conditions could be added + //! on adapting predictors, or thresholds etc. Note that search + //! could also be performed on subpel positions directly while + //! pattern needs not be restricted on integer positions only. + + //! Allocate memory and assign search patterns + if(!p_Vid->sdiamond) + { + p_Vid->sdiamond = allocEPZSpattern (4); + assignEPZSpattern (p_Vid->sdiamond, SDIAMOND, TRUE, TRUE, p_Vid->sdiamond); + } + if(!p_Vid->square) + { + p_Vid->square = allocEPZSpattern (8); + assignEPZSpattern (p_Vid->square, SQUARE, TRUE, TRUE, p_Vid->square); + } + if(!p_Vid->ediamond) + { + p_Vid->ediamond = allocEPZSpattern (12); + assignEPZSpattern (p_Vid->ediamond, EDIAMOND, TRUE, TRUE, p_Vid->ediamond); + } + if(!p_Vid->ldiamond) + { + p_Vid->ldiamond = allocEPZSpattern (8); + assignEPZSpattern (p_Vid->ldiamond, LDIAMOND, TRUE, TRUE, p_Vid->ldiamond); + } + if(!p_Vid->sbdiamond) + { + p_Vid->sbdiamond = allocEPZSpattern (12); + assignEPZSpattern (p_Vid->sbdiamond, SBDIAMOND, FALSE, TRUE, p_Vid->sdiamond); + } + if(!p_Vid->pmvfast) + { + p_Vid->pmvfast = allocEPZSpattern (8); + assignEPZSpattern (p_Vid->pmvfast, LDIAMOND, FALSE, TRUE, p_Vid->sdiamond); + } + + return memory_size; +} + +/*! +************************************************************************ +* \brief +* Delete EPZS Alocated memory +************************************************************************ +*/ +void +EPZSDelete (VideoParameters * p_Vid) +{ + // Free search patterns + if(p_Vid->pmvfast) + { + freeEPZSpattern (p_Vid->pmvfast); + p_Vid->pmvfast = NULL; + } + if(p_Vid->sbdiamond) + { + freeEPZSpattern (p_Vid->sbdiamond); + p_Vid->sbdiamond = NULL; + } + if(p_Vid->ldiamond) + { + freeEPZSpattern (p_Vid->ldiamond); + p_Vid->ldiamond = NULL; + } + if(p_Vid->ediamond) + { + freeEPZSpattern (p_Vid->ediamond); + p_Vid->ediamond = NULL; + } + if(p_Vid->sdiamond) + { + freeEPZSpattern (p_Vid->sdiamond); + p_Vid->sdiamond = NULL; + } + if(p_Vid->square) + { + freeEPZSpattern (p_Vid->square); + p_Vid->square = NULL; + } +} + +/*! +************************************************************************ +* \brief +* Allocate co-located memory +* +* \param size_x +* horizontal luma size +* \param size_y +* vertical luma size +* \param mb_adaptive_frame_field_flag +* flag that indicates macroblock adaptive frame/field coding +* +* \return +* the allocated EPZSColocParams structure +************************************************************************ +*/ +static EPZSColocParams * +allocEPZScolocated (int size_x, int size_y, int mb_adaptive_frame_field_flag) +{ + EPZSColocParams *s; + s = calloc (1, sizeof (EPZSColocParams)); + if (NULL == s) + no_mem_exit ("alloc_EPZScolocated: s"); + + s->size_x = size_x; + s->size_y = size_y; + get_mem3Dmv (&(s->frame), 2, (size_y >> BLOCK_SHIFT), (size_x >> BLOCK_SHIFT)); + + if (mb_adaptive_frame_field_flag) + { + get_mem3Dmv (&(s->top), 2, (size_y >> (BLOCK_SHIFT + 1)), (size_x >> BLOCK_SHIFT)); + get_mem3Dmv (&(s->bot), 2, (size_y >> (BLOCK_SHIFT + 1)), (size_x >> BLOCK_SHIFT)); + } + + s->mb_adaptive_frame_field_flag = mb_adaptive_frame_field_flag; + + return s; +} + +/*! +************************************************************************ +* \brief +* Free co-located memory. +* +* \param p +* structure to be freed +* +************************************************************************ +*/ +static void +freeEPZScolocated (EPZSColocParams * p) +{ + + if (p) + { + free_mem3Dmv (p->frame); + if (p->mb_adaptive_frame_field_flag) + { + free_mem3Dmv (p->top); + free_mem3Dmv (p->bot); + } + + free (p); + p = NULL; + } +} + +/*! +************************************************************************ +* \brief +* EPZS Search Window Predictor Initialization +************************************************************************ +*/ +static void +EPZSWindowPredictorInit (short search_range, EPZSStructure * predictor, short mode) +{ + short pos; + short searchpos, fieldsearchpos; + int prednum = -1; + short i; + short search_range_qpel = 2; + SPoint *point = predictor->point; + + if (mode == 0) + { + for (pos = (short) (RoundLog2 (search_range) - 2); pos > -1; pos--) + { + searchpos = ((search_range << search_range_qpel) >> pos); + + for (i = 1; i >= -1; i -= 2) + { + point[++prednum].motion.mv_x = i * searchpos; + point[prednum].motion.mv_y = 0; + point[++prednum].motion.mv_x = i * searchpos; + point[prednum].motion.mv_y = i * searchpos; + point[++prednum].motion.mv_x = 0; + point[prednum].motion.mv_y = i * searchpos; + point[++prednum].motion.mv_x = -i * searchpos; + point[prednum].motion.mv_y = i * searchpos; + } + } + } + else // if (mode == 0) + { + for (pos = (short) (RoundLog2 (search_range) - 2); pos > -1; pos--) + { + searchpos = ((search_range << search_range_qpel) >> pos); + + fieldsearchpos = ((3 * searchpos + 1) << search_range_qpel) >> 1; + for (i = 1; i >= -1; i -= 2) + { + point[++prednum].motion.mv_x = i * searchpos; + point[prednum].motion.mv_y = 0; + point[++prednum].motion.mv_x = i * searchpos; + point[prednum].motion.mv_y = i * searchpos; + point[++prednum].motion.mv_x = 0; + point[prednum].motion.mv_y = i * searchpos; + point[++prednum].motion.mv_x = -i * searchpos; + point[prednum].motion.mv_y = i * searchpos; + } + + for (i = 1; i >= -1; i -= 2) + { + point[++prednum].motion.mv_x = i * fieldsearchpos; + point[prednum].motion.mv_y = -i * searchpos; + point[++prednum].motion.mv_x = i * fieldsearchpos; + point[prednum].motion.mv_y = 0; + point[++prednum].motion.mv_x = i * fieldsearchpos; + point[prednum].motion.mv_y = i * searchpos; + point[++prednum].motion.mv_x = i * searchpos; + point[prednum].motion.mv_y = i * fieldsearchpos; + point[++prednum].motion.mv_x = 0; + point[prednum].motion.mv_y = i * fieldsearchpos; + point[++prednum].motion.mv_x = -i * searchpos; + point[prednum].motion.mv_y = i * fieldsearchpos; + } + } + } + + predictor->searchPoints = prednum; +} + +/*! +************************************************************************ +* \brief +* EPZS Global Initialization +************************************************************************ +*/ +int +EPZSStructInit (Slice * currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + int max_list_number = p_Vid->mb_aff_frame_flag ? 6 : 2; + int pel_error_me = 1 << (p_Vid->bitdepth_luma - 8); + int pel_error_me_cr = 1 << (p_Vid->bitdepth_chroma - 8); + int i, memory_size = 0; + double chroma_weight = + p_Inp->ChromaMEEnable ? pel_error_me_cr * p_Inp->ChromaMEWeight * (double) (p_Vid->width_cr * p_Vid->height_cr) / + (double) (p_Vid->width * p_Vid->height) : 0; + int searchlevels = RoundLog2 (p_Inp->search_range[p_Vid->view_id]) - 1; + int searcharray = + p_Inp->BiPredMotionEstimation ? (2 * imax (p_Inp->search_range[p_Vid->view_id], p_Inp->BiPredMESearchRange[p_Vid->view_id]) + + 1) << 2 : (2 * p_Inp->search_range[p_Vid->view_id] + 1) << 2; + p_EPZS->p_Vid = p_Vid; + p_EPZS->BlkCount = 1; + + //! In this implementation we keep threshold limits fixed. + //! However one could adapt these limits based on lagrangian + //! optimization considerations (i.e. qp), while also allow + //! adaptation of the limits themselves based on content or complexity. + + for (i = 0; i < 8; ++i) + { +#if (MVC_EXTENSION_ENABLE) + if ( (currSlice->view_id) && (p_Inp->EnableEnhLayerEPZSScalers) ) + { + p_EPZS->medthres[i] = p_Inp->EPZSMedThresScale[currSlice->view_id] * (MED_THRES_BASE[i] * pel_error_me + (int) (MED_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->maxthres[i] = p_Inp->EPZSMaxThresScale[currSlice->view_id] * (MAX_THRES_BASE[i] * pel_error_me + (int) (MAX_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->minthres[i] = p_Inp->EPZSMinThresScale[currSlice->view_id] * (MIN_THRES_BASE[i] * pel_error_me + (int) (MIN_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->subthres[i] = p_Inp->EPZSSubPelThresScale[currSlice->view_id] * (MED_THRES_BASE[i] * pel_error_me + (int) (MED_THRES_BASE[i] * chroma_weight + 0.5)); + } + else + { + p_EPZS->medthres[i] = p_Inp->EPZSMedThresScale[0] * (MED_THRES_BASE[i] * pel_error_me + (int) (MED_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->maxthres[i] = p_Inp->EPZSMaxThresScale[0] * (MAX_THRES_BASE[i] * pel_error_me + (int) (MAX_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->minthres[i] = p_Inp->EPZSMinThresScale[0] * (MIN_THRES_BASE[i] * pel_error_me + (int) (MIN_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->subthres[i] = p_Inp->EPZSSubPelThresScale[0] * (MED_THRES_BASE[i] * pel_error_me + (int) (MED_THRES_BASE[i] * chroma_weight + 0.5)); + } +#else + p_EPZS->medthres[i] = p_Inp->EPZSMedThresScale * (MED_THRES_BASE[i] * pel_error_me + (int) (MED_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->maxthres[i] = p_Inp->EPZSMaxThresScale * (MAX_THRES_BASE[i] * pel_error_me + (int) (MAX_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->minthres[i] = p_Inp->EPZSMinThresScale * (MIN_THRES_BASE[i] * pel_error_me + (int) (MIN_THRES_BASE[i] * chroma_weight + 0.5)); + p_EPZS->subthres[i] = p_Inp->EPZSSubPelThresScale * (MED_THRES_BASE[i] * pel_error_me + (int) (MED_THRES_BASE[i] * chroma_weight + 0.5)); +#endif + up_scale(&p_EPZS->medthres[i]); + up_scale(&p_EPZS->maxthres[i]); + up_scale(&p_EPZS->minthres[i]); + up_scale(&p_EPZS->subthres[i]); + } + //! Allocate and assign window based predictors. + //! Other window types could also be used, while method could be + //! made a bit more adaptive (i.e. patterns could be assigned + //! based on neighborhood + p_EPZS->window_predictor = allocEPZSpattern (searchlevels * 8); + p_EPZS->window_predictor_ext = allocEPZSpattern (searchlevels * 20); + EPZSWindowPredictorInit ((short) p_Inp->search_range[p_Vid->view_id], p_EPZS->window_predictor, 0); + EPZSWindowPredictorInit ((short) p_Inp->search_range[p_Vid->view_id], p_EPZS->window_predictor_ext, 1); + + //! Also assing search predictor memory + // maxwindow + spatial + blocktype + temporal + memspatial +#if (MVC_EXTENSION_ENABLE) + p_EPZS->predictor = allocEPZSpattern (searchlevels * 20 + 5 + 5 + 9 * (p_Inp->EPZSTemporal[0] | p_Inp->EPZSTemporal[1]) + 3 * (p_Inp->EPZSSpatialMem)); +#else + p_EPZS->predictor = allocEPZSpattern (searchlevels * 20 + 5 + 5 + 9 * (p_Inp->EPZSTemporal) + 3 * (p_Inp->EPZSSpatialMem)); +#endif + + //! Finally assign memory for all other elements + //! (distortion, EPZSMap, and temporal predictors) + + //memory_size += get_offset_mem2Dshort(&EPZSMap, searcharray, searcharray, (searcharray>>1), (searcharray>>1)); + memory_size += get_mem3Ddistblk (&(p_EPZS->distortion), max_list_number, 7, (p_Vid->width + MB_BLOCK_SIZE)/ BLOCK_SIZE); + if (p_Inp->BiPredMotionEstimation) + memory_size += get_mem3Ddistblk (&(p_EPZS->bi_distortion), max_list_number, 7, (p_Vid->width + MB_BLOCK_SIZE) / BLOCK_SIZE); + memory_size += get_mem3Ddistblk (&(p_EPZS->distortion_hpel), max_list_number, 7, (p_Vid->width + MB_BLOCK_SIZE)/ BLOCK_SIZE); + memory_size += get_mem2Dshort ((short ***) &(p_EPZS->EPZSMap), searcharray, searcharray); + + if (p_Inp->EPZSSpatialMem) + { +#if EPZSREF + memory_size += get_mem5Dmv (&(p_EPZS->p_motion), 6, p_Vid->max_num_references, 7, 4, p_Vid->width / BLOCK_SIZE); +#else + memory_size += get_mem4Dmv (&(p_EPZS->p_motion), 6, 7, 4, p_Vid->width / BLOCK_SIZE); +#endif + } + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->EPZSTemporal[currSlice->view_id] ) +#else + if (p_Inp->EPZSTemporal) +#endif + { + p_EPZS->p_colocated = allocEPZScolocated (p_Vid->width, p_Vid->height, p_Vid->active_sps->mb_adaptive_frame_field_flag); + } + + switch (p_Inp->EPZSPattern) + { + case 5: + p_EPZS->searchPattern = p_Vid->pmvfast; + break; + case 4: + p_EPZS->searchPattern = p_Vid->sbdiamond; + break; + case 3: + p_EPZS->searchPattern = p_Vid->ldiamond; + break; + case 2: + p_EPZS->searchPattern = p_Vid->ediamond; + break; + case 1: + p_EPZS->searchPattern = p_Vid->square; + break; + case 0: + default: + p_EPZS->searchPattern = p_Vid->sdiamond; + break; + } + + switch (p_Inp->EPZSDual) + { + case 6: + p_EPZS->searchPatternD = p_Vid->pmvfast; + break; + case 5: + p_EPZS->searchPatternD = p_Vid->sbdiamond; + break; + case 4: + p_EPZS->searchPatternD = p_Vid->ldiamond; + break; + case 3: + p_EPZS->searchPatternD = p_Vid->ediamond; + break; + case 2: + p_EPZS->searchPatternD = p_Vid->square; + break; + case 1: + default: + p_EPZS->searchPatternD = p_Vid->sdiamond; + break; + } + + return memory_size; +} + +/*! +************************************************************************ +* \brief +* Delete EPZS Alocated memory +************************************************************************ +*/ +void +EPZSStructDelete (Slice * currSlice) +{ + InputParameters *p_Inp = currSlice->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->EPZSTemporal[currSlice->view_id]) +#else + if (p_Inp->EPZSTemporal) +#endif + freeEPZScolocated (p_EPZS->p_colocated); + + //free_offset_mem2Dshort(EPZSMap, searcharray, (searcharray>>1), (searcharray>>1)); + free_mem2Dshort ((short **) p_EPZS->EPZSMap); + free_mem3Ddistblk (p_EPZS->distortion); + free_mem3Ddistblk (p_EPZS->distortion_hpel); + + if (p_Inp->BiPredMotionEstimation) + free_mem3Ddistblk (p_EPZS->bi_distortion); + + freeEPZSpattern (p_EPZS->window_predictor_ext); + freeEPZSpattern (p_EPZS->window_predictor); + freeEPZSpattern (p_EPZS->predictor); + + if (p_Inp->EPZSSpatialMem) + { +#if EPZSREF + free_mem5Dmv (p_EPZS->p_motion); +#else + free_mem4Dmv (p_EPZS->p_motion); +#endif + } + + free (currSlice->p_EPZS); + currSlice->p_EPZS = NULL; +} + +//! For ME purposes restricting the co-located partition is not necessary. +/*! +************************************************************************ +* \brief +* EPZS Slice Level Initialization +************************************************************************ +*/ +void +EPZSSliceInit (Slice * currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + StorablePicture *p_Pic = p_Vid->enc_picture; + EPZSColocParams *p = currSlice->p_EPZS->p_colocated; + StorablePicture ***listX = currSlice->listX; + StorablePicture *fs, *fs_top, *fs_bottom; + StorablePicture *fs1, *fs_top1, *fs_bottom1, *fsx; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + int i, j, k, jj, jdiv, loffset; + int prescale, iTRb, iTRp; + int list = (currSlice->slice_type == B_SLICE) ? LIST_1 : LIST_0; + int tempmv_scale[2]; + int epzs_scale[2][6][MAX_LIST_SIZE]; + int iref; + int invmv_precision = 8; + + // Lets compute scaling factoes between all references in lists. + // Needed to scale spatial predictors. + for (j = LIST_0; j < 2 + (currSlice->mb_aff_frame_flag << 2); ++j) + { + for (k = 0; k < currSlice->listXsize[j]; ++k) + { + for (i = 0; i < currSlice->listXsize[j]; ++i) + { + if ((j >> 1) == 0) + { + iTRb = iClip3 (-128, 127, p_Pic->poc - listX[j][i]->poc); + iTRp = iClip3 (-128, 127, p_Pic->poc - listX[j][k]->poc); + } + else if ((j >> 1) == 1) + { + iTRb = iClip3 (-128, 127, p_Pic->top_poc - listX[j][i]->poc); + iTRp = iClip3 (-128, 127, p_Pic->top_poc - listX[j][k]->poc); + } + else + { + iTRb = iClip3 (-128, 127, p_Pic->bottom_poc - listX[j][i]->poc); + iTRp = iClip3 (-128, 127, p_Pic->bottom_poc - listX[j][k]->poc); + } + + if (iTRp != 0) + { + prescale = (16384 + iabs (iTRp / 2)) / iTRp; + p_EPZS->mv_scale[j][i][k] = iClip3 (-2048, 2047, rshift_rnd_sf ((iTRb * prescale), 6)); + } + else + p_EPZS->mv_scale[j][i][k] = 256; + } + } + } + +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->EPZSTemporal[currSlice->view_id]) +#else + if (p_Inp->EPZSTemporal) +#endif + { + MotionVector **MotionVector0 = p->frame[LIST_0]; + MotionVector **MotionVector1 = p->frame[LIST_1]; + + fs_top = fs_bottom = fs = listX[list][0]; + if (currSlice->listXsize[list] > 1) + fs_top1 = fs_bottom1 = fs1 = listX[list][1]; + else + fs_top1 = fs_bottom1 = fs1 = listX[list][0]; + for (j = 0; j < 6; ++j) + { + for (i = 0; i < 6; ++i) + { + epzs_scale[0][j][i] = 256; + epzs_scale[1][j][i] = 256; + } + } + + for (j = 0; j < 2 + (currSlice->mb_aff_frame_flag << 2); j += 2) + { + for (i = 0; i < currSlice->listXsize[j]; ++i) + { + if (j == 0) + iTRb = iClip3 (-128, 127, p_Pic->poc - listX[LIST_0 + j][i]->poc); + else if (j == 2) + iTRb = iClip3 (-128, 127, p_Pic->top_poc - listX[LIST_0 + j][i]->poc); + else + iTRb = iClip3 (-128, 127, p_Pic->bottom_poc - listX[LIST_0 + j][i]->poc); + iTRp = iClip3 (-128, 127, listX[list + j][0]->poc - listX[LIST_0 + j][i]->poc); + + if (iTRp != 0) + { + prescale = (16384 + iabs (iTRp / 2)) / iTRp; + prescale = iClip3 (-2048, 2047, rshift_rnd_sf ((iTRb * prescale), 6)); + + //prescale = (iTRb * prescale + 32) >> 6; + } + else // This could not happen but lets use it in case that reference is removed. + prescale = 256; + + epzs_scale[0][j][i] = rshift_rnd_sf ((p_EPZS->mv_scale[j][0][i] * prescale), 8); + epzs_scale[0][j + 1][i] = prescale - 256; + + if (currSlice->listXsize[list + j] > 1) + { + iTRp = iClip3 (-128, 127, listX[list + j][1]->poc - listX[LIST_0 + j][i]->poc); + if (iTRp != 0) + { + prescale = (16384 + iabs (iTRp / 2)) / iTRp; + prescale = iClip3 (-2048, 2047, rshift_rnd_sf ((iTRb * prescale), 6)); + //prescale = (iTRb * prescale + 32) >> 6; + } + else // This could not happen but lets use it for case that reference is removed. + prescale = 256; + + epzs_scale[1][j][i] = rshift_rnd_sf ((p_EPZS->mv_scale[j][1][i] * prescale), 8); + epzs_scale[1][j + 1][i] = prescale - 256; + } + else + { + epzs_scale[1][j][i] = epzs_scale[0][j][i]; + epzs_scale[1][j + 1][i] = epzs_scale[0][j + 1][i]; + } + } + } + + if (currSlice->mb_aff_frame_flag) + { + fs_top = listX[list + 2][0]; + fs_bottom = listX[list + 4][0]; + + if (currSlice->listXsize[0] > 1) + { + fs_top1 = listX[list + 2][1]; + fs_bottom1 = listX[list + 4][1]; + } + } + else + { + if (currSlice->structure != FRAME) + { + if ((currSlice->structure != fs->structure) && (fs->coded_frame)) + { + if (currSlice->structure == TOP_FIELD) + { + fs_top = fs_bottom = fs = listX[list][0]->top_field; + fs_top1 = fs_bottom1 = fs1 = listX[list][0]->bottom_field; + } + else + { + fs_top = fs_bottom = fs = listX[list][0]->bottom_field; + fs_top1 = fs_bottom1 = fs1 = listX[list][0]->top_field; + } + } + } + } + + if (!currSlice->active_sps->frame_mbs_only_flag) + { + if (currSlice->mb_aff_frame_flag) + { + for (j = 0; j < fs->size_y >> 2; ++j) + { + jj = j >> 1; + jdiv = jj + 4 * (j >> 3); + for (i = 0; i < fs->size_x >> 2; ++i) + { + if (fs->mv_info[j][i].field_frame) + { + //! Assign frame buffers for field MBs + //! Check whether we should use top or bottom field mvs. + //! Depending on the assigned poc values. + if (iabs (p_Pic->poc - fs_bottom->poc) > iabs (p_Pic->poc - fs_top->poc)) + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + + if (fs->mv_info[jdiv][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs_top1; + loffset = 1; + } + else + { + fsx = fs_top; + loffset = 0; + } + + if (fs->mv_info[jdiv][i] .ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fs->mv_info[jdiv][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + break; + } + } + + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, &fsx->mv_info[jj][i].mv[LIST_0], invmv_precision); + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + else + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs->mv_info[jdiv + 4][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs_bottom1; + loffset = 1; + } + else + { + fsx = fs_bottom; + loffset = 0; + } + + if (fs->mv_info[jdiv + 4][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fs->mv_info[jdiv + 4][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + break; + } + } + + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, &fsx->mv_info[jj][i].mv[LIST_0], invmv_precision); + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + } + else + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + + if (fs->mv_info[j][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs1; + loffset = 1; + } + else + { + fsx = fs; + loffset = 0; + } + + if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fsx->mv_info[j][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + break; + } + } + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, &fsx->mv_info[j][i].mv[LIST_0], invmv_precision); + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + } + } + } + else + { + for (j = 0; j < fs->size_y >> 2; ++j) + { + jj = j >> 1; + jdiv = jj + 4 * (j >> 3); + for (i = 0; i < fs->size_x >> 2; ++i) + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs->mv_info[j][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs1; + loffset = 1; + } + else + { + fsx = fs; + loffset = 0; + } + + if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fsx->mv_info[j][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + + break; + } + } + + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, &fsx->mv_info[j][i].mv[LIST_0], invmv_precision); + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + } + } + + //! Generate field MVs from Frame MVs + if (currSlice->structure || currSlice->mb_aff_frame_flag) + { + for (j = 0; j < fs->size_y >> 3; ++j) + { + for (i = 0; i < fs->size_x >> 2; ++i) + { + if (!currSlice->mb_aff_frame_flag) + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs->mv_info[j][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs1; + loffset = 1; + } + else + { + fsx = fs; + loffset = 0; + } + + if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fsx->mv_info[j][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + break; + } + } + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, &fsx->mv_info[j][i].mv[LIST_0], invmv_precision); + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + else + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs_bottom->mv_info[j][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs_bottom1; + loffset = 1; + } + else + { + fsx = fs_bottom; + loffset = 0; + } + + if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (2 * currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + 4]); ++iref) + { + if (currSlice->listX[LIST_0 + 4][iref] == fsx->mv_info[j][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0 + 4][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1 + 4][iref]; + break; + } + } + + compute_scaled (&p->bot[LIST_0][j][i], &p->bot[LIST_1][j][i], tempmv_scale, &fsx->mv_info[j][i].mv[LIST_0], invmv_precision); + } + else + { + p->bot[LIST_0][j][i] = zero_mv; + p->bot[LIST_1][j][i] = zero_mv; + } + + if (!fs->mv_info[2 * j][i].field_frame) + { + p->bot[LIST_0][j][i].mv_y = (p->bot[LIST_0][j][i].mv_y + 1) >> 1; + p->bot[LIST_1][j][i].mv_y = (p->bot[LIST_1][j][i].mv_y + 1) >> 1; + } + + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs_top->mv_info[j][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs_top1; + loffset = 1; + } + else + { + fsx = fs_top; + loffset = 0; + } + if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (2 * currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + 2]); ++iref) + { + if (currSlice->listX[LIST_0 + 2][iref] == fsx->mv_info[j][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0 + 2][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1 + 2][iref]; + break; + } + } + + compute_scaled (&p->top[LIST_0][j][i], &p->top[LIST_1][j][i], tempmv_scale, &fsx->mv_info[j][i].mv[LIST_0], invmv_precision); + } + else + { + p->top[LIST_0][j][i] = zero_mv; + p->top[LIST_1][j][i] = zero_mv; + } + + if (!fs->mv_info[2 * j][i].field_frame) + { + p->top[LIST_0][j][i].mv_y = (p->top[LIST_0][j][i].mv_y + 1) >> 1; + p->top[LIST_1][j][i].mv_y = (p->top[LIST_1][j][i].mv_y + 1) >> 1; + } + } + } + } + } + + //! Use inference flag to remap mvs/references + //! Frame with field co-located + if (!currSlice->structure) + { + for (j = 0; j < fs->size_y >> 2; ++j) + { + jj = j >> 1; + jdiv = (j >> 1) + ((j >> 3) << 2); + for (i = 0; i < fs->size_x >> 2; ++i) + { + if (fs->mv_info[j][i].field_frame) + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs->mv_info[jdiv][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs1; + loffset = 1; + } + else + { + fsx = fs; + loffset = 0; + } + + if (fsx->mv_info[jdiv][i].ref_pic[LIST_0] != NULL) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fsx->mv_info[jdiv][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + break; + } + } + if (iabs (p_Pic->poc - fsx->bottom_field->poc) > iabs (p_Pic->poc - fsx->top_field->poc)) + { + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, + &fsx->top_field->mv_info[jj][i].mv[LIST_0], invmv_precision); + } + else + { + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, + &fsx->bottom_field->mv_info[jj][i].mv[LIST_0], invmv_precision); + } + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + } + } + } + } + else + { + for (j = 0; j < fs->size_y >> 2; ++j) + { + for (i = 0; i < fs->size_x >> 2; ++i) + { + tempmv_scale[LIST_0] = 256; + tempmv_scale[LIST_1] = 0; + if (fs->mv_info[j][i].ref_pic[LIST_0] == NULL && currSlice->listXsize[LIST_0] > 1) + { + fsx = fs1; + loffset = 1; + } + else + { + fsx = fs; + loffset = 0; + } + //if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL) + if (fsx->mv_info[j][i].ref_pic[LIST_0] != NULL && (!p_Vid->view_id || ((fsx->ref_pic_na[0]<0 || fsx->mv_info[j][i].ref_idx[LIST_0] != fsx->ref_pic_na[0])))) + { + for (iref = 0; iref < imin (currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0]); ++iref) + { + if (currSlice->listX[LIST_0][iref] == fsx->mv_info[j][i].ref_pic[LIST_0]) + { + tempmv_scale[LIST_0] = epzs_scale[loffset][LIST_0][iref]; + tempmv_scale[LIST_1] = epzs_scale[loffset][LIST_1][iref]; + break; + } + } + compute_scaled (&MotionVector0[j][i], &MotionVector1[j][i], tempmv_scale, &fsx->mv_info[j][i].mv[LIST_0], invmv_precision); + } + else + { + MotionVector0[j][i] = zero_mv; + MotionVector1[j][i] = zero_mv; + } + } + } + } + + if (!currSlice->active_sps->frame_mbs_only_flag) + { + for (j = 0; j < fs->size_y >> 2; ++j) + { + for (i = 0; i < fs->size_x >> 2; ++i) + { + if ((!currSlice->mb_aff_frame_flag && !currSlice->structure && fs->mv_info[j][i].field_frame) + || (currSlice->mb_aff_frame_flag && fs->mv_info[j][i].field_frame)) + { + MotionVector0[j][i].mv_y *= 2; + MotionVector1[j][i].mv_y *= 2; + } + else if (currSlice->structure && !fs->mv_info[j][i].field_frame) + { + MotionVector0[j][i].mv_y = (short) rshift_rnd_sf (MotionVector0[j][i].mv_y, 1); + MotionVector1[j][i].mv_y = (short) rshift_rnd_sf (MotionVector1[j][i].mv_y, 1); + } + } + } + } + } + +} + + +static void +is_block_available (Macroblock * currMB, StorablePicture * ref_picture, MEBlock * mv_block, int block_available[4]) +{ + if ((mv_block->block_y << 2) > 0) + { + if ((mv_block->block_x << 2) < 8) // first column of 8x8 blocks + { + if ((mv_block->block_y << 2) == 8) + { + block_available[0] = (mv_block->blocksize_x != MB_BLOCK_SIZE) || (currMB->mb_x < (ref_picture->size_x >> 4) - 1); + } + else + { + block_available[0] = ((mv_block->block_x << 2) + mv_block->blocksize_x != 8) + || (currMB->mb_x < (ref_picture->size_x >> 4) - 1); + } + } + else + { + block_available[0] = ((mv_block->block_x << 2) + mv_block->blocksize_x != MB_BLOCK_SIZE) || (currMB->mb_x < (ref_picture->size_x >> 4) - 1); + } + } + else + { + block_available[0] = ((mv_block->block_x << 2) + mv_block->blocksize_x != MB_BLOCK_SIZE) || (currMB->mb_x < (ref_picture->size_x >> 4) - 1); + } + + block_available[1] = ((mv_block->block_y << 2) + mv_block->blocksize_y != MB_BLOCK_SIZE) || ((currMB->mb_y < (ref_picture->size_y >> 4) - 1)); + block_available[2] = mv_block->block[0].available; + block_available[3] = mv_block->block[1].available; +} + +/*! +************************************************************************ +* \brief +* EPZS Block Type Predictors +************************************************************************ +*/ +void +EPZSBlockTypePredictorsMB (Slice * currSlice, MEBlock * mv_block, SPoint * point, int *prednum) +{ + int blocktype = mv_block->blocktype; + int block_x = mv_block->block_x; + int block_y = mv_block->block_y; + int list = mv_block->list; + int ref = mv_block->ref_idx; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + MotionVector ****all_mv = currSlice->all_mv[list]; + MotionVector *cur_mv = &point[*prednum].motion; + + if (blocktype != 1) + { + *cur_mv = all_mv[ref][BLOCK_PARENT[blocktype]][block_y][block_x]; + + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + + if(BLOCK_PARENT[blocktype] !=1) + { + cur_mv = &point[*prednum].motion; + *cur_mv = all_mv[ref][1][block_y][block_x]; + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + } + } + + if (ref > 0) + { + cur_mv = &point[*prednum].motion; + scale_mv (cur_mv, p_EPZS->mv_scale[list][ref][ref - 1], &all_mv[ref - 1][blocktype][block_y][block_x], 8); + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + + if (ref > 1) + { + cur_mv = &point[*prednum].motion; + scale_mv (cur_mv, p_EPZS->mv_scale[list][ref][0], &all_mv[0][blocktype][block_y][block_x], 8); + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + } + } +} + +/*! +*********************************************************************** +* \brief +* Spatial Predictors +* AMT/HYC +*********************************************************************** +*/ +short +EPZS_spatial_predictors (EPZSParameters * p_EPZS, MEBlock *mv_block, int list, int list_offset, short ref, struct pic_motion_params **mv_info) +{ + PixelPos * block = mv_block->block; + short refA = 0, refB = 0, refC = 0, refD = 0; + VideoParameters *p_Vid = p_EPZS->p_Vid; + int *mot_scale = p_EPZS->mv_scale[list + list_offset][ref]; + SPoint *point = p_EPZS->predictor->point; + + // zero predictor + (point++)->motion = zero_mv; + + // Non MB-AFF mode + if (!p_Vid->mb_aff_frame_flag) + { + refA = block[0].available ? (short) mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] : -1; + refB = block[1].available ? (short) mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] : -1; + refC = block[2].available ? (short) mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] : -1; + refD = block[3].available ? (short) mv_info[block[3].pos_y][block[3].pos_x].ref_idx[list] : -1; + + // Left Predictor + if (block[0].available) + { + scale_mv (&point->motion, mot_scale[refA], &mv_info[block[0].pos_y][block[0].pos_x].mv[list], 8); + /* + if (*((int*) &point->motion) == 0) + { + point->motion.mv_x = 12; + point->motion.mv_y = 0; + } + */ + ++point; + } + else + { + (point)->motion.mv_x = 12; + (point++)->motion.mv_y = 0; + } + // Up predictor + if (block[1].available) + { + scale_mv (&point->motion, mot_scale[refB], &mv_info[block[1].pos_y][block[1].pos_x].mv[list], 8); + /* + if (*((int*) &point->motion) == 0) + { + point->motion.mv_x = 0; + point->motion.mv_y = 12; + } + */ + ++point; + } + else + { + (point)->motion.mv_x = 0; + (point++)->motion.mv_y = 12; + } + + // Up-Right predictor + if (block[2].available) + { + scale_mv (&point->motion, mot_scale[refC], &mv_info[block[2].pos_y][block[2].pos_x].mv[list], 8); + /* + if (*((int*) &point->motion) == 0) + { + point->motion.mv_x = -12; + point->motion.mv_y = 0; + } + */ + ++point; + } + else + { + (point)->motion.mv_x = -12; + (point++)->motion.mv_y = 0; + } + + //Up-Left predictor + if (block[3].available) + { + scale_mv (&point->motion, mot_scale[refD], &mv_info[block[3].pos_y][block[3].pos_x].mv[list], 8); + /* + if (*((int*) &point->motion) == 0) + { + point->motion.mv_x = 0; + point->motion.mv_y = -12; + } + */ + ++point; + } + else + { + (point)->motion.mv_x = 0; + (point++)->motion.mv_y = -12; + } + } + else // MB-AFF mode + { + // Field Macroblock + if (list_offset) + { + refA = block[0].available ? p_Vid->mb_data[block[0].mb_addr].mb_field ? (short) mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] + : (short) mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] * 2 : -1; + refB = block[1].available ? p_Vid->mb_data[block[1].mb_addr].mb_field ? (short) mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] + : (short) mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] * 2 : -1; + refC = block[2].available ? p_Vid->mb_data[block[2].mb_addr].mb_field ? (short) mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] + : (short) mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] * 2 : -1; + refD = block[3].available ? p_Vid->mb_data[block[3].mb_addr].mb_field ? (short) mv_info[block[3].pos_y][block[3].pos_x].ref_idx[list] + : (short) mv_info[block[3].pos_y][block[3].pos_x].ref_idx[list] * 2 : -1; + + // Left Predictor + if (block[0].available) + { + scale_mv (&point->motion, mot_scale[refA], &mv_info[block[0].pos_y][block[0].pos_x].mv[list], 8); + if (!p_Vid->mb_data[block[0].mb_addr].mb_field) + //point->motion.mv_y = (short) rshift_rnd_sf(point->motion.mv_y, 1); + point->motion.mv_y <<= 1; + ++point; + } + else + { + (point)->motion.mv_x = 12; + (point++)->motion.mv_y = 0; + } + + // Up predictor + if (block[1].available) + { + scale_mv (&point->motion, mot_scale[refB], &mv_info[block[1].pos_y][block[1].pos_x].mv[list], 8); + if (!p_Vid->mb_data[block[1].mb_addr].mb_field) + //point->motion.mv_y = (short) rshift_rnd_sf(point->motion.mv_y, 1); + point->motion.mv_y <<= 1; + ++point; + } + else + { + (point)->motion.mv_x = 0; + (point++)->motion.mv_y = 12; + } + + // Up-Right predictor + if (block[2].available) + { + scale_mv (&point->motion, mot_scale[refC], &mv_info[block[2].pos_y][block[2].pos_x].mv[list], 8); + if (!p_Vid->mb_data[block[2].mb_addr].mb_field) + //point->motion.mv_y = (short) rshift_rnd_sf(point->motion.mv_y, 1); + point->motion.mv_y <<= 1; + ++point; + } + else + { + (point)->motion.mv_x = -12; + (point++)->motion.mv_y = 0; + } + + //Up-Left predictor + if (block[3].available) + { + scale_mv (&point->motion, mot_scale[refD], &mv_info[block[3].pos_y][block[3].pos_x].mv[list], 8); + if (!p_Vid->mb_data[block[3].mb_addr].mb_field) + //point->motion.mv_y = (short) rshift_rnd_sf(point->motion.mv_y, 1); + point->motion.mv_y <<= 1; + ++point; + } + else + { + (point)->motion.mv_x = 0; + (point++)->motion.mv_y = -12; + } + } + else // Frame macroblock + { + refA = block[0].available + ? p_Vid->mb_data[block[0].mb_addr].mb_field + ? (short) mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] >> 1 : (short) mv_info[block[0].pos_y][block[0].pos_x].ref_idx[list] : -1; + refB = block[1].available + ? p_Vid->mb_data[block[1].mb_addr].mb_field + ? (short) mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] >> 1 : (short) mv_info[block[1].pos_y][block[1].pos_x].ref_idx[list] : -1; + refC = block[2].available + ? p_Vid->mb_data[block[2].mb_addr].mb_field + ? (short) mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] >> 1 : (short) mv_info[block[2].pos_y][block[2].pos_x].ref_idx[list] : -1; + refD = block[3].available + ? p_Vid->mb_data[block[3].mb_addr].mb_field + ? (short) mv_info[block[3].pos_y][block[3].pos_x].ref_idx[list] >> 1 : (short) mv_info[block[3].pos_y][block[3].pos_x].ref_idx[list] : -1; + + // Left Predictor + if (block[0].available) + { + scale_mv (&point->motion, mot_scale[refA], &mv_info[block[0].pos_y][block[0].pos_x].mv[list], 8); + if (p_Vid->mb_data[block[0].mb_addr].mb_field) + point->motion.mv_y = (short) rshift_rnd_sf (point->motion.mv_y, 1); + ++point; + } + else + { + (point)->motion.mv_x = 12; + (point++)->motion.mv_y = 0; + } + + // Up predictor + if (block[1].available) + { + scale_mv (&point->motion, mot_scale[refB], &mv_info[block[1].pos_y][block[1].pos_x].mv[list], 8); + if (p_Vid->mb_data[block[1].mb_addr].mb_field) + point->motion.mv_y = (short) rshift_rnd_sf (point->motion.mv_y, 1); + ++point; + } + else + { + (point)->motion.mv_x = 0; + (point++)->motion.mv_y = 12; + } + + // Up-Right predictor + if (block[2].available) + { + scale_mv (&point->motion, mot_scale[refC], &mv_info[block[2].pos_y][block[2].pos_x].mv[list], 8); + if (p_Vid->mb_data[block[2].mb_addr].mb_field) + point->motion.mv_y = (short) rshift_rnd_sf (point->motion.mv_y, 1); + ++point; + } + else + { + (point)->motion.mv_x = -12; + (point++)->motion.mv_y = 0; + } + + //Up-Left predictor + if (block[3].available) + { + scale_mv (&point->motion, mot_scale[refD], &mv_info[block[3].pos_y][block[3].pos_x].mv[list], 8); + if (p_Vid->mb_data[block[3].mb_addr].mb_field) + point->motion.mv_y = (short) rshift_rnd_sf (point->motion.mv_y, 1); + ++point; + } + else + { + (point)->motion.mv_x = 12; + (point++)->motion.mv_y = 0; + } + } + } + + return ((refA == -1) + (refB == -1) + ((refC == -1) && (refD == -1))); +} + +/*! +*********************************************************************** +* \brief +* Temporal Predictors +* AMT/HYC +*********************************************************************** +*/ +void +EPZS_temporal_predictors (Macroblock *currMB, //! <-- Current Macroblock + StorablePicture *ref_picture, //! <-- Current reference picture + EPZSParameters * p_EPZS, //! <-- EPZS structure + MEBlock *mv_block, //! <-- motion estimation information block + int *prednum, + distblk stopCriterion, + distblk min_mcost) +{ + int list_offset = currMB->list_offset; + int blockshape_x = (mv_block->blocksize_x >> 2); // horizontal block size in 4-pel units + int blockshape_y = (mv_block->blocksize_y >> 2); // vertical block size in 4-pel units + int o_block_x = mv_block->pos_x2; + int o_block_y = mv_block->pos_y2; + int list = mv_block->list; + int ref = mv_block->ref_idx; + + EPZSColocParams *p_Coloc = p_EPZS->p_colocated; + SPoint * point = p_EPZS->predictor->point; + int mvScale = p_EPZS->mv_scale[list + list_offset][ref][0]; + MotionVector **col_mv = (list_offset == 0) ? p_Coloc->frame[list] : (list_offset == 2) ? p_Coloc->top[list] : p_Coloc->bot[list]; + MotionVector *cur_mv = &point[*prednum].motion; + + *prednum += add_predictor (cur_mv, col_mv[o_block_y][o_block_x], mvScale, 8); + if (min_mcost > stopCriterion && ref < 2) + { + int block_available[4]; + is_block_available (currMB, ref_picture, mv_block, block_available); + + if (block_available[2]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y][o_block_x - 1], mvScale, 8); + //Up_Left + if (block_available[3]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y - 1][o_block_x - 1], mvScale, 8); + } + + //Down_Left + if (block_available[1]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y + blockshape_y][o_block_x - 1], mvScale, 8); + } + } + + // Up + if (block_available[3]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y - 1][o_block_x], mvScale, 8); + } + + // Up - Right + if (block_available[0]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y][o_block_x + blockshape_x], mvScale, 8); + if (block_available[3]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y - 1][o_block_x + blockshape_x], mvScale, 8); + } + + if (block_available[1]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y + blockshape_y][o_block_x + blockshape_x], mvScale, 8); + } + } + + if (block_available[1]) + { + *prednum += add_predictor (&point[*prednum].motion, col_mv[o_block_y + blockshape_y][o_block_x], mvScale, 8); + } + } +} + + +/*! +************************************************************************ +* \brief +* EPZS Block Type Predictors +************************************************************************ +*/ +void +EPZSBlockTypePredictors (Slice * currSlice, MEBlock *mv_block, SPoint * point, int *prednum) +{ + int blocktype = mv_block->blocktype; + int block_x = mv_block->block_x; + int block_y = mv_block->block_y; + int list = mv_block->list; + int ref = mv_block->ref_idx; + MotionVector ****all_mv = currSlice->all_mv[list]; + MotionVector *cur_mv = &point[*prednum].motion; + + *cur_mv = all_mv[ref][BLOCK_PARENT[blocktype]][block_y][block_x]; + + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + + if ((ref > 0) && (currSlice->structure != FRAME)) + { + EPZSParameters *p_EPZS = currSlice->p_EPZS; + cur_mv = &point[*prednum].motion; + scale_mv (cur_mv, p_EPZS->mv_scale[list][ref][ref - 1], &all_mv[ref - 1][blocktype][block_y][block_x], 8); + + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + if (ref > 1) + { + cur_mv = &point[*prednum].motion; + scale_mv (cur_mv, p_EPZS->mv_scale[list][ref][0], &all_mv[0][blocktype][block_y][block_x], 8); + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); + } + } + + cur_mv = &point[*prednum].motion; + *cur_mv = all_mv[ref][1][block_y][block_x]; + + //*prednum += ((cur_mv->mv_x | cur_mv->mv_y) != 0); + *prednum += (*((int *) cur_mv) != 0); +} + +/*! +************************************************************************ +* \brief +* EPZS Window Based Predictors +************************************************************************ +*/ +void +EPZSWindowPredictors (MotionVector * mv, EPZSStructure * predictor, int *prednum, EPZSStructure * windowPred) +{ + int pos; + SPoint *wPoint = &windowPred->point[0]; + SPoint *pPoint = &predictor->point[(*prednum)]; + + for (pos = 0; pos < windowPred->searchPoints; ++pos) + { + (pPoint++)->motion = add_MVs ((wPoint++)->motion, mv); + } + *prednum += windowPred->searchPoints; +} + +/*! +*********************************************************************** +* \brief +* Spatial Predictors +* AMT/HYC +*********************************************************************** +*/ +void +EPZS_spatial_memory_predictors (EPZSParameters * p_EPZS, //!< EPZS Parameters + MEBlock * mv_block, //!< Motion estimation structure + int list, //!< Current list + int *prednum, //!< predictor position + int img_width) //!< image width +{ + + SPoint *point = p_EPZS->predictor->point; + + int blocktype = mv_block->blocktype - 1; + + int by = mv_block->block_y; + + int bs_x = (mv_block->blocksize_x >> 2); // horizontal block size in 4-pel units + int bs_y = (mv_block->blocksize_y >> 2); // vertical block size in 4-pel units + int pic_x = mv_block->pos_x2; + + int ref = mv_block->ref_idx; + +#if EPZSREF + MotionVector **prd_mv = p_EPZS->p_motion[list][ref][blocktype]; + MotionVector *cur_mv = &point[*prednum].motion; + + // Left Predictor + if (pic_x > 0) + { + *cur_mv = prd_mv[by][pic_x - bs_x]; + *prednum += (*((int *) cur_mv) != 0); + cur_mv = &point[*prednum].motion; + } + + by = (by > 0) ? by - bs_y : 4 - bs_y; + + // Up predictor + *cur_mv = prd_mv[by][pic_x]; + *prednum += (*((int *) cur_mv) != 0); + + // Up-Right predictor + if (pic_x + bs_x < img_width) + { + cur_mv = &point[*prednum].motion; + *cur_mv = prd_mv[by][pic_x + bs_x]; + *prednum += (*((int *) cur_mv) != 0); + } +#else + int mot_scale = p_EPZS->mv_scale[list][ref][0]; + + MotionVector **prd_mv = p_EPZS->p_motion[list][blocktype]; + + // Left Predictor + point[*prednum].motion.mv_x = (pic_x > 0) + ? (short) rshift_rnd_sf ((mot_scale * prd_mv[by][pic_x - bs_x].mv_x), 8) + : 0; + point[*prednum].motion.mv_y = (pic_x > 0) + ? (short) rshift_rnd_sf ((mot_scale * prd_mv[by][pic_x - bs_x].mv_y), 8) + : 0; + *prednum += ((point[*prednum].motion.mv_x != 0) || (point[*prednum].motion.mv_y != 0)); + + // Up predictor + point[*prednum].motion.mv_x = (by > 0) + ? (short) rshift_rnd_sf ((mot_scale * prd_mv[by - bs_y][pic_x].mv_x), 8) + : (short) rshift_rnd_sf ((mot_scale * prd_mv[4 - bs_y][pic_x].mv_x), 8); + point[*prednum].motion.mv_y = (by > 0) + ? (short) rshift_rnd_sf ((mot_scale * prd_mv[by - bs_y][pic_x].mv_y), 8) + : (short) rshift_rnd_sf ((mot_scale * prd_mv[4 - bs_y][pic_x].mv_y), 8); + *prednum += ((point[*prednum].motion.mv_x != 0) || (point[*prednum].motion.mv_y != 0)); + + // Up-Right predictor + point[*prednum].motion.mv_x = (pic_x + bs_x < img_width) + ? (by > 0) + ? (short) rshift_rnd_sf ((mot_scale * prd_mv[by - bs_y][pic_x + bs_x].mv_x), 8) + : (short) rshift_rnd_sf ((mot_scale * prd_mv[4 - bs_y][pic_x + bs_x].mv_x), 8) + : 0; + point[*prednum].motion.mv_y = (pic_x + bs_x < img_width) + ? (by > 0) + ? (short) rshift_rnd_sf ((mot_scale * prd_mv[by - bs_y][pic_x + bs_x].mv_y), 8) + : (short) rshift_rnd_sf ((mot_scale * prd_mv[4 - bs_y][pic_x + bs_x].mv_y), 8) + : 0; + *prednum += ((point[*prednum].motion.mv_x != 0) || (point[*prednum].motion.mv_y != 0)); +#endif +} + +/*! +************************************************************************************* +* \brief +* Determine stop criterion for EPZS +************************************************************************************* +*/ +distblk +EPZSDetermineStopCriterion (EPZSParameters * p_EPZS, distblk *prevSad, MEBlock * mv_block, distblk lambda_dist) +{ + int blocktype = mv_block->blocktype; + int blockshape_x = (mv_block->blocksize_x >> 2); + PixelPos *block = mv_block->block; + distblk sadA, sadB, sadC, stopCriterion; + sadA = block[0].available ? prevSad[-blockshape_x] : DISTBLK_MAX; + sadB = block[1].available ? prevSad[0] : DISTBLK_MAX; + sadC = block[2].available ? prevSad[blockshape_x] : DISTBLK_MAX; + + stopCriterion = distblkmin (sadA, distblkmin (sadB, sadC)); + stopCriterion = distblkmax (stopCriterion, p_EPZS->minthres[blocktype]); + stopCriterion = distblkmin (stopCriterion, p_EPZS->maxthres[blocktype] + lambda_dist); + stopCriterion = (9 * distblkmax (p_EPZS->medthres[blocktype] + lambda_dist, stopCriterion) + 2 * p_EPZS->medthres[blocktype]) >> 3; + + return stopCriterion + lambda_dist; +} + +/*! +*********************************************************************** +* \brief +* Report function for EPZS Fast ME +* AMT/HYC +*********************************************************************** +*/ +void +EPZSOutputStats (InputParameters * p_Inp, FILE * stat, short stats_file) +{ + if (stats_file == 1) + { + fprintf (stat, " EPZS Pattern : %s\n", EPZS_PATTERN[p_Inp->EPZSPattern]); + fprintf (stat, " EPZS Dual Pattern : %s\n", EPZS_DUAL_PATTERN[p_Inp->EPZSDual]); + fprintf (stat, " EPZS Fixed Predictors : %s\n", EPZS_FIXED_PREDICTORS[p_Inp->EPZSFixed]); +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + fprintf (stat, " BL EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal[0]]); + fprintf (stat, " EL EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal[1]]); + } + else + { + fprintf (stat, " EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal[0]]); + } +#else + fprintf (stat, " EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal]); +#endif + fprintf (stat, " EPZS Spatial Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSSpatialMem]); +#if (MVC_EXTENSION_ENABLE) + if ( (p_Inp->num_of_views == 2) && (p_Inp->EnableEnhLayerEPZSScalers) ) + { + fprintf (stat, " BL EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale[0], p_Inp->EPZSMinThresScale[0], p_Inp->EPZSMaxThresScale[0]); + fprintf (stat, " EL EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale[1], p_Inp->EPZSMinThresScale[1], p_Inp->EPZSMaxThresScale[1]); + } + else + { + fprintf (stat, " EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale[0], p_Inp->EPZSMinThresScale[0], p_Inp->EPZSMaxThresScale[0]); + } +#else + fprintf (stat, " EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale, p_Inp->EPZSMinThresScale, p_Inp->EPZSMaxThresScale); +#endif + fprintf (stat, " EPZS Subpel ME : %s\n", EPZS_SUBPEL_METHOD[p_Inp->EPZSSubPelME]); + fprintf (stat, " EPZS Subpel ME BiPred : %s\n", EPZS_SUBPEL_METHOD[p_Inp->EPZSSubPelMEBiPred]); + } + else + { + fprintf (stat, " EPZS Pattern : %s\n", EPZS_PATTERN[p_Inp->EPZSPattern]); + fprintf (stat, " EPZS Dual Pattern : %s\n", EPZS_DUAL_PATTERN[p_Inp->EPZSDual]); + fprintf (stat, " EPZS Fixed Predictors : %s\n", EPZS_FIXED_PREDICTORS[p_Inp->EPZSFixed]); +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + fprintf (stat, " BL EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal[0]]); + fprintf (stat, " EL EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal[1]]); + } + else + { + fprintf (stat, " EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal[0]]); + } +#else + fprintf (stat, " EPZS Temporal Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSTemporal]); +#endif + fprintf (stat, " EPZS Spatial Predictors : %s\n", EPZS_OTHER_PREDICTORS[p_Inp->EPZSSpatialMem]); +#if (MVC_EXTENSION_ENABLE) + if ( (p_Inp->num_of_views == 2) && (p_Inp->EnableEnhLayerEPZSScalers) ) + { + fprintf (stat, " BL EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale[0], p_Inp->EPZSMinThresScale[0], p_Inp->EPZSMaxThresScale[0]); + fprintf (stat, " EL EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale[1], p_Inp->EPZSMinThresScale[1], p_Inp->EPZSMaxThresScale[1]); + } + else + { + fprintf (stat, " EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale[0], p_Inp->EPZSMinThresScale[0], p_Inp->EPZSMaxThresScale[0]); + } +#else + fprintf (stat, " EPZS Threshold Multipliers : (%d %d %d)\n", p_Inp->EPZSMedThresScale, p_Inp->EPZSMinThresScale, p_Inp->EPZSMaxThresScale); +#endif + fprintf (stat, " EPZS Subpel ME : %s\n", EPZS_SUBPEL_METHOD[p_Inp->EPZSSubPelME]); + fprintf (stat, " EPZS Subpel ME BiPred : %s\n", EPZS_SUBPEL_METHOD[p_Inp->EPZSSubPelMEBiPred]); + } +} diff --git a/lencod/src/me_epzs_int.c b/lencod/src/me_epzs_int.c new file mode 100644 index 0000000..c30a691 --- /dev/null +++ b/lencod/src/me_epzs_int.c @@ -0,0 +1,1030 @@ + +/*! +************************************************************************************* +* \file me_epzs_int.c +* +* \brief +* Motion Estimation using EPZS +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "refbuf.h" +#include "macroblock.h" +#include "me_distortion.h" +#include "me_epzs.h" +#include "me_epzs_common.h" +#include "mv_search.h" + +// Functions + +/*! +*********************************************************************** +* \brief +* FAST Motion Estimation using EPZS +* AMT/HYC +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_integer_motion_estimation (Macroblock * currMB, // <-- current Macroblock + MotionVector * pred_mv, // <-- motion vector predictor in sub-pel units + MEBlock * mv_block, // <-- motion vector information + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int blocktype = mv_block->blocktype; + + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + MotionVector *mv = &mv_block->mv[list]; + SearchWindow *searchRange = &mv_block->searchRange; + int mapCenter_x = searchRange->max_x - mv->mv_x; + int mapCenter_y = searchRange->max_y - mv->mv_y; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + distblk lambda_dist = weighted_cost(lambda_factor, 2); + distblk stopCriterion = p_EPZS->medthres[blocktype] + lambda_dist; + distblk *prevSad = &p_EPZS->distortion[cur_list][blocktype - 1][mv_block->pos_x2]; + + MotionVector *p_motion = NULL; + + EPZSStructure *searchPatternF = p_EPZS->searchPattern; + uint16 **EPZSMap = &p_EPZS->EPZSMap[mapCenter_y]; + uint16 *EPZSPoint = &p_EPZS->EPZSMap[searchRange->max_y][searchRange->max_x]; + + MotionVector center = pad_MVs (*mv, mv_block); + MotionVector pred = pad_MVs (*pred_mv, mv_block); + MotionVector tmp = *mv, cand = center; + + ++p_EPZS->BlkCount; + if (p_EPZS->BlkCount == 0) + ++p_EPZS->BlkCount; + + if (p_Inp->EPZSSpatialMem) + { +#if EPZSREF + p_motion = &p_EPZS->p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][mv_block->pos_x2]; +#else + p_motion = &p_EPZS->p_motion[cur_list][blocktype - 1][mv_block->block_y][mv_block->pos_x2]; +#endif + } + + // Clear EPZSMap + // memset(EPZSMap[0],FALSE,searcharray*searcharray); + // Check median candidate; + //p_EPZS->EPZSMap[0][0] = p_EPZS->BlkCount; + *EPZSPoint = p_EPZS->BlkCount; + + //--- initialize motion cost (cost for motion vector) and check --- + min_mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + //--- add residual cost to motion cost --- + min_mcost += mv_block->computePredFPel (ref_picture, mv_block, DISTBLK_MAX - min_mcost, &cand); + + + // Additional threshold for ref>0 + //if ((ref > 0 && currSlice->structure == FRAME) && (*prevSad < imin (p_EPZS->medthres[blocktype] + lambda_dist, min_mcost))) + if ((ref > 0 && currSlice->structure == FRAME) && + ((*prevSad < distblkmin (p_EPZS->medthres[blocktype] + lambda_dist, min_mcost)) || (*prevSad * 8 < min_mcost))) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + //! If p_EPZS->medthres satisfied, then terminate, otherwise generate Predictors + //! Condition could be strengthened by consideration distortion of adjacent partitions. + if (min_mcost > stopCriterion) + { + SPoint *p_EPZS_point = p_EPZS->predictor->point; + Boolean checkMedian = FALSE; + distblk second_mcost = DISTBLK_MAX; + distblk mcost; + int prednum = 5; + int conditionEPZS; + MotionVector tmp2 = {0, 0}, tmv; + int pos; + short invalid_refs = 0; + + stopCriterion = EPZSDetermineStopCriterion (p_EPZS, prevSad, mv_block, lambda_dist); + + if (min_mcost < (stopCriterion >> 1)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + // This seems ok to add since this is considered a good enough position + if ((ref == 0) || (*prevSad > min_mcost)) + *prevSad = min_mcost; + + return min_mcost; + } + + //! Add Spatial Predictors in predictor list. + //! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little + //! in terms of performance and could be removed with little penalty if any. + invalid_refs = EPZS_spatial_predictors (p_EPZS, mv_block, + list, currMB->list_offset, ref, motion); + + if (p_Inp->EPZSSpatialMem) + EPZS_spatial_memory_predictors (p_EPZS, mv_block, cur_list, &prednum, ref_picture->size_x >> 2); + + // Temporal predictors +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->EPZSTemporal[currSlice->view_id] ) +#else + // Temporal predictors + if (p_Inp->EPZSTemporal) +#endif + { + EPZS_temporal_predictors (currMB, ref_picture, p_EPZS, mv_block, &prednum, stopCriterion, min_mcost); + } + + //! Window Size Based Predictors + //! Basically replaces a Hierarchical ME concept and helps escaping local minima, or + //! determining large motion variations. + //! Following predictors can be adjusted further (i.e. removed, conditioned etc) + //! based on distortion, correlation of adjacent MVs, complexity etc. These predictors + //! and their conditioning could also be moved after all other predictors have been + //! tested. Adaptation could also be based on type of material and coding mode (i.e. + //! field/frame coding,MBAFF etc considering the higher dependency with opposite parity field + //conditionEPZS = ((min_mcost > stopCriterion) + // && (p_Inp->EPZSFixed > 1 || (p_Inp->EPZSFixed && currSlice->slice_type == P_SLICE))); + //conditionEPZS = ((ref == 0) && (min_mcost > stopCriterion) + //&& (p_Inp->EPZSFixed > 1 || (p_Inp->EPZSFixed && currSlice->slice_type == P_SLICE))); + //conditionEPZS = ((min_mcost > stopCriterion) && ((ref < 2 && blocktype < 4) + conditionEPZS = (p_Inp->EPZSFixed == 3 && (currMB->mb_x == 0 || currMB->mb_y == 0)) + || ((min_mcost > 3 * stopCriterion) && ((ref < 2 && blocktype < 4) || (ref < 1 && blocktype == 4) + || ((currSlice->structure != FRAME || currMB->list_offset) + && ref < 3)) + && (p_Inp->EPZSFixed > 1 || (p_Inp->EPZSFixed && currSlice->slice_type == P_SLICE))); + + if (conditionEPZS) + EPZSWindowPredictors (mv, p_EPZS->predictor, &prednum, + (invalid_refs > 2) && (ref < 1 + (currSlice->structure != FRAME || currMB->list_offset)) + ? p_EPZS->window_predictor_ext : p_EPZS->window_predictor); + + //! Blocktype/Reference dependent predictors. + //! Since already mvs for other blocktypes/references have been computed, we can reuse + //! them in order to easier determine the optimal point. Use of predictors could depend + //! on cost, + //conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > stopCriterion) || currSlice->structure != FRAME || currMB->list_offset); + conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > 2 * stopCriterion)); + + if (conditionEPZS && currMB->mbAddrX != 0 && p_Inp->EPZSBlockType) + EPZSBlockTypePredictorsMB (currSlice, mv_block, p_EPZS_point, &prednum); + + //! Check all predictors + for (pos = 0; pos < prednum; ++pos) + { + tmv = p_EPZS_point[pos].motion; + //if (((iabs (tmv.mv_x - mv->mv_x) > searchRange->max_x || iabs (tmv.mv_y - mv->mv_y) > searchRange->max_y)) && (tmv.mv_x || tmv.mv_y)) + if ((iabs (tmv.mv_x - mv->mv_x) - searchRange->max_x <= 0) && (iabs (tmv.mv_y - mv->mv_y) - searchRange->max_y <= 0)) + { + EPZSPoint = &EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x]; + if (*EPZSPoint != p_EPZS->BlkCount) + { + *EPZSPoint = p_EPZS->BlkCount; + cand = pad_MVs (tmv, mv_block); + + //--- set motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (mcost < second_mcost) + { + mcost += mv_block->computePredFPel (ref_picture, mv_block, second_mcost - mcost, &cand); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + tmp2 = tmp; + tmp = tmv; + second_mcost = min_mcost; + min_mcost = mcost; + checkMedian = TRUE; + } + //else if (mcost < second_mcost && (tmp.mv_x != tmv.mv_x || tmp.mv_y != tmv.mv_y)) + else if (mcost < second_mcost) + { + tmp2 = tmv; + second_mcost = mcost; + checkMedian = TRUE; + } + } + } + } + } + + if ((ref > 0 && currSlice->structure == FRAME) && (*prevSad * 3 < min_mcost)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + *mv = tmp; + + // this condition seems redundant since (*prevSad * 3 < min_mcost) + //if ((*prevSad > min_mcost)) + // *prevSad = min_mcost; + + return min_mcost; + } + + //! Refine using EPZS pattern if needed + //! Note that we are using a conservative threshold method. Threshold + //! could be tested after checking only a certain number of predictors + //! instead of the full set. Code could be easily modified for this task. + if (min_mcost > stopCriterion) + { + const int mv_range = 10; + int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0; + int totalCheckPts = 0, motionDirection = 0; + + //! Adapt pattern based on different conditions. + if (p_Inp->EPZSPattern != 0) + { + if ((min_mcost < stopCriterion + ((3 * p_EPZS->medthres[blocktype]) >> 1))) + { + if ((tmp.mv_x == 0 && tmp.mv_y == 0) + || (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else if (ref > 0 && blocktype != 1) + searchPatternF = p_Vid->square; + else + searchPatternF = p_EPZS->searchPattern; + } + + //! center on best predictor + center = tmp; + + for (;;) + { + totalCheckPts = searchPatternF->searchPoints; + do + { + checkPts = totalCheckPts; + do + { + tmv = add_MVs (center, &(searchPatternF->point[pointNumber].motion)); + + if (((iabs (tmv.mv_x - mv->mv_x) - searchRange->max_x) <= 0) && ((iabs (tmv.mv_y - mv->mv_y) - searchRange->max_y) <= 0)) + { + EPZSPoint = &EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x]; + if (*EPZSPoint != p_EPZS->BlkCount) + { + *EPZSPoint = p_EPZS->BlkCount; + cand = pad_MVs (tmv, mv_block); + + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (mcost < min_mcost) + { + mcost += mv_block->computePredFPel (ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + tmp = tmv; + min_mcost = mcost; + motionDirection = pointNumber; + } + } + } + } + ++pointNumber; + if (pointNumber >= searchPatternF->searchPoints) + pointNumber -= searchPatternF->searchPoints; + checkPts--; + } + while (checkPts > 0); + + if (nextLast || ((tmp.mv_x == center.mv_x) && (tmp.mv_y == center.mv_y))) + { + patternStop = searchPatternF->stopSearch; + searchPatternF = searchPatternF->nextpattern; + totalCheckPts = searchPatternF->searchPoints; + nextLast = searchPatternF->nextLast; + motionDirection = 0; + pointNumber = 0; + } + else + { + totalCheckPts = searchPatternF->point[motionDirection].next_points; + pointNumber = searchPatternF->point[motionDirection].start_nmbr; + center = tmp; + } + } + while (patternStop != 1); + + if ((ref > 0) && (currSlice->structure == FRAME) + && ((4 * *prevSad < min_mcost) || ((3 * *prevSad < min_mcost) && (*prevSad <= stopCriterion)))) + { + *mv = tmp; +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + return min_mcost; + } + + //! Check Second best predictor with EPZS pattern + conditionEPZS = (checkMedian == TRUE) + && (ref == 0 || (ref > 0 && min_mcost < 2 * *prevSad)) + && (min_mcost > (( 3 * stopCriterion) >> 1)) && (p_Inp->EPZSDual > 0); + + if (!conditionEPZS) + break; + + pointNumber = 0; + patternStop = 0; + motionDirection = 0; + nextLast = 0; + + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (tmp.mv_x == mv->mv_x && tmp.mv_y == mv->mv_y)) + { + if (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range)) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_EPZS->searchPatternD; + + //! Second best. Note that following code is identical as for best predictor. + center = tmp2; + checkMedian = FALSE; + } + } + } + + if ((ref == 0) || (*prevSad > min_mcost)) + *prevSad = min_mcost; +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + //printf("value %d %d %d %d\n", p_motion->mv_x, p_motion->mv_y, p_motion[cur_list][ref][0][0][0].mv_x, p_motion[list + list_offset][ref][0][0][0].mv_y); + //printf("xxxxx %d %d %d %d\n", p_motion->mv_x, p_motion->mv_y, p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][pic_pix_x2].mv_x, p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][pic_pix_x2].mv_y); + } + + *mv = tmp; + + return min_mcost; +} + + +/*! +*********************************************************************** +* \brief +* FAST Motion Estimation using EPZS +* AMT/HYC +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_integer_subMB_motion_estimation (Macroblock * currMB, // <-- current Macroblock + MotionVector * pred_mv, // <-- motion vector predictor in sub-pel units + MEBlock * mv_block, // <-- motion vector information + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int blocktype = mv_block->blocktype; + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + MotionVector *mv = &mv_block->mv[list]; + MotionVector center = pad_MVs (*mv, mv_block); + MotionVector cand = center; + MotionVector pred = pad_MVs (*pred_mv, mv_block); + MotionVector tmp = *mv; + SearchWindow *searchRange = &mv_block->searchRange; + int mapCenter_x = searchRange->max_x - mv->mv_x; + int mapCenter_y = searchRange->max_y - mv->mv_y; + + short pic_pix_x2 = mv_block->pos_x2; + distblk lambda_dist = weighted_cost(lambda_factor,3); + distblk stopCriterion = p_EPZS->medthres[blocktype] + lambda_dist; + distblk *prevSad = &p_EPZS->distortion[cur_list][blocktype - 1][pic_pix_x2]; + MotionVector *p_motion = NULL; + + EPZSStructure *searchPatternF = p_EPZS->searchPattern; + uint16 **EPZSMap = &p_EPZS->EPZSMap[mapCenter_y]; + + ++p_EPZS->BlkCount; + if (p_EPZS->BlkCount == 0) + ++p_EPZS->BlkCount; + + if (p_Inp->EPZSSpatialMem) + { +#if EPZSREF + p_motion = &p_EPZS->p_motion[cur_list][ref][blocktype - 1][mv_block->block_y][pic_pix_x2]; +#else + p_motion = &p_EPZS->p_motion[cur_list][blocktype - 1][mv_block->block_y][pic_pix_x2]; +#endif + } + + // Clear p_EPZS->EPZSMap + // memset(p_EPZS->EPZSMap[0],FALSE,searcharray*searcharray); + // Check median candidate; + //p_EPZS->EPZSMap[0][0] = p_EPZS->BlkCount; + p_EPZS->EPZSMap[searchRange->max_y][searchRange->max_x] = p_EPZS->BlkCount; + + //--- initialize motion cost (cost for motion vector) and check --- + min_mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + //--- add residual cost to motion cost --- + min_mcost += mv_block->computePredFPel (ref_picture, mv_block, DISTBLK_MAX-min_mcost, &cand); + + + // Additional threshold for ref>0 + if ((ref > 0 && currSlice->structure == FRAME) && + ((*prevSad < distblkmin (p_EPZS->medthres[blocktype] + lambda_dist, min_mcost)) || (*prevSad * 6 < min_mcost))) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + //! If p_EPZS->medthres satisfied, then terminate, otherwise generate Predictors + //! Condition could be strengthened by consideration distortion of adjacent partitions. + if (min_mcost > stopCriterion) + { + SPoint *p_EPZS_point = p_EPZS->predictor->point; + Boolean checkMedian = FALSE; + distblk second_mcost = DISTBLK_MAX; + distblk mcost; + int prednum = 5; + int conditionEPZS; + + MotionVector tmv, tmp2 = {0,0}; + int pos; + + stopCriterion = EPZSDetermineStopCriterion (p_EPZS, prevSad, mv_block, lambda_dist); + + if (min_mcost < (stopCriterion >> 1)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + //! Add Spatial Predictors in predictor list. + //! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little + //! in terms of performance and could be removed with little penalty if any. + EPZS_spatial_predictors (p_EPZS, mv_block, list, currMB->list_offset, ref, motion); + + if (p_Inp->EPZSSpatialMem) + EPZS_spatial_memory_predictors (p_EPZS, mv_block, cur_list, &prednum, ref_picture->size_x >> 2); + + //! Blocktype/Reference dependent predictors. + //! Since already mvs for other blocktypes/references have been computed, we can reuse + //! them in order to easier determine the optimal point. Use of predictors could depend + //! on cost, + conditionEPZS = (ref == 0 || (ref > 0 && min_mcost > 2 * stopCriterion)); + + if (conditionEPZS && currMB->mbAddrX != 0 && p_Inp->EPZSBlockType) + EPZSBlockTypePredictors (currSlice, mv_block, p_EPZS_point, &prednum); + + //! Check all predictors + for (pos = 0; pos < prednum; ++pos) + { + tmv = p_EPZS_point[pos].motion; + //if (((iabs (tmv.mv_x - mv->mv_x) > searchRange->max_x || iabs (tmv.mv_y - mv->mv_y) > searchRange->max_y)) && (tmv.mv_x || tmv.mv_y)) + if ((iabs (tmv.mv_x - mv->mv_x) - searchRange->max_x <= 0) && (iabs (tmv.mv_y - mv->mv_y) - searchRange->max_y <= 0)) + { + + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + + cand = pad_MVs (tmv, mv_block); + + //--- set motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (mcost < second_mcost) + { + mcost += mv_block->computePredFPel (ref_picture, mv_block, second_mcost - mcost, &cand); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + tmp2 = tmp; + tmp = tmv; + second_mcost = min_mcost; + min_mcost = mcost; + checkMedian = TRUE; + } + //else if (mcost < second_mcost && (tmp.mv_x != tmv.mv_x || tmp.mv_y != tmv.mv_y)) + else if (mcost < second_mcost) + { + tmp2 = tmv; + second_mcost = mcost; + checkMedian = TRUE; + } + } + } + } + + if ((ref > 0 && currSlice->structure == FRAME) && (*prevSad * 3 < min_mcost)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + return min_mcost; + } + + // At this point, let us add an early termination criterion + // after checking each predictor. This can help speed up a lot. + if (min_mcost < ((3 * stopCriterion) >> 2)) + { +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + *mv = tmp; + return min_mcost; + } + } + + //! Refine using EPZS pattern if needed + //! Note that we are using a conservative threshold method. Threshold + //! could be tested after checking only a certain number of predictors + //! instead of the full set. Code could be easily modified for this task. + if (min_mcost > stopCriterion) + { + int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0; + int totalCheckPts = 0, motionDirection = 0; + const int mv_range = 12; + + //! Adapt pattern based on different conditions. + if (p_Inp->EPZSPattern != 0) + { + if ((min_mcost < stopCriterion + ((3 * p_EPZS->medthres[blocktype]) >> 1))) + { + if ((blocktype == 7) + || (tmp.mv_x == 0 && tmp.mv_y == 0) || (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_Vid->square; + } + + //! center on best predictor + center = tmp; + for (;;) + { + totalCheckPts = searchPatternF->searchPoints; + do + { + checkPts = totalCheckPts; + do + { + tmv = add_MVs (center, &(searchPatternF->point[pointNumber].motion)); + + if ((iabs (tmv.mv_x - mv->mv_x) <= searchRange->max_x) && (iabs (tmv.mv_y - mv->mv_y) <= searchRange->max_y)) + { + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + cand = pad_MVs(tmv, mv_block); + + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + if (mcost < min_mcost) + { + + mcost += mv_block->computePredFPel (ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + tmp = tmv; + min_mcost = mcost; + motionDirection = pointNumber; + } + } + } + } + ++pointNumber; + if (pointNumber >= searchPatternF->searchPoints) + pointNumber -= searchPatternF->searchPoints; + checkPts--; + } + while (checkPts > 0); + + if (nextLast || ((tmp.mv_x == center.mv_x) && (tmp.mv_y == center.mv_y))) + { + patternStop = searchPatternF->stopSearch; + searchPatternF = searchPatternF->nextpattern; + totalCheckPts = searchPatternF->searchPoints; + nextLast = searchPatternF->nextLast; + motionDirection = 0; + pointNumber = 0; + } + else + { + totalCheckPts = searchPatternF->point[motionDirection].next_points; + pointNumber = searchPatternF->point[motionDirection].start_nmbr; + center = tmp; + } + } + while (patternStop != 1); + + if ((ref > 0) && (currSlice->structure == FRAME) + && ((4 * *prevSad < min_mcost) || ((3 * *prevSad < min_mcost) && (*prevSad <= stopCriterion)))) + { + *mv = tmp; +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + return min_mcost; + } + + //! Check Second best predictor with EPZS pattern + conditionEPZS = (checkMedian == TRUE) && (blocktype != 7) + //conditionEPZS = (checkMedian == TRUE) + && (ref == 0 || (ref > 0 && min_mcost < 2 * *prevSad)) + && ((currSlice->slice_type == P_SLICE)) && (min_mcost > ((3 * stopCriterion) >> 1)) && (p_Inp->EPZSDual > 0); + + if (!conditionEPZS) + break; + + pointNumber = 0; + patternStop = 0; + motionDirection = 0; + nextLast = 0; + + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (tmp.mv_x == mv->mv_x && tmp.mv_y == mv->mv_y)) + { + if ((blocktype == 7) || (iabs (tmp.mv_x - mv->mv_x) < (mv_range) && iabs (tmp.mv_y - mv->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_EPZS->searchPatternD; + + //! Now consider second best. + center = tmp2; + checkMedian = FALSE; + } + } + } + + if ((ref == 0) || (*prevSad > min_mcost)) + *prevSad = min_mcost; + +#if EPZSREF + if (p_Inp->EPZSSpatialMem) +#else + if (p_Inp->EPZSSpatialMem && ref == 0) +#endif + { + *p_motion = tmp; + } + + *mv = tmp; + + return min_mcost; +} + +/*! +*********************************************************************** +* \brief +* FAST Motion Estimation using EPZS +* AMT/HYC +* \return +* minimum motion cost after search +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_integer_bipred_motion_estimation (Macroblock * currMB, // <-- Current Macroblock + int list, // <-- reference list + MotionVector * pred_mv1, // <-- motion vector predictor in sub-pel units + MotionVector * pred_mv2, // <-- motion vector predictor in sub-pel units + MotionVector * mv1, // <--> in: search center (x|y) / out: motion vector (x|y) - in sub-pel units + MotionVector * mv2, // <--> in: search center (x|y) + MEBlock * mv_block, // <-- motion vector information + int search_range, // <-- 1-d search range in sub-pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int blocktype = mv_block->blocktype; + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture1 = currSlice->listX[list + currMB->list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[(list ^ 1) + currMB->list_offset][0]; + + int mapCenter_x = search_range - mv1->mv_x; + int mapCenter_y = search_range - mv1->mv_y; + distblk lambda_dist = weighted_cost(lambda_factor, 4); + distblk stopCriterion = p_EPZS->medthres[blocktype] + lambda_dist; + distblk *prevSad = &p_EPZS->bi_distortion[list + currMB->list_offset][blocktype - 1][mv_block->pos_x2]; + EPZSStructure *searchPatternF = p_EPZS->searchPattern; + uint16 **EPZSMap = &p_EPZS->EPZSMap[mapCenter_y]; + + MotionVector tmp = *mv1; + MotionVector center1 = pad_MVs (*mv1, mv_block); + MotionVector center2 = pad_MVs (*mv2, mv_block); + MotionVector pred1 = pad_MVs (*pred_mv1, mv_block); + MotionVector pred2 = pad_MVs (*pred_mv2, mv_block); + MotionVector cand1 = center1; + MotionVector cand2 = center2; + + ++p_EPZS->BlkCount; + if (p_EPZS->BlkCount == 0) + ++p_EPZS->BlkCount; + + + // Clear p_EPZS->EPZSMap + //memset(p_EPZS->EPZSMap[0],FALSE,searcharray*searcharray); + // Check median candidate; + //p_EPZS->EPZSMap[0][0] = p_EPZS->BlkCount; + p_EPZS->EPZSMap[search_range][search_range] = p_EPZS->BlkCount; + + //--- initialize motion cost (cost for motion vector) and check --- + min_mcost = mv_cost (p_Vid, lambda_factor, &cand1, &pred1); + min_mcost += mv_cost (p_Vid, lambda_factor, &cand2, &pred2); + + //--- add residual cost to motion cost --- + min_mcost += mv_block->computeBiPredFPel (ref_picture1, ref_picture2, mv_block, DISTBLK_MAX-min_mcost, &cand1, &cand2); + + //! If p_EPZS->medthres satisfied, then terminate, otherwise generate Predictors + if (min_mcost > stopCriterion) + { + SPoint *p_EPZS_point = p_EPZS->predictor->point; + Boolean checkMedian = FALSE; + distblk second_mcost = DISTBLK_MAX; + distblk mcost; + int prednum = 5; + MotionVector tmv, tmp2 = { 0, 0 }; + int pos; + + stopCriterion = EPZSDetermineStopCriterion (p_EPZS, prevSad, mv_block, lambda_dist); + + + //! Add Spatial Predictors in predictor list. + //! Scheme adds zero, left, top-left, top, top-right. Note that top-left adds very little + //! in terms of performance and could be removed with little penalty if any. + EPZS_spatial_predictors (p_EPZS, mv_block, list, currMB->list_offset, ref, motion); + + //! Check all predictors + for (pos = 0; pos < prednum; ++pos) + { + tmv = p_EPZS_point[pos].motion; + //if ((iabs (tmv.mv_x - mv1->mv_x) > search_range || iabs (tmv.mv_y - mv1->mv_y) > search_range) && (tmv.mv_x || tmv.mv_y)) + if (iabs (tmv.mv_x - mv1->mv_x) <= search_range && iabs (tmv.mv_y - mv1->mv_y) <= search_range) + { + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + + cand1 = pad_MVs (tmv, mv_block); + + //--- set motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand1, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, &cand2, &pred2); + + if (mcost >= second_mcost) + continue; + + mcost += mv_block->computeBiPredFPel (ref_picture1, ref_picture2, mv_block, second_mcost - mcost, &cand1, &cand2); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + tmp2 = tmp; + tmp = tmv; + second_mcost = min_mcost; + min_mcost = mcost; + checkMedian = TRUE; + } + //else if (mcost < second_mcost && (tmp.mv_x != tmv.mv_x || tmp.mv_y != tmv.mv_y)) + else if (mcost < second_mcost) + { + tmp2 = tmv; + second_mcost = mcost; + checkMedian = TRUE; + } + } + } + } + + //! Refine using EPZS pattern if needed + //! Note that we are using a conservative threshold method. Threshold + //! could be tested after checking only a certain number of predictors + //! instead of the full set. Code could be easily modified for this task. + if (min_mcost > stopCriterion) + { + int conditionEPZS; + int patternStop = 0, pointNumber = 0, checkPts, nextLast = 0; + int totalCheckPts = 0, motionDirection = 0; + + const int mv_range = 12; + + //! Adapt pattern based on different conditions. + if (p_Inp->EPZSPattern != 0) + { + if ((min_mcost < stopCriterion + ((4 * p_EPZS->medthres[blocktype]) >> 1))) + { + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (iabs (tmp.mv_x - mv1->mv_x) < (mv_range) && iabs (tmp.mv_y - mv1->mv_y) < (mv_range))) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else if (blocktype > 5 || (ref > 0 && blocktype != 1)) + searchPatternF = p_Vid->square; + else + searchPatternF = p_EPZS->searchPattern; + } + + //! center on best predictor + center1 = tmp; + for (;;) + { + totalCheckPts = searchPatternF->searchPoints; + do + { + checkPts = totalCheckPts; + do + { + tmv = add_MVs (center1, &(searchPatternF->point[pointNumber].motion)); + + if ((iabs (tmv.mv_x - mv1->mv_x) <= search_range) && (iabs (tmv.mv_y - mv1->mv_y) <= search_range)) + { + if (EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] != p_EPZS->BlkCount) + { + EPZSMap[tmv.mv_y][mapCenter_x + tmv.mv_x] = p_EPZS->BlkCount; + cand1 = pad_MVs (tmv, mv_block); + + mcost = mv_cost (p_Vid, lambda_factor, &cand1, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, &cand2, &pred2); + + if (mcost < min_mcost) + { + mcost += mv_block->computeBiPredFPel (ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cand1, &cand2); + + if (mcost < min_mcost) + { + tmp = tmv; + min_mcost = mcost; + motionDirection = pointNumber; + } + } + } + } + ++pointNumber; + if (pointNumber >= searchPatternF->searchPoints) + pointNumber -= searchPatternF->searchPoints; + checkPts--; + } + while (checkPts > 0); + + if (nextLast || ((tmp.mv_x == center1.mv_x) && (tmp.mv_y == center1.mv_y))) + { + patternStop = searchPatternF->stopSearch; + searchPatternF = searchPatternF->nextpattern; + totalCheckPts = searchPatternF->searchPoints; + nextLast = searchPatternF->nextLast; + motionDirection = 0; + pointNumber = 0; + } + else + { + totalCheckPts = searchPatternF->point[motionDirection].next_points; + pointNumber = searchPatternF->point[motionDirection].start_nmbr; + center1 = tmp; + } + } + while (patternStop != 1); + + //! Check Second best predictor with EPZS pattern + conditionEPZS = (checkMedian == TRUE) && (blocktype < 5) && (min_mcost > stopCriterion) && (p_Inp->EPZSDual > 0); + + if (!conditionEPZS) + break; + + pointNumber = 0; + patternStop = 0; + motionDirection = 0; + nextLast = 0; + + if ((tmp.mv_x == 0 && tmp.mv_y == 0) || (tmp.mv_x == mv1->mv_x && tmp.mv_y == mv1->mv_y)) + { + if (iabs (tmp.mv_x - mv1->mv_x) < (mv_range) && iabs (tmp.mv_y - mv1->mv_y) < (mv_range)) + searchPatternF = p_Vid->sdiamond; + else + searchPatternF = p_Vid->square; + } + else + searchPatternF = p_EPZS->searchPatternD; + totalCheckPts = searchPatternF->searchPoints; + + //! Second best. Note that following code is identical as for best predictor. + center1 = tmp2; + checkMedian = FALSE; + } + } + } + + if (mv_block->iteration_no == 0) + { + *prevSad = min_mcost; + } + + *mv1 = tmp; + + return min_mcost; +} + diff --git a/lencod/src/me_epzs_sub.c b/lencod/src/me_epzs_sub.c new file mode 100644 index 0000000..220a0c4 --- /dev/null +++ b/lencod/src/me_epzs_sub.c @@ -0,0 +1,423 @@ + +/*! +************************************************************************************* +* \file me_epzs_sub.c +* +* \brief +* SubPel Motion Estimation refinement using EPZS +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* +************************************************************************************* +*/ + +#include "contributors.h" + +#include "global.h" +#include "refbuf.h" +#include "me_epzs.h" +#include "mv_search.h" + +/*! +*********************************************************************** +* \brief +* Fast sub pixel block motion search to support EPZS +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_sub_pel_motion_estimation ( Macroblock *currMB, // <-- current Macroblock + MotionVector *pred, // <-- motion vector predictor in sub-pel units + MEBlock *mv_block, // <-- motion vector information + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + int pos, best_pos = 0, second_pos = 0; + distblk mcost; + distblk second_mcost = DISTBLK_MAX; + int max_pos2 = ( (!p_Vid->start_me_refinement_hp || !p_Vid->start_me_refinement_qp) ? imax(1, mv_block->search_pos2) : mv_block->search_pos2); + + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + MotionVector *mv = &mv_block->mv[list]; + MotionVector cand; + MotionVector padded_mv = pad_MVs (*mv, mv_block); + MotionVector pred_mv = pad_MVs (*pred, mv_block); + + int start_pos = 5, end_pos = max_pos2; + int lambda_factor = lambda[H_PEL]; + distblk lambda_dist = weighted_cost(lambda_factor, 2); + distblk sub_threshold = p_EPZS->subthres[mv_block->blocktype] + lambda_dist; + + /********************************* + ***** ***** + ***** HALF-PEL REFINEMENT ***** + ***** ***** + *********************************/ + + //===== loop over search positions ===== + for (best_pos = 0, pos = p_Vid->start_me_refinement_hp; pos < imin(5, max_pos2); ++pos) + { + cand = add_MVs(search_point_hp[pos], &padded_mv); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv); + if (mcost < second_mcost) + { + mcost += mv_block->computePredHPel(ref_picture, mv_block, second_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + second_mcost = min_mcost; + second_pos = best_pos; + min_mcost = mcost; + best_pos = pos; + } + else if (mcost < second_mcost) + { + second_mcost = mcost; + second_pos = pos; + } + } + } + + if (best_pos ==0 && (pred->mv_x == mv->mv_x) && (pred->mv_y == mv->mv_y) && min_mcost < sub_threshold) + { + return min_mcost; + } + + if(mv_block->search_pos2 >= 9) + { + if (best_pos !=0 || (iabs(pred->mv_x - mv->mv_x) + iabs(pred->mv_y - mv->mv_y))) + { + start_pos = next_start_pos[best_pos][second_pos]; + end_pos = next_end_pos[best_pos][second_pos]; + + for (pos = start_pos; pos < end_pos; ++pos) + { + cand = add_MVs(search_point_hp[pos], &padded_mv); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv); + + if (mcost < min_mcost) + { + mcost += mv_block->computePredHPel( ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + } + } + } + + if (best_pos) + { + add_mvs(mv, &search_point_hp[best_pos]); + padded_mv = pad_MVs (*mv, mv_block); + } + + /************************************ + ***** ***** + ***** QUARTER-PEL REFINEMENT ***** + ***** ***** + ************************************/ + end_pos = (min_mcost < sub_threshold) ? 1 : 5; + second_mcost = DISTBLK_MAX; + + if ( !p_Vid->start_me_refinement_qp ) + { + best_pos = -1; + min_mcost = DISTBLK_MAX; + } + else + { + best_pos = 0; + } + lambda_factor = lambda[Q_PEL]; + + //===== loop over search positions ===== + for (pos = p_Vid->start_me_refinement_qp; pos < end_pos; ++pos) + { + cand = add_MVs(search_point_qp[pos], &padded_mv); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv); + + if (mcost < second_mcost) + { + mcost += mv_block->computePredQPel(ref_picture, mv_block, second_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + second_mcost = min_mcost; + second_pos = best_pos; + min_mcost = mcost; + best_pos = pos; + } + else if (mcost < second_mcost) + { + second_mcost = mcost; + second_pos = pos; + } + } + } + + //if (best_pos ==0 && (pred->mv_x == mv->mv_x) && (pred->mv_y == mv->mv_y) && min_mcost < sub_threshold) + if ( (min_mcost > sub_threshold)) + { + + if (best_pos !=0 || (iabs(pred->mv_x - mv->mv_x) + iabs(pred->mv_y - mv->mv_y))) + { + start_pos = next_start_pos[best_pos][second_pos]; + end_pos = next_end_pos[best_pos][second_pos]; + + for (pos = start_pos; pos < end_pos; ++pos) + { + cand = add_MVs(search_point_qp[pos], &padded_mv); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv); + + if (mcost < min_mcost) + { + mcost += mv_block->computePredQPel(ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + } + } + } + + if (best_pos) + { + add_mvs(mv, &search_point_qp[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost; +} + + +/*! +*********************************************************************** +* \brief +* Fast bipred sub pixel block motion search to support EPZS +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +EPZS_sub_pel_bipred_motion_estimation (Macroblock *currMB, // <-- current Macroblock + MEBlock *mv_block, // <-- motion vector information + int list, // <-- reference picture list + MotionVector *pred1, // <-- motion vector predictor in sub-pel units + MotionVector *pred2, // <-- motion vector predictor in sub-pel units + MotionVector *mv1, // <--> in: search center / out: motion vector - in sub-pel units + MotionVector *mv2, // <--> in: search center / out: motion vector - in sun-pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + EPZSParameters *p_EPZS = currSlice->p_EPZS; + + int list_offset = p_Vid->mb_data[currMB->mbAddrX].list_offset; + + int pos, best_pos = 0, second_pos = 0; + distblk mcost; + distblk second_mcost = DISTBLK_MAX; + + + int start_hp = (min_mcost == DISTBLK_MAX) ? 0 : p_Vid->start_me_refinement_hp; + int max_pos2 = ( (!p_Vid->start_me_refinement_hp || !p_Vid->start_me_refinement_qp) ? imax(1, mv_block->search_pos2) : mv_block->search_pos2); + + short ref = mv_block->ref_idx; + StorablePicture *ref_picture1 = currSlice->listX[list + list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[(list ^ 1) + list_offset][0]; + MotionVector cand; + MotionVector padded_mv1 = pad_MVs (*mv1, mv_block); + MotionVector padded_mv2 = pad_MVs (*mv2, mv_block); + MotionVector pred_mv1 = pad_MVs (*pred1, mv_block); + MotionVector pred_mv2 = pad_MVs (*pred2, mv_block); + + int start_pos = 5, end_pos = max_pos2; + int lambda_factor = lambda[H_PEL]; + distblk lambda_dist = weighted_cost(lambda_factor, 2); + distblk sub_threshold = p_EPZS->subthres[mv_block->blocktype] + lambda_dist; + + distblk mcost2 = mv_cost (p_Vid, lambda_factor, &padded_mv2, &pred_mv2); + min_mcost -= mcost2; + + /********************************* + ***** ***** + ***** HALF-PEL REFINEMENT ***** + ***** ***** + *********************************/ + + //===== loop over search positions ===== + for (best_pos = 0, pos = start_hp; pos < 5; ++pos) + { + cand = add_MVs(search_point_hp[pos], &padded_mv1); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv1); + + if (mcost < second_mcost) + { + mcost += mv_block->computeBiPredHPel(ref_picture1, ref_picture2, mv_block, second_mcost - mcost, &cand, &padded_mv2); + + if (mcost < min_mcost) + { + second_mcost = min_mcost; + second_pos = best_pos; + min_mcost = mcost; + best_pos = pos; + } + else if (mcost < second_mcost) + { + second_mcost = mcost; + second_pos = pos; + } + } + } + + if (best_pos ==0 && (pred1->mv_x == mv1->mv_x) && (pred1->mv_y == mv1->mv_y) && min_mcost < sub_threshold) + { + return min_mcost; + } + + if(mv_block->search_pos2 >= 9) + { + if (best_pos !=0 || (iabs(pred1->mv_x - mv1->mv_x) + iabs(pred1->mv_y - mv1->mv_y))) + { + start_pos = next_start_pos[best_pos][second_pos]; + end_pos = next_end_pos[best_pos][second_pos]; + + for (pos = start_pos; pos < end_pos; ++pos) + { + cand = add_MVs(search_point_hp[pos], &padded_mv1); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv1); + + if (mcost < min_mcost) + { + mcost += mv_block->computeBiPredHPel(ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cand, &padded_mv2); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + } + } + } + + if (best_pos) + { + add_mvs (mv1, &search_point_hp[best_pos]); + padded_mv1 = pad_MVs (*mv1, mv_block); + } + + /************************************ + ***** ***** + ***** QUARTER-PEL REFINEMENT ***** + ***** ***** + ************************************/ + end_pos = (min_mcost < sub_threshold) ? 1 : 5; + second_mcost = DISTBLK_MAX; + + if ( !p_Vid->start_me_refinement_qp ) + { + best_pos = -1; + min_mcost = DISTBLK_MAX; + } + else + { + best_pos = 0; + min_mcost += mcost2; + } + lambda_factor = lambda[Q_PEL]; + mcost2 = mv_cost (p_Vid, lambda_factor, &padded_mv2, &pred_mv2); + min_mcost -= mcost2; + + //===== loop over search positions ===== + for (pos = p_Vid->start_me_refinement_qp; pos < 5; ++pos) + { + cand = add_MVs(search_point_qp[pos], &padded_mv1); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv1); + + if (mcost < second_mcost) + { + mcost += mv_block->computeBiPredQPel(ref_picture1, ref_picture2, mv_block, second_mcost - mcost, &cand, &padded_mv2); + + if (mcost < min_mcost) + { + second_mcost = min_mcost; + second_pos = best_pos; + min_mcost = mcost; + best_pos = pos; + } + else if (mcost < second_mcost) + { + second_mcost = mcost; + second_pos = pos; + } + } + } + + if ( (min_mcost > sub_threshold)) + { + + if (best_pos !=0 || (iabs(pred1->mv_x - mv1->mv_x) + iabs(pred1->mv_y - mv1->mv_y))) + { + start_pos = next_start_pos[best_pos][second_pos]; + end_pos = next_end_pos[best_pos][second_pos]; + + for (pos = start_pos; pos < end_pos; ++pos) + { + cand = add_MVs(search_point_qp[pos], &padded_mv1); + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred_mv1); + + if (mcost < min_mcost) + { + mcost += mv_block->computeBiPredQPel(ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cand, &padded_mv2); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + } + } + } + + if (best_pos) + { + add_mvs(mv1, &search_point_qp[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost + mcost2; +} + diff --git a/lencod/src/me_fullfast.c b/lencod/src/me_fullfast.c new file mode 100644 index 0000000..b2d00f3 --- /dev/null +++ b/lencod/src/me_fullfast.c @@ -0,0 +1,690 @@ + +/*! +************************************************************************************* +* \file me_fullfast.c +* +* \brief +* Motion Estimation using Full Search Fast +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* +************************************************************************************* +*/ + +// Includes +#include "contributors.h" +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "refbuf.h" + +#include "me_distortion.h" +#include "me_fullsearch.h" +#include "me_fullfast.h" +#include "conformance.h" +#include "mv_search.h" + + +// Functions +/*! + *********************************************************************** + * \brief + * Full pixel block motion search + *********************************************************************** + */ + + +/*! + *********************************************************************** + * \brief + * function creating arrays for fast integer motion estimation + *********************************************************************** + */ +void initialize_fast_full_search (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i, j, k, list; + int search_range = p_Inp->SearchMode[0] == FAST_FULL_SEARCH ? p_Inp->search_range[0] : p_Inp->search_range[1]; + int max_pos = (2*search_range+1) * (2*search_range+1); + MEFullFast *p_me_ffast = NULL; + + if ((p_Vid->p_ffast_me = calloc (1, sizeof (MEFullFast))) == NULL) + no_mem_exit ("initialize_fast_full_search: p_Vid->p_ffast_me"); + p_me_ffast = p_Vid->p_ffast_me; + + if ((p_me_ffast->BlockSAD = (distpel*****)malloc (2 * sizeof(distpel****))) == NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->BlockSAD"); + + for (list=0; list<2;list++) + { + if ((p_me_ffast->BlockSAD[list] = (distpel****)malloc ((p_Vid->max_num_references) * sizeof(distpel***))) == NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->BlockSAD"); + for (i = 0; i < p_Vid->max_num_references; i++) + { + if ((p_me_ffast->BlockSAD[list][i] = (distpel***)malloc (8 * sizeof(distpel**))) == NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->BlockSAD"); + for (j = 1; j < 8; j++) + { + if ((p_me_ffast->BlockSAD[list][i][j] = (distpel**)malloc (16 * sizeof(distpel*))) == NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->BlockSAD"); + for (k = 0; k < 16; k++) + { + if ((p_me_ffast->BlockSAD[list][i][j][k] = (distpel*)malloc (max_pos * sizeof(distpel))) == NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->BlockSAD"); + } + } + } + } + + if ((p_me_ffast->search_setup_done = (int**)malloc (2*sizeof(int*)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->search_setup_done"); + if ((p_me_ffast->search_center = (MotionVector**) malloc (2 * sizeof(MotionVector*)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->search_center"); + if ((p_me_ffast->search_center_padded = (MotionVector**) malloc (2 * sizeof(MotionVector*)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->search_center_padded"); + + if ((p_me_ffast->pos_00 = (int**)malloc (2*sizeof(int*)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->pos_00"); + if ((p_me_ffast->max_search_range = (int**)malloc (2*sizeof(int*)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->max_search_range"); + + for (list=0; list<2; list++) + { + if ((p_me_ffast->search_setup_done[list] = (int*)malloc ((p_Vid->max_num_references)*sizeof(int)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->search_setup_done"); + if ((p_me_ffast->search_center[list] = (MotionVector*) malloc ((p_Vid->max_num_references) * sizeof(MotionVector)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->search_center"); + if ((p_me_ffast->search_center_padded[list] = (MotionVector*) malloc ((p_Vid->max_num_references) * sizeof(MotionVector)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->search_center_padded"); + + + if ((p_me_ffast->pos_00[list] = (int*)malloc ((p_Vid->max_num_references)*sizeof(int)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->pos_00"); + if ((p_me_ffast->max_search_range[list] = (int*)malloc ((p_Vid->max_num_references)*sizeof(int)))==NULL) + no_mem_exit ("initialize_fast_full_search: p_me_ffast->max_search_range"); + } + + // assign max search ranges for reference frames + if (p_Inp->full_search == 2) + { + for (list=0;list<2;list++) + for (i=0; imax_num_references; i++) + p_me_ffast->max_search_range[list][i] = search_range; + } + else + { + for (list=0;list<2;list++) + { + p_me_ffast->max_search_range[list][0] = search_range; + for (i=1; i< p_Vid->max_num_references; i++) p_me_ffast->max_search_range[list][i] = search_range / 2; + } + } +} + +/*! + *********************************************************************** + * \brief + * function for deleting the arrays for fast integer motion estimation + *********************************************************************** + */ +void +clear_fast_full_search (VideoParameters *p_Vid) +{ + int i, j, k, list; + MEFullFast *p_me_ffast = p_Vid->p_ffast_me; + + for (list=0; list<2; list++) + { + for (i = 0; i < p_Vid->max_num_references; i++) + { + for (j = 1; j < 8; j++) + { + for (k = 0; k < 16; k++) + { + free (p_me_ffast->BlockSAD[list][i][j][k]); + } + free (p_me_ffast->BlockSAD[list][i][j]); + } + free (p_me_ffast->BlockSAD[list][i]); + } + free (p_me_ffast->BlockSAD[list]); + } + free (p_me_ffast->BlockSAD); + + for (list=0; list<2; list++) + { + free (p_me_ffast->search_setup_done[list]); + free (p_me_ffast->search_center_padded[list]); + free (p_me_ffast->search_center[list]); + free (p_me_ffast->pos_00[list]); + free (p_me_ffast->max_search_range[list]); + } + free (p_me_ffast->search_setup_done); + free (p_me_ffast->search_center_padded); + free (p_me_ffast->search_center); + free (p_me_ffast->pos_00); + free (p_me_ffast->max_search_range); + free (p_me_ffast); + +} + + +/*! + *********************************************************************** + * \brief + * function resetting flags for fast integer motion estimation + * (have to be called in start_macroblock()) + *********************************************************************** + */ +void reset_fast_full_search (VideoParameters *p_Vid) +{ + int list; + for (list=0; list<2; list++) + memset(&p_Vid->p_ffast_me->search_setup_done [list][0], 0, p_Vid->max_num_references * sizeof(int)); +} +/*! + *********************************************************************** + * \brief + * calculation of SAD for larger blocks on the basis of 4x4 blocks + *********************************************************************** + */ +void +update_full_search_large_blocks (MEFullFast *p_ffast_me, int list, int refindex, int max_pos) +{ +#define ADD_UP_BLOCKS() _o=*_bo; _i=*_bi; _j=*_bj; for(pos=0;posBlockSAD; + + int pos; + distpel **_bo, **_bi, **_bj; + distpel *_o, *_i, *_j; + + //--- blocktype 6 --- + _bo = BlockSAD[list][refindex][6]; + _bi = BlockSAD[list][refindex][7]; + _bj = _bi + 4; + ADD_UP_BLOCKS(); INCREMENT(1); + ADD_UP_BLOCKS(); INCREMENT(1); + ADD_UP_BLOCKS(); INCREMENT(1); + ADD_UP_BLOCKS(); INCREMENT(5); + ADD_UP_BLOCKS(); INCREMENT(1); + ADD_UP_BLOCKS(); INCREMENT(1); + ADD_UP_BLOCKS(); INCREMENT(1); + ADD_UP_BLOCKS(); + + //--- blocktype 5 --- + _bo = BlockSAD[list][refindex][5]; + _bi = BlockSAD[list][refindex][7]; + _bj = _bi + 1; + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); + + //--- blocktype 4 --- + _bo = BlockSAD[list][refindex][4]; + _bi = BlockSAD[list][refindex][6]; + _bj = _bi + 1; + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); INCREMENT(6); + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); + + //--- blocktype 3 --- + _bo = BlockSAD[list][refindex][3]; + _bi = BlockSAD[list][refindex][4]; + _bj = _bi + 8; + ADD_UP_BLOCKS(); INCREMENT(2); + ADD_UP_BLOCKS(); + + //--- blocktype 2 --- + _bo = BlockSAD[list][refindex][2]; + _bi = BlockSAD[list][refindex][4]; + _bj = _bi + 2; + ADD_UP_BLOCKS(); INCREMENT(8); + ADD_UP_BLOCKS(); + + //--- blocktype 1 --- + _bo = BlockSAD[list][refindex][1]; + _bi = BlockSAD[list][refindex][3]; + _bj = _bi + 2; + ADD_UP_BLOCKS(); +} + + +/*! + *********************************************************************** + * \brief + * Setup the fast search for an macroblock + *********************************************************************** + */ +void setup_fast_full_search (Macroblock *currMB, MEBlock *mv_block, int list) // <-- reference frame parameter, list0 or 1 +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int (*dist_method) (int x) = p_Inp->MEErrorMetric[0] ? iabs2 : iabs; +#if (JM_MEM_DISTORTION) + int* imgpel_dist = p_Inp->MEErrorMetric[0] ? p_Vid->imgpel_quad : p_Vid->imgpel_abs; +#endif + MotionVector pmv; + imgpel orig_pels[768]; + imgpel *srcptr = orig_pels, *refptr; + int k, x, y; + MotionVector cand, offset; + int ref_x, ref_y, pos, bindex, blky; + distblk LineSadBlk0, LineSadBlk1, LineSadBlk2, LineSadBlk3; + PixelPos block[4]; // neighbor blocks + MEFullFast *p_me_ffast = p_Vid->p_ffast_me; + + + short ref = mv_block->ref_idx; + distpel** block_sad = p_me_ffast->BlockSAD[list][ref][7]; + int search_range = p_me_ffast->max_search_range[list][ref]; + int max_pos = (2*search_range+1) * (2*search_range+1); + + int list_offset = p_Vid->mb_data[currMB->mbAddrX].list_offset; + int apply_weights = ( (p_Vid->active_pps->weighted_pred_flag && (currSlice->slice_type == P_SLICE || (currSlice->slice_type == SP_SLICE))) || + (p_Vid->active_pps->weighted_bipred_idc && (currSlice->slice_type == B_SLICE))) && p_Inp->UseWeightedReferenceME; + int weighted_pel; + StorablePicture *ref_picture = currSlice->listX[list+list_offset][ref]; + + int wp_luma_round = 0; + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + int wp_chroma_round = 0; + short weight_luma = mv_block->weight_luma, weight_cr[2]; + short offset_luma = mv_block->offset_luma, offset_cr[2]; + search_range <<= 2; + + //===== get search center: predictor of 16x16 block ===== + get_neighbors(currMB, block, 0, 0, 16); + currMB->GetMVPredictor (currMB, block, &pmv, ref, p_Vid->enc_picture->mv_info, list, 0, 0, 16, 16); + +#if (JM_INT_DIVIDE) + p_Vid->p_ffast_me->search_center[list][ref].mv_x = ((pmv.mv_x + 2) >> 2) * 4; + p_Vid->p_ffast_me->search_center[list][ref].mv_y = ((pmv.mv_y + 2) >> 2) * 4; +#else + p_Vid->p_ffast_me->search_center[list][ref].mv_x = (pmv.mv_x / 4) * 4; + p_Vid->p_ffast_me->search_center[list][ref].mv_y = (pmv.mv_y / 4) * 4; +#endif + if (!p_Inp->rdopt) + { + //--- correct center so that (0,0) vector is inside --- + p_Vid->p_ffast_me->search_center[list][ref].mv_x = (short) iClip3(-search_range, search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_x); + p_Vid->p_ffast_me->search_center[list][ref].mv_y = (short) iClip3(-search_range, search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_y); + } + + p_Vid->p_ffast_me->search_center[list][ref].mv_x = (short) iClip3(p_Vid->MaxHmvR[4] + search_range, p_Vid->MaxHmvR[5] - search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_x); + p_Vid->p_ffast_me->search_center[list][ref].mv_y = (short) iClip3(p_Vid->MaxVmvR[4] + search_range, p_Vid->MaxVmvR[5] - search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_y); + + p_Vid->p_ffast_me->search_center_padded[list][ref] = pad_MVs(p_Vid->p_ffast_me->search_center[list][ref], mv_block); + + offset = p_Vid->p_ffast_me->search_center_padded[list][ref]; + //===== copy original block for fast access ===== + for (y = currMB->opix_y; y < currMB->opix_y + MB_BLOCK_SIZE; y++) + { + memcpy(srcptr, &p_Vid->pCurImg[y][currMB->pix_x], MB_BLOCK_SIZE * sizeof(imgpel)); + srcptr += MB_BLOCK_SIZE; + } + + if ( mv_block->ChromaMEEnable) + { + for (k = 1; k < 3; k++) + { + for (y = currMB->opix_c_y; y < currMB->opix_c_y + p_Vid->mb_cr_size_y; y++) + { + memcpy(srcptr, &p_Vid->pImgOrg[k][y][currMB->pix_c_x], p_Vid->mb_cr_size_x * sizeof(imgpel)); + srcptr += p_Vid->mb_cr_size_x; + } + } + } + + + //===== determine position of (0,0)-vector ===== + if (!p_Inp->rdopt) + { + ref_x = mv_block->pos_x_padded - offset.mv_x; + ref_y = mv_block->pos_y_padded - offset.mv_y; + + for (pos = 0; pos < max_pos; pos++) + { + if (ref_x == p_Vid->spiral_qpel_search[pos].mv_x && ref_y == p_Vid->spiral_qpel_search[pos].mv_y) + { + p_me_ffast->pos_00[list][ref] = pos; + break; + } + } + } + + //===== loop over search range (spiral search): get blockwise SAD ===== + if (apply_weights) + { + weight_luma = currSlice->wp_weight[list + list_offset][ref][0]; + offset_luma = currSlice->wp_offset[list + list_offset][ref][0]; + wp_luma_round = currSlice->wp_luma_round; + luma_log_weight_denom = currSlice->luma_log_weight_denom; + chroma_log_weight_denom = currSlice->chroma_log_weight_denom; + wp_chroma_round = currSlice->wp_chroma_round; + + if (mv_block->ChromaMEEnable) + { + weight_cr[0] = currSlice->wp_weight[list + list_offset][ref][1]; + weight_cr[1] = currSlice->wp_weight[list + list_offset][ref][2]; + offset_cr[0] = currSlice->wp_offset[list + list_offset][ref][1]; + offset_cr[1] = currSlice->wp_offset[list + list_offset][ref][2]; + } + + for (pos = 0; pos < max_pos; pos++) + { + cand = add_MVs(offset, &p_Vid->spiral_qpel_search[pos]); + + srcptr = orig_pels; + bindex = 0; + + refptr = UMVLine4X (ref_picture, cand.mv_y, cand.mv_x); + + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < 4; y++) + { + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + refptr += p_Vid->padded_size_x - MB_BLOCK_SIZE; + } + block_sad[bindex++][pos] = (distpel) LineSadBlk0; + block_sad[bindex++][pos] = (distpel) LineSadBlk1; + block_sad[bindex++][pos] = (distpel) LineSadBlk2; + block_sad[bindex++][pos] = (distpel) LineSadBlk3; + + } + if (mv_block->ChromaMEEnable) + { + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + for (k = 0; k < 2; k ++) + { + bindex = 0; + + refptr = UMVLine8X_chroma (ref_picture, k+1, cand.mv_y, cand.mv_x); + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < p_Vid->mb_cr_size_y; y+=BLOCK_SIZE) + { + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + } + refptr += p_Vid->cr_padded_size_x - p_Vid->mb_cr_size_x; + } + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk0); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk1); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk2); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk3); + ++bindex; + } + } + } + } + } + else + { + for (pos = 0; pos < max_pos; pos++) + { + cand = add_MVs(offset, &p_Vid->spiral_qpel_search[pos]); + srcptr = orig_pels; + bindex = 0; + + refptr = UMVLine4X (ref_picture, cand.mv_y, cand.mv_x); + + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < 4; y++) + { +#if (JM_MEM_DISTORTION) + // Distortion for first 4x4 block + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + // Distortion for second 4x4 block + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + // Distortion for third 4x4 block + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + // Distortion for fourth 4x4 block + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; +#else + // Distortion for first 4x4 block + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + // Distortion for second 4x4 block + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + // Distortion for third 4x4 block + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + // Distortion for fourth 4x4 block + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); +#endif + + refptr += p_Vid->padded_size_x - MB_BLOCK_SIZE; + } + block_sad[bindex++][pos] = (distpel) LineSadBlk0; + block_sad[bindex++][pos] = (distpel) LineSadBlk1; + block_sad[bindex++][pos] = (distpel) LineSadBlk2; + block_sad[bindex++][pos] = (distpel) LineSadBlk3; + } + + if (mv_block->ChromaMEEnable) + { + for (k = 0; k < 2; k ++) + { + bindex = 0; + + refptr = UMVLine8X_chroma (ref_picture, k+1, cand.mv_y, cand.mv_x); + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < p_Vid->mb_cr_size_y; y+=BLOCK_SIZE) + { + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + } + refptr += p_Vid->cr_padded_size_x - p_Vid->mb_cr_size_x; + } + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk0); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk1); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk2); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk3); + ++bindex; + } + } + } + } + } + + //===== combine SAD's for larger block types ===== + update_full_search_large_blocks (p_Vid->p_ffast_me, list, ref, max_pos); + + //===== set flag marking that search setup have been done ===== + p_Vid->p_ffast_me->search_setup_done[list][ref] = 1; +} + + +/*! + *********************************************************************** + * \brief + * Fast Full pixel block motion search + *********************************************************************** + */ +distblk // ==> minimum motion cost after search +fast_full_search_motion_estimation (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor (x) in sub-pel units + MEBlock *mv_block, // <-- motion estimation parameters + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + MEFullFast *p_me_ffast = p_Vid->p_ffast_me; + distblk mcost; + int pos; + int search_range = imax(mv_block->searchRange.max_x, mv_block->searchRange.max_y) >> 2; + int max_pos = (2*search_range+1)*(2*search_range+1); // number of search positions + int best_pos = 0; // position with minimum motion cost + int block_index; // block index for indexing SAD array + distpel* block_sad; // pointer to SAD array + int list = mv_block->list; + short ref = mv_block->ref_idx; + MotionVector cand = {0, 0}, *offset = &p_Vid->p_ffast_me->search_center[list][ref]; + int max_mvd = p_Vid->max_mvd-1; + + block_index = (mv_block->block_y << 2) + (mv_block->block_x); // block index for indexing SAD array + block_sad = p_me_ffast->BlockSAD[list][ref][mv_block->blocktype][block_index]; // pointer to SAD array + + //===== set up fast full integer search if needed / set search center ===== + if (!p_Vid->p_ffast_me->search_setup_done[list][ref]) + { + currMB->p_SetupFastFullPelSearch (currMB, mv_block, list); + } + + //===== cost for (0,0)-vector: it is done before, because MVCost can be negative ===== + if (!p_Inp->rdopt && GetMaxMVD(&cand, pred_mv)pos_00[list][ref]]; + up_scale(&min_mcost); + min_mcost += mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + + best_pos = p_me_ffast->pos_00[list][ref]; + } + + //===== loop over all search positions ===== + for (pos=0; posspiral_qpel_search[pos], offset); + /* //only for debug purpose; + if(GetMaxMVD(&cand, pred_mv) >= max_mvd) + { + printf("\n\n%d: out of range(%s%d)!\n\n", p_Vid->frame_no, __FILE__, __LINE__); + } + */ + //--- check residual cost --- + if (mcost < min_mcost && GetMaxMVD(&cand, pred_mv)mv[list] = add_MVs (p_Vid->spiral_qpel_search[best_pos], offset); + + return min_mcost; +} + diff --git a/lencod/src/me_fullfast_otf.c b/lencod/src/me_fullfast_otf.c new file mode 100644 index 0000000..eb4959a --- /dev/null +++ b/lencod/src/me_fullfast_otf.c @@ -0,0 +1,378 @@ +/*! +************************************************************************************* +* \file me_fullfast_otf.c +* +* \brief +* Motion Estimation using Full Search Fast (extention for on-the-fly interpolation) +* +* +************************************************************************************* +*/ + +// Includes +#include "contributors.h" +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" + +#include "me_distortion.h" +#include "get_block_otf.h" + +#include "me_fullsearch.h" +#include "me_fullfast.h" +#include "me_fullfast_otf.h" +#include "conformance.h" +#include "mv_search.h" + +/*! + *********************************************************************** + * \brief + * Setup the fast search for an macroblock (interpolation on-the-fly) + *********************************************************************** + */ +void SetupFastFullPelSearch_otf (Macroblock *currMB, MEBlock *mv_block, int list) // <-- reference frame parameter, list0 or 1 +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int (*dist_method) (int x) = p_Inp->MEErrorMetric[0 + (( p_Vid->dpb_layer_id >= 1 ) ? 3 : 0)] ? iabs2 : iabs; +#if (JM_MEM_DISTORTION) + int* imgpel_dist = p_Inp->MEErrorMetric[0 + p_Vid->layer_offset] ? p_Vid->imgpel_quad : p_Vid->imgpel_abs; +#endif + MotionVector pmv; + imgpel orig_pels[768]; + imgpel data[MB_PIXELS] ; + int tmp_data[ (MB_BLOCK_SIZE+5)*(MB_BLOCK_SIZE+5) ] ; + imgpel *srcptr = orig_pels, *refptr = data ; + int k, x, y; + MotionVector cand, offset; + int ref_x, ref_y, pos, bindex, blky; + distblk LineSadBlk0, LineSadBlk1, LineSadBlk2, LineSadBlk3; + PixelPos block[4]; // neighbor blocks + MEFullFast *p_me_ffast = p_Vid->p_ffast_me; + + + short ref = mv_block->ref_idx; + distpel** block_sad = p_me_ffast->BlockSAD[list][ref][7]; + int search_range = p_me_ffast->max_search_range[list][ref]; + int max_pos = (2*search_range+1) * (2*search_range+1); + + int list_offset = p_Vid->mb_data[currMB->mbAddrX].list_offset; + int apply_weights = ( (p_Vid->active_pps->weighted_pred_flag && (currSlice->slice_type == P_SLICE || (currSlice->slice_type == SP_SLICE))) || + (p_Vid->active_pps->weighted_bipred_idc && (currSlice->slice_type == B_SLICE))) && p_Inp->UseWeightedReferenceME; + int weighted_pel; + StorablePicture *ref_picture = currSlice->listX[list+list_offset][ref]; + + int wp_luma_round = 0; + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + int wp_chroma_round = 0; + short weight_luma = mv_block->weight_luma, weight_cr[2]; + short offset_luma = mv_block->offset_luma, offset_cr[2]; + search_range <<= 2; + + //===== get search center: predictor of 16x16 block ===== + get_neighbors(currMB, block, 0, 0, 16); + currMB->GetMVPredictor (currMB, block, &pmv, ref, p_Vid->enc_picture->mv_info, list, 0, 0, 16, 16); + +#if (JM_INT_DIVIDE) + p_Vid->p_ffast_me->search_center[list][ref].mv_x = ((pmv.mv_x + 2) >> 2) * 4; + p_Vid->p_ffast_me->search_center[list][ref].mv_y = ((pmv.mv_y + 2) >> 2) * 4; +#else + p_Vid->p_ffast_me->search_center[list][ref].mv_x = (pmv.mv_x / 4) * 4; + p_Vid->p_ffast_me->search_center[list][ref].mv_y = (pmv.mv_y / 4) * 4; +#endif + if (!p_Inp->rdopt) + { + //--- correct center so that (0,0) vector is inside --- + p_Vid->p_ffast_me->search_center[list][ref].mv_x = (short) iClip3(-search_range, search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_x); + p_Vid->p_ffast_me->search_center[list][ref].mv_y = (short) iClip3(-search_range, search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_y); + } + + p_Vid->p_ffast_me->search_center[list][ref].mv_x = (short) iClip3(p_Vid->MaxHmvR[4] + search_range, p_Vid->MaxHmvR[5] - search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_x); + p_Vid->p_ffast_me->search_center[list][ref].mv_y = (short) iClip3(p_Vid->MaxVmvR[4] + search_range, p_Vid->MaxVmvR[5] - search_range, p_Vid->p_ffast_me->search_center[list][ref].mv_y); + + p_Vid->p_ffast_me->search_center_padded[list][ref] = pad_MVs(p_Vid->p_ffast_me->search_center[list][ref], mv_block); + + offset = p_Vid->p_ffast_me->search_center_padded[list][ref]; + //===== copy original block for fast access ===== + for (y = currMB->opix_y; y < currMB->opix_y + MB_BLOCK_SIZE; y++) + { + memcpy(srcptr, &p_Vid->pCurImg[y][currMB->pix_x], MB_BLOCK_SIZE * sizeof(imgpel)); + srcptr += MB_BLOCK_SIZE; + } + + if ( mv_block->ChromaMEEnable) + { + for (k = 1; k < 3; k++) + { + for (y = currMB->opix_c_y; y < currMB->opix_c_y + p_Vid->mb_cr_size_y; y++) + { + memcpy(srcptr, &p_Vid->pImgOrg[k][y][currMB->pix_c_x], p_Vid->mb_cr_size_x * sizeof(imgpel)); + srcptr += p_Vid->mb_cr_size_x; + } + } + } + + + //===== determine position of (0,0)-vector ===== + if (!p_Inp->rdopt) + { + ref_x = mv_block->pos_x_padded - offset.mv_x; + ref_y = mv_block->pos_y_padded - offset.mv_y; + + for (pos = 0; pos < max_pos; pos++) + { + if (ref_x == p_Vid->spiral_qpel_search[pos].mv_x && ref_y == p_Vid->spiral_qpel_search[pos].mv_y) + { + p_me_ffast->pos_00[list][ref] = pos; + break; + } + } + } + + //===== loop over search range (spiral search): get blockwise SAD ===== + if (apply_weights) + { + weight_luma = currSlice->wp_weight[list + list_offset][ref][0]; + offset_luma = currSlice->wp_offset[list + list_offset][ref][0]; + wp_luma_round = currSlice->wp_luma_round; + luma_log_weight_denom = currSlice->luma_log_weight_denom; + chroma_log_weight_denom = currSlice->chroma_log_weight_denom; + wp_chroma_round = currSlice->wp_chroma_round; + + if (mv_block->ChromaMEEnable) + { + weight_cr[0] = currSlice->wp_weight[list + list_offset][ref][1]; + weight_cr[1] = currSlice->wp_weight[list + list_offset][ref][2]; + offset_cr[0] = currSlice->wp_offset[list + list_offset][ref][1]; + offset_cr[1] = currSlice->wp_offset[list + list_offset][ref][2]; + } + + for (pos = 0; pos < max_pos; pos++) + { + cand = add_MVs(offset, &p_Vid->spiral_qpel_search[pos]); + + srcptr = orig_pels; + bindex = 0; + refptr = data ; + p_Dpb->pf_get_block_luma ( p_Vid, refptr, tmp_data, cand.mv_x, cand.mv_y, MB_BLOCK_SIZE, MB_BLOCK_SIZE, ref_picture, 0 ) ; + + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < 4; y++) + { + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + weighted_pel = iClip1( p_Vid->max_imgpel_value, ((weight_luma * *refptr++ + wp_luma_round) >> luma_log_weight_denom) + offset_luma); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + } + block_sad[bindex++][pos] = (distpel) LineSadBlk0; + block_sad[bindex++][pos] = (distpel) LineSadBlk1; + block_sad[bindex++][pos] = (distpel) LineSadBlk2; + block_sad[bindex++][pos] = (distpel) LineSadBlk3; + + } + if (mv_block->ChromaMEEnable) + { + int max_imgpel_value_uv = p_Vid->max_pel_value_comp[1]; + + for (k = 0; k < 2; k ++) + { + bindex = 0; + refptr = data ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, refptr, tmp_data, cand.mv_x, cand.mv_y, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y, ref_picture, k+1 ); + + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < p_Vid->mb_cr_size_y; y+=BLOCK_SIZE) + { + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk0 += dist_method (weighted_pel - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk1 += dist_method (weighted_pel - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk2 += dist_method (weighted_pel - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + weighted_pel = iClip1( max_imgpel_value_uv, ((weight_cr[k] * *refptr++ + wp_chroma_round) >> chroma_log_weight_denom) + offset_cr[k]); + LineSadBlk3 += dist_method (weighted_pel - *srcptr++); + } + } + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk0); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk1); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk2); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk3); + ++bindex; + } + } + } + } + } + else + { + for (pos = 0; pos < max_pos; pos++) + { + cand = add_MVs(offset, &p_Vid->spiral_qpel_search[pos]); + srcptr = orig_pels; + bindex = 0; + + refptr = data; + p_Dpb->pf_get_block_luma( p_Vid, refptr, tmp_data, cand.mv_x, cand.mv_y, MB_BLOCK_SIZE, MB_BLOCK_SIZE, ref_picture, 0 ) ; + + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < 4; y++) + { +#if (JM_MEM_DISTORTION) + // Distortion for first 4x4 block + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk0 += imgpel_dist[ *refptr++ - *srcptr++ ]; + // Distortion for second 4x4 block + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk1 += imgpel_dist[ *refptr++ - *srcptr++ ]; + // Distortion for third 4x4 block + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk2 += imgpel_dist[ *refptr++ - *srcptr++ ]; + // Distortion for fourth 4x4 block + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; + LineSadBlk3 += imgpel_dist[ *refptr++ - *srcptr++ ]; +#else + // Distortion for first 4x4 block + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + // Distortion for second 4x4 block + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + // Distortion for third 4x4 block + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + // Distortion for fourth 4x4 block + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); +#endif + } + block_sad[bindex++][pos] = (distpel) LineSadBlk0; + block_sad[bindex++][pos] = (distpel) LineSadBlk1; + block_sad[bindex++][pos] = (distpel) LineSadBlk2; + block_sad[bindex++][pos] = (distpel) LineSadBlk3; + } + + if (mv_block->ChromaMEEnable) + { + for (k = 0; k < 2; k ++) + { + bindex = 0; + + refptr = data ; + p_Dpb->pf_get_block_chroma[OTF_ME]( p_Vid, refptr, tmp_data, cand.mv_x, cand.mv_y, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y, ref_picture, k+1 ); + + for (blky = 0; blky < 4; blky++) + { + LineSadBlk0 = LineSadBlk1 = LineSadBlk2 = LineSadBlk3 = 0; + + for (y = 0; y < p_Vid->mb_cr_size_y; y+=BLOCK_SIZE) + { + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk0 += dist_method (*refptr++ - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk1 += dist_method (*refptr++ - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk2 += dist_method (*refptr++ - *srcptr++); + } + for (x = 0; x < p_Vid->mb_cr_size_x; x += BLOCK_SIZE) + { + LineSadBlk3 += dist_method (*refptr++ - *srcptr++); + } + } + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk0); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk1); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk2); + ++bindex; + block_sad[bindex][pos] = block_sad[bindex][pos] + ((distpel) LineSadBlk3); + ++bindex; + } + } + } + } + } + + //===== combine SAD's for larger block types ===== + update_full_search_large_blocks (p_Vid->p_ffast_me, list, ref, max_pos); + + //===== set flag marking that search setup have been done ===== + p_Vid->p_ffast_me->search_setup_done[list][ref] = 1; +} diff --git a/lencod/src/me_fullsearch.c b/lencod/src/me_fullsearch.c new file mode 100644 index 0000000..d702fce --- /dev/null +++ b/lencod/src/me_fullsearch.c @@ -0,0 +1,534 @@ + +/*! +************************************************************************************* +* \file me_fullsearch.c +* +* \brief +* Motion Estimation using Fullsearch +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +* +************************************************************************************* +*/ + +// Includes +#include "contributors.h" +#include + +#include "global.h" +#include "image.h" +#include "memalloc.h" +#include "mb_access.h" +#include "refbuf.h" +#include "macroblock.h" +#include "me_distortion.h" +#include "me_fullsearch.h" +#include "mv_search.h" + +// Functions +/*! + *********************************************************************** + * \brief + * Full pixel block motion search + *********************************************************************** + */ +distblk // ==> minimum motion cost after search +full_search_motion_estimation (Macroblock *currMB , // <-- current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor in sub-pel units + MEBlock *mv_block, // <-- motion estimation structure + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + int search_range = imin(mv_block->searchRange.max_x, mv_block->searchRange.max_y)>> 2; + distblk mcost; + int pos; + MotionVector cand, center, pred; + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture = currSlice->listX[mv_block->list+currMB->list_offset][ref]; + + int best_pos = 0; // position with minimum motion cost + int max_pos = (2*search_range+1)*(2*search_range+1); // number of search positions + + MotionVector *mv = &mv_block->mv[(short) mv_block->list]; + int check_for_00 = (mv_block->blocktype==1 && !p_Inp->rdopt && currSlice->slice_type!=B_SLICE && ref==0); + center.mv_x = mv_block->pos_x_padded + mv->mv_x; // center position x (in sub-pel units) + center.mv_y = mv_block->pos_y_padded + mv->mv_y; // center position y (in sub-pel units) + pred.mv_x = mv_block->pos_x_padded + pred_mv->mv_x; // predicted position x (in sub-pel units) + pred.mv_y = mv_block->pos_y_padded + pred_mv->mv_y; // predicted position y (in sub-pel units) + + + //===== loop over all search positions ===== + for (pos=0; posspiral_qpel_search[pos].mv_x; + cand.mv_y = center.mv_y + p_Vid->spiral_qpel_search[pos].mv_y; + + //--- initialize motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + if (check_for_00 && cand.mv_x == mv_block->pos_x_padded && cand.mv_y == mv_block->pos_y_padded) + { + distblk tmp = weighted_cost (lambda_factor, 16); + mcost = mcost > tmp? (mcost-tmp): 0; + } + if (mcost >= min_mcost) continue; + + //--- add residual cost to motion cost --- + mcost += mv_block->computePredFPel(ref_picture, mv_block, min_mcost - mcost, &cand); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + best_pos = pos; + min_mcost = mcost; + } + } + + + //===== set best motion vector and return minimum motion cost ===== + if (best_pos) + { + add_mvs(mv, &p_Vid->spiral_qpel_search[best_pos]); + } + return min_mcost; +} + +/*! + *********************************************************************** + * \brief + * Full pixel block motion search + *********************************************************************** + */ +distblk // ==> minimum motion cost after search +full_search_bipred_motion_estimation (Macroblock *currMB, // <-- current Macroblock + int list, // <-- reference list + MotionVector *pred_mv1, // <-- motion vector predictor from first list (x|y) in sub-pel units + MotionVector *pred_mv2, // <-- motion vector predictor from second list (x|y) in sub-pel units + MotionVector *mv1, // <--> in: search center (x|y) / out: motion vector (x|y) - in sub-pel units + MotionVector *mv2, // <--> in: search center (x|y) + MEBlock *mv_block, // <-- motion vector information + int search_range, // <-- 1-d search range in sub-pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture1 = currSlice->listX[list + currMB->list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[(list ^ 1) + currMB->list_offset][0]; + distblk mcost; + int pos; + + int best_pos = 0; // position with minimum motion cost + int max_pos = (2 * (search_range >> 2) +1)*(2 * (search_range >> 2) + 1); // number of search positions + + MotionVector center1, center2, cand, pred1, pred2; + pred1.mv_x = mv_block->pos_x_padded + pred_mv1->mv_x; // predicted position x (in sub-pel units) + pred1.mv_y = mv_block->pos_y_padded + pred_mv1->mv_y; // predicted position y (in sub-pel units) + pred2.mv_x = mv_block->pos_x_padded + pred_mv2->mv_x; // predicted position x (in sub-pel units) + pred2.mv_y = mv_block->pos_y_padded + pred_mv2->mv_y; // predicted position y (in sub-pel units) + center1.mv_x = mv_block->pos_x_padded + mv1->mv_x; // center position x (in sub-pel units) + center1.mv_y = mv_block->pos_y_padded + mv1->mv_y; // center position y (in sub-pel units) + center2.mv_x = mv_block->pos_x_padded + mv2->mv_x; // center position x of static mv (in sub-pel units) + center2.mv_y = mv_block->pos_y_padded + mv2->mv_y; // center position y of static mv (in sub-pel units) + + + //===== loop over all search positions ===== + for (pos=0; posspiral_qpel_search[pos].mv_x; + cand.mv_y = center1.mv_y + p_Vid->spiral_qpel_search[pos].mv_y; + + //--- initialize motion cost (cost for motion vector) and check --- + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, ¢er2, &pred2); + + if (mcost >= min_mcost) continue; + + //--- add residual cost to motion cost --- + mcost += mv_block->computeBiPredFPel(ref_picture1, ref_picture2, mv_block, min_mcost - mcost, + &cand, ¢er2); + + //--- check if motion cost is less than minimum cost --- + if (mcost < min_mcost) + { + best_pos = pos; + min_mcost = mcost; + } + } + + //===== set best motion vector and return minimum motion cost ===== + if (best_pos) + { + add_mvs(mv1, &p_Vid->spiral_qpel_search[best_pos]); + } + return min_mcost; +} + +/*! + *********************************************************************** + * \brief + * Sub pixel block motion search + *********************************************************************** + */ +distblk // ==> minimum motion cost after search +sub_pel_motion_estimation (Macroblock *currMB, // <-- Current Macroblock + MotionVector *pred, // <-- motion vector predictor in sub-pel units + MEBlock *mv_block, // <-- motion estimation structure + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + distblk mcost; + int pos, best_pos; + + MotionVector cand; + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + MotionVector *mv = &mv_block->mv[list]; + + int check_position0 = (!p_Inp->rdopt && currSlice->slice_type != B_SLICE && ref==0 && mv_block->blocktype==1 && mv->mv_x == 0 && mv->mv_y ==0); + + int max_pos2 = ( !p_Vid->start_me_refinement_hp ? imax(1, mv_block->search_pos2) : mv_block->search_pos2); + MotionVector cmv; + + int lambda_factor = lambda[H_PEL]; + + /********************************* + ***** ***** + ***** HALF-PEL REFINEMENT ***** + ***** ***** + *********************************/ + + //===== loop over search positions ===== + for (best_pos = 0, pos = p_Vid->start_me_refinement_hp; pos < max_pos2; pos++) + { + cand.mv_x = mv->mv_x + p_Vid->spiral_hpel_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv->mv_y + p_Vid->spiral_hpel_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred); + + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + + mcost += mv_block->computePredHPel( ref_picture, mv_block, min_mcost - mcost, &cmv); + + if (pos==0 && check_position0) + { + mcost -= weighted_cost (lambda_factor, 16); + } + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + if (best_pos) + { + mv->mv_x = mv->mv_x + p_Vid->spiral_hpel_search[best_pos].mv_x; + mv->mv_y = mv->mv_y + p_Vid->spiral_hpel_search[best_pos].mv_y; + } + if ( !p_Vid->start_me_refinement_qp ) + min_mcost = DISTBLK_MAX; + /************************************ + ***** ***** + ***** QUARTER-PEL REFINEMENT ***** + ***** ***** + ************************************/ + + lambda_factor = lambda[Q_PEL]; + + //===== loop over search positions ===== + for (best_pos = 0, pos = p_Vid->start_me_refinement_qp; pos < mv_block->search_pos4; pos++) + { + cand.mv_x = mv->mv_x + p_Vid->spiral_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv->mv_y + p_Vid->spiral_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cmv); + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + if (best_pos) + { + add_mvs(mv, &p_Vid->spiral_search[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost; +} + + +/*! +*********************************************************************** +* \brief +* Bipred Sub pixel block motion search +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +sub_pel_bipred_motion_estimation (Macroblock *currMB, // <-- current Macroblock + MEBlock *mv_block, // <-- motion vector information + int list, // <-- reference picture list + MotionVector *pred_mv1, // <-- motion vector predictor (x) in sub-pel units + MotionVector *pred_mv2, // <-- motion vector predictor (x) in sub-pel units + MotionVector *mv1, // <--> in: search center (x) / out: motion vector (x) - in sub-pel units + MotionVector *mv2, // <--> in: search center (x) / out: motion vector (x) - in sub-pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int list_offset = p_Vid->mb_data[currMB->mbAddrX].list_offset; + distblk mcost; + int pos, best_pos; + MotionVector cand; + int start_hp = (min_mcost == DISTBLK_MAX) ? 0 : p_Vid->start_me_refinement_hp; + int max_pos2 = ( !p_Vid->start_me_refinement_hp ? imax(1, mv_block->search_pos2) : mv_block->search_pos2); + + MotionVector cmv, smv = pad_MVs(*mv2, mv_block); + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture1 = currSlice->listX[list + list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[(list ^ 1) + list_offset][0]; + + int lambda_factor = lambda[H_PEL]; + + /********************************* + ***** ***** + ***** HALF-PEL REFINEMENT ***** + ***** ***** + *********************************/ + + //===== loop over search positions ===== + for (best_pos = 0, pos = start_hp; pos < max_pos2; pos++) + { + cand.mv_x = mv1->mv_x + p_Vid->spiral_hpel_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv1->mv_y + p_Vid->spiral_hpel_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv1); + mcost += mv_cost (p_Vid, lambda_factor, mv2, pred_mv2); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + mcost += mv_block->computeBiPredHPel(ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cmv, &smv); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + + if (best_pos) + { + add_mvs(mv1, &p_Vid->spiral_hpel_search[best_pos]); + } + + /************************************ + ***** ***** + ***** QUARTER-PEL REFINEMENT ***** + ***** ***** + ************************************/ + if ( !p_Vid->start_me_refinement_qp ) + min_mcost = DISTBLK_MAX; + + lambda_factor = lambda[Q_PEL]; + + //===== loop over search positions ===== + for (best_pos = 0, pos = p_Vid->start_me_refinement_qp; pos < mv_block->search_pos4; pos++) + { + cand.mv_x = mv1->mv_x + p_Vid->spiral_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv1->mv_y + p_Vid->spiral_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv1); + mcost += mv_cost (p_Vid, lambda_factor, mv2, pred_mv2); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + mcost += mv_block->computeBiPredQPel(ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cmv, &smv); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + + } + + if (best_pos) + { + add_mvs(mv1, &p_Vid->spiral_search[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost; +} + +/*! + *********************************************************************** + * \brief + * Brute Force Sub pixel block motion search + *********************************************************************** + */ +distblk // ==> minimum motion cost after search +full_sub_pel_motion_estimation (Macroblock *currMB, // <-- Current Macroblock + MotionVector *pred, // <-- motion vector predictor in sub-pel units + MEBlock *mv_block, // <-- motion estimation structure + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + distblk mcost; + int pos, best_pos; + + MotionVector cand; + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + MotionVector *mv = &mv_block->mv[list]; + + int check_position0 = (!p_Inp->rdopt && currSlice->slice_type != B_SLICE && ref==0 && mv_block->blocktype==1 && mv->mv_x == 0 && mv->mv_y ==0); + + MotionVector cmv; + + int lambda_factor = lambda[Q_PEL]; + + //===== loop over all search positions ===== + for (best_pos = 0, pos = 0; pos < 81; pos++) + { + cand.mv_x = mv->mv_x + p_Vid->spiral_search[pos].mv_x; + cand.mv_y = mv->mv_y + p_Vid->spiral_search[pos].mv_y; + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cmv); + + if (pos == 0 && check_position0) + { + mcost -= weighted_cost (lambda_factor, 16); + } + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + + if (best_pos) + { + add_mvs(mv, &p_Vid->spiral_search[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost; +} + +/*! +*********************************************************************** +* \brief +* Brute Force Bipred Sub pixel block motion search +*********************************************************************** +*/ +distblk // ==> minimum motion cost after search +full_sub_pel_bipred_motion_estimation (Macroblock *currMB, // <-- current Macroblock + MEBlock *mv_block, // <-- motion vector information + int list, // <-- reference picture list + MotionVector *pred_mv1, // <-- motion vector predictor (x) in sub-pel units + MotionVector *pred_mv2, // <-- motion vector predictor (x) in sub-pel units + MotionVector *mv1, // <--> in: search center (x) / out: motion vector (x) - in pel units + MotionVector *mv2, // <--> in: search center (x) / out: motion vector (x) - in pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + int list_offset = p_Vid->mb_data[currMB->mbAddrX].list_offset; + distblk mcost; + int pos, best_pos; + MotionVector cand; + + MotionVector cmv, smv = pad_MVs(*mv2, mv_block); + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture1 = currSlice->listX[list + list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[(list ^ 1) + list_offset][0]; + + int lambda_factor = lambda[Q_PEL]; + + //===== loop over search positions ===== + for (best_pos = 0, pos = 0; pos < 81; pos++) + { + cand.mv_x = mv1->mv_x + p_Vid->spiral_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv1->mv_y + p_Vid->spiral_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv1); + mcost += mv_cost (p_Vid, lambda_factor, mv2, pred_mv2); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + mcost += mv_block->computeBiPredQPel(ref_picture1, ref_picture2, mv_block, min_mcost - mcost, &cmv, &smv); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + } + + if (best_pos) + { + add_mvs(mv1, &p_Vid->spiral_search[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost; +} + diff --git a/lencod/src/me_umhex.c b/lencod/src/me_umhex.c new file mode 100644 index 0000000..d5655f3 --- /dev/null +++ b/lencod/src/me_umhex.c @@ -0,0 +1,1396 @@ + +/*! + ************************************************************************ + * + * \file me_umhex.c + * + * \brief + * Fast integer pel motion estimation and fractional pel motion estimation + * algorithms are described in this file. + * 1. UMHEX_get_mem() and UMHEX_free_mem() are functions for allocation and release + * of memories about motion estimation + * 2. UMHEX_BlockMotionSearch() is the function for fast integer pel motion + * estimation and fractional pel motion estimation + * 3. UMHEX_DefineThreshold() defined thresholds for early termination + * \author + * Main contributors: (see contributors.h for copyright, address and affiliation details) + * - Zhibo Chen + * - JianFeng Xu + * - Wenfang Fu + * - Xiaozhong Xu + * \date + * 2006.1 + ************************************************************************ + */ + +#include + +#include "global.h" +#include "memalloc.h" +#include "me_umhex.h" +#include "refbuf.h" +#include "mb_access.h" +#include "image.h" +#include "enc_statistics.h" +#include "macroblock.h" +#include "me_distortion.h" +#include "mv_search.h" +#include "me_fullsearch.h" + +#define Q_BITS 15 +#define MIN_IMG_WIDTH 176 + +static const MotionVector Diamond[4] = {{-4, 0}, {4, 0}, {0, -4}, {0, 4}}; +static const MotionVector Hexagon[6] = {{-8, 0}, {8, 0},{-4, -8}, {4, 8}, {-4, 8}, {4 , -8}}; +static const short Big_Hexagon_X[16] = {0,-8, -16,-16,-16, -16, -16, -8, 0, 8, 16, 16, 16, 16, 16, 8}; +static const short Big_Hexagon_Y[16] = {8, 12, 8, 4, 0, -4, -8, -12, -16, -12, -8, -4, 0, 4, 8, 12}; + +static const int Multi_Ref_Thd[8] = {0, 300, 120, 120, 60, 30, 30, 15}; +static const int Big_Hexagon_Thd[8] = {0, 3000, 1500, 1500, 800, 400, 400, 200}; +static const int Median_Pred_Thd[8] = {0, 750, 350, 350, 170, 80, 80, 40}; +static const int Threshold_DSR[8] = {0, 2200, 1000, 1000, 500, 250, 250, 120}; + + +void UMHEX_DefineThreshold(VideoParameters *p_Vid) +{ + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + + p_UMHex->AlphaFourth_1[1] = 0.01f; + p_UMHex->AlphaFourth_1[2] = 0.01f; + p_UMHex->AlphaFourth_1[3] = 0.01f; + p_UMHex->AlphaFourth_1[4] = 0.02f; + p_UMHex->AlphaFourth_1[5] = 0.03f; + p_UMHex->AlphaFourth_1[6] = 0.03f; + p_UMHex->AlphaFourth_1[7] = 0.04f; + + p_UMHex->AlphaFourth_2[1] = 0.06f; + p_UMHex->AlphaFourth_2[2] = 0.07f; + p_UMHex->AlphaFourth_2[3] = 0.07f; + p_UMHex->AlphaFourth_2[4] = 0.08f; + p_UMHex->AlphaFourth_2[5] = 0.12f; + p_UMHex->AlphaFourth_2[6] = 0.11f; + p_UMHex->AlphaFourth_2[7] = 0.15f; + + p_UMHex->BlockType_LUT[0][0] = 7; // 4x4 + p_UMHex->BlockType_LUT[0][1] = 6; // 4x8 + p_UMHex->BlockType_LUT[1][0] = 5; // 8x4 + p_UMHex->BlockType_LUT[1][1] = 4; // 8x8 + p_UMHex->BlockType_LUT[1][3] = 3; // 8x16 + p_UMHex->BlockType_LUT[3][1] = 2; // 16x8 + p_UMHex->BlockType_LUT[3][3] = 1; // 16x16 + + return; +} +/*! +************************************************************************ +* \brief +* Set MB thresholds for fast motion estimation +* Those thresholds may be adjusted to trade off rate-distortion +* performance and UMHEX speed +************************************************************************ +*/ + +void UMHEX_DefineThresholdMB(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + int gb_qp_per = (p_Inp->qp[P_SLICE])/6; + int gb_qp_rem = (p_Inp->qp[P_SLICE])%6; + + int gb_q_bits = Q_BITS+gb_qp_per; + int gb_qp_const,Thresh4x4; + + float Quantize_step; + int i; + // scale factor: defined for different image sizes + float scale_factor = (float)((1-p_Inp->UMHexScale*0.1)+p_Inp->UMHexScale*0.1*(p_Vid->width/MIN_IMG_WIDTH)); + // QP factor: defined for different quantization steps + float QP_factor = (float)((1.0-0.90*(p_Inp->qp[P_SLICE]/51.0f))); + distblk dbScalar = dist_scale(1); + + gb_qp_const=(1<p_Quant->q_params_4x4[0][1][gb_qp_rem][0][0].ScaleComp); + Quantize_step = Thresh4x4/(4*5.61f)*2.0f*scale_factor; + p_UMHex->Bsize[7]=(16*16)*Quantize_step*dbScalar; + + p_UMHex->Bsize[6] = p_UMHex->Bsize[7]*4*dbScalar; + p_UMHex->Bsize[5] = p_UMHex->Bsize[7]*4*dbScalar; + p_UMHex->Bsize[4] = p_UMHex->Bsize[5]*4*dbScalar; + p_UMHex->Bsize[3] = p_UMHex->Bsize[4]*4*dbScalar; + p_UMHex->Bsize[2] = p_UMHex->Bsize[4]*4*dbScalar; + p_UMHex->Bsize[1] = p_UMHex->Bsize[2]*4*dbScalar; + + for(i=1;i<8;i++) + { + //ET_Thd1: early termination after median prediction + p_UMHex->Median_Pred_Thd_MB[i] = (distblk) (Median_Pred_Thd[i]* scale_factor*QP_factor*dbScalar); + //ET_thd2: early termination after every circle of 16 points Big-Hex Search + p_UMHex->Big_Hexagon_Thd_MB[i] = (distblk) (Big_Hexagon_Thd[i]* scale_factor*QP_factor*dbScalar); + //threshold for multi ref case + p_UMHex->Multi_Ref_Thd_MB[i] = (distblk) (Multi_Ref_Thd[i] * scale_factor*QP_factor*dbScalar); + //threshold for usage of DSR technique. DSR ref to JVT-R088 + p_UMHex->Threshold_DSR_MB[i] = (distblk) (Threshold_DSR[i] * scale_factor*QP_factor*dbScalar); + } +} + +/*! +************************************************************************ +* \brief +* Allocation of space for fast motion estimation +************************************************************************ +*/ +int UMHEX_get_mem(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + + int memory_size = 0; + int search_range = p_Inp->SearchMode[0] == UM_HEX ? p_Inp->search_range[0] : p_Inp->search_range[1]; + + if (NULL==(p_UMHex->flag_intra = calloc ((p_Vid->width>>4)+1,sizeof(byte)))) no_mem_exit("UMHEX_get_mem: p_UMHex->flag_intra"); //fwf 20050330 + + memory_size += get_mem2D(&p_UMHex->McostState, 2*search_range+1, 2*search_range+1); + + memory_size += get_mem4Ddistblk(&(p_UMHex->fastme_ref_cost), p_Vid->max_num_references, 9, 4, 4); + memory_size += get_mem3Ddistblk(&(p_UMHex->fastme_l0_cost), 9, p_Vid->height >> 2, p_Vid->width >> 2); + memory_size += get_mem3Ddistblk(&(p_UMHex->fastme_l1_cost), 9, p_Vid->height >> 2, p_Vid->width >> 2); + memory_size += get_mem2Ddistblk(&(p_UMHex->fastme_best_cost), 7, p_Vid->width >> 2); + + memory_size += get_mem2D(&p_UMHex->SearchState, 7, 7); + if(p_Inp->BiPredMotionEstimation == 1)//memory allocation for bipred mode + { + memory_size += get_mem3Ddistblk(&(p_UMHex->fastme_l0_cost_bipred), 9, p_Vid->height >> 2, p_Vid->width >> 2);//for bipred + memory_size += get_mem3Ddistblk(&(p_UMHex->fastme_l1_cost_bipred), 9, p_Vid->height >> 2, p_Vid->width >> 2);//for bipred + } + + return memory_size; +} + +/*! +************************************************************************ +* \brief +* Free space for fast motion estimation +************************************************************************ +*/ +void UMHEX_free_mem(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + free_mem2D(p_UMHex->McostState); + + free_mem4Ddistblk(p_UMHex->fastme_ref_cost); + free_mem3Ddistblk(p_UMHex->fastme_l0_cost ); + free_mem3Ddistblk(p_UMHex->fastme_l1_cost); + free_mem2Ddistblk(p_UMHex->fastme_best_cost); + + free_mem2D(p_UMHex->SearchState); + free (p_UMHex->flag_intra); + if(p_Inp->BiPredMotionEstimation == 1) + { + free_mem3Ddistblk(p_UMHex->fastme_l0_cost_bipred);//for bipred + free_mem3Ddistblk(p_UMHex->fastme_l1_cost_bipred);//for bipred + } + free(p_UMHex); +} + +/*! +************************************************************************ +* \brief +* UMHEXIntegerPelBlockMotionSearch: fast pixel block motion search +* this algorithm is called UMHexagonS(see JVT-D016),which includes +* four steps with different kinds of search patterns +* \par Input: +* imgpel* orig_pic, // <-- original picture +* int ref, // <-- reference frame (0... or -1 (backward)) +* int pic_pix_x, // <-- absolute x-coordinate of regarded AxB block +* int pic_pix_y, // <-- absolute y-coordinate of regarded AxB block +* int blocktype, // <-- block type (1-16x16 ... 7-4x4) +* int pred_mv[2], // <-- motion vector predictor (x|y) in sub-pel units +* MotionVector *mv, // --> motion vector (x|y) - in sub-pel units +* int search_range, // <-- 1-d search range in sub-pel units +* int min_mcost, // <-- minimum motion cost (cost for center or huge value) +* int lambda_factor // <-- lagrangian parameter for determining motion cost +* \par +* Two macro definitions defined in this program: +* 1. EARLY_TERMINATION: early termination algrithm, refer to JVT-D016.doc +* 2. SEARCH_ONE_PIXEL: search one pixel in search range +* \author +* Main contributors: (see contributors.h for copyright, address and affiliation details) +* - Zhibo Chen +* - JianFeng Xu +* - Xiaozhong Xu +* \date : +* 2006.1 +************************************************************************ +*/ +distblk // ==> minimum motion cost after search +UMHEXIntegerPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // < <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // < <-- minimum motion cost (cost for center or huge value) + int lambda_factor // < <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + + int blocktype = mv_block->blocktype; + short blocksize_x = mv_block->blocksize_x; // horizontal block size + short blocksize_y = mv_block->blocksize_y; // vertical block size + short pic_pix_x2 = mv_block->pos_x2; + short block_x = mv_block->block_x; + short block_y = mv_block->block_y; + + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + + MotionVector *mv = &mv_block->mv[list]; + MotionVector iMinNow, cand, center, pred, best = {0, 0}; + + int search_step; + int pos; + distblk mcost; + distblk *SAD_prediction = p_UMHex->fastme_best_cost[blocktype-1];//multi ref SAD prediction + int i, j, m; + float betaFourth_1,betaFourth_2; + int temp_Big_Hexagon_X[16];// temp for Big_Hexagon_X; + int temp_Big_Hexagon_Y[16];// temp for Big_Hexagon_Y; + distblk ET_Thred = p_UMHex->Median_Pred_Thd_MB[blocktype];//ET threshold in use + int search_range = mv_block->searchRange.max_x >> 2; + + short pic_pix_x = mv_block->pos_x_padded; + short pic_pix_y = mv_block->pos_y_padded; + pred.mv_x = pic_pix_x + pred_mv->mv_x; // predicted position x (in sub-pel units) + pred.mv_y = pic_pix_y + pred_mv->mv_y; // predicted position y (in sub-pel units) + center.mv_x = pic_pix_x + mv->mv_x; // center position x (in sub-pel units) + center.mv_y = pic_pix_y + mv->mv_y; // center position y (in sub-pel units) + + + + //////allocate memory for search state////////////////////////// + memset(p_UMHex->McostState[0],0,(2*p_Inp->search_range[p_Vid->view_id]+1)*(2*p_Inp->search_range[p_Vid->view_id]+1)); + + + //check the center median predictor + + cand = center; + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + mcost += mv_block->computePredFPel(ref_picture, mv_block, min_mcost - mcost, &cand); + + p_UMHex->McostState[search_range][search_range] = 1; + if (mcost < min_mcost) + { + min_mcost = mcost; + best = cand; + } + + iMinNow = best; + + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL + } + + if(center.mv_x != pic_pix_x || center.mv_y != pic_pix_y) + { + cand.mv_x = pic_pix_x ; + cand.mv_y = pic_pix_y ; + SEARCH_ONE_PIXEL + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL + } + } + /***********************************init process*************************/ + //for multi ref + if(ref>0 && currSlice->structure == FRAME && min_mcost > ET_Thred && SAD_prediction[pic_pix_x2] < p_UMHex->Multi_Ref_Thd_MB[blocktype]) + goto terminate_step; + + //ET_Thd1: early termination for low motion case + if( min_mcost < ET_Thred) + { + goto terminate_step; + } + else // hybrid search for main search loop + { + /****************************(MV and SAD prediction)********************************/ + UMHEX_setup(currMB, ref, mv_block->list, block_y, block_x, blocktype, currSlice->all_mv ); + ET_Thred = p_UMHex->Big_Hexagon_Thd_MB[blocktype]; // ET_Thd2: early termination Threshold for strong motion + + // Threshold defined for EARLY_TERMINATION + if (p_UMHex->pred_SAD == 0) + { + betaFourth_1=0; + betaFourth_2=0; + } + else + { + betaFourth_1 = p_UMHex->Bsize[blocktype]/((float)p_UMHex->pred_SAD * p_UMHex->pred_SAD)-p_UMHex->AlphaFourth_1[blocktype]; + betaFourth_2 = p_UMHex->Bsize[blocktype]/((float)p_UMHex->pred_SAD * p_UMHex->pred_SAD)-p_UMHex->AlphaFourth_2[blocktype]; + + } + /*********************************************end of init ***********************************************/ + } + // first_step: initial start point prediction + + if(blocktype>1) + { + cand.mv_x = (short) (pic_pix_x + (p_UMHex->pred_MV_uplayer[0] / 4) * 4); + cand.mv_y = (short) (pic_pix_y + (p_UMHex->pred_MV_uplayer[1] / 4) * 4); + SEARCH_ONE_PIXEL + } + + + //prediction using mV of last ref moiton vector + if(p_UMHex->pred_MV_ref_flag == 1) //Notes: for interlace case, ref==1 should be added + { + cand.mv_x = (short) (pic_pix_x + (p_UMHex->pred_MV_ref[0] / 4) * 4); + cand.mv_y = (short) (pic_pix_y + (p_UMHex->pred_MV_ref[1] / 4) * 4); + SEARCH_ONE_PIXEL + } + // Small local search + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL + } + + //early termination algorithm, refer to JVT-G016 + EARLY_TERMINATION + + if(blocktype>6) + goto fourth_1_step; + else + goto sec_step; + +sec_step: //Unsymmetrical-cross search + iMinNow = best; + + for(i = 4; i < search_range << 2; i+=8) + { + search_step = i; + cand.mv_x = (short) (iMinNow.mv_x + search_step); + cand.mv_y = iMinNow.mv_y ; + SEARCH_ONE_PIXEL + cand.mv_x = (short) (iMinNow.mv_x - search_step); + cand.mv_y = iMinNow.mv_y ; + SEARCH_ONE_PIXEL + } + for(i = 4; i < (search_range << 1);i+=8) + { + search_step = i; + cand.mv_x = iMinNow.mv_x ; + cand.mv_y = (short) (iMinNow.mv_y + search_step); + SEARCH_ONE_PIXEL + cand.mv_x = iMinNow.mv_x ; + cand.mv_y = (short) (iMinNow.mv_y - search_step); + SEARCH_ONE_PIXEL + } + + + //early termination alogrithm, refer to JVT-G016 + EARLY_TERMINATION + + iMinNow = best; + + //third_step: // Uneven Multi-Hexagon-grid Search + //sub step 1: 5x5 squre search + for(pos=1;pos<25;pos++) + { + cand.mv_x = iMinNow.mv_x + p_Vid->spiral_qpel_search[pos].mv_x; + cand.mv_y = iMinNow.mv_y + p_Vid->spiral_qpel_search[pos].mv_y; + SEARCH_ONE_PIXEL + } + + //early termination alogrithm, refer to JVT-G016 + EARLY_TERMINATION + + //sub step 2: Multi-Hexagon-grid search + memcpy(temp_Big_Hexagon_X,Big_Hexagon_X,64); + memcpy(temp_Big_Hexagon_Y,Big_Hexagon_Y,64); + for(i=1;i<=(search_range >> 2); i++) + { + + for (m = 0; m < 16; m++) + { + cand.mv_x = (short) (iMinNow.mv_x + temp_Big_Hexagon_X[m]); + cand.mv_y = (short) (iMinNow.mv_y + temp_Big_Hexagon_Y[m]); + temp_Big_Hexagon_X[m] += Big_Hexagon_X[m]; + temp_Big_Hexagon_Y[m] += Big_Hexagon_Y[m]; + + SEARCH_ONE_PIXEL + } + // ET_Thd2: early termination Threshold for strong motion + if(min_mcost < ET_Thred) + { + goto terminate_step; + } + } + + + //fourth_step: //Extended Hexagon-based Search + // the fourth step with a small search pattern +fourth_1_step: //sub step 1: small Hexagon search + for(i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 6; m++) + { + cand.mv_x = iMinNow.mv_x + Hexagon[m].mv_x; + cand.mv_y = iMinNow.mv_y + Hexagon[m].mv_y; + SEARCH_ONE_PIXEL + } + + if (best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + { + break; + } + } +fourth_2_step: //sub step 2: small Diamond search + + for(i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL + } + if(best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + break; + } + +terminate_step: + + // store SAD infomation for prediction + //FAST MOTION ESTIMATION. ZHIBO CHEN 2003.3 + for (i=0; i < (blocksize_x>>2); i++) + { + for (j=0; j < (blocksize_y>>2); j++) + { + if(mv_block->list == 0) + { + p_UMHex->fastme_ref_cost[ref][blocktype][block_y+j][block_x+i] = min_mcost; + if (ref==0) + p_UMHex->fastme_l0_cost[blocktype][(currMB->block_y)+block_y+j][(currMB->block_x)+block_x+i] = min_mcost; + } + else + { + p_UMHex->fastme_l1_cost[blocktype][(currMB->block_y)+block_y+j][(currMB->block_x)+block_x+i] = min_mcost; + } + } + } + //for multi ref SAD prediction + if ((ref==0) || (SAD_prediction[pic_pix_x2] > min_mcost)) + SAD_prediction[pic_pix_x2] = min_mcost; + + mv->mv_x = (short) (best.mv_x - pic_pix_x); + mv->mv_y = (short) (best.mv_y - pic_pix_y); + return min_mcost; +} + +distblk // ==> minimum motion cost after search +UMHEXSubPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // < <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + static const MotionVector DiamondQ[4] = {{-1, 0}, { 0, 1}, { 1, 0}, { 0, -1}}; + distblk mcost; + MotionVector cand, iMinNow, currmv = {0, 0}, cand_pad; + + int list = mv_block->list; + int list_offset = currMB->list_offset; + short ref = mv_block->ref_idx; + MotionVector *mv = &mv_block->mv[list]; + + StorablePicture *ref_picture = currSlice->listX[list+list_offset][ref]; + + int dynamic_search_range = 3, i; + int m; + int pred_frac_mv_x,pred_frac_mv_y,abort_search; + + //int pred_frac_up_mv_x, pred_frac_up_mv_y; + + pred_frac_mv_x = (pred_mv->mv_x - mv->mv_x) & 0x03; + pred_frac_mv_y = (pred_mv->mv_y - mv->mv_y) & 0x03; + + //pred_frac_up_mv_x = (p_UMHex->pred_MV_uplayer[0] - mv->mv_x) & 0x03; + //pred_frac_up_mv_y = (p_UMHex->pred_MV_uplayer[1] - mv->mv_y) & 0x03; + + + memset(p_UMHex->SearchState[0], 0,(2 * dynamic_search_range + 1)*(2 * dynamic_search_range + 1)); + + if( !p_Vid->start_me_refinement_hp ) + { + p_UMHex->SearchState[dynamic_search_range][dynamic_search_range] = 1; + cand = *mv; + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + cand_pad = pad_MVs (cand, mv_block); //cand = pad_MVs (cand, mv_block); + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cand_pad); //&cand); + + if (mcost < min_mcost) + { + min_mcost = mcost; + currmv = cand; + } + } + else + { + p_UMHex->SearchState[dynamic_search_range][dynamic_search_range] = 1; + currmv = *mv; + } + + if(pred_frac_mv_x!=0 || pred_frac_mv_y!=0) + { + cand.mv_x = (short) (mv->mv_x + pred_frac_mv_x); + cand.mv_y = (short) (mv->mv_y + pred_frac_mv_y); + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + p_UMHex->SearchState[cand.mv_y -mv->mv_y + dynamic_search_range][cand.mv_x - mv->mv_x + dynamic_search_range] = 1; + cand_pad = pad_MVs (cand, mv_block); //cand = pad_MVs (cand, mv_block); + + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cand_pad); //&cand); + + if (mcost < min_mcost) + { + min_mcost = mcost; + currmv = cand; + } + } + + iMinNow = currmv; + + for(i = 0; i < dynamic_search_range; i++) + { + abort_search=1; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + DiamondQ[m].mv_x; + cand.mv_y = iMinNow.mv_y + DiamondQ[m].mv_y; + + if(iabs(cand.mv_x - mv->mv_x) <= dynamic_search_range && iabs(cand.mv_y - mv->mv_y) <= dynamic_search_range) + { + if(!p_UMHex->SearchState[cand.mv_y -mv->mv_y + dynamic_search_range][cand.mv_x -mv->mv_x + dynamic_search_range]) + { + p_UMHex->SearchState[cand.mv_y -mv->mv_y + dynamic_search_range][cand.mv_x -mv->mv_x + dynamic_search_range] = 1; + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + cand_pad = pad_MVs (cand, mv_block); //cand = pad_MVs (cand, mv_block); + + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cand_pad); // &cand); + if (mcost < min_mcost) + { + min_mcost = mcost; + currmv = cand; + abort_search = 0; + } + } + } + } + iMinNow = currmv; + if(abort_search) + { + break; + } + } + + *mv = currmv; + + //===== return minimum motion cost ===== + return min_mcost; +} + +distblk // ==> minimum motion cost after search +UMHEXSubPelBlockME (Macroblock *currMB, // <-- Current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda + ) +{ + if(mv_block->blocktype >3) + { + min_mcost = UMHEXSubPelBlockMotionSearch (currMB, pred_mv, mv_block, min_mcost, lambda[Q_PEL]); + } + else + { + min_mcost = sub_pel_motion_estimation (currMB, pred_mv, mv_block, min_mcost, lambda); + } + + return min_mcost; +} + +/*! +************************************************************************ +* \brief +* Functions for SAD prediction of intra block cases. +* 1. void UMHEX_decide_intrabk_SAD() judges the block coding type(intra/inter) +* of neibouring blocks +* 2. void UMHEX_skip_intrabk_SAD() set the SAD to zero if neigouring block coding +* type is intra +* \date +* 2003.4 +************************************************************************ +*/ +void UMHEX_decide_intrabk_SAD(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + if (currMB->pix_x == 0 && currMB->pix_y == 0) + { + p_UMHex->flag_intra_SAD = 0; + } + else if (currMB->pix_x == 0) + { + p_UMHex->flag_intra_SAD = p_UMHex->flag_intra[(currMB->pix_x)>>4]; + } + else if (currMB->pix_y == 0) + { + p_UMHex->flag_intra_SAD = p_UMHex->flag_intra[((currMB->pix_x)>>4)-1]; + } + else + { + p_UMHex->flag_intra_SAD = ((p_UMHex->flag_intra[(currMB->pix_x)>>4])||(p_UMHex->flag_intra[((currMB->pix_x)>>4)-1])||(p_UMHex->flag_intra[((currMB->pix_x)>>4)+1])) ; + } + } + return; +} + +void UMHEX_skip_intrabk_SAD(Macroblock *currMB, int ref_max) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + int i,j,k, ref; + if (p_Vid->number > 0) + p_UMHex->flag_intra[(currMB->pix_x)>>4] = (currMB->best_mode == 9 || currMB->best_mode == 10) ? 1:0; + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE && (currMB->best_mode == 9 || currMB->best_mode == 10)) + { + for (k=0; k < 9;k++) + { + for (j=0; j < 4; j++) + { + for (i=0; i < 4; i++) + { + p_UMHex->fastme_l0_cost[k][j][i] = 0; + p_UMHex->fastme_l1_cost[k][j][i] = 0; + + for (ref=0; ref < ref_max;ref++) + { + p_UMHex->fastme_ref_cost[ref][k][j][i] = 0; + } + } + } + } + + } + return; +} + + +void UMHEX_setup(Macroblock *currMB, short ref, int list, int block_y, int block_x, int blocktype, MotionVector *****all_mv) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + + int N_Bframe=0; + int n_Bframe=0; + int temp_blocktype = 0; + int indication_blocktype[8]={0,0,1,1,2,4,4,5}; + InputParameters *p_Inp = currMB->p_Inp; + N_Bframe = p_Inp->NumberBFrames; + n_Bframe =(N_Bframe) ? (p_Vid->p_Stats->frame_ctr[B_SLICE]%(N_Bframe+1)): 0; + + + /**************************** MV prediction **********************/ + //MV uplayer prediction + if (blocktype>1) + { + temp_blocktype = indication_blocktype[blocktype]; + p_UMHex->pred_MV_uplayer[0] = all_mv[list][ref][temp_blocktype][block_y][block_x].mv_x; + p_UMHex->pred_MV_uplayer[1] = all_mv[list][ref][temp_blocktype][block_y][block_x].mv_y; + } + + + //MV ref-frame prediction + p_UMHex->pred_MV_ref_flag = 0; + if(list==0) + { + if (p_Vid->field_picture) + { + if ( ref > 1) + { + p_UMHex->pred_MV_ref[0] = all_mv[0][ref-2][blocktype][block_y][block_x].mv_x; + p_UMHex->pred_MV_ref[0] = (int)(p_UMHex->pred_MV_ref[0]*((ref>>1)+1)/(float)((ref>>1))); + p_UMHex->pred_MV_ref[1] = all_mv[0][ref-2][blocktype][block_y][block_x].mv_y; + p_UMHex->pred_MV_ref[1] = (int)(p_UMHex->pred_MV_ref[1]*((ref>>1)+1)/(float)((ref>>1))); + p_UMHex->pred_MV_ref_flag = 1; + } + if (currSlice->slice_type == B_SLICE && (ref==0 || ref==1) ) + { + p_UMHex->pred_MV_ref[0] =(int) (all_mv[1][0][blocktype][block_y][block_x].mv_x * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + p_UMHex->pred_MV_ref[1] =(int) (all_mv[1][0][blocktype][block_y][block_x].mv_y * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + p_UMHex->pred_MV_ref_flag = 1; + } + } + else //frame case + { + if ( ref > 0) + { + p_UMHex->pred_MV_ref[0] = all_mv[0][ref-1][blocktype][block_y][block_x].mv_x; + p_UMHex->pred_MV_ref[0] = (int)(p_UMHex->pred_MV_ref[0]*(ref+1)/(float)(ref)); + p_UMHex->pred_MV_ref[1] = all_mv[0][ref-1][blocktype][block_y][block_x].mv_y; + p_UMHex->pred_MV_ref[1] = (int)(p_UMHex->pred_MV_ref[1]*(ref+1)/(float)(ref)); + p_UMHex->pred_MV_ref_flag = 1; + } + if (currSlice->slice_type == B_SLICE && (ref==0)) //B frame forward prediction, first ref + { + p_UMHex->pred_MV_ref[0] =(int) (all_mv[1][0][blocktype][block_y][block_x].mv_x * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + p_UMHex->pred_MV_ref[1] =(int) (all_mv[1][0][blocktype][block_y][block_x].mv_y * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + p_UMHex->pred_MV_ref_flag = 1; + } + } + } + /******************************SAD prediction**********************************/ + if (list==0 && ref>0) //pred_SAD_ref + { + + if (p_UMHex->flag_intra_SAD) //add this for irregular motion + { + p_UMHex->pred_SAD = 0; + } + else + { + if (p_Vid->field_picture) + { + if (ref > 1) + { + p_UMHex->pred_SAD = p_UMHex->fastme_ref_cost[ref-2][blocktype][block_y][block_x]; + } + else + { + p_UMHex->pred_SAD = p_UMHex->fastme_ref_cost[0][blocktype][block_y][block_x]; + } + } + else + { + p_UMHex->pred_SAD = p_UMHex->fastme_ref_cost[ref-1][blocktype][block_y][block_x]; + } + + } + } + else if (blocktype>1) // pred_SAD_uplayer + { + if (p_UMHex->flag_intra_SAD) + { + p_UMHex->pred_SAD = 0; + } + else + { + p_UMHex->pred_SAD = (list==1) ? (p_UMHex->fastme_l1_cost[temp_blocktype][(currMB->block_y)+block_y][(currMB->block_x)+block_x]) : (p_UMHex->fastme_l0_cost[temp_blocktype][(currMB->block_y)+block_y][(currMB->block_x)+block_x]); + p_UMHex->pred_SAD /= 2; + } + } + else p_UMHex->pred_SAD = 0 ; // pred_SAD_space + +} + +/*! +************************************************************************ +* \brief +* UMHEXBipredIntegerPelBlockMotionSearch: fast pixel block motion search for bipred mode +* this algrithm is called UMHexagonS(see JVT-D016),which includes +* four steps with different kinds of search patterns +* \author +* Main contributors: (see contributors.h for copyright, address and affiliation details) +* - Zhibo Chen +* - JianFeng Xu +* - Xiaozhong Xu +* \date : +* 2006.1 +************************************************************************ +*/ +distblk // ==> minimum motion cost after search +UMHEXBipredIntegerPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + int list, // <-- current reference list + MotionVector *pred_mv1, // <-- motion vector predictor (x|y) in sub-pel units + MotionVector *pred_mv2, // <-- motion vector predictor (x|y) in sub-pel units + MotionVector *mv1, // <--> in: search center (x|y) / out: motion vector (x|y) - in sub-pel units + MotionVector *mv2, // <--> in: search center (x|y) + MEBlock *mv_block, // <-- motion vector information + int search_range, // <-- 1-d search range in sub-pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + int temp_Big_Hexagon_X[16];// = Big_Hexagon_X; + int temp_Big_Hexagon_Y[16];// = Big_Hexagon_Y; + + int search_step; + int i,m,j; + float betaFourth_1,betaFourth_2; + int pos; + distblk mcost; + short blocktype = mv_block->blocktype; + short blocksize_x = mv_block->blocksize_x; // horizontal block size + short blocksize_y = mv_block->blocksize_y; // vertical block size + + short pic_pix_x = mv_block->pos_x_padded; + short pic_pix_y = mv_block->pos_y_padded; + + short block_x = mv_block->block_x; + short block_y = mv_block->block_y; + distblk ET_Thred = p_UMHex->Median_Pred_Thd_MB[blocktype]; + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture1 = currSlice->listX[list + currMB->list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[list == 0 ? 1 + currMB->list_offset: currMB->list_offset][ 0 ]; + + MotionVector iMinNow, best, cand; + + MotionVector pred1 = pad_MVs(*pred_mv1, mv_block); // predicted position x (in sub-pel units) + MotionVector pred2 = pad_MVs(*pred_mv2, mv_block); // predicted position x (in sub-pel units) + MotionVector center1 = pad_MVs(*mv1, mv_block); // predicted position x (in sub-pel units) + MotionVector center2 = pad_MVs(*mv2, mv_block); // predicted position x (in sub-pel units) + + + search_range >>= 2; + ////////////////////////////////////////////////////////////////////////// + + //////allocate memory for search state////////////////////////// + memset(p_UMHex->McostState[0],0,(2*search_range+1)*(2*search_range+1)); + + //check the center median predictor + best = cand = center2; + mcost = mv_cost (p_Vid, lambda_factor, ¢er1, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, &cand, &pred2); + mcost += mv_block->computeBiPredFPel(ref_picture1, ref_picture2, mv_block, DISTBLK_MAX-mcost, ¢er1, &cand); + + p_UMHex->McostState[search_range][search_range] = 1; + + if (mcost < min_mcost) + { + min_mcost = mcost; + best = cand; + } + + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + if(center2.mv_x != pic_pix_x || center2.mv_y != pic_pix_y) + { + cand.mv_x = pic_pix_x ; + cand.mv_y = pic_pix_y ; + SEARCH_ONE_PIXEL_BIPRED; + + iMinNow = best; + + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + } + /***********************************init process*************************/ + + if( min_mcost < ET_Thred) + { + goto terminate_step; + } + else + { + int N_Bframe=0; + int n_Bframe=0; + MotionVector *****bipred_mv = currSlice->bipred_mv[list]; + N_Bframe = p_Inp->NumberBFrames; + n_Bframe = p_Vid->p_Stats->frame_ctr[B_SLICE]%(N_Bframe+1); + + + /**************************** MV prediction **********************/ + //MV uplayer prediction + // non for bipred mode + + //MV ref-frame prediction + + if(list==0) + { + if (p_Vid->field_picture) + { + p_UMHex->pred_MV_ref[0] =(int) (bipred_mv[1][0][blocktype][block_y][block_x].mv_x * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + p_UMHex->pred_MV_ref[1] =(int) (bipred_mv[1][0][blocktype][block_y][block_x].mv_y * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + } + else //frame case + { + p_UMHex->pred_MV_ref[0] =(int) (bipred_mv[1][0][blocktype][block_y][block_x].mv_x * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + p_UMHex->pred_MV_ref[1] =(int) (bipred_mv[1][0][blocktype][block_y][block_x].mv_y * (-n_Bframe)/(N_Bframe-n_Bframe+1.0f)); + } + } + /******************************SAD prediction**********************************/ + p_UMHex->pred_SAD =distblkmin(distblkmin(p_UMHex->SAD_a,p_UMHex->SAD_b),p_UMHex->SAD_c); // pred_SAD_space + ET_Thred = p_UMHex->Big_Hexagon_Thd_MB[blocktype]; + + ///////Threshold defined for early termination/////////////////// + if (p_UMHex->pred_SAD == 0) + { + betaFourth_1=0; + betaFourth_2=0; + } + else + { + betaFourth_1 = p_UMHex->Bsize[blocktype]/(p_UMHex->pred_SAD * p_UMHex->pred_SAD)-p_UMHex->AlphaFourth_1[blocktype]; + betaFourth_2 = p_UMHex->Bsize[blocktype]/(p_UMHex->pred_SAD * p_UMHex->pred_SAD)-p_UMHex->AlphaFourth_2[blocktype]; + } + } + + /***********************************end of init *************************/ + + + + // first_step: initial start point prediction + //prediction using mV of last ref moiton vector + if(list == 0) + { + cand.mv_x = (short) (pic_pix_x + (p_UMHex->pred_MV_ref[0] / 4) * 4); + cand.mv_y = (short) (pic_pix_y + (p_UMHex->pred_MV_ref[1] / 4) * 4); + SEARCH_ONE_PIXEL_BIPRED; + } + + + //small local search + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + //early termination alogrithm, refer to JVT-G016 + EARLY_TERMINATION; + + + //sec_step: //Unsymmetrical-cross search + iMinNow = best; + + for(i = 1; i < search_range; i+=2) + { + search_step = i; + cand.mv_x = (short) (iMinNow.mv_x + search_step); + cand.mv_y = iMinNow.mv_y ; + SEARCH_ONE_PIXEL_BIPRED; + cand.mv_x = (short) (iMinNow.mv_x - search_step); + SEARCH_ONE_PIXEL_BIPRED; + } + + for(i = 1; i < (search_range >> 1);i+=2) + { + search_step = i; + cand.mv_x = iMinNow.mv_x ; + cand.mv_y = (short) (iMinNow.mv_y + search_step); + SEARCH_ONE_PIXEL_BIPRED; + cand.mv_y = (short) (iMinNow.mv_y - search_step); + SEARCH_ONE_PIXEL_BIPRED; + } + //early termination alogrithm, refer to JVT-G016 + EARLY_TERMINATION; + + //third_step: // Uneven Multi-Hexagon-grid Search + iMinNow = best; + //sub step1: 5x5 square search + for(pos=1;pos<25;pos++) + { + cand.mv_x = iMinNow.mv_x + p_Vid->spiral_qpel_search[pos].mv_x; + cand.mv_y = iMinNow.mv_y + p_Vid->spiral_qpel_search[pos].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + //early termination alogrithm, refer to JVT-G016 + EARLY_TERMINATION; //added back by xxz + + //sub step2: multi-grid-hexagon-search + memcpy(temp_Big_Hexagon_X,Big_Hexagon_X,64); + memcpy(temp_Big_Hexagon_Y,Big_Hexagon_Y,64); + for(i=1;i<=(p_Inp->search_range[p_Vid->view_id] >> 2); i++) + { + + for (m = 0; m < 16; m++) + { + cand.mv_x = (short) (iMinNow.mv_x + temp_Big_Hexagon_X[m]); + cand.mv_y = (short) (iMinNow.mv_y + temp_Big_Hexagon_Y[m]); + temp_Big_Hexagon_X[m] += Big_Hexagon_X[m]; + temp_Big_Hexagon_Y[m] += Big_Hexagon_Y[m]; + + SEARCH_ONE_PIXEL_BIPRED; + } + if(min_mcost < ET_Thred) + { + goto terminate_step; + + } + } + //fourth step: Local Refinement: Extended Hexagon-based Search +fourth_1_step: + + for(i=0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 6; m++) + { + cand.mv_x = iMinNow.mv_x + Hexagon[m].mv_x; + cand.mv_y = iMinNow.mv_y + Hexagon[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + if(best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + break; + } +fourth_2_step: + + for(i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + if(best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + break; + } + +terminate_step: + for (i=0; i < (blocksize_x>>2); i++) + { + for (j=0; j < (blocksize_y>>2); j++) + { + if(list == 0) + { + p_UMHex->fastme_l0_cost_bipred[blocktype][(currMB->block_y)+block_y+j][(currMB->block_x)+block_x+i] = min_mcost; + } + else + { + p_UMHex->fastme_l1_cost_bipred[blocktype][(currMB->block_y)+block_y+j][(currMB->block_x)+block_x+i] = min_mcost; + } + } + } + + mv1->mv_x = (short) (best.mv_x - pic_pix_x); + mv1->mv_y = (short) (best.mv_y - pic_pix_y); + + return min_mcost; +} + +/*! +************************************************************************ +* \brief +* Set motion vector predictor +************************************************************************ +*/ +void UMHEXSetMotionVectorPredictor (Macroblock *currMB, + MotionVector *pmv, + struct pic_motion_params **mv_info, + short ref_frame, + int list, + int mb_x, + int mb_y, + int blockshape_x, + int blockshape_y, + MEBlock *mv_block) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + UMHexStruct *p_UMHex = p_Vid->p_UMHex; + int mv_a, mv_b, mv_c; + short pred_vec=0; + int mvPredType, rFrameL, rFrameU, rFrameUR; + int hv; + + PixelPos block_a, block_b, block_c, block_d; + + // added for bipred mode + distblk *** fastme_l0_cost_flag = (p_UMHex->bipred_flag ? p_UMHex->fastme_l0_cost_bipred : p_UMHex->fastme_l0_cost); + distblk *** fastme_l1_cost_flag = (p_UMHex->bipred_flag ? p_UMHex->fastme_l1_cost_bipred : p_UMHex->fastme_l1_cost); + //Dynamic Search Range + + int dsr_temp_search_range[2]; + int dsr_mv_avail, dsr_mv_max, dsr_mv_sum, dsr_small_search_range; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + // neighborhood SAD init + p_UMHex->SAD_a = 0; + p_UMHex->SAD_b = 0; + p_UMHex->SAD_c = 0; + p_UMHex->SAD_d = 0; + + get4x4Neighbour(currMB, mb_x - 1 , mb_y , mb_size, &block_a); + get4x4Neighbour(currMB, mb_x , mb_y - 1, mb_size, &block_b); + get4x4Neighbour(currMB, mb_x + blockshape_x, mb_y - 1, mb_size, &block_c); + get4x4Neighbour(currMB, mb_x - 1 , mb_y - 1, mb_size, &block_d); + + if (mb_y > 0) + { + if (mb_x < 8) // first column of 8x8 blocks + { + if (mb_y==8) + { + if (blockshape_x == 16) block_c.available = 0; + } + else + { + if (mb_x+blockshape_x == 8) block_c.available = 0; + } + } + else + { + if (mb_x+blockshape_x == 16) block_c.available = 0; + } + } + + if (!block_c.available) + { + block_c=block_d; + } + + mvPredType = MVPRED_MEDIAN; + + if (!p_Vid->mb_aff_frame_flag) + { + rFrameL = block_a.available ? mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list] : -1; + rFrameU = block_b.available ? mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] : -1; + rFrameUR = block_c.available ? mv_info[block_c.pos_y][block_c.pos_x].ref_idx[list] : -1; + } + else + { + if (p_Vid->mb_data[currMB->mbAddrX].mb_field) + { + rFrameL = block_a.available + ? (p_Vid->mb_data[block_a.mb_addr].mb_field + ? mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list] + : mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list] * 2) : -1; + rFrameU = block_b.available + ? (p_Vid->mb_data[block_b.mb_addr].mb_field + ? mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] + : mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] * 2) : -1; + rFrameUR = block_c.available + ? (p_Vid->mb_data[block_c.mb_addr].mb_field + ? mv_info[block_c.pos_y][block_c.pos_x].ref_idx[list] + : mv_info[block_c.pos_y][block_c.pos_x].ref_idx[list] * 2) : -1; + } + else + { + rFrameL = block_a.available + ? (p_Vid->mb_data[block_a.mb_addr].mb_field + ? mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list] >>1 + : mv_info[block_a.pos_y][block_a.pos_x].ref_idx[list]) : -1; + rFrameU = block_b.available ? + p_Vid->mb_data[block_b.mb_addr].mb_field ? + mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] >>1: + mv_info[block_b.pos_y][block_b.pos_x].ref_idx[list] : + -1; + rFrameUR = block_c.available ? + p_Vid->mb_data[block_c.mb_addr].mb_field ? + mv_info[block_c.pos_y][block_c.pos_x].ref_idx[list] >>1: + mv_info[block_c.pos_y][block_c.pos_x].ref_idx[list] : + -1; + } + } + + /* Prediction if only one of the neighbors uses the reference frame + * we are checking + */ + if(rFrameL == ref_frame && rFrameU != ref_frame && rFrameUR != ref_frame) mvPredType = MVPRED_L; + else if(rFrameL != ref_frame && rFrameU == ref_frame && rFrameUR != ref_frame) mvPredType = MVPRED_U; + else if(rFrameL != ref_frame && rFrameU != ref_frame && rFrameUR == ref_frame) mvPredType = MVPRED_UR; + // Directional predictions + if(blockshape_x == 8 && blockshape_y == 16) + { + if(mb_x == 0) + { + if(rFrameL == ref_frame) + mvPredType = MVPRED_L; + } + else + { + if( rFrameUR == ref_frame) + mvPredType = MVPRED_UR; + } + } + else if(blockshape_x == 16 && blockshape_y == 8) + { + if(mb_y == 0) + { + if(rFrameU == ref_frame) + mvPredType = MVPRED_U; + } + else + { + if(rFrameL == ref_frame) + mvPredType = MVPRED_L; + } + } + + // neighborhood SAD prediction + if((p_Inp->UMHexDSR == 1 || p_Inp->BiPredMotionEstimation == 1)) + { + p_UMHex->SAD_a = block_a.available ? ((list==1) ? (fastme_l1_cost_flag[p_UMHex->UMHEX_blocktype][block_a.pos_y][block_a.pos_x]) : (fastme_l0_cost_flag[p_UMHex->UMHEX_blocktype][block_a.pos_y][block_a.pos_x])) : 0; + p_UMHex->SAD_b = block_b.available ? ((list==1) ? (fastme_l1_cost_flag[p_UMHex->UMHEX_blocktype][block_b.pos_y][block_b.pos_x]) : (fastme_l0_cost_flag[p_UMHex->UMHEX_blocktype][block_b.pos_y][block_b.pos_x])) : 0; + p_UMHex->SAD_d = block_d.available ? ((list==1) ? (fastme_l1_cost_flag[p_UMHex->UMHEX_blocktype][block_d.pos_y][block_d.pos_x]) : (fastme_l0_cost_flag[p_UMHex->UMHEX_blocktype][block_d.pos_y][block_d.pos_x])) : 0; + p_UMHex->SAD_c = block_c.available ? ((list==1) ? (fastme_l1_cost_flag[p_UMHex->UMHEX_blocktype][block_c.pos_y][block_c.pos_x]) : (fastme_l0_cost_flag[p_UMHex->UMHEX_blocktype][block_c.pos_y][block_c.pos_x])) : p_UMHex->SAD_d; + } + for (hv=0; hv < 2; hv++) + { + if (!p_Vid->mb_aff_frame_flag || hv==0) + { + mv_a = block_a.available ? mv_info[block_a.pos_y][block_a.pos_x].mv[list].mv_x : 0; + mv_b = block_b.available ? mv_info[block_b.pos_y][block_b.pos_x].mv[list].mv_x : 0; + mv_c = block_c.available ? mv_info[block_c.pos_y][block_c.pos_x].mv[list].mv_x : 0; + } + else + { + if (p_Vid->mb_data[currMB->mbAddrX].mb_field) + { + mv_a = block_a.available ? p_Vid->mb_data[block_a.mb_addr].mb_field + ? mv_info[block_a.pos_y][block_a.pos_x].mv[list].mv_y + : mv_info[block_a.pos_y][block_a.pos_x].mv[list].mv_y / 2 + : 0; + mv_b = block_b.available ? p_Vid->mb_data[block_b.mb_addr].mb_field + ? mv_info[block_b.pos_y][block_b.pos_x].mv[list].mv_y + : mv_info[block_b.pos_y][block_b.pos_x].mv[list].mv_y / 2 + : 0; + mv_c = block_c.available ? p_Vid->mb_data[block_c.mb_addr].mb_field + ? mv_info[block_c.pos_y][block_c.pos_x].mv[list].mv_y + : mv_info[block_c.pos_y][block_c.pos_x].mv[list].mv_y / 2 + : 0; + } + else + { + mv_a = block_a.available ? p_Vid->mb_data[block_a.mb_addr].mb_field + ? mv_info[block_a.pos_y][block_a.pos_x].mv[list].mv_y * 2 + : mv_info[block_a.pos_y][block_a.pos_x].mv[list].mv_y + : 0; + mv_b = block_b.available ? p_Vid->mb_data[block_b.mb_addr].mb_field + ? mv_info[block_b.pos_y][block_b.pos_x].mv[list].mv_y * 2 + : mv_info[block_b.pos_y][block_b.pos_x].mv[list].mv_y + : 0; + mv_c = block_c.available ? p_Vid->mb_data[block_c.mb_addr].mb_field + ? mv_info[block_c.pos_y][block_c.pos_x].mv[list].mv_y * 2 + : mv_info[block_c.pos_y][block_c.pos_x].mv[list].mv_y + : 0; + } + } + + switch (mvPredType) + { + case MVPRED_MEDIAN: + if(!(block_b.available || block_c.available)) + { + pred_vec = (short) mv_a; + } + else + { + pred_vec = (short) (mv_a+mv_b+mv_c-imin(mv_a,imin(mv_b,mv_c))-imax(mv_a,imax(mv_b,mv_c))); + } + break; + case MVPRED_L: + pred_vec = (short) mv_a; + break; + case MVPRED_U: + pred_vec = (short) mv_b; + break; + case MVPRED_UR: + pred_vec = (short) mv_c; + break; + default: + break; + } + + if (hv == 0) + pmv->mv_x = pred_vec; + else + pmv->mv_y = pred_vec; + + //Dynamic Search Range + if (p_Inp->UMHexDSR) + { + dsr_mv_avail=block_a.available+block_b.available+block_c.available; + if(dsr_mv_avail < 2) + { + dsr_temp_search_range[hv] = p_Inp->search_range[p_Vid->view_id]; + } + else + { + dsr_mv_max = imax(iabs(mv_a),imax(iabs(mv_b),iabs(mv_c))); + dsr_mv_sum = (iabs(mv_a)+iabs(mv_b)+iabs(mv_c)); + if(dsr_mv_sum == 0) dsr_small_search_range = (p_Inp->search_range[p_Vid->view_id] + 4) >> 3; + else if(dsr_mv_sum > 3 ) dsr_small_search_range = (p_Inp->search_range[p_Vid->view_id] + 2) >>2; + else dsr_small_search_range = (3*p_Inp->search_range[p_Vid->view_id] + 8) >> 4; + dsr_temp_search_range[hv]=imin(p_Inp->search_range[p_Vid->view_id],imax(dsr_small_search_range,dsr_mv_max<<1)); + if(distblkmax(p_UMHex->SAD_a, distblkmax(p_UMHex->SAD_b,p_UMHex->SAD_c)) > p_UMHex->Threshold_DSR_MB[p_UMHex->UMHEX_blocktype]) + dsr_temp_search_range[hv] = p_Inp->search_range[p_Vid->view_id]; + } + } + } + + //Dynamic Search Range + if (p_Inp->UMHexDSR) + { + int search_range = imax(dsr_temp_search_range[0],dsr_temp_search_range[1]); + search_range <<= 2; + + if (p_Inp->full_search == 2) + { + mv_block->searchRange.min_x = -search_range; + mv_block->searchRange.max_x = search_range; + mv_block->searchRange.min_y = -search_range; + mv_block->searchRange.max_y = search_range; + } + else if (p_Inp->full_search == 1) + { + int scale = (imin(ref_frame,1)+1); + mv_block->searchRange.min_x = -search_range / scale; + mv_block->searchRange.max_x = search_range / scale; + mv_block->searchRange.min_y = -search_range / scale; + mv_block->searchRange.max_y = search_range / scale; + } + else + { + int scale = ((imin(ref_frame,1)+1) * imin(2,p_UMHex->BlockType_LUT[(blockshape_y >> 2) - 1][(blockshape_x >> 2) - 1])); + mv_block->searchRange.min_x = -search_range / scale; + mv_block->searchRange.max_x = search_range / scale; + mv_block->searchRange.min_y = -search_range / scale; + mv_block->searchRange.max_y = search_range / scale; + } + } +} + +#undef SEARCH_ONE_PIXEL + diff --git a/lencod/src/me_umhexsmp.c b/lencod/src/me_umhexsmp.c new file mode 100644 index 0000000..01f4ac8 --- /dev/null +++ b/lencod/src/me_umhexsmp.c @@ -0,0 +1,1025 @@ + +/*! + ************************************************************************************* + * + * \file me_umhexsmp.c + * + * \brief + * Fast integer pixel and sub pixel motion estimation + * Improved and simplified from the original UMHexagonS algorithms + * See JVT-P021 for details + * + * \author + * Main contributors: (see contributors.h for copyright, address and affiliation details) + * - Zhibo Chen + * - JianFeng Xu + * - Wenfang Fu + * + * - Xiaoquan Yi + * - Jun Zhang + * + * \date + * 6. Nov. 2006 + ************************************************************************************* + */ + +#include + +#include "global.h" +#include "memalloc.h" +#include "me_umhexsmp.h" +#include "refbuf.h" +#include "macroblock.h" +#include "me_distortion.h" +#include "mv_search.h" + + +static const MotionVector Diamond[4] = {{-4, 0}, {4, 0}, {0, -4}, {0, 4}}; +static const MotionVector Diamond_SubPelSearch[4] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; +static const MotionVector Hexagon[6] = {{-8, 0}, {8, 0},{-4, -8}, {4, 8}, {-4, 8}, {4 , -8}}; +static const short Big_Hexagon_X[16] = {-16, 16, 0, 0,-16, 16,-16, 16,-16, 16,-16, 16,-8, 8,-8, 8}; +static const short Big_Hexagon_Y[16] = { 0, 0,-16, 16,-4, 4, 4,-4,-8, 8, 8,-8,-12, 12, 12,-12}; + +static const short block_type_shift_factor[8] = {0, 0, 1, 1, 2, 3, 3, 1}; // last one relaxed to 1 instead 4 + +// Macro for motion estimation cost computation per match +#undef SEARCH_ONE_PIXEL_BIPRED +#undef SEARCH_ONE_PIXEL +#define SEARCH_ONE_PIXEL \ +if((iabs(cand.mv_x - center.mv_x)>>2) <= search_range && \ + (iabs(cand.mv_y - center.mv_y)>>2) <= search_range) \ +{ \ + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); \ + mcost += mv_block->computePredFPel( ref_picture, mv_block, min_mcost - mcost, &cand); \ + if (mcost < min_mcost) \ + { \ + best = cand; \ + min_mcost = mcost; \ + } \ +} + +#define SEARCH_ONE_PIXEL_BIPRED \ +if ((iabs(cand.mv_x - center2.mv_x)>>2) <= search_range \ +&& (iabs(cand.mv_y - center2.mv_y)>>2) <= search_range) \ +{ \ + mcost = mv_cost (p_Vid, lambda_factor, ¢er1, &pred1); \ + mcost += mv_cost (p_Vid, lambda_factor, &cand, &pred2); \ + if (mcost < min_mcost) \ + { \ + mcost += mv_block->computeBiPredFPel(ref_picture1, ref_picture2, \ + mv_block, min_mcost - mcost, ¢er1, &cand); \ + if (mcost < min_mcost) \ + { \ + best = cand; \ + min_mcost = mcost; \ + } \ + } \ +} + +/*! + ************************************************************************ + * \brief + * Set thresholds for fast motion estimation + * Those thresholds may be adjusted to trade off rate-distortion + * performance and simplified UMHEX speed + ************************************************************************ + */ +void smpUMHEX_init(VideoParameters *p_Vid) +{ + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + + p_UMHexSMP->SymmetricalCrossSearchThreshold1 = dist_scale(800); + p_UMHexSMP->SymmetricalCrossSearchThreshold2 = dist_scale(7000); + p_UMHexSMP->ConvergeThreshold = dist_scale(1000); + p_UMHexSMP->SubPelThreshold1 = dist_scale(1000); + p_UMHexSMP->SubPelThreshold3 = dist_scale(400); +} + +/*! + ************************************************************************ + * \brief + * Allocation of space for fast motion estimation + ************************************************************************ + */ +int smpUMHEX_get_mem(VideoParameters *p_Vid) +{ + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + int memory_size = 0; + if (NULL==(p_UMHexSMP->flag_intra = calloc((p_Vid->width>>4)+1, sizeof(byte)))) + no_mem_exit("smpUMHEX_get_mem: flag_intra"); + + memory_size += get_mem3Ddistblk(&p_UMHexSMP->l0_cost, 9, p_Vid->height >> 2, p_Vid->width >> 2); + memory_size += get_mem3Ddistblk(&p_UMHexSMP->l1_cost, 9, p_Vid->height >> 2, p_Vid->width >> 2); + memory_size += get_mem2D(&p_UMHexSMP->SearchState, 7, 7); + + return memory_size; +} + +/*! + ************************************************************************ + * \brief + * Free space for fast motion estimation + ************************************************************************ + */ +void smpUMHEX_free_mem(VideoParameters *p_Vid) +{ + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + free_mem3Ddistblk(p_UMHexSMP->l0_cost ); + free_mem3Ddistblk(p_UMHexSMP->l1_cost ); + free_mem2D(p_UMHexSMP->SearchState); + + free (p_UMHexSMP->flag_intra); + free (p_UMHexSMP); +} + + +/*! +************************************************************************ +* \brief +* Fast integer pixel block motion estimation +************************************************************************ +*/ +distblk // ==> minimum motion cost after search +smpUMHEXIntegerPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + int blocktype = mv_block->blocktype; + short blocksize_x = mv_block->blocksize_x; // horizontal block size + short blocksize_y = mv_block->blocksize_y; // vertical block size + short pic_pix_x = mv_block->pos_x_padded; + short pic_pix_y = mv_block->pos_y_padded; + + int list = mv_block->list; + int cur_list = list + currMB->list_offset; + short ref = mv_block->ref_idx; + StorablePicture *ref_picture = currSlice->listX[cur_list][ref]; + int search_range = mv_block->searchRange.max_x >> 2; + + MotionVector *mv = &mv_block->mv[list]; + MotionVector iMinNow, cand, center, pred, best = {0, 0}; + + int search_step; + distblk mcost; + uint16 i, j, m; + + pic_pix_x = mv_block->pos_x_padded; + pic_pix_y = mv_block->pos_y_padded; + pred.mv_x = pic_pix_x + pred_mv->mv_x; // predicted position x (in sub-pel units) + pred.mv_y = pic_pix_y + pred_mv->mv_y; // predicted position y (in sub-pel units) + center.mv_x = pic_pix_x + mv->mv_x; // center position x (in sub-pel units) + center.mv_y = pic_pix_y + mv->mv_y; // center position y (in sub-pel units) + + + //check the center median predictor + + cand = center; + mcost = mv_cost (p_Vid, lambda_factor, &cand, &pred); + + mcost += mv_block->computePredFPel(ref_picture, mv_block, min_mcost - mcost, &cand); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best = cand; + } + + iMinNow = best; + + // check 0 + if ((0 != pred_mv->mv_x) || (0 != pred_mv->mv_y)) + { + cand.mv_x = pic_pix_x; + cand.mv_y = pic_pix_y; + SEARCH_ONE_PIXEL; + iMinNow = best; + } + + // If the min_mcost is small enough, do a local search then terminate + // Ihis is good for stationary or quasi-stationary areas + if (min_mcost < (p_UMHexSMP->ConvergeThreshold >> block_type_shift_factor[blocktype])) + { + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL; + } + mv->mv_x = (short) (best.mv_x - pic_pix_x); + mv->mv_y = (short) (best.mv_y - pic_pix_y); + return min_mcost; + } + + // Small local search + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL; + } + + // First_step: Symmetrical-cross search + // If distortion is large, use large shapes. Otherwise, compact shapes are faster + if ( (blocktype == 1 && + min_mcost > (p_UMHexSMP->SymmetricalCrossSearchThreshold1 >> block_type_shift_factor[blocktype])) || + (min_mcost > (p_UMHexSMP->SymmetricalCrossSearchThreshold2>>block_type_shift_factor[blocktype])) ) + { + iMinNow = best; + + for(i = 4; i <= 4 * search_range - 4; i+= 8) + { + search_step = i; + cand.mv_x = (short) (iMinNow.mv_x + search_step); + cand.mv_y = iMinNow.mv_y; + SEARCH_ONE_PIXEL; + + cand.mv_x = (short) (iMinNow.mv_x - search_step); + SEARCH_ONE_PIXEL; + + cand.mv_x = iMinNow.mv_x; + cand.mv_y = (short) (iMinNow.mv_y + search_step); + SEARCH_ONE_PIXEL; + + cand.mv_y = (short) (iMinNow.mv_y - search_step); + SEARCH_ONE_PIXEL; + } + + // Hexagon Search + iMinNow = best; + + for (m = 0; m < 6; m++) + { + cand.mv_x = iMinNow.mv_x + Hexagon[m].mv_x; + cand.mv_y = iMinNow.mv_y + Hexagon[m].mv_y; + SEARCH_ONE_PIXEL; + } + // Multi Big Hexagon Search + iMinNow = best; + + for(i = 1; i <= search_range >> 2; i++) + { + for (m = 0; m < 16; m++) + { + cand.mv_x = iMinNow.mv_x + Big_Hexagon_X[m]*i; + cand.mv_y = iMinNow.mv_y + Big_Hexagon_Y[m]*i; + SEARCH_ONE_PIXEL; + } + } + } + + // Search up_layer predictor for non 16x16 blocks + if (blocktype > 1) + { + cand.mv_x = pic_pix_x + (p_UMHexSMP->pred_MV_uplayer_X / 4) * 4; + cand.mv_y = pic_pix_y + (p_UMHexSMP->pred_MV_uplayer_Y / 4) * 4; + SEARCH_ONE_PIXEL; + } + + if(center.mv_x != pic_pix_x || center.mv_y != pic_pix_y) + { + cand.mv_x = pic_pix_x; + cand.mv_y = pic_pix_y; + SEARCH_ONE_PIXEL; + + iMinNow = best; + // Local diamond search + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL; + } + } + + // If the minimum cost is small enough, do a local search + // and finish the search here + if (min_mcost < (p_UMHexSMP->ConvergeThreshold >> block_type_shift_factor[blocktype])) + { + iMinNow = best; + + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL; + } + mv->mv_x = (short) (best.mv_x - pic_pix_x); + mv->mv_y = (short) (best.mv_y - pic_pix_y); + return min_mcost; + } + + //second_step: Extended Hexagon-based Search + for(i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 6; m++) + { + cand.mv_x = iMinNow.mv_x + Hexagon[m].mv_x; + cand.mv_y = iMinNow.mv_y + Hexagon[m].mv_y; + SEARCH_ONE_PIXEL; + } + // The minimum cost point happens in the center + if (best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + { + break; + } + } + + //third_step: Small diamond search + for(i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL; + } + + // The minimum cost point happens in the center + if (best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + { + break; + } + } + + mv->mv_x = (short) (best.mv_x - pic_pix_x); + mv->mv_y = (short) (best.mv_y - pic_pix_y); + + for (j=(mv_block->pos_y2); j < (mv_block->pos_y2) + (blocksize_y>>2); j++) + { + for (i=(mv_block->pos_x2); i < (mv_block->pos_x2) + (blocksize_x>>2); i++) + { + if(mv_block->list == 0) + { + p_UMHexSMP->l0_cost[blocktype][j][i] = min_mcost; + } + else + { + p_UMHexSMP->l1_cost[blocktype][j][i] = min_mcost; + } + } + } + + return min_mcost; +} + +/*! + *********************************************************************** + * \brief + * Sub pixel block motion search enhanced + *********************************************************************** + */ +distblk // ==> minimum motion cost after search +smpUMHEXFullSubPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + int pos, best_pos; + distblk mcost; + + MotionVector cand; + + int blocktype = mv_block->blocktype; + int list = mv_block->list; + int list_offset = currMB->list_offset; + short ref = mv_block->ref_idx; + MotionVector *mv = &mv_block->mv[list]; + + int check_position0 = (!p_Inp->rdopt && currSlice->slice_type!=B_SLICE && ref==0 && blocktype==1 && mv->mv_x==0 && mv->mv_y==0); + + int max_pos2 = ( !p_Vid->start_me_refinement_hp ? imax(1, mv_block->search_pos2) : mv_block->search_pos2); + MotionVector cmv; + + StorablePicture *ref_picture = currSlice->listX[list + list_offset][ref]; + + + /********************************* + ***** ***** + ***** HALF-PEL REFINEMENT ***** + ***** ***** + *********************************/ + + //===== loop over search positions ===== + for (best_pos = 0, pos = p_Vid->start_me_refinement_hp; pos < max_pos2; pos++) + { + cand.mv_x = mv->mv_x + p_Vid->spiral_hpel_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv->mv_y + p_Vid->spiral_hpel_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cmv); + + if (pos==0 && check_position0) + { + distblk dbTmp = weighted_cost (lambda_factor, 16); + mcost = (mcost > dbTmp)? (mcost - dbTmp):0; + } + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + if (min_mcost < (p_UMHexSMP->SubPelThreshold3 >> block_type_shift_factor[blocktype])) + { + break; + } + } + + if (best_pos) + { + add_mvs(mv, &p_Vid->spiral_hpel_search[best_pos]); + } + + if ((mv->mv_x == 0) && (mv->mv_y == 0) && (pred_mv->mv_x == 0 && pred_mv->mv_y == 0) && + (min_mcost < (p_UMHexSMP->SubPelThreshold1 >> block_type_shift_factor[blocktype])) ) + { + best_pos = 0; + return min_mcost; + } + if ( !p_Vid->start_me_refinement_qp ) + min_mcost = DISTBLK_MAX; + /************************************ + ***** ***** + ***** QUARTER-PEL REFINEMENT ***** + ***** ***** + ************************************/ + + //===== loop over search positions ===== + for (best_pos = 0, pos = p_Vid->start_me_refinement_qp; pos < mv_block->search_pos4; pos++) + { + cand.mv_x = mv->mv_x + p_Vid->spiral_search[pos].mv_x; // quarter-pel units + cand.mv_y = mv->mv_y + p_Vid->spiral_search[pos].mv_y; // quarter-pel units + + //----- set motion vector cost ----- + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + + if (mcost >= min_mcost) continue; + + cmv = pad_MVs(cand, mv_block); + + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cmv); + + if (mcost < min_mcost) + { + min_mcost = mcost; + best_pos = pos; + } + if (min_mcost < (p_UMHexSMP->SubPelThreshold3 >> block_type_shift_factor[blocktype])) + { + break; + } + } + + if (best_pos) + { + add_mvs(mv, &p_Vid->spiral_search[best_pos]); + } + + //===== return minimum motion cost ===== + return min_mcost; +} + + +/*! + ************************************************************************ + * \brief + * Fast sub pixel block motion estimation + ************************************************************************ + */ +distblk // ==> minimum motion cost after search +smpUMHEXSubPelBlockMotionSearch ( + Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + distblk mcost; + MotionVector cand, iMinNow, currmv = {0, 0}, cand_pad; + + int blocktype = mv_block->blocktype; + int list = mv_block->list; + int list_offset = currMB->list_offset; + short ref = mv_block->ref_idx; + MotionVector *mv = &mv_block->mv[list]; + + StorablePicture *ref_picture = currSlice->listX[list+list_offset][ref]; + + short dynamic_search_range = 3, i, m; + int pred_frac_mv_x,pred_frac_mv_y,abort_search; + int pred_frac_up_mv_x, pred_frac_up_mv_y; + + pred_frac_mv_x = (pred_mv->mv_x - mv->mv_x) %4; //& 0x03; + pred_frac_mv_y = (pred_mv->mv_y - mv->mv_y) %4; //& 0x03; + + pred_frac_up_mv_x = (p_UMHexSMP->pred_MV_uplayer_X - mv->mv_x) & 0x03; + pred_frac_up_mv_y = (p_UMHexSMP->pred_MV_uplayer_Y - mv->mv_y) & 0x03; + + memset(p_UMHexSMP->SearchState[0], 0, (2 * dynamic_search_range + 1)*(2 * dynamic_search_range + 1)); + + p_UMHexSMP->SearchState[dynamic_search_range][dynamic_search_range] = 1; + if( !p_Vid->start_me_refinement_hp ) + { + cand.mv_x = mv->mv_x; + cand.mv_y = mv->mv_y; + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + cand_pad = pad_MVs (cand, mv_block); //cand = pad_MVs (cand, mv_block); + + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cand_pad); //&cand); + if (mcost < min_mcost) + { + min_mcost = mcost; + currmv = cand; + } + } + else + { + currmv = *mv; + } + + // If the min_mcost is small enough and other statistics are positive, + // better to stop the search now + if ( ((mv->mv_x) == 0) && ((mv->mv_y) == 0) && + (pred_frac_mv_x == 0 && pred_frac_up_mv_x == 0) && + (pred_frac_mv_y == 0 && pred_frac_up_mv_y == 0) && + (min_mcost < (p_UMHexSMP->SubPelThreshold1 >> block_type_shift_factor[blocktype])) ) + { + *mv = currmv; + return min_mcost; + } + + if(pred_frac_mv_x || pred_frac_mv_y) + { + cand.mv_x = (short) (mv->mv_x + pred_frac_mv_x); + cand.mv_y = (short) (mv->mv_y + pred_frac_mv_y); + p_UMHexSMP->SearchState[cand.mv_y -mv->mv_y + dynamic_search_range][cand.mv_x - mv->mv_x + dynamic_search_range] = 1; + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + + cand_pad = pad_MVs (cand, mv_block); //cand = pad_MVs (cand, mv_block); + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cand_pad); //&cand); + + if (mcost < min_mcost) + { + min_mcost = mcost; + currmv = cand; + } + } + + // Multiple small diamond search + for(i = 0; i < dynamic_search_range; i++) + { + abort_search = 1; + + iMinNow = currmv; + + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond_SubPelSearch[m].mv_x; //Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond_SubPelSearch[m].mv_y; //Diamond[m].mv_y; + + if(iabs(cand.mv_x - mv->mv_x) <= dynamic_search_range && iabs(cand.mv_y - mv->mv_y) <= dynamic_search_range) + { + if(!p_UMHexSMP->SearchState[cand.mv_y - mv->mv_y + dynamic_search_range][cand.mv_x - mv->mv_x + dynamic_search_range]) + { + p_UMHexSMP->SearchState[cand.mv_y - mv->mv_y + dynamic_search_range][cand.mv_x - mv->mv_x + dynamic_search_range] = 1; + mcost = mv_cost (p_Vid, lambda_factor, &cand, pred_mv); + cand_pad = pad_MVs (cand, mv_block); //cand = pad_MVs (cand, mv_block); + mcost += mv_block->computePredQPel( ref_picture, mv_block, min_mcost - mcost, &cand_pad); //&cand); + if (mcost < min_mcost) + { + min_mcost = mcost; + currmv = cand; + abort_search = 0; + } + if (min_mcost < (p_UMHexSMP->SubPelThreshold3 >> block_type_shift_factor[blocktype])) + { + *mv = currmv; + return min_mcost; + } + } + } + } + // If the minimum cost point is in the center, break out the loop + if (abort_search) + { + break; + } + } + + *mv = currmv; + + //===== return minimum motion cost ===== + return min_mcost; +} + +distblk // ==> minimum motion cost after search +smpUMHEXSubPelBlockME (Macroblock *currMB, // <-- current Macroblock + MotionVector *pred_mv, // <-- motion vector predictor (x|y) in sub-pel units + MEBlock *mv_block, + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int* lambda_factor ) +{ + if(mv_block->blocktype > 1) + { + min_mcost = smpUMHEXSubPelBlockMotionSearch (currMB, pred_mv, mv_block, min_mcost, lambda_factor[Q_PEL]); + } + else + { + min_mcost = smpUMHEXFullSubPelBlockMotionSearch (currMB, pred_mv, mv_block, min_mcost, lambda_factor[Q_PEL]); + } + + return min_mcost; +} + +/*! + ************************************************************************ + * \brief + * smpUMHEXBipredIntegerPelBlockMotionSearch: fast pixel block motion search for bipred mode + * + ************************************************************************ + */ +distblk // ==> minimum motion cost after search +smpUMHEXBipredIntegerPelBlockMotionSearch (Macroblock *currMB, // <-- current Macroblock + int list, // <-- Current reference list + MotionVector *pred_mv1, // <-- motion vector predictor (x|y) in sub-pel units + MotionVector *pred_mv2, // <-- motion vector predictor (x|y) in sub-pel units + MotionVector *mv1, // <--> in: search center (x|y) / out: motion vector (x|y) - in sub-pel units + MotionVector *mv2, // <--> in: search center (x|y) + MEBlock *mv_block, // <-- motion vector information + int search_range, // <-- 1-d search range in sub-pel units + distblk min_mcost, // <-- minimum motion cost (cost for center or huge value) + int lambda_factor // <-- lagrangian parameter for determining motion cost + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + + int search_step; + int i, m; + distblk mcost; + short blocktype = mv_block->blocktype; + + short pic_pix_x = mv_block->pos_x_padded; + short pic_pix_y = mv_block->pos_y_padded; + short ref = mv_block->ref_idx; + + StorablePicture *ref_picture1 = currSlice->listX[list + currMB->list_offset][ref]; + StorablePicture *ref_picture2 = currSlice->listX[list == 0 ? 1 + currMB->list_offset: currMB->list_offset][ 0 ]; + + MotionVector iMinNow, best, cand, pred1, pred2, center1, center2; + search_range >>= 2; + + pred1.mv_x = mv_block->pos_x_padded + pred_mv1->mv_x; // predicted position x (in sub-pel units) + pred1.mv_y = mv_block->pos_y_padded + pred_mv1->mv_y; // predicted position y (in sub-pel units) + pred2.mv_x = mv_block->pos_x_padded + pred_mv2->mv_x; // predicted position x (in sub-pel units) + pred2.mv_y = mv_block->pos_y_padded + pred_mv2->mv_y; // predicted position y (in sub-pel units) + + center2.mv_x = mv_block->pos_x_padded + mv1->mv_x; // center position x (in sub-pel units) + center2.mv_y = mv_block->pos_y_padded + mv1->mv_y; // center position y (in sub-pel units) + center1.mv_x = mv_block->pos_x_padded + mv2->mv_x; // mvx of second pred (in sub-pel units) + center1.mv_y = mv_block->pos_y_padded + mv2->mv_y; // mvy of second pred (in sub-pel units) + + //check the center median predictor + best = cand = center2; + mcost = mv_cost (p_Vid, lambda_factor, ¢er1, &pred1); + mcost += mv_cost (p_Vid, lambda_factor, &cand, &pred2); + mcost += mv_block->computeBiPredFPel(ref_picture1, ref_picture2, mv_block, + DISTBLK_MAX, ¢er1, &cand); + if (mcost < min_mcost) + { + min_mcost = mcost; + best = cand; + } + + iMinNow = best; + if (0 != pred_mv1->mv_x || 0 != pred_mv1->mv_y || 0 != pred_mv2->mv_x || 0 != pred_mv2->mv_y) + { + cand.mv_x = pic_pix_x; + cand.mv_y = pic_pix_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + // If the min_mcost is small enough, do a local search then terminate + // This is good for stationary or quasi-stationary areas + if ((min_mcost<<3) < (p_UMHexSMP->ConvergeThreshold >> (block_type_shift_factor[blocktype]))) + { + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + mv1->mv_x = (short) (best.mv_x - pic_pix_x); + mv1->mv_y = (short) (best.mv_y - pic_pix_y); + return min_mcost; + } + + // Small local search + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + // First_step: Symmetrical-cross search + // If distortion is large, use large shapes. Otherwise, compact shapes are faster + if ((blocktype == 1 && + (min_mcost<<2) > (p_UMHexSMP->SymmetricalCrossSearchThreshold1 >> block_type_shift_factor[blocktype])) || + ((min_mcost<<2) > (p_UMHexSMP->SymmetricalCrossSearchThreshold2>>block_type_shift_factor[blocktype]))) + { + iMinNow.mv_x = best.mv_x; + iMinNow.mv_y = best.mv_y; + + for (i = 8; i <= 4 * search_range; i+= 8) + { + search_step = i - 4; + cand.mv_x = (short) (iMinNow.mv_x + search_step); + cand.mv_y = iMinNow.mv_y; + SEARCH_ONE_PIXEL_BIPRED; + cand.mv_x = (short) (iMinNow.mv_x - search_step); + SEARCH_ONE_PIXEL_BIPRED; + + cand.mv_x = iMinNow.mv_x; + cand.mv_y = (short) (iMinNow.mv_y + search_step); + SEARCH_ONE_PIXEL_BIPRED; + cand.mv_y = (short) (iMinNow.mv_y - search_step); + SEARCH_ONE_PIXEL_BIPRED; + } + + // Hexagon Search + iMinNow.mv_x = best.mv_x; + iMinNow.mv_y = best.mv_y; + for (m = 0; m < 6; m++) + { + cand.mv_x = iMinNow.mv_x + Hexagon[m].mv_x; + cand.mv_y = iMinNow.mv_y + Hexagon[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + // Multi Big Hexagon Search + iMinNow = best; + for(i = 1; i <= search_range / 4; i++) + { + for (m = 0; m < 16; m++) + { + cand.mv_x = (short) (iMinNow.mv_x + Big_Hexagon_X[m] * i); + cand.mv_y = (short) (iMinNow.mv_y + Big_Hexagon_Y[m] * i); + SEARCH_ONE_PIXEL_BIPRED; + } + } + } + + // Search up_layer predictor for non 16x16 blocks + if (blocktype > 1) + { + cand.mv_x = pic_pix_x + (p_UMHexSMP->pred_MV_uplayer_X / 4) * 4; + cand.mv_y = pic_pix_y + (p_UMHexSMP->pred_MV_uplayer_Y / 4) * 4; + SEARCH_ONE_PIXEL_BIPRED; + } + + if(center2.mv_x != pic_pix_x || center2.mv_x != pic_pix_y) + { + cand.mv_x = pic_pix_x; + cand.mv_y = pic_pix_y; + SEARCH_ONE_PIXEL_BIPRED; + + iMinNow = best; + // Local diamond search + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + } + + // If the minimum cost is small enough, do a local search + // and finish the search here + if ((min_mcost<<2) < (p_UMHexSMP->ConvergeThreshold >> block_type_shift_factor[blocktype])) + { + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + mv1->mv_x = (short) (best.mv_x - pic_pix_x); + mv1->mv_y = (short) (best.mv_y - pic_pix_y); + return min_mcost; + } + + // Second_step: Extended Hexagon-based Search + for (i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 6; m++) + { + cand.mv_x = iMinNow.mv_x + Hexagon[m].mv_x; + cand.mv_y = iMinNow.mv_y + Hexagon[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + // The minimum cost point happens in the center + if (best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + { + break; + } + } + + // Third_step: Small diamond search + for (i = 0; i < search_range; i++) + { + iMinNow = best; + for (m = 0; m < 4; m++) + { + cand.mv_x = iMinNow.mv_x + Diamond[m].mv_x; + cand.mv_y = iMinNow.mv_y + Diamond[m].mv_y; + SEARCH_ONE_PIXEL_BIPRED; + } + + // The minimum cost point happens in the center + if (best.mv_x == iMinNow.mv_x && best.mv_y == iMinNow.mv_y) + { + break; + } + } + + mv1->mv_x = (short) (best.mv_x - pic_pix_x); + mv1->mv_y = (short) (best.mv_y - pic_pix_y); + return min_mcost; +} + +/*! + ************************************************************************ + * \brief + * Set neighbouring block mode (intra/inter) + * used for fast motion estimation + ************************************************************************ + */ +void smpUMHEX_decide_intrabk_SAD(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + if (currMB->pix_x == 0 && currMB->pix_y == 0) + { + p_UMHexSMP->flag_intra_SAD = 0; + } + else if (currMB->pix_x == 0) + { + p_UMHexSMP->flag_intra_SAD = p_UMHexSMP->flag_intra[(currMB->pix_x)>>4]; + } + else if (currMB->pix_y == 0) + { + p_UMHexSMP->flag_intra_SAD = p_UMHexSMP->flag_intra[((currMB->pix_x)>>4)-1]; + } + else + { + p_UMHexSMP->flag_intra_SAD = ((p_UMHexSMP->flag_intra[(currMB->pix_x)>>4])|| + (p_UMHexSMP->flag_intra[((currMB->pix_x)>>4)-1])|| + (p_UMHexSMP->flag_intra[((currMB->pix_x)>>4)+1])) ; + } + } + return; +} + +/*! + ************************************************************************ + * \brief + * Set cost to zero if neighbouring block is intra + * used for fast motion estimation + ************************************************************************ + */ +void smpUMHEX_skip_intrabk_SAD(Macroblock *currMB) +{ + short i, j, k; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + + if (p_Vid->number > 0) + { + p_UMHexSMP->flag_intra[(currMB->pix_x)>>4] = (currMB->best_mode == 9 || currMB->best_mode == 10) ? 1 : 0; + } + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE && (currMB->best_mode == 9 || currMB->best_mode == 10)) + { + for (k=0; k < 9;k++) + { + for (j=0; j < 4; j++) + { + for (i=0; i < 4; i++) + { + p_UMHexSMP->l0_cost[k][j][i] = 0; + p_UMHexSMP->l1_cost[k][j][i] = 0; + } + } + } + } + return; +} + +/*! + ************************************************************************ + * \brief + * Set up prediction MV and prediction up layer cost + * used for fast motion estimation + ************************************************************************ + */ +void smpUMHEX_setup(Macroblock *currMB, + short ref, + int list, + int block_y, + int block_x, + int blocktype, + MotionVector *****all_mv) +{ + VideoParameters *p_Vid = currMB->p_Vid; + UMHexSMPStruct *p_UMHexSMP = p_Vid->p_UMHexSMP; + + if (blocktype > 6) + { + p_UMHexSMP->pred_MV_uplayer_X = all_mv[list][ref][5][block_y][block_x].mv_x; + p_UMHexSMP->pred_MV_uplayer_Y = all_mv[list][ref][5][block_y][block_x].mv_y; + } + else if (blocktype > 4) + { + p_UMHexSMP->pred_MV_uplayer_X = all_mv[list][ref][4][block_y][block_x].mv_x; + p_UMHexSMP->pred_MV_uplayer_Y = all_mv[list][ref][4][block_y][block_x].mv_y; + } + else if (blocktype == 4) + { + p_UMHexSMP->pred_MV_uplayer_X = all_mv[list][ref][2][block_y][block_x].mv_x; + p_UMHexSMP->pred_MV_uplayer_Y = all_mv[list][ref][2][block_y][block_x].mv_y; + } + else if (blocktype > 1) + { + p_UMHexSMP->pred_MV_uplayer_X = all_mv[list][ref][1][block_y][block_x].mv_x; + p_UMHexSMP->pred_MV_uplayer_Y = all_mv[list][ref][1][block_y][block_x].mv_y; + } + + if (blocktype > 1) + { + if (blocktype > 6) + { + p_UMHexSMP->pred_SAD_uplayer = (list==1) ? + (p_UMHexSMP->l1_cost[5][(currMB->block_y)+block_y][(currMB->block_x)+block_x]) + : (p_UMHexSMP->l0_cost[5][(currMB->block_y)+block_y][(currMB->block_x)+block_x]); + p_UMHexSMP->pred_SAD_uplayer /= 2; + } + else if (blocktype > 4) + { + p_UMHexSMP->pred_SAD_uplayer = (list==1) ? + (p_UMHexSMP->l1_cost[4][(currMB->block_y)+block_y][(currMB->block_x)+block_x]) + : (p_UMHexSMP->l0_cost[4][(currMB->block_y)+block_y][(currMB->block_x)+block_x]); + p_UMHexSMP->pred_SAD_uplayer /= 2; + } + else if (blocktype == 4) + { + p_UMHexSMP->pred_SAD_uplayer = (list==1) ? + (p_UMHexSMP->l1_cost[2][(currMB->block_y)+block_y][(currMB->block_x)+block_x]) + : (p_UMHexSMP->l0_cost[2][(currMB->block_y)+block_y][(currMB->block_x)+block_x]); + p_UMHexSMP->pred_SAD_uplayer /= 2; + } + else + { + p_UMHexSMP->pred_SAD_uplayer = (list==1) ? + (p_UMHexSMP->l1_cost[1][(currMB->block_y)+block_y][(currMB->block_x)+block_x]) + : (p_UMHexSMP->l0_cost[1][(currMB->block_y)+block_y][(currMB->block_x)+block_x]); + p_UMHexSMP->pred_SAD_uplayer /= 2; + } + + p_UMHexSMP->pred_SAD_uplayer = p_UMHexSMP->flag_intra_SAD ? 0 : p_UMHexSMP->pred_SAD_uplayer; + } +} + diff --git a/lencod/src/mmco.c b/lencod/src/mmco.c new file mode 100644 index 0000000..d6ff3bf --- /dev/null +++ b/lencod/src/mmco.c @@ -0,0 +1,479 @@ +/*! + ************************************************************************************* + * \file mmco.c + * + * \brief + * MMCO example operations. + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Athanasios Leontaris + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include +#include "global.h" + +#include "image.h" +#include "nalucommon.h" +#include "report.h" + + +void mmco_long_term(VideoParameters *p_Vid, int current_pic_num) +{ + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2; + + if ( !p_Vid->currentPicture->idr_flag ) + { + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm"); + + tmp_drpm->Next=NULL; + + tmp_drpm->memory_management_control_operation = 0; + + if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm2"); + tmp_drpm2->Next=tmp_drpm; + + tmp_drpm2->memory_management_control_operation = 3; + tmp_drpm2->long_term_frame_idx = current_pic_num; + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2; + } + else + { + p_Vid->long_term_reference_flag = TRUE; + } +} + +#if HM50_LIKE_MMCO +void hm50_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + int pic_num = 0; + + int target_poc=-1; + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2; + + // only support GOP Size = 8, 4 reference frames, 2 in list0 and 2 in list1 + if ( p_Vid->p_Inp->NumberBFrames != 7 || + p_Vid->p_Inp->num_ref_frames != 4 || + p_Vid->p_Inp->B_List0_refs[0] != 2 || + p_Vid->p_Inp->B_List1_refs[0] != 2 ) + { + return; + } + +#if CRA + // for CRA pictures, we have MMCO already + if ( p_Vid->p_Inp->useCRA ) + { + if ( ( p_Vid->currentSlice->slice_type == B_SLICE || p_Vid->currentSlice->slice_type == P_SLICE ) && p_Vid->currentSlice->p_Dpb->ref_frames_in_buffer >= 2 ) + { + if ( ( (p_Vid->currentSlice->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + return; + } + } + } +#endif + + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if ( p_Vid->currentPicture->idr_flag ) + return; + + if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0) + return; + + switch ( p_Vid->currentSlice->ThisPOC / 2 % 8 ) + { + case 0: + target_poc = p_Vid->currentSlice->ThisPOC - 32; + break; + case 4: + target_poc = p_Vid->currentSlice->ThisPOC - 16; + break; + case 2: + target_poc = p_Vid->currentSlice->ThisPOC - 8; + break; + case 6: + target_poc = p_Vid->currentSlice->ThisPOC - 8; + break; + default: + target_poc = -1; + break; + } + + if ( target_poc < 0 ) + return; + + + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc == target_poc) + { + pic_num = p_Dpb->fs[i]->frame->pic_num; + } + } + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm"); + tmp_drpm->Next=NULL; + + tmp_drpm->memory_management_control_operation = 0; + + if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm2"); + tmp_drpm2->Next=tmp_drpm; + + tmp_drpm2->memory_management_control_operation = 1; + + if ( p_Vid->num_of_layers == 1 ) + tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1; + else + tmp_drpm2->difference_of_pic_nums_minus1 = (current_pic_num - pic_num)/2 - 1; + + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2; +} +#endif + +#if CRA +void cra_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + int pic_num = 0; + + int min_poc=INT_MAX; + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2; + + int last_intra_poc = p_Vid->currentSlice->ThisPOC / 2 / p_Vid->p_Inp->intra_period * p_Vid->p_Inp->intra_period * 2; + + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if ( p_Vid->currentPicture->idr_flag ) + return; + + if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0) + return; + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm"); + tmp_drpm->Next=NULL; + + tmp_drpm->memory_management_control_operation = 0; + + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < last_intra_poc) + { + if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm2"); + tmp_drpm2->Next=tmp_drpm; + tmp_drpm2->memory_management_control_operation = 1; + + pic_num = p_Dpb->fs[i]->frame->pic_num; + + if ( p_Vid->num_of_layers == 1 ) + tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1; + else + tmp_drpm2->difference_of_pic_nums_minus1 = (current_pic_num - pic_num)/2 - 1; + + if ( tmp_drpm2->difference_of_pic_nums_minus1 < 0 ) + { + tmp_drpm2->difference_of_pic_nums_minus1 += p_Vid->currentSlice->max_frame_num; + } + if ( tmp_drpm2->difference_of_pic_nums_minus1 >= p_Vid->currentSlice->max_frame_num ) + { + tmp_drpm2->difference_of_pic_nums_minus1 -= p_Vid->currentSlice->max_frame_num; + } + + tmp_drpm = tmp_drpm2; + } + } + + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm; +} +#endif + +#if LD_REF_SETTING +void low_delay_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + int pic_num = 0; + + int min_poc=INT_MAX; + int min_poc_not_4x = INT_MAX; + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2; + +#if CRA + // for CRA pictures, we have MMCO already + if ( p_Vid->p_Inp->useCRA ) + { + if ( ( p_Vid->currentSlice->slice_type == B_SLICE || p_Vid->currentSlice->slice_type == P_SLICE ) && p_Vid->currentSlice->p_Dpb->ref_frames_in_buffer >= 2 ) + { + if ( ( (p_Vid->currentSlice->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + return; + } + } + } +#endif + + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if ( p_Vid->currentPicture->idr_flag ) + return; + + if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0) + return; + + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc) + { + min_poc = p_Dpb->fs[i]->frame->poc ; + pic_num = p_Dpb->fs[i]->frame->pic_num; + } + } + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc_not_4x && (p_Dpb->fs[i]->poc/2)%4!=0 ) + { + min_poc_not_4x = p_Dpb->fs[i]->frame->poc ; + pic_num = p_Dpb->fs[i]->frame->pic_num; + } + } + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm"); + tmp_drpm->Next=NULL; + + tmp_drpm->memory_management_control_operation = 0; + + if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm2"); + tmp_drpm2->Next=tmp_drpm; + + tmp_drpm2->memory_management_control_operation = 1; + + if ( p_Vid->num_of_layers == 1 ) + tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1; + else + tmp_drpm2->difference_of_pic_nums_minus1 = (current_pic_num - pic_num)/2 - 1; + + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2; +} +#endif + +/*! +************************************************************************ +* \brief +* POC-based reference management (FRAME) +************************************************************************ +*/ + +void poc_based_ref_management_frame_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned i; + int pic_num = 0; + + int min_poc=INT_MAX; + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2; + +#if CRA + // for CRA pictures, we have MMCO already + if ( p_Vid->p_Inp->useCRA ) + { + if ( ( p_Vid->currentSlice->slice_type == B_SLICE || p_Vid->currentSlice->slice_type == P_SLICE ) && p_Vid->currentSlice->p_Dpb->ref_frames_in_buffer >= 2 ) + { + if ( ( (p_Vid->currentSlice->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + return; + } + } + } +#endif + +#if HM50_LIKE_MMCO + if ( p_Vid->p_Inp->HM50LikeMMCO ) + { + // for the case that we already have MMCO, just return + if ( p_Vid->p_Inp->NumberBFrames != 7 || + p_Vid->p_Inp->num_ref_frames != 4 || + p_Vid->p_Inp->B_List0_refs[0] != 2 || + p_Vid->p_Inp->B_List1_refs[0] != 2 ) + { + return; + } + } +#endif + + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if ( p_Vid->currentPicture->idr_flag ) + return; + + if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0) + return; + + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc) + { + min_poc = p_Dpb->fs[i]->frame->poc ; + pic_num = p_Dpb->fs[i]->frame->pic_num; + } + } + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm"); + tmp_drpm->Next=NULL; + + tmp_drpm->memory_management_control_operation = 0; + + if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm2"); + tmp_drpm2->Next=tmp_drpm; + + tmp_drpm2->memory_management_control_operation = 1; + tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num - 1; + + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm2; +} + +/*! +************************************************************************ +* \brief +* POC-based reference management (FIELD) +************************************************************************ +*/ + +void poc_based_ref_management_field_pic(DecodedPictureBuffer *p_Dpb, int current_pic_num) +{ + VideoParameters *p_Vid = p_Dpb->p_Vid; + unsigned int i; + int pic_num1 = 0, pic_num2 = 0; + + int min_poc=INT_MAX; + DecRefPicMarking_t *tmp_drpm,*tmp_drpm2, *tmp_drpm3; + + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if ( p_Vid->currentPicture->idr_flag ) + return; + + if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0) + return; + + if ( p_Vid->structure == TOP_FIELD ) + { + for (i=0; iused_size;i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->poc < min_poc) + { + min_poc = p_Dpb->fs[i]->poc; + pic_num1 = p_Dpb->fs[i]->top_field->pic_num; + pic_num2 = p_Dpb->fs[i]->bottom_field->pic_num; + } + } + } + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) no_mem_exit("poc_based_ref_management_field_pic: tmp_drpm"); + tmp_drpm->Next=NULL; + tmp_drpm->memory_management_control_operation = 0; + + if ( p_Vid->structure == BOTTOM_FIELD ) + { + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm; + return; + } + + if (NULL==(tmp_drpm2=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) no_mem_exit("poc_based_ref_management_field_pic: tmp_drpm2"); + tmp_drpm2->Next=tmp_drpm; + tmp_drpm2->memory_management_control_operation = 1; + tmp_drpm2->difference_of_pic_nums_minus1 = current_pic_num - pic_num1 - 1; + + if (NULL==(tmp_drpm3=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) no_mem_exit("poc_based_ref_management_field_pic: tmp_drpm3"); + tmp_drpm3->Next=tmp_drpm2; + tmp_drpm3->memory_management_control_operation = 1; + tmp_drpm3->difference_of_pic_nums_minus1 = current_pic_num - pic_num2 - 1; + + p_Vid->dec_ref_pic_marking_buffer = tmp_drpm3; +} + + +/*! +************************************************************************ +* \brief +* Temporal layer-based reference management (FRAME) +************************************************************************ +*/ + +void tlyr_based_ref_management_frame_pic(VideoParameters *p_Vid, int current_pic_num) +{ + unsigned i, first = 1; + DecRefPicMarking_t *drpm = NULL, *current_drpm = NULL, *tmp_drpm = NULL; + struct decoded_picture_buffer *p_Dpb = p_Vid->p_Dpb_layer[0]; + + if (p_Vid->dec_ref_pic_marking_buffer!=NULL) + return; + + if ( p_Vid->currentPicture->idr_flag ) + return; + + if ((p_Dpb->ref_frames_in_buffer + p_Dpb->ltref_frames_in_buffer)==0) + return; + + for (i = 0; i < p_Dpb->used_size; i++) + { + if (p_Dpb->fs[i]->is_reference && (!(p_Dpb->fs[i]->is_long_term)) && p_Dpb->fs[i]->frame->temporal_layer > p_Vid->enc_picture->temporal_layer) + { + if (NULL == (tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm2"); + tmp_drpm->memory_management_control_operation = 1; + tmp_drpm->difference_of_pic_nums_minus1 = current_pic_num - p_Dpb->fs[i]->frame->pic_num - 1; + + if (first) + { + drpm = current_drpm = tmp_drpm; + first = 0; + } + else + { + current_drpm->Next = tmp_drpm; + current_drpm = current_drpm->Next; + } + } + } + + if (first) + return; + + if (NULL==(tmp_drpm=(DecRefPicMarking_t*)calloc (1,sizeof (DecRefPicMarking_t)))) + no_mem_exit("poc_based_ref_management: tmp_drpm"); + tmp_drpm->Next=NULL; + + tmp_drpm->memory_management_control_operation = 0; + + current_drpm->Next=tmp_drpm; + + p_Vid->dec_ref_pic_marking_buffer = drpm; +} + diff --git a/lencod/src/mode_decision.c b/lencod/src/mode_decision.c new file mode 100644 index 0000000..13a201a --- /dev/null +++ b/lencod/src/mode_decision.c @@ -0,0 +1,819 @@ + +/*! +*************************************************************************** +* \file mode_decision.c +* +* \brief +* Main macroblock mode decision functions and helpers +* +************************************************************************** +*/ + +#include +#include +#include + +#include "global.h" +#include "image.h" +#include "ratectl.h" +#include "mode_decision.h" +#include "md_common.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "macroblock.h" +#include "rdoq.h" +#include "q_around.h" +#include "slice.h" +#include "conformance.h" +#include "rdopt.h" + + +/*! +************************************************************************************* +* \brief +* Reset Valid Modes +************************************************************************************* +*/ +void reset_valid_modes(RD_PARAMS *enc_mb) +{ + memset(enc_mb->valid, 0, MAXMODE * sizeof(short)); +} + + +/*! +************************************************************************************* +* \brief +* Checks whether a primary SP slice macroblock was encoded as I16 +************************************************************************************* +*/ +static inline int check_for_SI16(int **lrec, int pix_x, int pix_y) +{ + int i,j; + for (i = pix_y; i < pix_y + MB_BLOCK_SIZE; i++) + { + for (j = pix_x;j < pix_x + MB_BLOCK_SIZE; j++) + if (lrec[i][j] != -16) + return 0; + } + return 1; +} + +/*! +************************************************************************************* +* \brief +* Update parameters after encoding a macroblock +************************************************************************************* +*/ +void end_encode_one_macroblock(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + update_qp_cbp(currMB); + + if ( (currSlice->mb_aff_frame_flag) + && (currMB->mbAddrX & 0x01) + && (currMB->mb_type ? 0:(((currSlice->slice_type == B_SLICE)) ? !currMB->cbp:1)) // bottom is skip + && ((currMB->PrevMB)->mb_type ? 0:(((currSlice->slice_type == B_SLICE)) ? !(currMB->PrevMB)->cbp:1)) + && !(field_flag_inference(currMB) == currMB->mb_field)) // top is skip + { + currSlice->rddata->min_rdcost = 1e30; // don't allow coding of a MB pair as skip if wrong inference + } + else + currSlice->rddata->min_rdcost = (double)currMB->min_rdcost; + + currSlice->rddata->min_dcost = (double)currMB->min_dcost; + currSlice->rddata->min_rate = (double)currMB->min_rate; + + if(p_Inp->SearchMode[p_Vid->view_id] == UM_HEX) + { + UMHEX_skip_intrabk_SAD(currMB, currSlice->listXsize[currMB->list_offset]); + } + else if(p_Inp->SearchMode[p_Vid->view_id] == UM_HEX_SIMPLE) + { + smpUMHEX_skip_intrabk_SAD(currMB); + } + + //--- constrain intra prediction --- + if(p_Inp->UseConstrainedIntraPred && (currSlice->slice_type == P_SLICE || currSlice->slice_type == B_SLICE)) + { + p_Vid->intra_block[currMB->mbAddrX] = IS_INTRA(currMB); + } +} + +/*! +************************************************************************************* +* \brief +* Initialize Encoding parameters for Macroblock +************************************************************************************* +*/ +void init_enc_mb_params(Macroblock* currMB, RD_PARAMS *enc_mb, int intra) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; +#if (MVC_EXTENSION_ENABLE) + int *InterSearch = p_Inp->InterSearch[(p_Vid->num_of_layers > 1) ? currSlice->view_id : 0][(currSlice->slice_type == B_SLICE)]; +#else + int *InterSearch = p_Inp->InterSearch[0][(currSlice->slice_type == B_SLICE)]; +#endif + + int l,k; + + enc_mb->curr_mb_field = (short) ((currSlice->mb_aff_frame_flag) && (currMB->mb_field)); + + // Set valid modes + enc_mb->valid[I8MB] = (short) ((!p_Inp->DisableIntraInInter[p_Vid->view_id] || intra )? p_Inp->Transform8x8Mode : 0); + enc_mb->valid[I4MB] = (short) ((!p_Inp->DisableIntraInInter[p_Vid->view_id] || intra )? ((p_Inp->Transform8x8Mode == 2) ? 0 : 1) : 0); + enc_mb->valid[I4MB] = (short) ((!p_Inp->DisableIntra4x4 ) ? enc_mb->valid[I4MB] : 0); + enc_mb->valid[I16MB] = (short) ((!p_Inp->DisableIntraInInter[p_Vid->view_id] || intra )? 1 : 0); + enc_mb->valid[I16MB] = (short) ((!p_Inp->DisableIntra16x16) ? enc_mb->valid[I16MB] : 0); + enc_mb->valid[IPCM] = (short) ((!p_Inp->DisableIntraInInter[p_Vid->view_id] || intra )? (p_Inp->EnableIPCM > 0 ? 1:0) : 0); + enc_mb->valid[SI4MB] = 0; + //enc_mb->valid[SI4MB] = (short) (currSlice->slice_type == SI_SLICE); + //enc_mb->valid[SI4MB] = (short) ( p_Inp->DisableIntra4x4 ? 0 : enc_mb->valid[SI4MB]); + + enc_mb->valid[0] = (short) (!intra && InterSearch[0]); + enc_mb->valid[1] = (short) (!intra && InterSearch[1]); + enc_mb->valid[2] = (short) (!intra && InterSearch[2]); + enc_mb->valid[3] = (short) (!intra && InterSearch[3]); + enc_mb->valid[4] = (short) (!intra && InterSearch[4]); + enc_mb->valid[5] = (short) (!intra && InterSearch[5] && !(p_Inp->Transform8x8Mode==2)); + enc_mb->valid[6] = (short) (!intra && InterSearch[6] && !(p_Inp->Transform8x8Mode==2)); + enc_mb->valid[7] = (short) (!intra && InterSearch[7] && !(p_Inp->Transform8x8Mode==2)); + enc_mb->valid[P8x8] = (short) (enc_mb->valid[4] || enc_mb->valid[5] || enc_mb->valid[6] || enc_mb->valid[7]); + + + if (currSlice->UseRDOQuant && p_Inp->RDOQ_CP_Mode && (p_Vid->qp != p_Vid->masterQP) ) + RDOQ_update_mode(currSlice, enc_mb); + + if(currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + { + if(currSlice->slice_type == SI_SLICE) + { + reset_valid_modes(enc_mb); + if(check_for_SI16(p_Vid->lrec, currMB->pix_x, currMB->pix_y)) + { + enc_mb->valid[I16MB] = 1; + } + else + { + enc_mb->valid[I4MB] = 1; + } + } + + if(p_Vid->sp2_frame_indicator) + { + if(check_for_SI16(p_Vid->lrec, currMB->pix_x, currMB->pix_y)) + { + reset_valid_modes(enc_mb); + enc_mb->valid[I16MB] = 1; + } + else + { + enc_mb->valid[I8MB] = 0; + enc_mb->valid[IPCM] = 0; + enc_mb->valid[0] = 0; + //enc_mb->valid[I16MB] = 0; + } + } + } + + //===== SET LAGRANGE PARAMETERS ===== + // Note that these are now computed at the slice level to reduce + // computations and cleanup code. + enc_mb->lambda_md = p_Vid->lambda_md[currSlice->slice_type][p_Vid->masterQP]; + //#if JCOST_CALC_SCALEUP + enc_mb->lambda_mdfp = LAMBDA_FACTOR(enc_mb->lambda_md); + //#endif + + memcpy(enc_mb->lambda_me, p_Vid->lambda_me[currSlice->slice_type][p_Vid->masterQP], 3 * sizeof(double)); + memcpy(enc_mb->lambda_mf, p_Vid->lambda_mf[currSlice->slice_type][p_Vid->masterQP], 3 * sizeof(int)); + + if (!currSlice->mb_aff_frame_flag) + { + for (l = LIST_0; l < BI_PRED; l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + if(currSlice->structure != currSlice->listX[l][k]->structure) + { + if (currSlice->structure == TOP_FIELD) + currSlice->listX[l][k]->chroma_vector_adjustment = -2; + else if (currSlice->structure == BOTTOM_FIELD) + currSlice->listX[l][k]->chroma_vector_adjustment = 2; + else + currSlice->listX[l][k]->chroma_vector_adjustment= 0; + } + else + currSlice->listX[l][k]->chroma_vector_adjustment= 0; + } + } + } + else + { + if (enc_mb->curr_mb_field) + { + for (l = currMB->list_offset; l <= currMB->list_offset + LIST_1; l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + { + currSlice->listX[l][k]->chroma_vector_adjustment= 0; + if((currMB->mbAddrX & 0x01) == 0 && currSlice->listX[l][k]->structure == BOTTOM_FIELD) + currSlice->listX[l][k]->chroma_vector_adjustment = -2; + if((currMB->mbAddrX & 0x01) == 1 && currSlice->listX[l][k]->structure == TOP_FIELD) + currSlice->listX[l][k]->chroma_vector_adjustment = 2; + } + } + } + else + { + for (l = currMB->list_offset; l <= currMB->list_offset + LIST_1; l++) + { + for(k = 0; k < currSlice->listXsize[l]; k++) + currSlice->listX[l][k]->chroma_vector_adjustment = 0; + } + } + } + + // reset chroma intra predictor to default + currMB->c_ipred_mode = DC_PRED_8; + + + if(p_Inp->SearchMode[p_Vid->view_id] == UM_HEX) + { + UMHEX_decide_intrabk_SAD(currMB); + UMHEX_DefineThresholdMB(p_Vid, p_Inp); + } + else if (p_Inp->SearchMode[p_Vid->view_id] == UM_HEX_SIMPLE) + { + smpUMHEX_decide_intrabk_SAD(currMB); + } + +} + + +void update_mcost(Slice *currSlice, int ref_lambda, short ref, int cur_list, distblk mcost, distblk *bmcost, char *best_ref) +{ + {//! Edited by Joao Carreira - Force InterView Prediction +#if( MVC_EXTENSION_ENABLE) + //! check if you want to force interview prediction + if( currSlice->flag_Force_InterView == 1 && currSlice->view_id != BASE_VIEW_IDX && cur_list == LIST_0) + { + if( currSlice->listX[cur_list][ref]->view_id != BASE_VIEW_IDX ) + return; + + //! check if we already force it + //! if we already force the best reference to be a base view frame we do not + // need to do it again. now just let the encoder run normally + if( currSlice->listX[cur_list][*best_ref]->view_id != BASE_VIEW_IDX ) + { + //! reset best motion cost to the maximum value + *bmcost = INT_MAX; + } + } +#endif + } + + if (mcost < *bmcost) + { + mcost += ref_cost(currSlice, ref_lambda, ref, cur_list); + + if (mcost < *bmcost) + { + *bmcost = mcost; + *best_ref = (char)ref; + } + } +} +/*! +************************************************************************************* +* \brief +* computation of prediction list (including biprediction) cost +************************************************************************************* +*/ +void list_prediction_cost(Macroblock *currMB, int list, int block, int mode, RD_PARAMS *enc_mb, distblk bmcost[5], char best_ref[2]) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + short ref; + int cur_list = list < BI_PRED ? currMB->list_offset + list : currMB->list_offset; + int ref_lambda = (p_Inp->rdopt) ? enc_mb->lambda_mf[Q_PEL] : enc_mb->lambda_mf[Q_PEL] >> 2; + + //--- get cost and reference frame for forward prediction --- + if (list < BI_PRED) + { + distblk **motion_cost = p_Vid->motion_cost[mode][list]; + + int sp_indicator = (p_Inp->sp2_frame_indicator || p_Inp->sp_output_indicator); + + if (!p_Vid->checkref || list) + { + if (p_Inp->sp2_frame_indicator == 0 && p_Inp->sp_output_indicator == 0) + { + for (ref = 0; ref < currSlice->listXsize[cur_list]; ref++) + { + update_mcost(currSlice, ref_lambda, ref, cur_list, motion_cost[ref][block], &bmcost[list], &best_ref[list]); + } + } + else + { + for (ref = 0; ref < currSlice->listXsize[cur_list]; ref++) + { + // limit the number of reference frames to 1 when switching SP frames are used + if((((currSlice->slice_type != P_SLICE && currSlice->slice_type != SP_SLICE)) || (ref == 0))) + { + update_mcost(currSlice, ref_lambda, ref, cur_list, motion_cost[ref][block], &bmcost[list], &best_ref[list]); + } + } + } + } + else + { + for (ref = 0; ref < currSlice->listXsize[cur_list]; ref++) + { + if (ref == 0 || (p_Inp->RestrictRef && CheckReliabilityOfRef (currMB, block, list, ref, mode))) + { + // limit the number of reference frames to 1 when switching SP frames are used + if( !(sp_indicator) || (((currSlice->slice_type != P_SLICE && currSlice->slice_type != SP_SLICE))|| (ref == 0))) + { + update_mcost(currSlice, ref_lambda, ref, cur_list, motion_cost[ref][block], &bmcost[list], &best_ref[list]); + } + } + } + } + } + else if (list == BI_PRED) + { + if (p_Vid->active_pps->weighted_bipred_idc == 1) + { + int weight_sum = currSlice->wbp_weight[0][(int) best_ref[LIST_0]][(int) best_ref[LIST_1]][0] + + currSlice->wbp_weight[1][(int) best_ref[LIST_0]][(int) best_ref[LIST_1]][0]; + + if (weight_sum < -128 || weight_sum > 127) + { + bmcost[list] = DISTBLK_MAX; + } + else + { + bmcost[list] = ref_cost(currSlice, ref_lambda, (short) best_ref[LIST_0], cur_list) + + ref_cost(currSlice, ref_lambda, (short) best_ref[LIST_1], cur_list + LIST_1); + bmcost[list] += BIDPartitionCost (currMB, mode, block, best_ref, enc_mb->lambda_mf[Q_PEL]); + } + } + else + { + bmcost[list] = ref_cost(currSlice, ref_lambda, (short) best_ref[LIST_0], cur_list) + + ref_cost(currSlice, ref_lambda, (short) best_ref[LIST_1], cur_list + LIST_1); + bmcost[list] += BIDPartitionCost (currMB, mode, block, best_ref, enc_mb->lambda_mf[Q_PEL]); + } + } + else + { + if (p_Vid->active_pps->weighted_bipred_idc == 1) + { + int weight_sum = currSlice->wbp_weight[0][0][0][0] + currSlice->wbp_weight[1][0][0][0]; + + if (weight_sum < -128 || weight_sum > 127) + { + bmcost[list] = DISTBLK_MAX; + } + else + { + bmcost[list] = ref_cost(currSlice, ref_lambda, 0, cur_list) + ref_cost(currSlice, ref_lambda, 0, cur_list + LIST_1); + bmcost[list] += BPredPartitionCost(currMB, mode, block, 0, 0, enc_mb->lambda_mf[Q_PEL], !(list&1)); + } + } + else + { + bmcost[list] = ref_cost(currSlice, ref_lambda, 0, cur_list) + ref_cost(currSlice, ref_lambda, 0, cur_list + LIST_1); + bmcost[list] += BPredPartitionCost(currMB, mode, block, 0, 0, enc_mb->lambda_mf[Q_PEL], !(list&1)); + } + } +} + +static inline distblk compute_ref_cost(Slice *currSlice, RD_PARAMS *enc_mb, int ref, int list) +{ + return weighted_cost(enc_mb->lambda_mf[Q_PEL],((currSlice->listXsize[list] <= 1)? 0 : currSlice->p_Vid->refbits[ref])); +} + +/*! +************************************************************************************* +* \brief +* Determination of prediction list based on simple distortion computation +************************************************************************************* +*/ +void determine_prediction_list( distblk bmcost[5], Info8x8 *best, distblk *cost) +{ + int bestlist; + *cost += distblkminarray ( bmcost, 5, &bestlist); + + if (bestlist <= BI_PRED) //LIST_0, LIST_1 & BI_DIR + { + best->pdir = (char) bestlist; + best->bipred= 0; + } + else //BI_PRED_L0 & BI_PRED_L1 + { + best->pdir = 2; + best->bipred = (char) (bestlist - 2); + //! Edited by Joao Carreira - Do not limit bi prediction to the first frame of list + best->ref[LIST_0] = 0; + best->ref[LIST_1] = 0; + } +} + + +/*! +************************************************************************************* +* \brief +* RD decision process +************************************************************************************* +*/ +void compute_mode_RD_cost(Macroblock *currMB, + RD_PARAMS *enc_mb, + short mode, + short *inter_skip) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + int terminate_16x16 = 0, terminate_trans = 0, ctr16x16 = 0; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + int bslice = (currSlice->slice_type == B_SLICE); + + //--- transform size --- + currMB->luma_transform_size_8x8_flag = (byte) (p_Inp->Transform8x8Mode==2 + ? (mode >= 1 && mode <= 3) + || (mode == 0 && bslice && p_Vid->active_sps->direct_8x8_inference_flag) + || ((mode == P8x8) && (enc_mb->valid[4])) + : 0); + + currSlice->set_modes_and_refs_for_blocks (currMB, (short) mode); + //memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + // Encode with coefficients + currSlice->NoResidueDirect = 0; + + if ((p_Inp->FastCrIntraDecision ) || (currMB->c_ipred_mode == DC_PRED_8 || (IS_INTRA(currMB) ))) + { + do + { + // This seems to have a problem since we are not properly copying the right b8x8info (transform based) + terminate_16x16 = bslice_16x16_termination_control(p_Inp, p_Vid->b8x8info, &ctr16x16, mode, bslice); + do + { + RD_8x8DATA *t8x8_data = currMB->luma_transform_size_8x8_flag ? p_RDO->tr8x8 : p_RDO->tr4x4; + + if (mode == P8x8 ) //&& !(p_Inp->RDOQ_QP_Num > 1 && currSlice->dQPCnt > 0)) + { + p_Vid->b8x8info->best[P8x8][0] = t8x8_data->part[0]; + p_Vid->b8x8info->best[P8x8][1] = t8x8_data->part[1]; + p_Vid->b8x8info->best[P8x8][2] = t8x8_data->part[2]; + p_Vid->b8x8info->best[P8x8][3] = t8x8_data->part[3]; + } + // check if prediction parameters are in valid range. + if (CheckPredictionParams(currMB, p_Vid->b8x8info, mode) == TRUE) + { + if (RDCost_for_macroblocks (currMB, enc_mb->lambda_mdfp, mode)) + { + //Rate control + if (p_Inp->RCEnable) + { + if(mode == P8x8) + { + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, t8x8_data->mpr8x8); + } + else + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, p_RDO->pred); + } + + store_macroblock_parameters (currMB, mode); + + if(p_Inp->rdopt == 2 && mode == 0 && p_Inp->EarlySkipEnable) + { + // check transform quantized coeff. + if(currMB->cbp == 0) + *inter_skip = 1; + } + } + } + // This code needs to be fixed - BUG? ATOUR + + terminate_trans = transform_termination_control(currMB, mode); + + }while (!terminate_trans); + }while (!terminate_16x16); + + // Encode with no coefficients. Currently only for direct. This could be extended to all other modes as in example. + //if (bslice && mode < P8x8 && (*inter_skip == 0) && enc_mb->valid[mode] && currMB->cbp && (currMB->cbp&15) != 15 && !p_Inp->nobskip + if ( (bslice && mode == 0 && (*inter_skip == 0) && enc_mb->valid[mode] && currMB->cbp && (currMB->cbp&15) != 15 && !p_Inp->nobskip + && !(currMB->qp_scaled[0] == 0 && p_Vid->active_sps->lossless_qpprime_flag==1) ) + ) + { + currSlice->NoResidueDirect = 1; + if(mode == P8x8) + { + RD_8x8DATA *t8x8_data = currMB->luma_transform_size_8x8_flag ? p_RDO->tr8x8 : p_RDO->tr4x4; + p_Vid->b8x8info->best[P8x8][0] = t8x8_data->part[0]; + p_Vid->b8x8info->best[P8x8][1] = t8x8_data->part[1]; + p_Vid->b8x8info->best[P8x8][2] = t8x8_data->part[2]; + p_Vid->b8x8info->best[P8x8][3] = t8x8_data->part[3]; + if(p_Inp->Transform8x8Mode == 1 && currMB->valid_8x8 && currMB->valid_4x4) + { + RestoreMV8x8(currSlice, (!currMB->luma_transform_size_8x8_flag)); + } + } + if (CheckPredictionParams(currMB, p_Vid->b8x8info, mode) == TRUE) + { + if (RDCost_for_macroblocks (currMB, enc_mb->lambda_mdfp, mode)) + { + //Rate control + if (p_Inp->RCEnable) + rc_store_diff(currSlice->diffy, &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, p_RDO->pred); + + if (p_Vid->AdaptiveRounding) + reset_adaptive_rounding_direct(p_Vid); + + store_macroblock_parameters (currMB, mode); + } + } + if(mode == P8x8) + { + if(p_Inp->Transform8x8Mode == 1 && currMB->valid_8x8 && currMB->valid_4x4) + { + RestoreMV8x8(currSlice, 0); + } + } + } + + //modes 0 and 1 of a B frame + if (p_Vid->AdaptiveRounding && bslice && mode <= 1) + { + if (currMB->temp_transform_size_8x8_flag) + update_adaptive_rounding_16x16( p_Vid, p_Vid->ARCofAdj8x8, mode); + else + update_adaptive_rounding_16x16( p_Vid, p_Vid->ARCofAdj4x4, mode); + } + } +} + +void get_initial_mb16x16_cost(Macroblock* currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + RDOPTStructure *p_RDO = currSlice->p_RDO; + if (currMB->mb_left && currMB->mb_up) + { + p_Vid->mb16x16_cost = (p_Vid->mb16x16_cost_frame[currMB->mbAddrX - 1] + + p_Vid->mb16x16_cost_frame[currMB->mbAddrX - (p_Vid->width>>4)] + 1)/2.0; + } + else if (currMB->mb_left) + { + p_Vid->mb16x16_cost = p_Vid->mb16x16_cost_frame[currMB->mbAddrX - 1]; + } + else if (currMB->mb_up) + { + p_Vid->mb16x16_cost = p_Vid->mb16x16_cost_frame[currMB->mbAddrX - (p_Vid->width>>4)]; + } + else + { + p_Vid->mb16x16_cost = CALM_MF_FACTOR_THRESHOLD; + } + + p_RDO->lambda_mf_factor = p_Vid->mb16x16_cost < CALM_MF_FACTOR_THRESHOLD ? 1.0 : sqrt(p_Vid->mb16x16_cost / (CALM_MF_FACTOR_THRESHOLD * p_Vid->lambda_mf_factor[currSlice->slice_type][p_Vid->qp])); +} + +void adjust_mb16x16_cost(Macroblock *currMB, distblk cost) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + p_Vid->mb16x16_cost = (double) cost; + p_Vid->mb16x16_cost_frame[currMB->mbAddrX] = p_Vid->mb16x16_cost; +#if JCOST_CALC_SCALEUP + p_RDO->lambda_mf_factor = (p_Vid->mb16x16_cost < CALM_MF_FACTOR_THRESHOLD * (1 << LAMBDA_ACCURACY_BITS)) + ? 1.0 + : sqrt(p_Vid->mb16x16_cost / (CALM_MF_FACTOR_THRESHOLD*(1<lambda_mf_factor[currSlice->slice_type][p_Vid->qp])); +#else + p_RDO->lambda_mf_factor = (p_Vid->mb16x16_cost < CALM_MF_FACTOR_THRESHOLD) + ? 1.0 + : sqrt(p_Vid->mb16x16_cost / (CALM_MF_FACTOR_THRESHOLD * p_Vid->lambda_mf_factor[currSlice->slice_type][p_Vid->qp])); +#endif +} + +void update_lambda_costs(Macroblock *currMB, RD_PARAMS *enc_mb, int lambda_mf[3]) +{ + InputParameters *p_Inp = currMB->p_Inp; + RDOPTStructure *p_RDO = currMB->p_Slice->p_RDO; + + int MEPos; + for (MEPos = 0; MEPos < 3; MEPos ++) + { + lambda_mf[MEPos] = p_Inp->CtxAdptLagrangeMult == 0 ? enc_mb->lambda_mf[MEPos] : (int)(enc_mb->lambda_mf[MEPos] * sqrt(p_RDO->lambda_mf_factor)); + } +} + +/*! +************************************************************************************* +* \brief +* Return array's minimum and its index +************************************************************************************* +*/ +int iminarray ( int arr[], int size, int *minind ) +{ + int i; + int mincand = arr[0]; + *minind = 0; + for ( i = 1; i < size; i++ ) + { + if (arr[i] < mincand) + { + mincand = arr[i]; + *minind = i; + } + } + return mincand; +} + +distblk distblkminarray ( distblk arr[], int size, int *minind ) +{ + int i; + distblk mincand = arr[0]; + *minind = 0; + for ( i = 1; i < size; i++ ) + { + if (arr[i] < mincand) + { + mincand = arr[i]; + *minind = i; + } + } + return mincand; +} + +/*! +************************************************************************************* +* \brief +* Determines whether bi prediction is enabaled for current mode +************************************************************************************* +*/ +int is_bipred_enabled(VideoParameters *p_Vid, int mode) +{ + //return 0; + return p_Vid->bipred_enabled[(mode == P8x8) ? 4: mode]; +} + +/*! +************************************************************************************* +* \brief +* Decides whether to perform transform 8x8 for this mode +************************************************************************************* +*/ +int transform_termination_control(Macroblock* currMB, int mode) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + // Go through transform modes. + // Note that if currMB->cbp is 0 one could choose to skip 8x8 mode + // although this could be due to deadzoning decisions. + //if (p_Inp->Transform8x8Mode==1 && currMB->cbp!=0) + if (p_Inp->Transform8x8Mode == 1) + { + //=========== try the 8x8 transform with mb_types 16x16,16x8, 8x16, 8x8, and DIRECT 16x16 =========== + if (currMB->luma_transform_size_8x8_flag == FALSE && + ((mode >= 1 && mode <= 3) || ((currSlice->slice_type == B_SLICE) && mode == 0 && p_Vid->active_sps->direct_8x8_inference_flag) || (mode == P8x8))) + //if (currMB->luma_transform_size_8x8_flag == FALSE && + //((mode >= 1 && mode <= 3) || ((currSlice->slice_type == B_SLICE) && mode == 0 && active_sps->direct_8x8_inference_flag))) + { + //try with 8x8 transform size + currMB->luma_transform_size_8x8_flag = TRUE; + return 0; + } + else + { + currMB->luma_transform_size_8x8_flag = FALSE; + return 1; + } + } + else + { + return 1; + } +} + +/*! +************************************************************************************* +* \brief +* Update prediction direction for mode P16x16 to check all prediction directions +************************************************************************************* +*/ +int bslice_16x16_termination_control(InputParameters *p_Inp, Block8x8Info *b8x8info, int *ctr16x16, int mode, int bslice) +{ + int lastcheck = 1; + //--- for INTER16x16 in BSLICEs check all prediction directions --- + if (mode == 1 && bslice) + { + char pdir = 0; + short i; + char bipred_me = 0; + + switch (*ctr16x16) + { + case 0: + pdir = 0; + lastcheck = 0; + break; + case 1: + pdir = 1; + lastcheck = 0; + break; + case 2: + pdir = 2; + if (p_Inp->BiPredMotionEstimation) + { + lastcheck = 0; + } + break; + case 3: + pdir = 2; + bipred_me = 1; + lastcheck = 0; + break; + case 4: + pdir = 2; + bipred_me = 2; + break; + default: + error("invalid 'ctr16x16' value", -1); + break; + } + for (i = 0; i< 4; i++) + { + b8x8info->best[1][i].bipred = bipred_me; + b8x8info->best[1][i].pdir = pdir; + } + (*ctr16x16)++; + } + return lastcheck; +} + +/*! +************************************************************************************** +* \brief +* Compute bipred costs +************************************************************************************** +*/ +void get_bipred_cost(Macroblock *currMB, int mode, int block, int i, int j, Info8x8 *best, RD_PARAMS *enc_mb, distblk bmcost[5]) +{ + Slice *currSlice = currMB->p_Slice; + MotionVector *bi0_mv_l0 = &currSlice->bipred_mv[0][LIST_0][0][mode][j][i]; + MotionVector *bi0_mv_l1 = &currSlice->bipred_mv[0][LIST_1][0][mode][j][i]; + MotionVector *bi1_mv_l0 = &currSlice->bipred_mv[1][LIST_0][0][mode][j][i]; + MotionVector *bi1_mv_l1 = &currSlice->bipred_mv[1][LIST_1][0][mode][j][i]; + distblk MaxVal = DISTBLK_MAX; + + if (best->ref[0] == 0 && best->ref[1] == 0) + { + MotionVector *single_mv_l0 = &currSlice->all_mv [LIST_0][0][mode][j][i]; + MotionVector *single_mv_l1 = &currSlice->all_mv [LIST_1][0][mode][j][i]; + + if ((single_mv_l0->mv_x != bi0_mv_l0->mv_x) || (single_mv_l0->mv_y != bi0_mv_l0->mv_y) || + (single_mv_l1->mv_x != bi0_mv_l1->mv_x) || (single_mv_l1->mv_y != bi0_mv_l1->mv_y)) + list_prediction_cost(currMB, BI_PRED_L0, block, mode, enc_mb, bmcost, 0); + else + bmcost[BI_PRED_L0] = MaxVal; + + if ((single_mv_l0->mv_x != bi1_mv_l0->mv_x) || (single_mv_l0->mv_y != bi1_mv_l0->mv_y) || + (single_mv_l1->mv_x != bi1_mv_l1->mv_x) || (single_mv_l1->mv_y != bi1_mv_l1->mv_y)) + { + if ((bi0_mv_l0->mv_x != bi1_mv_l0->mv_x) || (bi0_mv_l0->mv_y != bi1_mv_l0->mv_y) || + (bi0_mv_l1->mv_x != bi1_mv_l1->mv_x) || (bi0_mv_l1->mv_y != bi1_mv_l1->mv_y)) + list_prediction_cost(currMB, BI_PRED_L1, block, mode, enc_mb, bmcost, 0); + else + bmcost[BI_PRED_L1] = MaxVal; + } + else + bmcost[BI_PRED_L1] = MaxVal; + } + else + { + //! Edited by Joao Carreira + list_prediction_cost(currMB, BI_PRED_L0, block, mode, enc_mb, bmcost, 0); + //list_prediction_cost(currMB, BI_PRED_L0, block, mode, enc_mb, bmcost, best->ref); + if ((bi0_mv_l0->mv_x != bi1_mv_l0->mv_x) || (bi0_mv_l0->mv_y != bi1_mv_l0->mv_y) || + (bi0_mv_l1->mv_x != bi1_mv_l1->mv_x) || (bi0_mv_l1->mv_y != bi1_mv_l1->mv_y)) + list_prediction_cost(currMB, BI_PRED_L1, block, mode, enc_mb, bmcost, 0); + //list_prediction_cost(currMB, BI_PRED_L1, block, mode, enc_mb, bmcost, best->ref); + else + bmcost[BI_PRED_L1] = MaxVal; + } +} + + diff --git a/lencod/src/mode_decision_P8x8.c b/lencod/src/mode_decision_P8x8.c new file mode 100644 index 0000000..829dff8 --- /dev/null +++ b/lencod/src/mode_decision_P8x8.c @@ -0,0 +1,1080 @@ + +/*! + *************************************************************************** + * \file mode_decision_8x8.c + * + * \brief + * Mode decision functions for 8x8 submacroblock + * + ************************************************************************** + */ + +#include +#include +#include + +#include "global.h" +#include "image.h" +#include "mode_decision.h" +#include "macroblock.h" +#include "errdo.h" +#include "q_around.h" +#include "md_common.h" +#include "rdopt.h" + + +void copy_part_info(Info8x8 *b8x8, Info8x8 *part) +{ + b8x8[0] = part[0]; + b8x8[1] = part[1]; + b8x8[2] = part[2]; + b8x8[3] = part[3]; +} + +/*! +************************************************************************************* +* \brief +* Mode Decision for an 8x8 sub-macroblock +************************************************************************************* +*/ +void submacroblock_mode_decision_p_slice(Macroblock *currMB, + RD_PARAMS *enc_mb, + RD_8x8DATA *dataTr, + int ****cofACtr, + int block, + distblk *cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int transform8x8 = currMB->luma_transform_size_8x8_flag; + int64 curr_cbp_blk; + int j, k; + int index; + int mode; + distblk min_rdcost, rdcost = 0; + distblk min_cost8x8; + distblk bmcost[5] = {DISTBLK_MAX}; + int cnt_nonz = 0; + int best_cnt_nonz = 0; + int maxindex = (transform8x8) ? 2 : 5; + int block_x, block_y; + int lambda_mf[3]; + + int ****fadjust = transform8x8? p_Vid->ARCofAdj8x8 : p_Vid->ARCofAdj4x4; + + //--- set coordinates --- + int j0 = ((block>>1)<<3); + int j1 = (j0>>2); + int i0 = ((block&0x01)<<3); + int i1 = (i0>>2); + + Boolean valid_8x8 = FALSE; + Boolean stored_state_8x8 = FALSE; + +#ifdef BEST_NZ_COEFF + int best_nz_coeff[2][2]; +#endif + + Info8x8 *partition = &(dataTr->part[block]); + Info8x8 best = init_info_8x8_struct(); + + *partition = best; + if (transform8x8) + currMB->valid_8x8 = FALSE; + else + currMB->valid_4x4 = FALSE; + +#ifdef BEST_NZ_COEFF + for(j = 0; j <= 1; j++) + { + for(i = 0; i <= 1; i++) + best_nz_coeff[i][j] = p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + j] = 0; + } +#endif + + if(p_Inp->subMBCodingState == 2) + currSlice->store_coding_state(currMB, currSlice->p_RDO->cs_tmp); + + //===== LOOP OVER POSSIBLE CODING MODES FOR 8x8 SUB-PARTITION ===== + for (min_cost8x8 = DISTBLK_MAX, min_rdcost = DISTBLK_MAX, index = 1; index < maxindex; index++) + { + + mode = b8_mode_table[index]; + + best.mode = (char) mode; + *cost = 0; + + if (enc_mb->valid[mode] && (!(transform8x8 == 1 && mode > 4)) && (transform8x8 == 0 || mode != 0 )) + { + if (transform8x8) + { + currMB->valid_8x8 = TRUE; + } + else + currMB->valid_4x4 = TRUE; + valid_8x8 = TRUE; + curr_cbp_blk = 0; + + { + short b_ref; + + //======= motion estimation for all reference frames ======== + //----------------------------------------------------------- + memcpy(lambda_mf, enc_mb->lambda_mf, 3 * sizeof(int)); + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + RDOPTStructure *p_RDO = currSlice->p_RDO; + lambda_mf[F_PEL] = (int)(lambda_mf[F_PEL] * p_RDO->lambda_mf_factor); + lambda_mf[H_PEL] = (int)(lambda_mf[H_PEL] * p_RDO->lambda_mf_factor); + lambda_mf[Q_PEL] = (int)(lambda_mf[Q_PEL] * p_RDO->lambda_mf_factor); + } + + SubPartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- get cost and reference frame for LIST 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, enc_mb, bmcost, best.ref); + + //store LIST 0 reference index for every block + block_x = currMB->block_x + (block & 0x01)*2; + block_y = currMB->block_y + (block & 0x02); + b_ref = best.ref[LIST_0]; + + motion[block_y ][block_x ].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y ][block_x ].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 ][i1 ]; + motion[block_y ][block_x ].ref_idx [LIST_0] = (char) b_ref; + motion[block_y ][block_x + 1].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y ][block_x + 1].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 ][i1 + 1]; + motion[block_y ][block_x + 1].ref_idx [LIST_0] = (char) b_ref; + motion[block_y + 1][block_x ].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y + 1][block_x ].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 + 1][i1 ]; + motion[block_y + 1][block_x ].ref_idx [LIST_0] = (char) b_ref; + motion[block_y + 1][block_x + 1].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y + 1][block_x + 1].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 + 1][i1 + 1]; + motion[block_y + 1][block_x + 1].ref_idx [LIST_0] = (char) b_ref; + + best.pdir = 0; + *cost = bmcost[LIST_0]; + } // if (mode!=0) + + //--- get and check rate-distortion cost --- + rdcost = rdcost_for_8x8blocks (currMB, dataTr, &cnt_nonz, &curr_cbp_blk, enc_mb->lambda_mdfp, block, (short) mode, &best, min_rdcost); + + //--- set variables if best mode has changed --- + if (rdcost < min_rdcost) + { + min_cost8x8 = *cost; + min_rdcost = rdcost; + *partition = best; + partition->mode = (char) mode; + currMB->b8x8[block].mode = (char) mode; + +#ifdef BEST_NZ_COEFF + if (cnt_nonz) + { + for(i = 0; i <= 1; i++) + { + best_nz_coeff[i][0]= p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 ]; + best_nz_coeff[i][1]= p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + 1]; + } + } + else + { + for(i = 0; i <= 1; i++) + { + best_nz_coeff[i][0]= 0; + best_nz_coeff[i][1]= 0; + } + } +#endif + + //--- store number of nonzero coefficients --- + best_cnt_nonz = cnt_nonz; + + //--- store block cbp --- + dataTr->cbp_blk8x8 &= (~(0x33 << (((block>>1)<<3)+((block & 0x01)<<1)))); // delete bits for block + dataTr->cbp_blk8x8 |= curr_cbp_blk; + + //--- store coefficients --- + memcpy(&cofACtr[0][0][0][0],&currSlice->cofAC[block][0][0][0], 4 * 2 * 65 * sizeof(int)); + + if( currSlice->P444_joined ) + { + //--- store coefficients --- + memcpy(&cofACtr[1][0][0][0],&currSlice->cofAC[block + 4][0][0][0], 4 * 2 * 65 * sizeof(int)); + memcpy(&cofACtr[2][0][0][0],&currSlice->cofAC[block + 8][0][0][0], 4 * 2 * 65 * sizeof(int)); + } + + //--- store reconstruction and prediction --- + copy_image_data_8x8(&dataTr->rec_mbY8x8[j0], &p_Vid->enc_picture->imgY[currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8[j0], &currSlice->mb_pred[0][j0], i0, i0); + + if (p_Inp->rdopt == 3) + { + errdo_store_best_b8x8(currMB, transform8x8, block); + } + + if(currSlice->slice_type == SP_SLICE) + { + for (j = j0; j < j0 + BLOCK_SIZE_8x8; j++) + { + memcpy(&dataTr->lrec[j][i0],&p_Vid->lrec[currMB->pix_y + j][currMB->pix_x + i0], BLOCK_SIZE_8x8 * sizeof(int)); + } + } + + if(currSlice->P444_joined) + { + copy_image_data_8x8(&dataTr->rec_mb8x8_cr[0][j0], &p_Vid->enc_picture->imgUV[0][currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8CbCr[0][j0], &currSlice->mb_pred[1][j0], i0, i0); + + copy_image_data_8x8(&dataTr->rec_mb8x8_cr[1][j0], &p_Vid->enc_picture->imgUV[1][currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8CbCr[1][j0], &currSlice->mb_pred[2][j0], i0, i0); + } + + //--- store best 8x8 coding state --- + if (block < 3) + { + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_b8); + stored_state_8x8 = TRUE; + } + } // if (rdcost <= min_rdcost) + + //--- re-set coding state as it was before coding with current mode was performed --- + if (index != maxindex - 1) + { + if(p_Inp->subMBCodingState == 1) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + else if(p_Inp->subMBCodingState == 2) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_tmp); + } + } // if ((enc_mb->valid[mode] && (transform8x8 == 0 || mode != 0 || (mode == 0 && active_sps->direct_8x8_inference_flag))) + } // for (min_rdcost=1e30, index = 1; index<6; index++) + + if (valid_8x8 == TRUE) + { +#ifdef BEST_NZ_COEFF + for(i = 0; i <= 1; i++) + { + for(j = 0; j <= 1; j++) + p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + j] = best_nz_coeff[i][j]; + } +#endif + + if (!transform8x8) + { + if (min_cost8x8 != DISTBLK_MAX) + dataTr->mb_p8x8_cost += min_cost8x8; + else + dataTr->mb_p8x8_cost = DISTBLK_MAX; + } + + //----- set cbp and count of nonzero coefficients --- + if (best_cnt_nonz) + { + dataTr->cbp8x8 |= (1 << block); + dataTr->cnt_nonz_8x8 += best_cnt_nonz; + } + + if (!transform8x8) + { + if (block < 3) + { + //===== re-set reconstructed block ===== + j0 = 8*(block >> 1); + i0 = 8*(block & 0x01); + + // need to double check code since original did not use i0 + copy_image_data_8x8(&p_Vid->enc_picture->imgY[currMB->pix_y + j0], &dataTr->rec_mbY8x8[j0], currMB->pix_x + i0, i0); + + if (p_Inp->rdopt == 3) + { + errdo_get_best_b8x8(currMB, transform8x8, block); + } + + if(currSlice->slice_type == SP_SLICE) + { + for (j = j0; j < j0 + BLOCK_SIZE_8x8; j++) + { + memcpy(&p_Vid->lrec[currMB->pix_y + j][currMB->pix_x], dataTr->lrec[j], 2 * BLOCK_SIZE * sizeof(int)); // reset the coefficients for SP slice + } + } + + if(currSlice->P444_joined) + { + + for (k=0; k<2; k++) + { + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[k][currMB->pix_y + j0], &dataTr->rec_mb8x8_cr[k][j0], currMB->pix_x + i0, i0); + } + } + } // if (block<3) + } + else + { + //======= save motion data for 8x8 partition for transform size 8x8 ======== + currSlice->store_8x8_motion_vectors(currSlice, 0, block, partition); + } + + //===== set motion vectors and reference frames (prediction) ===== + currSlice->set_ref_and_motion_vectors (currMB, motion, partition, block); + + //===== set the coding state after current block ===== + //if (transform8x8 == 0 || block < 3) + if (stored_state_8x8 == TRUE) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_b8); + else + { + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + update_adaptive_rounding_8x8(p_Vid, p_Inp, dataTr, fadjust); + } + } +} + +/*! +************************************************************************************* +* \brief +* Mode Decision for an 8x8 sub-macroblock +************************************************************************************* +*/ +void submacroblock_mode_decision_b_slice(Macroblock *currMB, + RD_PARAMS *enc_mb, + RD_8x8DATA *dataTr, + int ****cofACtr, + int block, + distblk *cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int transform8x8 = currMB->luma_transform_size_8x8_flag; + int maxindex = (transform8x8) ? 2 : 5; + int64 curr_cbp_blk; + int k; + int index; + int mode; + distblk min_rdcost, rdcost = 0; + distblk min_cost8x8; + distblk bmcost[5] = {DISTBLK_MAX}; + int cnt_nonz = 0; + int best_cnt_nonz = 0; + int block_x, block_y; + int lambda_mf[3]; + + int ****fadjust = transform8x8? p_Vid->ARCofAdj8x8 : p_Vid->ARCofAdj4x4; + + //--- set coordinates --- + int j0 = ((block>>1)<<3); + int j1 = (j0>>2); + int i0 = ((block&0x01)<<3); + int i1 = (i0>>2); + + Boolean valid_8x8 = FALSE; + Boolean stored_state_8x8 = FALSE; + +#ifdef BEST_NZ_COEFF + int best_nz_coeff[2][2]; +#endif + + + Info8x8 *partition = &(dataTr->part[block]); + Info8x8 best = init_info_8x8_struct(); + *partition = best; + if (transform8x8) + currMB->valid_8x8 = FALSE; + else + currMB->valid_4x4 = FALSE; + +#ifdef BEST_NZ_COEFF + for(j = 0; j <= 1; j++) + { + for(i = 0; i <= 1; i++) + best_nz_coeff[i][j] = p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + j] = 0; + } +#endif + + if(p_Inp->subMBCodingState == 2) + currSlice->store_coding_state(currMB, currSlice->p_RDO->cs_tmp); + + //===== LOOP OVER POSSIBLE CODING MODES FOR 8x8 SUB-PARTITION ===== + for (min_cost8x8 = DISTBLK_MAX, min_rdcost = DISTBLK_MAX, index = 0; index < maxindex; index++) + { + + mode = b8_mode_table[index]; + + best.mode = (char) mode; + *cost = 0; + + if (enc_mb->valid[mode] && (!(transform8x8 == 1 && mode > 4)) && (transform8x8 == 0 || mode != 0 || (mode == 0 && p_Vid->active_sps->direct_8x8_inference_flag))) + { + if (transform8x8) + { + currMB->valid_8x8 = TRUE; + } + else + currMB->valid_4x4 = TRUE; + + valid_8x8 = TRUE; + curr_cbp_blk = 0; + + if (mode==0) //--- Direct8x8 Mode --- + { + block_x = currMB->block_x + (block & 0x01)*2; + block_y = currMB->block_y + (block & 0x02); + best.ref[LIST_0] = currSlice->direct_ref_idx[block_y][block_x][LIST_0]; + best.ref[LIST_1] = currSlice->direct_ref_idx[block_y][block_x][LIST_1]; + best.pdir = currSlice->direct_pdir[block_y][block_x]; + } // if (mode==0) + else + { + short b_ref; + + //======= motion estimation for all reference frames ======== + //----------------------------------------------------------- + memcpy(lambda_mf, enc_mb->lambda_mf, 3 * sizeof(int)); + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + RDOPTStructure *p_RDO = currSlice->p_RDO; + lambda_mf[F_PEL] = (int)(lambda_mf[F_PEL] * p_RDO->lambda_mf_factor); + lambda_mf[H_PEL] = (int)(lambda_mf[H_PEL] * p_RDO->lambda_mf_factor); + lambda_mf[Q_PEL] = (int)(lambda_mf[Q_PEL] * p_RDO->lambda_mf_factor); + } + + SubPartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- get cost and reference frame for LIST 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, enc_mb, bmcost, best.ref); + + //store LIST 0 reference index for every block + block_x = currMB->block_x + (block & 0x01)*2; + block_y = currMB->block_y + (block & 0x02); + b_ref = best.ref[LIST_0]; + + motion[block_y ][block_x ].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y ][block_x ].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 ][i1 ]; + motion[block_y ][block_x ].ref_idx [LIST_0] = (char) b_ref; + motion[block_y ][block_x + 1].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y ][block_x + 1].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 ][i1 + 1]; + motion[block_y ][block_x + 1].ref_idx [LIST_0] = (char) b_ref; + motion[block_y + 1][block_x ].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y + 1][block_x ].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 + 1][i1 ]; + motion[block_y + 1][block_x ].ref_idx [LIST_0] = (char) b_ref; + motion[block_y + 1][block_x + 1].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[block_y + 1][block_x + 1].mv [LIST_0] = currSlice->all_mv[LIST_0][b_ref][mode][j1 + 1][i1 + 1]; + motion[block_y + 1][block_x + 1].ref_idx [LIST_0] = (char) b_ref; + + //--- get cost and reference frame for LIST 1 prediction --- + bmcost[LIST_1] = DISTBLK_MAX; + bmcost[BI_PRED] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_1, block, mode, enc_mb, bmcost, best.ref); + + // Compute bipredictive cost between best list 0 and best list 1 references + list_prediction_cost(currMB, BI_PRED, block, mode, enc_mb, bmcost, best.ref); + + // currently Bi prediction ME is only supported for modes 1, 2, 3 and only for ref 0 and only for ref 0 + if (is_bipred_enabled(p_Vid, mode)) + { + get_bipred_cost(currMB, mode, block, i1, j1, &best, enc_mb, bmcost); + } + else + { + bmcost[BI_PRED_L0] = DISTBLK_MAX; + bmcost[BI_PRED_L1] = DISTBLK_MAX; + } + + //--- get prediction direction ---- + determine_prediction_list(bmcost, &best, cost); + + //store backward reference index for every block + for (k = LIST_0; k <= LIST_1; k++) + { + motion[block_y ][block_x ].ref_idx[k] = best.ref[k]; + motion[block_y ][block_x + 1].ref_idx[k] = best.ref[k]; + motion[block_y + 1][block_x ].ref_idx[k] = best.ref[k]; + motion[block_y + 1][block_x + 1].ref_idx[k] = best.ref[k]; + + if (best.bipred) + { + motion[block_y ][block_x ].mv[k] = currSlice->bipred_mv[best.bipred - 1][k][(short) best.ref[k]][mode][j1 ][i1 ]; + motion[block_y ][block_x + 1].mv[k] = currSlice->bipred_mv[best.bipred - 1][k][(short) best.ref[k]][mode][j1 ][i1 + 1]; + motion[block_y + 1][block_x ].mv[k] = currSlice->bipred_mv[best.bipred - 1][k][(short) best.ref[k]][mode][j1 + 1][i1 ]; + motion[block_y + 1][block_x + 1].mv[k] = currSlice->bipred_mv[best.bipred - 1][k][(short) best.ref[k]][mode][j1 + 1][i1 + 1]; + } + else + { + motion[block_y ][block_x ].mv[k] = currSlice->all_mv[k][(short) best.ref[k]][mode][j1 ][i1 ]; + motion[block_y ][block_x + 1].mv[k] = currSlice->all_mv[k][(short) best.ref[k]][mode][j1 ][i1 + 1]; + motion[block_y + 1][block_x ].mv[k] = currSlice->all_mv[k][(short) best.ref[k]][mode][j1 + 1][i1 ]; + motion[block_y + 1][block_x + 1].mv[k] = currSlice->all_mv[k][(short) best.ref[k]][mode][j1 + 1][i1 + 1]; + } + } + } // if (mode!=0) + + //--- get and check rate-distortion cost --- + rdcost = rdcost_for_8x8blocks (currMB, dataTr, &cnt_nonz, &curr_cbp_blk, enc_mb->lambda_mdfp, block, (short) mode, &best, min_rdcost); + + //--- set variables if best mode has changed --- + if (rdcost < min_rdcost) + { + min_cost8x8 = *cost; + min_rdcost = rdcost; + *partition = best; + partition->mode = (char) mode; + currMB->b8x8[block].mode = (char) mode; + +#ifdef BEST_NZ_COEFF + if (cnt_nonz) + { + for(i = 0; i <= 1; i++) + { + best_nz_coeff[i][0]= p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 ]; + best_nz_coeff[i][1]= p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + 1]; + } + } + else + { + for(i = 0; i <= 1; i++) + { + best_nz_coeff[i][0]= 0; + best_nz_coeff[i][1]= 0; + } + } +#endif + + //--- store number of nonzero coefficients --- + best_cnt_nonz = cnt_nonz; + + //--- store block cbp --- + dataTr->cbp_blk8x8 &= (~(0x33 << (((block>>1)<<3)+((block & 0x01)<<1)))); // delete bits for block + dataTr->cbp_blk8x8 |= curr_cbp_blk; + + //--- store coefficients --- + memcpy(&cofACtr[0][0][0][0],&currSlice->cofAC[block][0][0][0], 4 * 2 * 65 * sizeof(int)); + + if( currSlice->P444_joined ) + { + //--- store coefficients --- + memcpy(&cofACtr[1][0][0][0],&currSlice->cofAC[block + 4][0][0][0], 4 * 2 * 65 * sizeof(int)); + memcpy(&cofACtr[2][0][0][0],&currSlice->cofAC[block + 8][0][0][0], 4 * 2 * 65 * sizeof(int)); + } + + //--- store reconstruction and prediction --- + copy_image_data_8x8(&dataTr->rec_mbY8x8[j0], &p_Vid->enc_picture->imgY[currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8[j0], &currSlice->mb_pred[0][j0], i0, i0); + + if (p_Inp->rdopt == 3) + { + errdo_store_best_b8x8(currMB, transform8x8, block); + } + + if(currSlice->P444_joined) + { + copy_image_data_8x8(&dataTr->rec_mb8x8_cr[0][j0], &p_Vid->enc_picture->imgUV[0][currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8CbCr[0][j0], &currSlice->mb_pred[1][j0], i0, i0); + + copy_image_data_8x8(&dataTr->rec_mb8x8_cr[1][j0], &p_Vid->enc_picture->imgUV[1][currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8CbCr[1][j0], &currSlice->mb_pred[2][j0], i0, i0); + } + + //--- store best 8x8 coding state --- + if (block < 3) + { + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_b8); + stored_state_8x8 = TRUE; + } + } // if (rdcost <= min_rdcost) + + //--- re-set coding state as it was before coding with current mode was performed --- + if (index != maxindex - 1) + { + if(p_Inp->subMBCodingState == 1) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + else if(p_Inp->subMBCodingState == 2) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_tmp); + } + } // if ((enc_mb->valid[mode] && (transform8x8 == 0 || mode != 0 || (mode == 0 && active_sps->direct_8x8_inference_flag))) + } // for (min_rdcost=1e30, index = 0; index<6; index++) + + if (valid_8x8 == TRUE) + { +#ifdef BEST_NZ_COEFF + for(i = 0; i <= 1; i++) + { + for(j = 0; j <= 1; j++) + p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + j] = best_nz_coeff[i][j]; + } +#endif + + if (!transform8x8) + { + if (min_cost8x8 != DISTBLK_MAX) + dataTr->mb_p8x8_cost += min_cost8x8; + else + dataTr->mb_p8x8_cost = DISTBLK_MAX; + } + + //----- set cbp and count of nonzero coefficients --- + if (best_cnt_nonz) + { + dataTr->cbp8x8 |= (1 << block); + dataTr->cnt_nonz_8x8 += best_cnt_nonz; + } + + if (!transform8x8) + { + if (block < 3) + { + //===== re-set reconstructed block ===== + j0 = 8*(block >> 1); + i0 = 8*(block & 0x01); + + // need to double check code since original did not use i0 + copy_image_data_8x8(&p_Vid->enc_picture->imgY[currMB->pix_y + j0], &dataTr->rec_mbY8x8[j0], currMB->pix_x + i0, i0); + + if (p_Inp->rdopt == 3) + { + errdo_get_best_b8x8(currMB, transform8x8, block); + } + + if(currSlice->P444_joined) + { + + for (k=0; k<2; k++) + { + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[k][currMB->pix_y + j0], &dataTr->rec_mb8x8_cr[k][j0], currMB->pix_x + i0, i0); + } + } + } // if (block<3) + } + else + { + //======= save motion data for 8x8 partition for transform size 8x8 ======== + currSlice->store_8x8_motion_vectors(currSlice, 0, block, partition); + } + + //===== set motion vectors and reference frames (prediction) ===== + currSlice->set_ref_and_motion_vectors (currMB, motion, partition, block); + + //===== set the coding state after current block ===== + //if (transform8x8 == 0 || block < 3) + if (stored_state_8x8 == TRUE) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_b8); + else + { + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + update_adaptive_rounding_8x8(p_Vid, p_Inp, dataTr, fadjust); + } + } +} + +/*! +************************************************************************************* +* \brief +* Low Complexity Mode Decision for an 8x8 sub-macroblock +************************************************************************************* +*/ +void submacroblock_mode_decision_low(Macroblock *currMB, + RD_PARAMS *enc_mb, + RD_8x8DATA *dataTr, + int ****cofACtr, + int *have_direct, + int block, + distblk *cost_direct, + distblk *cost, + distblk *cost8x8_direct, + int transform8x8) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int64 curr_cbp_blk; + //double rdcost = 0.0; + int j0, i0; + int i, j; + int index; + int mode; + distblk min_cost8x8; + distblk direct4x4_tmp, direct8x8_tmp; + distblk bmcost[5] = {DISTBLK_MAX}; + int cnt_nonz = 0; + int dummy; + int best_cnt_nonz = 0; + int maxindex = (transform8x8) ? 2 : 5; + int block_x, block_y; + int lambda_mf[3]; + + int ****fadjust = transform8x8? p_Vid->ARCofAdj8x8 : p_Vid->ARCofAdj4x4; + short pdir; + + Boolean valid_8x8 = FALSE; + Boolean stored_state_8x8 = FALSE; + +#ifdef BEST_NZ_COEFF + int j1, i1; + int best_nz_coeff[2][2]; +#endif + + Info8x8 best = init_info_8x8_struct(); + dataTr->part[block].mode = 0; + if (transform8x8) + currMB->valid_8x8 = FALSE; + else + currMB->valid_4x4 = FALSE; + + //--- set coordinates --- + j0 = ((block>>1)<<3); + i0 = ((block&0x01)<<3); + +#ifdef BEST_NZ_COEFF + j1 = (j0>>2); + i1 = (i0>>2); + for(j = 0; j <= 1; j++) + { + for(i = 0; i <= 1; i++) + best_nz_coeff[i][j] = p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + j] = 0; + } +#endif + + if (transform8x8) + currMB->luma_transform_size_8x8_flag = TRUE; //switch to transform size 8x8 + + //--- store coding state before coding --- + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm); + + //===== LOOP OVER POSSIBLE CODING MODES FOR 8x8 SUB-PARTITION ===== + for (min_cost8x8 = DISTBLK_MAX, index = (currSlice->slice_type == B_SLICE ? 0 : 1); index < maxindex; index++) + { + mode = b8_mode_table[index]; + best.mode = (char) mode; + *cost = 0; + + if (enc_mb->valid[mode] && (!(transform8x8 == 1 && mode > 4)) && (transform8x8 == 0 || mode != 0 || (mode == 0 && p_Vid->active_sps->direct_8x8_inference_flag))) + { + if (transform8x8) + { + currMB->valid_8x8 = TRUE; + } + else + currMB->valid_4x4 = TRUE; + + valid_8x8 = TRUE; + curr_cbp_blk = 0; + + if (mode==0) + { + //--- Direct Mode --- + direct4x4_tmp = 0; + direct8x8_tmp = 0; + direct4x4_tmp = GetDirectCost8x8 ( currMB, block, &direct8x8_tmp); + if ((direct4x4_tmp==DISTBLK_MAX)||(*cost_direct==DISTBLK_MAX)) + { + *cost_direct = DISTBLK_MAX; + if (transform8x8) + *cost8x8_direct = DISTBLK_MAX; + } + else + { + *cost_direct += direct4x4_tmp; + if (transform8x8) + *cost8x8_direct += direct8x8_tmp; + } + (*have_direct) ++; + + if (transform8x8) + { + switch(p_Inp->Transform8x8Mode) + { + case 1: // Mixture of 8x8 & 4x4 transform + if((direct8x8_tmp < direct4x4_tmp) || !(enc_mb->valid[5] && enc_mb->valid[6] && enc_mb->valid[7])) + *cost = direct8x8_tmp; + else + *cost = direct4x4_tmp; + break; + case 2: // 8x8 Transform only + *cost = direct8x8_tmp; + break; + default: // 4x4 Transform only + *cost = direct4x4_tmp; + break; + } + if (p_Inp->Transform8x8Mode==2) + *cost = DISTBLK_MAX; + } + else + { + *cost = direct4x4_tmp; + } + + block_x = currMB->block_x + (block & 0x01)*2; + block_y = currMB->block_y + (block & 0x02); + best.ref[LIST_0] = currSlice->direct_ref_idx[block_y][block_x][LIST_0]; + best.ref[LIST_1] = currSlice->direct_ref_idx[block_y][block_x][LIST_1]; + best.pdir = currSlice->direct_pdir[block_y][block_x]; + } // if (mode==0) + else + { + short b_ref; + + //======= motion estimation for all reference frames ======== + //----------------------------------------------------------- + memcpy(lambda_mf, enc_mb->lambda_mf, 3 * sizeof(int)); + if (p_Inp->CtxAdptLagrangeMult == 1) + { + RDOPTStructure *p_RDO = currSlice->p_RDO; + lambda_mf[F_PEL] = (int)(lambda_mf[F_PEL] * p_RDO->lambda_mf_factor); + lambda_mf[H_PEL] = (int)(lambda_mf[H_PEL] * p_RDO->lambda_mf_factor); + lambda_mf[Q_PEL] = (int)(lambda_mf[Q_PEL] * p_RDO->lambda_mf_factor); + } + + SubPartitionMotionSearch (currMB, mode, block, lambda_mf); + + //--- get cost and reference frame for LIST 0 prediction --- + bmcost[LIST_0] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_0, block, mode, enc_mb, bmcost, best.ref); + + //store LIST 0 reference index for every block + block_x = currMB->block_x + (block & 0x01)*2; + block_y = currMB->block_y + (block & 0x02); + b_ref = best.ref[LIST_0]; + + for (j = block_y; j< block_y + 2; j++) + { + for (i = block_x; i< block_x + 2; i++) + { + motion[j][i].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[j][i].ref_idx [LIST_0] = (char) b_ref; + } + } + + if (currSlice->slice_type == B_SLICE) + { + //--- get cost and reference frame for LIST 1 prediction --- + bmcost[LIST_1] = DISTBLK_MAX; + bmcost[BI_PRED] = DISTBLK_MAX; + list_prediction_cost(currMB, LIST_1, block, mode, enc_mb, bmcost, best.ref); + + // Compute bipredictive cost between best list 0 and best list 1 references + list_prediction_cost(currMB, BI_PRED, block, mode, enc_mb, bmcost, best.ref); + + // currently Bi prediction ME is only supported for modes 1, 2, 3 and only for ref 0 and only for ref 0 + if (is_bipred_enabled(p_Vid, mode)) + { + list_prediction_cost(currMB, BI_PRED_L0, block, mode, enc_mb, bmcost, 0); + list_prediction_cost(currMB, BI_PRED_L1, block, mode, enc_mb, bmcost, 0); + } + else + { + bmcost[BI_PRED_L0] = DISTBLK_MAX; + bmcost[BI_PRED_L1] = DISTBLK_MAX; + } + + //--- get prediction direction ---- + determine_prediction_list(bmcost, &best, cost); + + //store backward reference index for every block + for (j = block_y; j< block_y + 2; j++) + { + for (i = block_x; i < block_x + 2; i++) + { + //motion[j][i].ref_pic [LIST_0] = currSlice->listX[currMB->list_offset][b_ref]; + motion[j][i].ref_idx [LIST_0] = (char) best.ref[LIST_0]; + motion[j][i].ref_idx [LIST_0] = (char) best.ref[LIST_1]; + } + } + } // if (currSlice->slice_type == B_SLICE) + else + { + best.pdir = 0; + *cost = bmcost[LIST_0]; + } + } // if (mode!=0) + if (*cost != DISTBLK_MAX) + *cost += (ref_cost(currSlice, enc_mb->lambda_mf[Q_PEL], (short) B8Mode2Value (currSlice, (short) mode, best.pdir), + (best.pdir < 1 ? currMB->list_offset : currMB->list_offset + LIST_1)) - 1); + + //--- set variables if best mode has changed --- + if (*cost < min_cost8x8) + { + min_cost8x8 = *cost; + + dataTr->part[block] = best; + currMB->b8x8[block].mode = (char) mode; + +#ifdef BEST_NZ_COEFF + if (cnt_nonz) + { + best_nz_coeff[0][0]= p_Vid->nz_coeff[currMB->mbAddrX][i1 ][j1 ]; + best_nz_coeff[0][1]= p_Vid->nz_coeff[currMB->mbAddrX][i1 ][j1 + 1]; + best_nz_coeff[1][0]= p_Vid->nz_coeff[currMB->mbAddrX][i1 + 1][j1 ]; + best_nz_coeff[1][1]= p_Vid->nz_coeff[currMB->mbAddrX][i1 + 1][j1 + 1]; + } + else + { + best_nz_coeff[0][0]= 0; + best_nz_coeff[0][1]= 0; + best_nz_coeff[1][0]= 0; + best_nz_coeff[1][1]= 0; + } +#endif + + //--- store number of nonzero coefficients --- + best_cnt_nonz = cnt_nonz; + + //--- store best 8x8 coding state --- + if (block < 3) + { + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_b8); + stored_state_8x8 = TRUE; + } + } // if (rdcost <= min_rdcost) + + //--- re-set coding state as it was before coding with current mode was performed --- + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + } // if ((enc_mb->valid[mode] && (transform8x8 == 0 || mode != 0 || (mode == 0 && active_sps->direct_8x8_inference_flag))) + } // for (min_rdcost=1e30, index=(currSlice->slice_type == B_SLICE ? 0 : 1); index<6; index++) + + if (valid_8x8 == TRUE) + { + int list_mode[2]; +#ifdef BEST_NZ_COEFF + for(i = 0; i <= 1; i++) + { + for(j = 0; j <= 1; j++) + p_Vid->nz_coeff[currMB->mbAddrX][i1 + i][j1 + j] = best_nz_coeff[i][j]; + } +#endif + + if (!transform8x8) + { + if (min_cost8x8 != DISTBLK_MAX) + dataTr->mb_p8x8_cost += min_cost8x8; + else + dataTr->mb_p8x8_cost = DISTBLK_MAX; + } + + + if (transform8x8) + { + if (min_cost8x8 != DISTBLK_MAX) + dataTr->mb_p8x8_cost += min_cost8x8; + else + dataTr->mb_p8x8_cost = DISTBLK_MAX; + + mode = dataTr->part[block].mode; + pdir = dataTr->part[block].pdir; + } + else + { + mode = dataTr->part[block].mode; + pdir = dataTr->part[block].pdir; + } + + curr_cbp_blk = 0; + currMB->b8x8[block].bipred = dataTr->part[block].bipred; + currMB->ar_mode = (short) ((mode != 0)? mode: P8x8); + + list_mode[0] = (pdir == 0 || pdir == 2 ? mode : 0); + list_mode[1] = (pdir == 1 || pdir == 2 ? mode : 0); + + best_cnt_nonz = currSlice->luma_residual_coding_8x8 (currMB, &dummy, &curr_cbp_blk, block, pdir, list_mode, dataTr->part[block].ref); + + if (currSlice->P444_joined) + { + best_cnt_nonz += currSlice->coeff_cost_cr[1] + currSlice->coeff_cost_cr[2]; + } + + dataTr->cbp_blk8x8 &= (~(0x33 << (((block>>1)<<3)+((block & 0x01)<<1)))); // delete bits for block + dataTr->cbp_blk8x8 |= curr_cbp_blk; + + //--- store coefficients --- + memcpy(cofACtr[0][0][0],currSlice->cofAC[block][0][0], 4 * 2 * 65 * sizeof(int)); + + if(currSlice->P444_joined) + { + //--- store coefficients --- + memcpy(cofACtr[1][0][0],currSlice->cofAC[block + 4][0][0], 4 * 2 * 65 * sizeof(int)); + memcpy(cofACtr[2][0][0],currSlice->cofAC[block + 8][0][0], 4 * 2 * 65 * sizeof(int)); + } + + + //--- store reconstruction and prediction --- + copy_image_data_8x8(&dataTr->rec_mbY8x8[j0], &p_Vid->enc_picture->imgY[currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8[j0], &currSlice->mb_pred[0][j0], i0, i0); + + + //--- store reconstruction and prediction --- + if(currSlice->slice_type == SP_SLICE) + { + for (j=j0; j < j0 + BLOCK_SIZE_8x8; j++) + { + memcpy(&dataTr->lrec[j][i0],&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x+i0],BLOCK_SIZE_8x8 * sizeof(int)); // store coefficients for primary SP slice + } + } + if(currSlice->P444_joined) + { + copy_image_data_8x8(&dataTr->rec_mb8x8_cr[0][j0], &p_Vid->enc_picture->imgUV[0][currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8CbCr[0][j0], &currSlice->mb_pred[1][j0], i0, i0); + copy_image_data_8x8(&dataTr->rec_mb8x8_cr[1][j0], &p_Vid->enc_picture->imgUV[1][currMB->pix_y + j0], i0, currMB->pix_x + i0); + copy_image_data_8x8(&dataTr->mpr8x8CbCr[1][j0], &currSlice->mb_pred[2][j0], i0, i0); + } + + + //----- set cbp and count of nonzero coefficients --- + if (best_cnt_nonz) + { + dataTr->cbp8x8 |= (1 << block); + dataTr->cnt_nonz_8x8 += best_cnt_nonz; + } + + if (!transform8x8) + { + if (block < 3) + { + //===== re-set reconstructed block ===== + j0 = 8*(block >> 1); + i0 = 8*(block & 0x01); + + copy_image_data_8x8(&p_Vid->enc_picture->imgY[currMB->pix_y + j0], &dataTr->rec_mbY8x8[j0], currMB->pix_x + i0, i0); + + if(currSlice->slice_type == SP_SLICE) + { + for (j = j0; j < j0 + BLOCK_SIZE_8x8; j++) + { + memcpy(&p_Vid->lrec[currMB->pix_y + j][currMB->pix_x], dataTr->lrec[j], 2 * BLOCK_SIZE * sizeof(int)); // reset the coefficients for SP slice + } + } + + if(currSlice->P444_joined) + { + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[0][currMB->pix_y + j0], &dataTr->rec_mb8x8_cr[0][j0], currMB->pix_x + i0, i0); + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[1][currMB->pix_y + j0], &dataTr->rec_mb8x8_cr[1][j0], currMB->pix_x + i0, i0); + } + } // if (block<3) + } + else + { + //======= save motion data for 8x8 partition for transform size 8x8 ======== + currSlice->store_8x8_motion_vectors(currSlice, 0, block, &dataTr->part[block]); + } + + //===== set motion vectors and reference frames (prediction) ===== + currSlice->set_ref_and_motion_vectors (currMB, motion, &dataTr->part[block], block); + + //===== set the coding state after current block ===== + //if (transform8x8 == 0 || block < 3) + if (stored_state_8x8 == TRUE) + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_b8); + else + { + update_adaptive_rounding_8x8(p_Vid, p_Inp, dataTr, fadjust); + } + } +} + diff --git a/lencod/src/mv_direct.c b/lencod/src/mv_direct.c new file mode 100644 index 0000000..a4e990a --- /dev/null +++ b/lencod/src/mv_direct.c @@ -0,0 +1,814 @@ + +/*! + ************************************************************************************* + * \file mv_direct.c + * + * \brief + * Direct Motion Vector Generation + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* +*/ + +#include "contributors.h" + +#include +#include +#include + +#include "global.h" + +#include "image.h" +#include "mv_search.h" +#include "refbuf.h" +#include "memalloc.h" +#include "mb_access.h" +#include "macroblock.h" +#include "mc_prediction.h" +#include "conformance.h" +#include "mode_decision.h" + +/*! + ************************************************************************ + * \brief + * Calculate Temporal Direct Mode Motion Vectors + ************************************************************************ + */ +void Get_Direct_MV_Temporal (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y; + MotionVector *****all_mvs; + int mv_scale; + int refList; + int ref_idx; + VideoParameters *p_Vid = currMB->p_Vid; + int list_offset = currMB->list_offset; + + StorablePicture **list1 = currSlice->listX[LIST_1 + list_offset]; + + PicMotionParams colocated; + + //temporal direct mode copy from decoder + for (block_y = 0; block_y < 4; block_y++) + { + pic_block_y = currMB->block_y + block_y; + opic_block_y = (currMB->opix_y >> 2) + block_y; + + for (block_x = 0; block_x < 4; block_x++) + { + pic_block_x = currMB->block_x + block_x; + opic_block_x = (currMB->pix_x>>2) + block_x; + + all_mvs = currSlice->all_mv; + if (p_Vid->active_sps->direct_8x8_inference_flag) + { + if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = list1[0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(opic_block_y)][RSD(opic_block_x)]; + else + colocated = list1[0]->mv_info[RSD(opic_block_y)][RSD(opic_block_x)]; + if(currSlice->mb_aff_frame_flag && currMB->mb_field && currSlice->listX[LIST_1][0]->coded_frame) + { + int iPosBlkY; + if(currSlice->listX[LIST_1][0]->motion.mb_field[currMB->mbAddrX] ) + iPosBlkY = (opic_block_y>>2)*8+4*(currMB->mbAddrX&1)+(opic_block_y&0x03); + else + iPosBlkY = RSD(opic_block_y)*2; + + if(colocated.ref_idx[LIST_0]>=0) + colocated.ref_pic[LIST_0] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_0]; + if(colocated.ref_idx[LIST_1]>=0) + colocated.ref_pic[LIST_1] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_1]; + } + } + else + { + if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = list1[0]->JVmv_info[currMB->p_Slice->colour_plane_id][opic_block_y][opic_block_x]; + else + colocated = list1[0]->mv_info[opic_block_y][opic_block_x]; + } + if(currSlice->mb_aff_frame_flag) + { + if(!currMB->mb_field && ((currSlice->listX[LIST_1][0]->coded_frame && currSlice->listX[LIST_1][0]->motion.mb_field[currMB->mbAddrX]) || + (!currSlice->listX[LIST_1][0]->coded_frame))) + { + if (iabs(p_Vid->enc_picture->poc - currSlice->listX[LIST_1+4][0]->poc)> iabs(p_Vid->enc_picture->poc -currSlice->listX[LIST_1+2][0]->poc) ) + { + if ( p_Vid->active_sps->direct_8x8_inference_flag) + { + if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = currSlice->listX[LIST_1+2][0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(opic_block_y)>>1][RSD(opic_block_x)]; + else + colocated = currSlice->listX[LIST_1+2][0]->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)]; + } + else + { + if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = currSlice->listX[LIST_1+2][0]->JVmv_info[currMB->p_Slice->colour_plane_id][(opic_block_y)>>1][(opic_block_x)]; + else + colocated = currSlice->listX[LIST_1+2][0]->mv_info[(opic_block_y)>>1][opic_block_x]; + } + if(currSlice->listX[LIST_1][0]->coded_frame) + { + int iPosBlkY = (RSD(opic_block_y)>>3)*8 + ((RSD(opic_block_y)>>1) & 0x03); + if(colocated.ref_idx[LIST_0] >=0) // && !colocated.ref_pic[LIST_0]) + colocated.ref_pic[LIST_0] = currSlice->listX[LIST_1+2][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_0]; + if(colocated.ref_idx[LIST_1] >=0) // && !colocated.ref_pic[LIST_1]) + colocated.ref_pic[LIST_1] = currSlice->listX[LIST_1+2][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_1]; + } + } + else + { + if (p_Vid->active_sps->direct_8x8_inference_flag ) + { + if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = currSlice->listX[LIST_1+4][0]->JVmv_info[currMB->p_Slice->colour_plane_id][RSD(opic_block_y)>>1][RSD(opic_block_x)]; + else + colocated = currSlice->listX[LIST_1+4][0]->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)]; + + } + else + { + if(currMB->p_Inp->separate_colour_plane_flag && currMB->p_Vid->yuv_format==YUV444) + colocated = currSlice->listX[LIST_1+4][0]->JVmv_info[currMB->p_Slice->colour_plane_id][(opic_block_y)>>1][opic_block_x]; + else + colocated = currSlice->listX[LIST_1+4][0]->mv_info[(opic_block_y)>>1][opic_block_x]; + } + if(currSlice->listX[LIST_1][0]->coded_frame) + { + int iPosBlkY = (RSD(opic_block_y)>>3)*8 + ((RSD(opic_block_y)>>1) & 0x03)+4; + if(colocated.ref_idx[LIST_0] >=0) // && !colocated.ref_pic[LIST_0]) + colocated.ref_pic[LIST_0] = currSlice->listX[LIST_1+4][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_0]; + if(colocated.ref_idx[LIST_1] >=0)// && !colocated.ref_pic[LIST_1]) + colocated.ref_pic[LIST_1] = currSlice->listX[LIST_1+4][0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_1]; + } + } + } + } + else if(!p_Vid->active_sps->frame_mbs_only_flag && !p_Vid->structure && !currSlice->listX[LIST_1][0]->coded_frame) + { + if (iabs(p_Vid->enc_picture->poc - list1[0]->bottom_field->poc)> iabs(p_Vid->enc_picture->poc -list1[0]->top_field->poc) ) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + list1[0]->top_field->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)] : list1[0]->top_field->mv_info[(opic_block_y)>>1][opic_block_x]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + list1[0]->bottom_field->mv_info[RSD(opic_block_y)>>1][RSD(opic_block_x)] : list1[0]->bottom_field->mv_info[(opic_block_y)>>1][opic_block_x]; + } + } + else if(!p_Vid->active_sps->frame_mbs_only_flag && p_Vid->structure && list1[0]->coded_frame) + { + int iPosBlkY; + int currentmb = 2*(list1[0]->size_x>>4) * (opic_block_y >> 2)+ (opic_block_x>>2)*2 + ((opic_block_y>>1) & 0x01); + if(p_Vid->structure!=list1[0]->structure) + { + if (p_Vid->structure == TOP_FIELD) + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + list1[0]->frame->top_field->mv_info[RSD(opic_block_y)][RSD(opic_block_x)] : list1[0]->frame->top_field->mv_info[opic_block_y][opic_block_x]; + } + else + { + colocated = p_Vid->active_sps->direct_8x8_inference_flag ? + list1[0]->frame->bottom_field->mv_info[RSD(opic_block_y)][RSD(opic_block_x)] : list1[0]->frame->bottom_field->mv_info[opic_block_y][opic_block_x]; + } + } + + if(!currSlice->listX[LIST_1][0]->frame->mb_aff_frame_flag || !list1[0]->frame->motion.mb_field[currentmb]) + iPosBlkY = 2*(RSD(opic_block_y)); + else + iPosBlkY = (RSD(opic_block_y)>>2)*8 + (RSD(opic_block_y) & 0x03)+4*(p_Vid->structure == BOTTOM_FIELD); + if(colocated.ref_idx[LIST_0] >=0) // && !colocated.ref_pic[LIST_0]) + colocated.ref_pic[LIST_0] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_0]; + if(colocated.ref_idx[LIST_1] >=0)// && !colocated.ref_pic[LIST_1]) + colocated.ref_pic[LIST_1] = list1[0]->frame->mv_info[iPosBlkY][RSD(opic_block_x)].ref_pic[LIST_1]; + } + + refList = ((colocated.ref_idx[LIST_0] == -1 || (p_Vid->view_id && colocated.ref_idx[LIST_0]==list1[0]->ref_pic_na[0]))? LIST_1 : LIST_0); + ref_idx = colocated.ref_idx[refList]; + + // next P is intra mode + if (ref_idx == -1 || (p_Vid->view_id && ref_idx==list1[0]->ref_pic_na[refList])) + { + all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = 0; + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = 0; + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + } + // next P is skip or inter mode + else + { + int mapped_idx=INVALIDINDEX; + int iref; + if( (currSlice->mb_aff_frame_flag && ( (currMB->mb_field && colocated.ref_pic[refList]->structure==FRAME) || + (!currMB->mb_field && colocated.ref_pic[refList]->structure!=FRAME))) || + (!currSlice->mb_aff_frame_flag && ((p_Vid->structure==FRAME && colocated.ref_pic[refList]->structure!=FRAME)|| + (p_Vid->structure!=FRAME && colocated.ref_pic[refList]->structure==FRAME))) ) + { + //! Frame with field co-located + for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]); iref++) + { + if (currSlice->listX[LIST_0 + list_offset][iref]->top_field == colocated.ref_pic[refList] || + currSlice->listX[LIST_0 + list_offset][iref]->bottom_field == colocated.ref_pic[refList] || + currSlice->listX[LIST_0 + list_offset][iref]->frame == colocated.ref_pic[refList] ) + { + if ((p_Vid->field_picture==1) && (currSlice->listX[LIST_0 + list_offset][iref]->structure != currSlice->structure)) + { + mapped_idx=INVALIDINDEX; + } + else + { + mapped_idx = iref; + break; + } + } + else //! invalid index. Default to zero even though this case should not happen + mapped_idx=INVALIDINDEX; + } + } + else + { + for (iref = 0; iref < imin(currSlice->num_ref_idx_active[LIST_0], currSlice->listXsize[LIST_0 + list_offset]);iref++) + { + if(currSlice->listX[LIST_0 + list_offset][iref] == colocated.ref_pic[refList]) + { + mapped_idx = iref; + break; + } + else //! invalid index. Default to zero even though this case should not happen + { + mapped_idx=INVALIDINDEX; + } + } + } + + if (mapped_idx != INVALIDINDEX) + { + MotionVector mv = colocated.mv[refList]; + mv_scale = currSlice->mvscale[LIST_0 + list_offset][mapped_idx]; + + if((currSlice->mb_aff_frame_flag && !currMB->mb_field && colocated.ref_pic[refList]->structure!=FRAME) || + (!currSlice->mb_aff_frame_flag && p_Vid->structure==FRAME && colocated.ref_pic[refList]->structure!=FRAME)) + mv.mv_y *= 2; + else if((currSlice->mb_aff_frame_flag && currMB->mb_field && colocated.ref_pic[refList]->structure==FRAME) || + (!currSlice->mb_aff_frame_flag && p_Vid->structure!=FRAME && colocated.ref_pic[refList]->structure==FRAME)) + mv.mv_y /= 2; + + if (mv_scale==9999) + { + // forward + all_mvs[LIST_0][0][0][block_y][block_x] = mv; + // backward + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + } + else + { + // forward + all_mvs[LIST_0][mapped_idx][0][block_y][block_x].mv_x = (short) ((mv_scale * mv.mv_x + 128) >> 8); + all_mvs[LIST_0][mapped_idx][0][block_y][block_x].mv_y = (short) ((mv_scale * mv.mv_y + 128) >> 8); + // backward + all_mvs[LIST_1][ 0][0][block_y][block_x].mv_x = (short) (((mv_scale - 256) * mv.mv_x + 128) >> 8); + all_mvs[LIST_1][ 0][0][block_y][block_x].mv_y = (short) (((mv_scale - 256) * mv.mv_y + 128) >> 8); + + } + + // Test Level Limits if satisfied. + if ( out_of_bounds_mvs(p_Vid, &all_mvs[LIST_0][mapped_idx][0][block_y][block_x])|| out_of_bounds_mvs(p_Vid, &all_mvs[LIST_1][0][0][block_y][block_x])) + { + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = -1; + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = -1; + currSlice->direct_pdir[pic_block_y][pic_block_x] = -1; + } + else + { + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = (char) mapped_idx; + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = 0; + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + } + } + else + { + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = -1; + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = -1; + currSlice->direct_pdir[pic_block_y][pic_block_x] = -1; + } + } + + if (p_Vid->active_pps->weighted_bipred_idc == 1 && currSlice->direct_pdir[pic_block_y][pic_block_x] == 2) + { + int weight_sum, i; + short l0_refX = currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0]; + short l1_refX = currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1]; + for (i=0;i< (p_Vid->active_sps->chroma_format_idc == YUV400 ? 1 : 3); i++) + { + weight_sum = currSlice->wbp_weight[0][l0_refX][l1_refX][i] + currSlice->wbp_weight[1][l0_refX][l1_refX][i]; + if (weight_sum < -128 || weight_sum > 127) + { + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_0] = -1; + currSlice->direct_ref_idx[pic_block_y][pic_block_x][LIST_1] = -1; + currSlice->direct_pdir [pic_block_y][pic_block_x] = -1; + break; + } + } + } + } + } +} + +static inline void set_direct_references(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info) +{ + if (mb->available) + { + char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; + *l0_rFrame = ref_idx[LIST_0]; + *l1_rFrame = ref_idx[LIST_1]; + } + else + { + *l0_rFrame = -1; + *l1_rFrame = -1; + } +} + +static void set_direct_references_mb_field(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info, Macroblock *mb_data) +{ + if (mb->available) + { + char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; + if (mb_data[mb->mb_addr].mb_field) + { + *l0_rFrame = ref_idx[LIST_0]; + *l1_rFrame = ref_idx[LIST_1]; + } + else + { + *l0_rFrame = (ref_idx[LIST_0] < 0) ? ref_idx[LIST_0] : ref_idx[LIST_0] * 2; + *l1_rFrame = (ref_idx[LIST_1] < 0) ? ref_idx[LIST_1] : ref_idx[LIST_1] * 2; + } + } + else + { + *l0_rFrame = -1; + *l1_rFrame = -1; + } +} + +static void set_direct_references_mb_frame(const PixelPos *mb, char *l0_rFrame, char *l1_rFrame, PicMotionParams **mv_info, Macroblock *mb_data) +{ + if (mb->available) + { + char *ref_idx = mv_info[mb->pos_y][mb->pos_x].ref_idx; + if (mb_data[mb->mb_addr].mb_field) + { + *l0_rFrame = (ref_idx[LIST_0] >> 1); + *l1_rFrame = (ref_idx[LIST_1] >> 1); + } + else + { + *l0_rFrame = ref_idx[LIST_0]; + *l1_rFrame = ref_idx[LIST_1]; + } + } + else + { + *l0_rFrame = -1; + *l1_rFrame = -1; + } +} + +static void test_valid_direct(Slice *currSlice, seq_parameter_set_rbsp_t *active_sps, char *direct_ref_idx, short l0_refX, short l1_refX, int pic_block_y, int pic_block_x) +{ + int weight_sum, i; + Boolean invalid_wp = FALSE; + for (i=0;i< (active_sps->chroma_format_idc == YUV400 ? 1 : 3); i++) + { + weight_sum = currSlice->wbp_weight[0][l0_refX][l1_refX][i] + currSlice->wbp_weight[1][l0_refX][l1_refX][i]; + if (weight_sum < -128 || weight_sum > 127) + { + invalid_wp = TRUE; + break; + } + } + if (invalid_wp == FALSE) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + else + { + direct_ref_idx[LIST_0] = -1; + direct_ref_idx[LIST_1] = -1; + currSlice->direct_pdir[pic_block_y][pic_block_x] = -1; + } +} + +/*! +************************************************************************************* +* \brief +* Temporary function for colocated info when direct_inference is enabled. +* +************************************************************************************* +*/ +int get_colocated_info(Macroblock *currMB, StorablePicture *list1, int i, int j) +{ + if (list1->is_long_term) + return 1; + else + { + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + if( (currSlice->mb_aff_frame_flag) || + (!p_Vid->active_sps->frame_mbs_only_flag && ((!currSlice->structure && !list1->coded_frame) || (currSlice->structure!=list1->structure && list1->coded_frame)))) + { + int jj = RSD(j); + int ii = RSD(i); + int jdiv = (jj>>1); + int moving; + PicMotionParams *fs = &list1->mv_info[jj][ii]; + + if(currSlice->structure && currSlice->structure!=list1->structure && list1->coded_frame) + { + if(currSlice->structure == TOP_FIELD) + fs = list1->top_field->mv_info[jj] + ii; + else + fs = list1->bottom_field->mv_info[jj] + ii; + } + else + { + if( (currSlice->mb_aff_frame_flag && ((!currMB->mb_field && list1->motion.mb_field[currMB->mbAddrX]) || + (!currMB->mb_field && !list1->coded_frame))) + || (!currSlice->mb_aff_frame_flag)) + { + if (iabs(p_Vid->enc_picture->poc - list1->bottom_field->poc)> iabs(p_Vid->enc_picture->poc -list1->top_field->poc) ) + { + fs = list1->top_field->mv_info[jdiv] + ii; + } + else + { + fs = list1->bottom_field->mv_info[jdiv] + ii; + } + } + } + moving = !((((fs->ref_idx[LIST_0] == 0) + && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) + || ((fs->ref_idx[LIST_0] == -1) + && (fs->ref_idx[LIST_1] == 0) + && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); + return moving; + } + else + { + PicMotionParams *fs = &list1->mv_info[RSD(j)][RSD(i)]; + int moving; + if(currMB->p_Vid->yuv_format == YUV444 && !currSlice->P444_joined) + fs = &list1->JVmv_info[(int)(p_Vid->colour_plane_id)][RSD(j)][RSD(i)]; + moving= !((((fs->ref_idx[LIST_0] == 0) + && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) + || ((fs->ref_idx[LIST_0] == -1) + && (fs->ref_idx[LIST_1] == 0) + && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); + + return moving; + } + } +} + +/*! +************************************************************************************* +* \brief +* Colocated info <= direct_inference is disabled. +************************************************************************************* +*/ +int get_colocated_info_4x4(Macroblock *currMB, StorablePicture *list1, int i, int j) +{ + if (list1->is_long_term) + return 1; + else + { + PicMotionParams *fs = &list1->mv_info[j][i]; + + int moving = !((((fs->ref_idx[LIST_0] == 0) + && (iabs(fs->mv[LIST_0].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_0].mv_y)>>1 == 0))) + || ((fs->ref_idx[LIST_0] == -1) + && (fs->ref_idx[LIST_1] == 0) + && (iabs(fs->mv[LIST_1].mv_x)>>1 == 0) + && (iabs(fs->mv[LIST_1].mv_y)>>1 == 0))); + + return moving; + } +} + +/*! +************************************************************************ +* \brief +* Calculate Spatial Direct Mode Motion Vectors +************************************************************************ +*/ +void Get_Direct_MV_Spatial_Normal (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + char l0_refA, l0_refB, l0_refC; + char l1_refA, l1_refB, l1_refC; + char l0_refX,l1_refX; + MotionVector pmvfw = zero_mv, pmvbw = zero_mv; + + int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y; + MotionVector *****all_mvs; + char *direct_ref_idx; + StorablePicture **list1 = currSlice->listX[LIST_1]; + + PixelPos mb[4]; + get_neighbors(currMB, mb, 0, 0, 16); + + set_direct_references(&mb[0], &l0_refA, &l1_refA, mv_info); + set_direct_references(&mb[1], &l0_refB, &l1_refB, mv_info); + set_direct_references(&mb[2], &l0_refC, &l1_refC, mv_info); + + l0_refX = (char) imin(imin((unsigned char) l0_refA, (unsigned char) l0_refB), (unsigned char) l0_refC); + l1_refX = (char) imin(imin((unsigned char) l1_refA, (unsigned char) l1_refB), (unsigned char) l1_refC); + + if (l0_refX >= 0) + currMB->GetMVPredictor (currMB, mb, &pmvfw, l0_refX, mv_info, LIST_0, 0, 0, 16, 16); + + if (l1_refX >= 0) + currMB->GetMVPredictor (currMB, mb, &pmvbw, l1_refX, mv_info, LIST_1, 0, 0, 16, 16); + + if (l0_refX == -1 && l1_refX == -1) + { + for (block_y=0; block_y<4; block_y++) + { + pic_block_y = currMB->block_y + block_y; + for (block_x=0; block_x<4; block_x++) + { + pic_block_x = currMB->block_x + block_x; + direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; + + currSlice->all_mv[LIST_0][0][0][block_y][block_x] = zero_mv; + currSlice->all_mv[LIST_1][0][0][block_y][block_x] = zero_mv; + + direct_ref_idx[LIST_0] = direct_ref_idx[LIST_1] = 0; + + if (p_Vid->active_pps->weighted_bipred_idc == 1) + test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, 0, 0, pic_block_y, pic_block_x); + else + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + } + } + } + else if (l0_refX == 0 || l1_refX == 0) + { + int (*get_colocated)(Macroblock *currMB, StorablePicture *list1, int i, int j) = + p_Vid->active_sps->direct_8x8_inference_flag ? get_colocated_info : get_colocated_info_4x4; + + int is_moving_block; + for (block_y = 0; block_y < 4; block_y++) + { + pic_block_y = currMB->block_y + block_y; + opic_block_y = (currMB->opix_y >> 2) + block_y; + + for (block_x=0; block_x<4; block_x++) + { + pic_block_x = currMB->block_x + block_x; + direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; + opic_block_x = (currMB->pix_x >> 2) + block_x; + + all_mvs = currSlice->all_mv; + is_moving_block = (get_colocated(currMB, list1[0], opic_block_x, opic_block_y) == 0); + + if (l0_refX < 0) + { + all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_0] = -1; + } + else if ((l0_refX == 0) && is_moving_block) + { + all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_0] = 0; + } + else + { + all_mvs[LIST_0][(short) l0_refX][0][block_y][block_x] = pmvfw; + direct_ref_idx[LIST_0] = (char)l0_refX; + } + + if (l1_refX < 0) + { + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_1] = -1; + } + else if((l1_refX == 0) && is_moving_block) + { + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_1] = 0; + } + else + { + all_mvs[LIST_1][(short) l1_refX][0][block_y][block_x] = pmvbw; + direct_ref_idx[LIST_1] = (char)l1_refX; + } + + if (direct_ref_idx[LIST_1] == -1) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 0; + else if (direct_ref_idx[LIST_0] == -1) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 1; + else if (p_Vid->active_pps->weighted_bipred_idc == 1) + test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, l0_refX, l1_refX, pic_block_y, pic_block_x); + else + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + } + } + } + else + { + for (block_y=0; block_y<4; block_y++) + { + pic_block_y = currMB->block_y + block_y; + + for (block_x=0; block_x<4; block_x++) + { + pic_block_x = currMB->block_x + block_x; + direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; + + all_mvs = currSlice->all_mv; + + if (l0_refX > 0) + { + all_mvs[LIST_0][(short) l0_refX][0][block_y][block_x] = pmvfw; + direct_ref_idx[LIST_0]= (char)l0_refX; + } + else + { + all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_0]=-1; + } + + if (l1_refX > 0) + { + all_mvs[LIST_1][(short) l1_refX][0][block_y][block_x] = pmvbw; + direct_ref_idx[LIST_1] = (char)l1_refX; + } + else + { + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_1] = -1; + } + + if (direct_ref_idx[LIST_1] == -1) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 0; + else if (direct_ref_idx[LIST_0] == -1) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 1; + else if (p_Vid->active_pps->weighted_bipred_idc == 1) + test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, l0_refX, l1_refX, pic_block_y, pic_block_x); + else + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Calculate Spatial Direct Mode Motion Vectors +************************************************************************ +*/ +void Get_Direct_MV_Spatial_MBAFF (Macroblock *currMB) +{ + char l0_refA, l0_refB, l0_refC; + char l1_refA, l1_refB, l1_refC; + char l0_refX,l1_refX; + MotionVector pmvfw = zero_mv, pmvbw = zero_mv; + + int block_x, block_y, pic_block_x, pic_block_y, opic_block_x, opic_block_y; + MotionVector *****all_mvs; + char *direct_ref_idx; + int is_moving_block; + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **mv_info = p_Vid->enc_picture->mv_info; + StorablePicture **list1 = currSlice->listX[LIST_1 + currMB->list_offset]; + + int (*get_colocated)(Macroblock *currMB, StorablePicture *list1, int i, int j) = + p_Vid->active_sps->direct_8x8_inference_flag ? get_colocated_info : get_colocated_info_4x4; + + PixelPos mb[4]; + get_neighbors(currMB, mb, 0, 0, 16); + + + if (currMB->mb_field) + { + set_direct_references_mb_field(&mb[0], &l0_refA, &l1_refA, mv_info, p_Vid->mb_data); + set_direct_references_mb_field(&mb[1], &l0_refB, &l1_refB, mv_info, p_Vid->mb_data); + set_direct_references_mb_field(&mb[2], &l0_refC, &l1_refC, mv_info, p_Vid->mb_data); + } + else + { + set_direct_references_mb_frame(&mb[0], &l0_refA, &l1_refA, mv_info, p_Vid->mb_data); + set_direct_references_mb_frame(&mb[1], &l0_refB, &l1_refB, mv_info, p_Vid->mb_data); + set_direct_references_mb_frame(&mb[2], &l0_refC, &l1_refC, mv_info, p_Vid->mb_data); + } + + l0_refX = (char) imin(imin((unsigned char) l0_refA, (unsigned char) l0_refB), (unsigned char) l0_refC); + l1_refX = (char) imin(imin((unsigned char) l1_refA, (unsigned char) l1_refB), (unsigned char) l1_refC); + + if (l0_refX >=0) + currMB->GetMVPredictor (currMB, mb, &pmvfw, l0_refX, mv_info, LIST_0, 0, 0, 16, 16); + + if (l1_refX >=0) + currMB->GetMVPredictor (currMB, mb, &pmvbw, l1_refX, mv_info, LIST_1, 0, 0, 16, 16); + + for (block_y=0; block_y<4; block_y++) + { + pic_block_y = currMB->block_y + block_y; + opic_block_y = (currMB->opix_y >> 2) + block_y; + + for (block_x=0; block_x<4; block_x++) + { + pic_block_x = currMB->block_x + block_x; + direct_ref_idx = currSlice->direct_ref_idx[pic_block_y][pic_block_x]; + opic_block_x = (currMB->pix_x >> 2) + block_x; + is_moving_block = (get_colocated(currMB, list1[0], opic_block_x, opic_block_y) == 0); + + all_mvs = currSlice->all_mv; + + if (l0_refX >=0) + { + if (!l0_refX && is_moving_block) + { + all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_0] = 0; + } + else + { + all_mvs[LIST_0][(short) l0_refX][0][block_y][block_x] = pmvfw; + direct_ref_idx[LIST_0] = (char)l0_refX; + } + } + else + { + all_mvs[LIST_0][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_0] = -1; + } + + if (l1_refX >=0) + { + if(l1_refX==0 && is_moving_block) + { + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_1] = (char)l1_refX; + } + else + { + all_mvs[LIST_1][(short) l1_refX][0][block_y][block_x] = pmvbw; + direct_ref_idx[LIST_1] = (char)l1_refX; + } + } + else + { + all_mvs[LIST_1][0][0][block_y][block_x] = zero_mv; + direct_ref_idx[LIST_1] = -1; + } + + // Test Level Limits if satisfied. + + // Test Level Limits if satisfied. + if ((out_of_bounds_mvs(p_Vid, &all_mvs[LIST_0][l0_refX < 0? 0 : l0_refX][0][block_y][block_x]) + || out_of_bounds_mvs(p_Vid, &all_mvs[LIST_1][l1_refX < 0? 0 : l1_refX][0][block_y][block_x]))) + { + direct_ref_idx[LIST_0] = -1; + direct_ref_idx[LIST_1] = -1; + currSlice->direct_pdir [pic_block_y][pic_block_x] = -1; + } + else + { + if (l0_refX < 0 && l1_refX < 0) + { + direct_ref_idx[LIST_0] = direct_ref_idx[LIST_1] = 0; + l0_refX = 0; + l1_refX = 0; + } + + if (direct_ref_idx[LIST_1] == -1) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 0; + else if (direct_ref_idx[LIST_0] == -1) + currSlice->direct_pdir[pic_block_y][pic_block_x] = 1; + else if (p_Vid->active_pps->weighted_bipred_idc == 1) + test_valid_direct(currSlice, currSlice->active_sps, direct_ref_idx, l0_refX, l1_refX, pic_block_y, pic_block_x); + else + currSlice->direct_pdir[pic_block_y][pic_block_x] = 2; + } + } + } +} diff --git a/lencod/src/mv_search.c b/lencod/src/mv_search.c new file mode 100644 index 0000000..e7cabe3 --- /dev/null +++ b/lencod/src/mv_search.c @@ -0,0 +1,1861 @@ + +/*! + ************************************************************************************* + * \file mv_search.c + * + * \brief + * Motion Vector Search, unified for B and P Pictures + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * - Inge Lille-Langoy + * - Rickard Sjoberg + * - Stephan Wenger + * - Jani Lainema + * - Detlev Marpe + * - Thomas Wedi + * - Heiko Schwarz + * - Alexis Michael Tourapis + * + ************************************************************************************* +*/ + +#include "contributors.h" + +#include +#include +#include + +#include "global.h" + +#include "image.h" +#include "mv_search.h" +#include "refbuf.h" +#include "memalloc.h" +#include "mb_access.h" +#include "macroblock.h" +#include "mc_prediction.h" +#include "conformance.h" +#include "mode_decision.h" + +// Motion estimation distortion header file +#include "me_distortion.h" +#include "me_distortion_otf.h" + +// Motion estimation search algorithms +#include "me_epzs.h" +#include "me_epzs_int.h" +#include "me_fullfast.h" +#include "me_fullfast_otf.h" +#include "me_fullsearch.h" +#include "me_umhex.h" +#include "me_umhexsmp.h" +#include "rdoq.h" + + +static const short bx0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,2,0,2}}; +static const short by0[5][4] = {{0,0,0,0}, {0,0,0,0}, {0,2,0,0}, {0,0,0,0}, {0,0,2,2}}; + + +static distblk GetSkipCostMB (Macroblock *currMB, int lambda); +static distblk BiPredBlockMotionSearch(Macroblock *currMB, MEBlock *, MotionVector*, int, int , int*); + +/*! + ************************************************************************ + * \brief + * Set search range. This needs to be changed to provide 2D support + ************************************************************************ + */ +void get_search_range(MEBlock *mv_block, InputParameters *p_Inp, short ref, int blocktype) +{ + SearchWindow *searchRange = &mv_block->searchRange; + + *searchRange = mv_block->p_Vid->searchRange; + //----- set search range --- + if (p_Inp->full_search == 1) + { + int scale = (imin(ref, 1) + 1); + searchRange->min_x /= scale; + searchRange->max_x /= scale; + searchRange->min_y /= scale; + searchRange->max_y /= scale; + } + else if (p_Inp->full_search != 2) + { + int scale = ((imin(ref, 1) + 1) * imin(2, blocktype)); + searchRange->min_x /= scale; + searchRange->max_x /= scale; + searchRange->min_y /= scale; + searchRange->max_y /= scale; + } +} + +/*! + ************************************************************************ + * \brief + * Set search range. This needs to be changed to provide 2D support + ************************************************************************ + */ +static inline void set_me_parameters( PicMotionParams **motion, const MotionVector *all_mv, int list, char ref, int step_h, int step_v, int pic_block_y, int pic_block_x) +{ + int i, j; + + // Set first line + for (j = pic_block_y; j < pic_block_y + step_v; j++) + { + for (i=pic_block_x; imv_x > min_x) && (blk->mv_x < max_x) && (blk->mv_y > min_y) && (blk->mv_y < max_y)) + { + *access_method = FAST_ACCESS; + } + else + { + *access_method = UMV_ACCESS; + } +} + +/*! + ************************************************************************ + * \brief + * Initialize ME engine + ************************************************************************ + */ +void init_ME_engine(Macroblock *currMB) +{ + InputParameters *p_Inp = currMB->p_Inp; + VideoParameters *p_Vid = currMB->p_Vid; + switch (p_Inp->SearchMode[p_Vid->view_id]) + { + case EPZS: + EPZS_setup_engine(currMB, p_Inp); + break; + case UM_HEX: + currMB->IntPelME = UMHEXIntegerPelBlockMotionSearch; + currMB->BiPredME = UMHEXBipredIntegerPelBlockMotionSearch; + currMB->SubPelBiPredME = sub_pel_bipred_motion_estimation; + currMB->SubPelME = UMHEXSubPelBlockME; + break; + case UM_HEX_SIMPLE: + currMB->IntPelME = smpUMHEXIntegerPelBlockMotionSearch; + currMB->BiPredME = smpUMHEXBipredIntegerPelBlockMotionSearch; + currMB->SubPelBiPredME = sub_pel_bipred_motion_estimation; + currMB->SubPelME = smpUMHEXSubPelBlockME; + break; + case FULL_SEARCH: + currMB->IntPelME = full_search_motion_estimation; + currMB->BiPredME = full_search_bipred_motion_estimation; + currMB->SubPelBiPredME = sub_pel_bipred_motion_estimation; + currMB->SubPelME = sub_pel_motion_estimation; + break; + case FAST_FULL_SEARCH: + default: + currMB->IntPelME = fast_full_search_motion_estimation; + currMB->BiPredME = full_search_bipred_motion_estimation; + currMB->SubPelBiPredME = sub_pel_bipred_motion_estimation; + currMB->SubPelME = sub_pel_motion_estimation; + currMB->p_SetupFastFullPelSearch = (p_Inp->OnTheFlyFractMCP) ? (SetupFastFullPelSearch_otf):(setup_fast_full_search); + break; + } +} + +/*! + ************************************************************************ + * \brief + * Prepare Motion Estimation parameters for single list ME + ************************************************************************ + */ +void PrepareMEParams(Slice *currSlice, MEBlock *mv_block, int ChromaMEEnable, int list, int ref) +{ + if (mv_block->apply_weights) + { + mv_block->weight_luma = currSlice->wp_weight[list][ref][0]; + mv_block->offset_luma = currSlice->wp_offset[list][ref][0]; + + if ( ChromaMEEnable) + { + mv_block->weight_cr[0] = currSlice->wp_weight[list][ref][1]; + mv_block->weight_cr[1] = currSlice->wp_weight[list][ref][2]; + mv_block->offset_cr[0] = currSlice->wp_offset[list][ref][1]; + mv_block->offset_cr[1] = currSlice->wp_offset[list][ref][2]; + } + } +} + +/*! + ************************************************************************ + * \brief + * Prepare Motion Estimation parameters for bipred list ME + ************************************************************************ + */ +void PrepareBiPredMEParams(Slice *currSlice, MEBlock *mv_block, int ChromaMEEnable, int list, int list_offset, int ref) +{ + if (mv_block->apply_weights) + { + if (list == LIST_0) + { + mv_block->weight1 = currSlice->wbp_weight[list_offset ][ref][0][0]; + mv_block->weight2 = currSlice->wbp_weight[list_offset + LIST_1][ref][0][0]; + mv_block->offsetBi = (currSlice->wp_offset[list_offset ][ref][0] + currSlice->wp_offset[list_offset + LIST_1][ref][0] + 1)>>1; + + if ( ChromaMEEnable) + { + mv_block->weight1_cr[0] = currSlice->wbp_weight[list_offset ][ref][0][1]; + mv_block->weight1_cr[1] = currSlice->wbp_weight[list_offset ][ref][0][2]; + mv_block->weight2_cr[0] = currSlice->wbp_weight[list_offset + LIST_1][ref][0][1]; + mv_block->weight2_cr[1] = currSlice->wbp_weight[list_offset + LIST_1][ref][0][2]; + + mv_block->offsetBi_cr[0] = (currSlice->wp_offset[list_offset ][ref][1] + currSlice->wp_offset[list_offset + LIST_1][ref][1] + 1) >> 1; + mv_block->offsetBi_cr[1] = (currSlice->wp_offset[list_offset ][ref][2] + currSlice->wp_offset[list_offset + LIST_1][ref][2] + 1) >> 1; + } + } + else + { + mv_block->weight1 = currSlice->wbp_weight[list_offset + LIST_1][0 ][ref][0]; + mv_block->weight2 = currSlice->wbp_weight[list_offset ][0 ][ref][0]; + mv_block->offsetBi = (currSlice->wp_offset[list_offset + LIST_1][0][0] + currSlice->wp_offset[list_offset][0][0] + 1)>>1; + + if ( ChromaMEEnable) + { + mv_block->weight1_cr[0] = currSlice->wbp_weight[list_offset + LIST_1][0 ][ref][1]; + mv_block->weight1_cr[1] = currSlice->wbp_weight[list_offset + LIST_1][0 ][ref][2]; + mv_block->weight2_cr[0] = currSlice->wbp_weight[list_offset ][0 ][ref][1]; + mv_block->weight2_cr[1] = currSlice->wbp_weight[list_offset ][0 ][ref][2]; + + mv_block->offsetBi_cr[0] = (currSlice->wp_offset[list_offset + LIST_1][0 ][1] + currSlice->wp_offset[list_offset ][0 ][1] + 1) >> 1; + mv_block->offsetBi_cr[1] = (currSlice->wp_offset[list_offset + LIST_1][0 ][2] + currSlice->wp_offset[list_offset ][0 ][2] + 1) >> 1; + } + } + } + else + { + mv_block->weight1 = (short) (1 << currSlice->luma_log_weight_denom); + mv_block->weight2 = (short) (1 << currSlice->luma_log_weight_denom); + mv_block->offsetBi = 0; + if ( ChromaMEEnable) + { + mv_block->weight1_cr[0] = 1<chroma_log_weight_denom; + mv_block->weight1_cr[1] = 1<chroma_log_weight_denom; + mv_block->weight2_cr[0] = 1<chroma_log_weight_denom; + mv_block->weight2_cr[1] = 1<chroma_log_weight_denom; + mv_block->offsetBi_cr[0] = 0; + mv_block->offsetBi_cr[1] = 0; + } + } +} + +/*! + ************************************************************************ + * \brief + * Get current block spatial neighbors + ************************************************************************ + */ +void get_neighbors(Macroblock *currMB, // <-- current Macroblock + PixelPos *block, // <--> neighbor blocks + int mb_x, // <-- block x position + int mb_y, // <-- block y position + int blockshape_x // <-- block width + ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, mb_x - 1, mb_y , mb_size, &block[0]); + get4x4Neighbour(currMB, mb_x, mb_y - 1, mb_size, &block[1]); + get4x4Neighbour(currMB, mb_x + blockshape_x, mb_y - 1, mb_size, &block[2]); + get4x4Neighbour(currMB, mb_x - 1, mb_y - 1, mb_size, &block[3]); + + if (mb_y > 0) + { + if (mb_x < 8) // first column of 8x8 blocks + { + if (mb_y == 8 ) + { + if (blockshape_x == MB_BLOCK_SIZE) + block[2].available = 0; + } + else if (mb_x + blockshape_x == 8) + { + block[2].available = 0; + } + } + else if (mb_x + blockshape_x == MB_BLOCK_SIZE) + { + block[2].available = 0; + } + } + + if (!block[2].available) + { + block[2] = block[3]; + } +} + +/*! +************************************************************************ +* \brief +* Initialize the motion search +************************************************************************ +*/ +void init_motion_search_module (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int bits; + int i_min, i_max,k; + int i, l; + int search_range_orig = p_Inp->SepViewInterSearch ? imax( p_Inp->search_range[0], p_Inp->search_range[1] ) : p_Inp->search_range[0]; + int search_range = search_range_orig; + int max_search_points = imax(9, (2 * search_range + 1) * (2 * search_range + 1)); + int max_ref_bits = 1 + 2 * (int)floor(log(imax(16, p_Vid->max_num_references + 1)) / log(2) + 1e-10); + int max_ref = (1<<((max_ref_bits>>1)+1))-1; + int number_of_subpel_positions = 4 * (2*search_range+3); + int max_mv_bits = 3 + 2 * (int)ceil (log(number_of_subpel_positions + 1) / log(2) + 1e-10); + int max_mvd = p_Inp->UseMVLimits? imax(4*imax(p_Inp->SetMVXLimit, p_Inp->SetMVYLimit), ((1<<( max_mv_bits >>1) ) - 1)): ((1<<( max_mv_bits >>1)) - 1); + + p_Vid->max_mvd = max_mvd; + p_Vid->imgpel_abs_range = (imax(p_Vid->max_pel_value_comp[0],p_Vid->max_pel_value_comp[1]) + 1) * 64; + + //===== CREATE ARRAYS ===== + //----------------------------- + if ((p_Vid->spiral_search = (MotionVector*)calloc(max_search_points, sizeof(MotionVector))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->spiral_search"); + if ((p_Vid->spiral_hpel_search = (MotionVector*)calloc(max_search_points, sizeof(MotionVector))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->spiral_hpel_search"); + if ((p_Vid->spiral_qpel_search = (MotionVector*)calloc(max_search_points, sizeof(MotionVector))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->spiral_qpel_search"); + + + if ((p_Vid->mvbits = (int*)calloc(2 * max_mvd + 1, sizeof(int))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->mvbits"); + + if ((p_Vid->refbits = (int*)calloc(max_ref, sizeof(int))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->refbits"); + +#if (JM_MEM_DISTORTION) + if ((p_Vid->imgpel_abs = (int*)calloc(p_Vid->imgpel_abs_range, sizeof(int))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->imgpel_abs"); + if ((p_Vid->imgpel_quad = (int*)calloc(p_Vid->imgpel_abs_range, sizeof(int))) == NULL) + no_mem_exit("init_motion_search_module: p_Vid->imgpel_quad"); + p_Vid->imgpel_abs += p_Vid->imgpel_abs_range / 2; + p_Vid->imgpel_quad += p_Vid->imgpel_abs_range / 2; +#endif + + if (p_Vid->max_num_references) + get_mem4Ddistblk (&p_Vid->motion_cost, 8, 2, p_Vid->max_num_references, 4); + + //--- set array offsets --- + p_Vid->mvbits += max_mvd; + + //===== INIT ARRAYS ===== + //--------------------------- + //--- init array: motion vector bits --- + p_Vid->mvbits[0] = 1; + for (bits = 3; bits <= max_mv_bits; bits += 2) + { + i_max = (short) (1 << (bits >> 1)); + i_min = i_max >> 1; + + for (i = i_min; i < i_max; i++) + p_Vid->mvbits[-i] = p_Vid->mvbits[i] = bits; + } + + //--- init array: reference frame bits --- + p_Vid->refbits[0] = 1; + for (bits=3; bits<=max_ref_bits; bits+=2) + { + i_max = (short) (1 << ((bits >> 1) + 1)) - 1; + i_min = i_max >> 1; + + for (i = i_min; i < i_max; i++) + p_Vid->refbits[i] = bits; + } + +#if (JM_MEM_DISTORTION) + //--- init array: absolute value --- + p_Vid->imgpel_abs[0] = 0; + + for (i=1; iimgpel_abs_range / 2; i++) + { + p_Vid->imgpel_abs[i] = p_Vid->imgpel_abs[-i] = i; + } + + //--- init array: square value --- + p_Vid->imgpel_quad[0] = 0; + + for (i=1; iimgpel_abs_range / 2; i++) + { + p_Vid->imgpel_quad[i] = p_Vid->imgpel_quad[-i] = i * i; + } +#endif + + //--- init array: search pattern --- + p_Vid->spiral_search[0].mv_x = p_Vid->spiral_search[0].mv_y = 0; + p_Vid->spiral_hpel_search[0].mv_x = p_Vid->spiral_hpel_search[0].mv_y = 0; + p_Vid->spiral_qpel_search[0].mv_x = p_Vid->spiral_qpel_search[0].mv_y = 0; + + for (k=1, l=1; l <= imax(1,search_range); l++) + { + for (i=-l+1; i< l; i++) + { + p_Vid->spiral_search[k].mv_x = (short) i; + p_Vid->spiral_search[k].mv_y = (short) -l; + p_Vid->spiral_hpel_search[k].mv_x = (short) (i<<1); + p_Vid->spiral_hpel_search[k].mv_y = (short) -(l<<1); + p_Vid->spiral_qpel_search[k].mv_x = (short) (i<<2); + p_Vid->spiral_qpel_search[k++].mv_y = (short) -(l<<2); + p_Vid->spiral_search[k].mv_x = (short) i; + p_Vid->spiral_search[k].mv_y = (short) l; + p_Vid->spiral_hpel_search[k].mv_x = (short) (i<<1); + p_Vid->spiral_hpel_search[k].mv_y = (short) (l<<1); + p_Vid->spiral_qpel_search[k].mv_x = (short) (i<<2); + p_Vid->spiral_qpel_search[k++].mv_y = (short) (l<<2); + } + for (i=-l; i<=l; i++) + { + p_Vid->spiral_search[k].mv_x = (short) -l; + p_Vid->spiral_search[k].mv_y = (short) i; + p_Vid->spiral_hpel_search[k].mv_x = (short) -(l<<1); + p_Vid->spiral_hpel_search[k].mv_y = (short) (i<<1); + p_Vid->spiral_qpel_search[k].mv_x = (short) -(l<<2); + p_Vid->spiral_qpel_search[k++].mv_y = (short) (i<<2); + p_Vid->spiral_search[k].mv_x = (short) l; + p_Vid->spiral_search[k].mv_y = (short) i; + p_Vid->spiral_hpel_search[k].mv_x = (short) (l<<1); + p_Vid->spiral_hpel_search[k].mv_y = (short) (i<<1); + p_Vid->spiral_qpel_search[k].mv_x = (short) (l<<2); + p_Vid->spiral_qpel_search[k++].mv_y = (short) (i<<2); + } + } + + // set global variable prior to ME + p_Vid->start_me_refinement_hp = (p_Inp->ChromaMEEnable == 1 || p_Inp->MEErrorMetric[F_PEL] != p_Inp->MEErrorMetric[H_PEL] ) ? 0 : 1; + p_Vid->start_me_refinement_qp = (p_Inp->ChromaMEEnable == 1 || p_Inp->MEErrorMetric[H_PEL] != p_Inp->MEErrorMetric[Q_PEL] ) ? 0 : 1; + + select_distortion(p_Vid, p_Inp); + + // Setup Distortion Metrics depending on refinement level + if( p_Inp->OnTheFlyFractMCP ) + { + for (i=0; i<3; i++) + { + switch( p_Inp->MEErrorMetric[i]) + { + case ERROR_SAD: + p_Vid->computeUniPred[i] = computeSAD_otf ; + p_Vid->computeUniPred[i + 3] = computeSADWP_otf ; + p_Vid->computeBiPred1[i] = computeBiPredSAD1_otf ; + p_Vid->computeBiPred2[i] = computeBiPredSAD2_otf ; + break; + case ERROR_SSE: + p_Vid->computeUniPred[i] = computeSSE_otf; + p_Vid->computeUniPred[i + 3] = computeSSEWP_otf; + p_Vid->computeBiPred1[i] = computeBiPredSSE1_otf; + p_Vid->computeBiPred2[i] = computeBiPredSSE2_otf; + break; + case ERROR_SATD : + default: + p_Vid->computeUniPred[i] = computeSATD_otf ; + p_Vid->computeUniPred[i + 3] = computeSATDWP_otf ; + p_Vid->computeBiPred1[i] = computeBiPredSATD1_otf ; + p_Vid->computeBiPred2[i] = computeBiPredSATD2_otf ; + break; + } + } + } + else + { + for (i=0; i<3; i++) + { + switch(p_Inp->MEErrorMetric[i]) + { + case ERROR_SAD: + p_Vid->computeUniPred[i] = computeSAD; + p_Vid->computeUniPred[i + 3] = computeSADWP; + p_Vid->computeBiPred1[i] = computeBiPredSAD1; + p_Vid->computeBiPred2[i] = computeBiPredSAD2; + break; + case ERROR_SSE: + p_Vid->computeUniPred[i] = computeSSE; + p_Vid->computeUniPred[i + 3] = computeSSEWP; + p_Vid->computeBiPred1[i] = computeBiPredSSE1; + p_Vid->computeBiPred2[i] = computeBiPredSSE2; + break; + case ERROR_SATD : + default: + p_Vid->computeUniPred[i] = computeSATD; + p_Vid->computeUniPred[i + 3] = computeSATDWP; + p_Vid->computeBiPred1[i] = computeBiPredSATD1; + p_Vid->computeBiPred2[i] = computeBiPredSATD2; + break; + } + } + } + if (!p_Inp->IntraProfile) + { + if(p_Inp->SearchMode[0] == FAST_FULL_SEARCH || p_Inp->SearchMode[1] == FAST_FULL_SEARCH) + initialize_fast_full_search (p_Vid, p_Inp); + + if (p_Inp->SearchMode[0] == UM_HEX || p_Inp->SearchMode[1] == UM_HEX) + UMHEX_DefineThreshold(p_Vid); + } +} + +/*! + ************************************************************************ + * \brief + * Free memory used by motion search + ************************************************************************ + */ +void +clear_motion_search_module (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + //int search_range = p_Inp->search_range; + //int number_of_subpel_positions = 4 * (2*search_range+3); + //int max_mv_bits = 3 + 2 * (int)ceil (log(number_of_subpel_positions + 1) / log(2) + 1e-10); + int max_mvd = p_Vid->max_mvd; //(1<<( max_mv_bits >>1) ) - 1; + + + //--- correct array offset --- + p_Vid->mvbits -= max_mvd; +#if (JM_MEM_DISTORTION) + p_Vid->imgpel_abs -= p_Vid->imgpel_abs_range / 2; + p_Vid->imgpel_quad -= p_Vid->imgpel_abs_range / 2; +#endif + + //--- delete arrays --- + free (p_Vid->spiral_search); + free (p_Vid->spiral_hpel_search); + free (p_Vid->spiral_qpel_search); + free (p_Vid->mvbits); + free (p_Vid->refbits); + +#if (JM_MEM_DISTORTION) + free (p_Vid->imgpel_abs); + free (p_Vid->imgpel_quad); +#endif + + + if (p_Vid->motion_cost) + free_mem4Ddistblk (p_Vid->motion_cost); + + if ((p_Inp->SearchMode[0] == FAST_FULL_SEARCH || p_Inp->SearchMode[1] == FAST_FULL_SEARCH) && (!p_Inp->IntraProfile) ) + clear_fast_full_search (p_Vid); +} + +static inline int mv_bit_cost(Macroblock *currMB, MotionVector **all_mv, int cur_list, short cur_ref, int by, int bx, int step_v0, int step_v, int step_h0, int step_h, int mvd_bits) +{ + int v, h; + MotionVector predMV; + PixelPos block[4]; // neighbor blocks + VideoParameters *p_Vid = currMB->p_Vid; + + for (v=by; vGetMVPredictor (currMB, block, &predMV, cur_ref, p_Vid->enc_picture->mv_info, cur_list, h, v, step_h, step_v); + + mvd_bits += p_Vid->mvbits[ all_mv[v>>2][h>>2].mv_x - predMV.mv_x ]; + mvd_bits += p_Vid->mvbits[ all_mv[v>>2][h>>2].mv_y - predMV.mv_y ]; + } + } + + return mvd_bits; +} + +/*! + *********************************************************************** + * \brief + * Motion Cost for Bidirectional modes + *********************************************************************** + */ +distblk BPredPartitionCost (Macroblock *currMB, + int blocktype, + int block8x8, + short ref_l0, + short ref_l1, + int lambda_factor, + int list) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + imgpel **cur_img = p_Vid->pCurImg; + + short pic_pix_x, pic_pix_y; + short v, h; + distblk mcost; + + int mvd_bits = 0; + + short parttype = (short) (blocktype < 4 ? blocktype : 4); + short step_h0 = block_size[ parttype][0]; + short step_v0 = block_size[ parttype][1]; + short step_h = block_size[blocktype][0]; + short step_v = block_size[blocktype][1]; + short by0_part = by0[parttype][block8x8] << 2; + short bx0_part = bx0[parttype][block8x8] << 2; + short block_size_x = block_size[blocktype][0]; + short block_size_y = block_size[blocktype][1]; + + MotionVector **all_mv_l0 = currSlice->bipred_mv[list][LIST_0][ref_l0][blocktype]; + MotionVector **all_mv_l1 = currSlice->bipred_mv[list][LIST_1][ref_l1][blocktype]; + imgpel **mb_pred = currSlice->mb_pred[0]; + + // List0 + mvd_bits = mv_bit_cost(currMB, all_mv_l0, LIST_0, ref_l0, by0_part, bx0_part, step_v0, step_v, step_h0, step_h, mvd_bits); + // List1 + mvd_bits = mv_bit_cost(currMB, all_mv_l1, LIST_1, ref_l1, by0_part, bx0_part, step_v0, step_v, step_h0, step_h, mvd_bits); + + mcost = weighted_cost (lambda_factor, mvd_bits); + + // Get prediction + for (v = by0_part; v < by0_part + step_v0; v = (short) (v + block_size_y)) + { + for (h = bx0_part; h < bx0_part + step_h0; h = (short) (h + block_size_x)) + { + p_Dpb->pf_luma_prediction_bi (currMB, h, v, block_size_x, block_size_y, blocktype, blocktype, ref_l0, ref_l1, list); + } + } + + //----- cost of residual signal ----- + if ((!currSlice->p_Inp->Transform8x8Mode) || (blocktype>4)) + { + short diff16[16]; + short *diff; + + pic_pix_y = currMB->opix_y; + pic_pix_x = currMB->pix_x; + for (v = by0_part; v < by0_part + step_v0; v += 4) + { + for (h = bx0_part; h < bx0_part + step_h0; h += 4) + { + diff = diff16; + calcDifference(cur_img, pic_pix_x+h, pic_pix_y+v, mb_pred, h, v, 4, 4, diff); + mcost += p_Vid->distortion4x4 (diff16, DISTBLK_MAX); + } + } + } + else + { + short diff64[64]; + short *diff; + + pic_pix_y = currMB->opix_y; + pic_pix_x = currMB->pix_x; + for (v = by0_part; v < by0_part + step_v0; v += 8) + { + for (h = bx0_part; h < bx0_part + step_h0; h += 8) + { + diff = diff64; + calcDifference(cur_img, pic_pix_x+h, pic_pix_y+v, mb_pred, h, v, 8, 8, diff); + mcost += p_Vid->distortion8x8(diff64, DISTBLK_MAX); + } + } + } + + return mcost; +} + +void update_mv_block(Macroblock *currMB, MEBlock *mv_block, int h, int v) +{ + mv_block->block_x = (short) h; + mv_block->block_y = (short) v; + mv_block->pos_x = (short) (currMB->pix_x + (h << 2)); + mv_block->pos_y = (short) (currMB->opix_y + (v << 2)); + mv_block->pos_x2 = (short) (mv_block->pos_x >> 2); + mv_block->pos_y2 = (short) (mv_block->pos_y >> 2); + mv_block->pos_x_padded = (short) (mv_block->pos_x << 2); + mv_block->pos_y_padded = (short) (mv_block->pos_y << 2); + + mv_block->pos_cr_x = (short) (mv_block->pos_x >> currMB->p_Vid->shift_cr_x); + mv_block->pos_cr_y = (short) (mv_block->pos_y >> currMB->p_Vid->shift_cr_y); +} + +/*! + *********************************************************************** + * \brief + * Init motion vector block + *********************************************************************** + */ +void init_mv_block(Macroblock *currMB, MEBlock *mv_block, short blocktype, int list, char ref_idx, short mb_x, short mb_y) +{ + InputParameters *p_Inp = currMB->p_Inp; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + mv_block->blocktype = blocktype; + mv_block->blocksize_x = block_size[blocktype][0]; // horizontal block size + mv_block->blocksize_y = block_size[blocktype][1]; // vertical block size + // update position info + update_mv_block(currMB, mv_block, mb_x, mb_y); + + mv_block->list = (char) list; + mv_block->ref_idx = ref_idx; + + mv_block->mv[LIST_0].mv_x = 0; + mv_block->mv[LIST_0].mv_y = 0; + mv_block->mv[LIST_1].mv_x = 0; + mv_block->mv[LIST_1].mv_y = 0; + // Init WP parameters + mv_block->p_Vid = p_Vid; + mv_block->p_Slice = currSlice; + mv_block->cost = INT_MAX; + mv_block->search_pos2 = 9; + mv_block->search_pos4 = 9; + + if (p_Inp->ChromaMEEnable) + get_mem2Dpel(&mv_block->orig_pic, 3, mv_block->blocksize_x * mv_block->blocksize_y); + else + get_mem2Dpel(&mv_block->orig_pic, 1, mv_block->blocksize_x * mv_block->blocksize_y); + + mv_block->ChromaMEEnable = p_Inp->ChromaMEEnable; + + mv_block->apply_bi_weights = p_Inp->UseWeightedReferenceME && ((currSlice->slice_type == B_SLICE) && p_Vid->active_pps->weighted_bipred_idc != 0); + mv_block->apply_weights = p_Inp->UseWeightedReferenceME && ( currSlice->weighted_prediction != 0 ); + + if (p_Inp->ChromaMEEnable) + { + mv_block->blocksize_cr_x = (short) (mv_block->blocksize_x >> p_Vid->shift_cr_x); + mv_block->blocksize_cr_y = (short) (mv_block->blocksize_y >> p_Vid->shift_cr_y); + + mv_block->ChromaMEWeight = p_Inp->ChromaMEWeight; + } + + if (mv_block->apply_weights) + { + // If implicit WP, single list weights are always non weighted + if ((currSlice->slice_type == B_SLICE) && (p_Vid->active_pps->weighted_bipred_idc == 2)) + { + mv_block->computePredFPel = p_Vid->computeUniPred[F_PEL]; + mv_block->computePredHPel = p_Vid->computeUniPred[H_PEL]; + mv_block->computePredQPel = p_Vid->computeUniPred[Q_PEL]; + } + else + { + mv_block->computePredFPel = p_Vid->computeUniPred[F_PEL + 3]; + mv_block->computePredHPel = p_Vid->computeUniPred[H_PEL + 3]; + mv_block->computePredQPel = p_Vid->computeUniPred[Q_PEL + 3]; + } + mv_block->computeBiPredFPel = p_Vid->computeBiPred2[F_PEL]; + mv_block->computeBiPredHPel = p_Vid->computeBiPred2[H_PEL]; + mv_block->computeBiPredQPel = p_Vid->computeBiPred2[Q_PEL]; + } + else + { + mv_block->computePredFPel = p_Vid->computeUniPred[F_PEL]; + mv_block->computePredHPel = p_Vid->computeUniPred[H_PEL]; + mv_block->computePredQPel = p_Vid->computeUniPred[Q_PEL]; + mv_block->computeBiPredFPel = p_Vid->computeBiPred1[F_PEL]; + mv_block->computeBiPredHPel = p_Vid->computeBiPred1[H_PEL]; + mv_block->computeBiPredQPel = p_Vid->computeBiPred1[Q_PEL]; + } +} + +/*! + *********************************************************************** + * \brief + * free motion vector block + *********************************************************************** + */ +void free_mv_block(MEBlock *mv_block) +{ + if (mv_block->orig_pic) + { + free_mem2Dpel(mv_block->orig_pic); + } +} + + +void get_original_block(VideoParameters *p_Vid, MEBlock *mv_block) +{ + //================================== + //===== GET ORIGINAL BLOCK ===== + //================================== + imgpel *orig_pic_tmp = mv_block->orig_pic[0]; + int bsx = mv_block->blocksize_x; + int pic_pix_x = mv_block->pos_x; + int i, j; + imgpel **cur_img = &p_Vid->pCurImg[mv_block->pos_y]; + + for (j = 0; j < mv_block->blocksize_y; j++) + { + memcpy(orig_pic_tmp,&cur_img[j][pic_pix_x], bsx * sizeof(imgpel)); + orig_pic_tmp += bsx; + } + + if ( p_Vid->p_Inp->ChromaMEEnable ) + { + bsx = mv_block->blocksize_cr_x; + pic_pix_x = mv_block->pos_cr_x; + + // copy the original cmp1 and cmp2 data to the orig_pic matrix + for ( i = 1; i<=2; i++) + { + cur_img = &p_Vid->pImgOrg[i][mv_block->pos_cr_y]; + orig_pic_tmp = mv_block->orig_pic[i]; + for (j = 0; j < mv_block->blocksize_cr_y; j++) + { + memcpy(orig_pic_tmp, &(cur_img[j][pic_pix_x]), bsx * sizeof(imgpel)); + orig_pic_tmp += bsx; + } + } + } +} + +void CheckSearchRange(VideoParameters *p_Vid, MotionVector *pPredMV, MotionVector *pSWC, MEBlock *mv_block) +{ + int iMaxMVD = p_Vid->max_mvd - 2; + SearchWindow *searchRange = &mv_block->searchRange; + int left = pSWC->mv_x + searchRange->min_x; + int right = pSWC->mv_x + searchRange->max_x; + int top = pSWC->mv_y + searchRange->min_y; + int down = pSWC->mv_y + searchRange->max_y; + + left = iClip3(pPredMV->mv_x - iMaxMVD, pPredMV->mv_x + iMaxMVD, left); + right = iClip3(pPredMV->mv_x - iMaxMVD, pPredMV->mv_x + iMaxMVD, right); + top = iClip3(pPredMV->mv_y - iMaxMVD, pPredMV->mv_y + iMaxMVD, top); + down = iClip3(pPredMV->mv_y - iMaxMVD, pPredMV->mv_y + iMaxMVD, down); + + if(leftmv_x = (short) ((left + right)>>1); + pSWC->mv_y = (short) ((top + down)>>1); + searchRange->min_x = left - pSWC->mv_x; + searchRange->max_x = imin(pSWC->mv_x-left, right-pSWC->mv_x); + searchRange->min_y = top - pSWC->mv_y; + searchRange->max_y = imin(pSWC->mv_y-top, down-pSWC->mv_y); + } + else + { + *pSWC = *pPredMV; + } +} + +/*! + *********************************************************************** + * \brief + * Block motion search + *********************************************************************** + */ +distblk //!< minimum motion cost after search +BlockMotionSearch (Macroblock *currMB, //!< Current Macroblock + MEBlock *mv_block, //!< Motion estimation information block + int mb_x, //!< x-coordinate inside macroblock + int mb_y, //!< y-coordinate inside macroblock + int* lambda_factor) //!< lagrangian parameter for determining motion cost +{ + // each 48-pel line stores the 16 luma pels (at 0) followed by 8 or 16 crcb[0] (at 16) and crcb[1] (at 32) pels + // depending on the type of chroma subsampling used: YUV 4:4:4, 4:2:2, and 4:2:0 + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int i, j; + distblk max_value = DISTBLK_MAX; + distblk min_mcost = max_value; + int block_x = (mb_x>>2); + int block_y = (mb_y>>2); + + int bsx = mv_block->blocksize_x; + int bsy = mv_block->blocksize_y; + + short pic_pix_x = (short) (currMB->pix_x + mb_x); + + int blocktype = mv_block->blocktype; + int list = mv_block->list; + short ref = mv_block->ref_idx; + MotionVector *mv = &mv_block->mv[list], pred; + + MotionVector **all_mv = &currSlice->all_mv[list][ref][blocktype][block_y]; + + distblk *prevSad = (p_Inp->SearchMode[p_Vid->view_id] == EPZS)? currSlice->p_EPZS->distortion[list + currMB->list_offset][blocktype - 1]: NULL; + + get_neighbors(currMB, mv_block->block, mb_x, mb_y, bsx); + + PrepareMEParams(currSlice, mv_block, p_Inp->ChromaMEEnable, list + currMB->list_offset, ref); + + //================================== + //===== GET ORIGINAL BLOCK ===== + //================================== + if (blocktype > 4) + get_original_block(p_Vid, mv_block); + + //=========================================== + //===== GET MOTION VECTOR PREDICTOR ===== + //=========================================== + if (p_Inp->SearchMode[p_Vid->view_id] == UM_HEX) + { + p_Vid->p_UMHex->UMHEX_blocktype = blocktype; + p_Vid->p_UMHex->bipred_flag = 0; + UMHEXSetMotionVectorPredictor(currMB, &pred, p_Vid->enc_picture->mv_info, ref, list, mb_x, mb_y, bsx, bsy, mv_block); + } + else if (p_Inp->SearchMode[p_Vid->view_id] == UM_HEX_SIMPLE) + { + smpUMHEX_setup(currMB, ref, list, block_y, block_x, blocktype, currSlice->all_mv ); + currMB->GetMVPredictor (currMB, mv_block->block, &pred, ref, p_Vid->enc_picture->mv_info, list, mb_x, mb_y, bsx, bsy); + } + else + { + currMB->GetMVPredictor (currMB, mv_block->block, &pred, ref, p_Vid->enc_picture->mv_info, list, mb_x, mb_y, bsx, bsy); + } + + + + //================================== + //===== INTEGER-PEL SEARCH ===== + //================================== + if (p_Inp->EPZSSubPelGrid) + { + *mv = pred; + } + else + { +#if (JM_INT_DIVIDE) + mv->mv_x = (short) (((pred.mv_x + 2) >> 2) * 4); + mv->mv_y = (short) (((pred.mv_y + 2) >> 2) * 4); +#else + mv->mv_x = (short) ((pred.mv_x / 4) * 4); + mv->mv_y = (short) ((pred.mv_y / 4) * 4); +#endif + } + + if (p_Inp->DisableMEPrediction == TRUE) + { + mv->mv_x = 0; + mv->mv_y = 0; + } + + if (!p_Inp->rdopt) + { + MotionVector center = *mv; + //--- adjust search center so that the (0,0)-vector is inside --- + mv->mv_x = (short) iClip3 (mv_block->searchRange.min_x, mv_block->searchRange.max_x, mv->mv_x); + mv->mv_y = (short) iClip3 (mv_block->searchRange.min_y, mv_block->searchRange.max_y, mv->mv_y); + //mvbits overflow checking; + if((mv->mv_x != center.mv_x) || (mv->mv_y != center.mv_y)) + CheckSearchRange(p_Vid, ¢er, mv, mv_block); + } + + // valid search range limits could be precomputed once during the initialization process + clip_mv_range(p_Vid, 0, mv, Q_PEL); + + //--- perform motion search --- + min_mcost = currMB->IntPelME (currMB, &pred, mv_block, min_mcost, lambda_factor[F_PEL]); + + //============================== + //===== SUB-PEL SEARCH ===== + //============================== + mv_block->ChromaMEEnable = (p_Inp->ChromaMEEnable == ME_YUV_FP_SP ) ? TRUE : FALSE; // set it externally + + if (!p_Inp->DisableSubpelME[p_Vid->view_id]) + { + if (p_Inp->SearchMode[p_Vid->view_id] != EPZS || (ref == 0 || currSlice->structure != FRAME || (ref > 0 && min_mcost < 3.5 * prevSad[pic_pix_x >> 2]))) + { + if ( !p_Vid->start_me_refinement_hp ) + { + min_mcost = max_value; + } + min_mcost = currMB->SubPelME (currMB, &pred, mv_block, min_mcost, lambda_factor); + } + } + + // clip mvs after me is performed (is not exactly the best) + // better solution is to modify search window appropriately + clip_mv_range(p_Vid, 0, mv, Q_PEL); + + if (!p_Inp->rdopt) + { + // Get the skip mode cost + if (blocktype == 1 && (currSlice->slice_type == P_SLICE|| (currSlice->slice_type == SP_SLICE) )) + { + distblk cost; + FindSkipModeMotionVector (currMB); + + cost = GetSkipCostMB (currMB, lambda_factor[Q_PEL]); + if (cost < min_mcost) + { + min_mcost = cost; + *mv = currSlice->all_mv [0][0][0][0][0]; + } + } + } + + //=============================================== + //===== SET MV'S AND RETURN MOTION COST ===== + //=============================================== + + // Set first line + for (i=block_x; i < block_x + (bsx>>2); i++) + { + all_mv[0][i] = *mv; + } + + // set all other lines + for (j=1; j < (bsy>>2); j++) + { + memcpy(&all_mv[j][block_x], &all_mv[0][block_x], (bsx>>2) * sizeof(MotionVector)); + } + + + // Bipred ME consideration: returns minimum bipred cost + if (is_bipred_enabled(p_Vid, blocktype) && (ref == 0)) + { + BiPredBlockMotionSearch(currMB, mv_block, &pred, mb_x, mb_y, lambda_factor); + } + + return min_mcost; +} + + +/*! + *********************************************************************** + * \brief + * Bi-predictive motion search + *********************************************************************** + */ +static distblk BiPredBlockMotionSearch(Macroblock *currMB, //!< Current Macroblock + MEBlock *mv_block, + MotionVector *pred_mv, //!< current list motion vector predictor + int mb_x, //!< x-coordinate inside macroblock + int mb_y, //!< y-coordinate inside macroblock + int* lambda_factor) //!< lagrangian parameter for determining motion cost +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + int list = mv_block->list; + int i, j; + short bipred_type = list ? 0 : 1; + MotionVector ***** bipred_mv = currSlice->bipred_mv[bipred_type]; + distblk min_mcostbi = DISTBLK_MAX; + MotionVector *mv = &mv_block->mv[list]; + MotionVector bimv, tempmv; + MotionVector pred_mv1, pred_mv2, pred_bi; + MotionVector *bi_mv1 = NULL, *bi_mv2 = NULL; + short iterlist = (short) list; + int block_x = (mb_x>>2); + int block_y = (mb_y>>2); + int blocktype = mv_block->blocktype; + int bsx = mv_block->blocksize_x; + int bsy = mv_block->blocksize_y; + //PixelPos block[4]; // neighbor blocks + + //get_neighbors(currMB, mv_block->block, mb_x, mb_y, bsx); + + if (p_Inp->SearchMode[p_Vid->view_id] == UM_HEX) + { + p_Vid->p_UMHex->bipred_flag = 1; + UMHEXSetMotionVectorPredictor(currMB, &pred_bi, p_Vid->enc_picture->mv_info, 0, list ^ 1, mb_x, mb_y, bsx, bsy, mv_block); + } + else + currMB->GetMVPredictor (currMB, mv_block->block, &pred_bi, 0, p_Vid->enc_picture->mv_info, list ^ 1, mb_x, mb_y, bsx, bsy); + + if ((p_Inp->SearchMode[p_Vid->view_id] != EPZS) || (p_Inp->EPZSSubPelGrid == 0)) + { + mv->mv_x = ((mv->mv_x + 2) >> 2) * 4; + mv->mv_y = ((mv->mv_y + 2) >> 2) * 4; + bimv.mv_x = ((pred_bi.mv_x + 2) >> 2) * 4; + bimv.mv_y = ((pred_bi.mv_y + 2) >> 2) * 4; + } + else + { + bimv = pred_bi; + } + + //Bi-predictive motion Refinements + for (mv_block->iteration_no = 0; mv_block->iteration_no <= p_Inp->BiPredMERefinements; mv_block->iteration_no++) + { + if (mv_block->iteration_no & 0x01) + { + pred_mv1 = *pred_mv; + pred_mv2 = pred_bi; + bi_mv1 = mv; + bi_mv2 = &bimv; + iterlist = (short) list; + } + else + { + pred_mv1 = pred_bi; + pred_mv2 = *pred_mv; + bi_mv1 = &bimv; + bi_mv2 = mv; + iterlist = (short) (list ^ 1); + } + + tempmv = *bi_mv1; + + PrepareBiPredMEParams(currSlice, mv_block, mv_block->ChromaMEEnable, iterlist, currMB->list_offset, mv_block->ref_idx); + // Get bipred mvs for list iterlist given previously computed mvs from other list + min_mcostbi = currMB->BiPredME (currMB, iterlist, + &pred_mv1, &pred_mv2, bi_mv1, bi_mv2, mv_block, + (p_Inp->BiPredMESearchRange[p_Vid->view_id] <<2)>>mv_block->iteration_no, min_mcostbi, lambda_factor[F_PEL]); + + if (mv_block->iteration_no > 0 && (tempmv.mv_x == bi_mv1->mv_x) && (tempmv.mv_y == bi_mv1->mv_y)) + { + break; + } + } + + if (!p_Inp->DisableSubpelME[p_Vid->view_id]) + { + if (p_Inp->BiPredMESubPel) + { + if ( !p_Vid->start_me_refinement_hp ) + min_mcostbi = DISTBLK_MAX; + PrepareBiPredMEParams(currSlice, mv_block, mv_block->ChromaMEEnable, iterlist, currMB->list_offset, mv_block->ref_idx); + + min_mcostbi = currMB->SubPelBiPredME (currMB, mv_block, iterlist, &pred_mv1, &pred_mv2, bi_mv1, bi_mv2, min_mcostbi, lambda_factor); + } + + if (p_Inp->BiPredMESubPel==2) + { + if ( !p_Vid->start_me_refinement_qp ) + min_mcostbi = DISTBLK_MAX; + PrepareBiPredMEParams(currSlice, mv_block, mv_block->ChromaMEEnable, iterlist ^ 1, currMB->list_offset, mv_block->ref_idx); + + min_mcostbi = currMB->SubPelBiPredME (currMB, mv_block, iterlist ^ 1, &pred_mv2, &pred_mv1, bi_mv2, bi_mv1, min_mcostbi, lambda_factor); + } + } + + clip_mv_range(p_Vid, 0, bi_mv1, Q_PEL); + clip_mv_range(p_Vid, 0, bi_mv2, Q_PEL); + + for (j=block_y; j < block_y + (bsy>>2); j++) + { + for (i=block_x ; i < block_x + (bsx>>2); i++) + { + bipred_mv[iterlist ][(short) mv_block->ref_idx][blocktype][j][i] = *bi_mv1; + bipred_mv[iterlist ^ 1][(short) mv_block->ref_idx][blocktype][j][i] = *bi_mv2; + } + } + + + return min_mcostbi; +} + +/*! + *********************************************************************** + * \brief + * Motion Cost for Bidirectional modes + *********************************************************************** + */ +distblk BIDPartitionCost (Macroblock *currMB, + int blocktype, + int block8x8, + char cur_ref[2], + int lambda_factor) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + imgpel **cur_img = p_Vid->pCurImg; + + short pic_pix_x, pic_pix_y; + int v, h; + distblk mcost; + + int mvd_bits = 0; + + int parttype = (blocktype < 4 ? blocktype : 4); + int step_h0 = block_size[ parttype][0]; + int step_v0 = block_size[ parttype][1]; + int step_h = block_size[blocktype][0]; + int step_v = block_size[blocktype][1]; + int bx = bx0[parttype][block8x8] << 2; + int by = by0[parttype][block8x8] << 2; + short block_size_x = block_size[blocktype][0]; // this is the same as step_h and could be removed + short block_size_y = block_size[blocktype][1]; // this is the same as step_v and could be removed + + MotionVector **all_mv_l0 = currSlice->all_mv [LIST_0][(int) cur_ref[LIST_0]][blocktype]; + MotionVector **all_mv_l1 = currSlice->all_mv [LIST_1][(int) cur_ref[LIST_1]][blocktype]; + short bipred_me = 0; //no bipred for this case + imgpel **mb_pred = currSlice->mb_pred[0]; + int list_mode[2]; + list_mode[0] = blocktype; + list_mode[1] = blocktype; + + //----- cost for motion vector bits ----- + // Should write a separate, small function to do this processing + // List0 + mvd_bits = mv_bit_cost(currMB, all_mv_l0, LIST_0, cur_ref[LIST_0], by, bx, step_v0, step_v, step_h0, step_h, mvd_bits); + // List1 + mvd_bits = mv_bit_cost(currMB, all_mv_l1, LIST_1, cur_ref[LIST_1], by, bx, step_v0, step_v, step_h0, step_h, mvd_bits); + + mcost = weighted_cost (lambda_factor, mvd_bits); + + // Get prediction + for (v = by; v < by + step_v0; v += block_size_y) + { + for (h = bx; h < bx + step_h0; h += block_size_x) + { + p_Dpb->pf_luma_prediction (currMB, h, v, block_size_x, block_size_y, 2, list_mode, cur_ref, bipred_me); + } + } + + //----- cost of residual signal ----- + if ((!currSlice->p_Inp->Transform8x8Mode) || (blocktype>4)) + { + short diff16[16]; + short *diff; + + pic_pix_y = (short) currMB->opix_y; + pic_pix_x = (short) currMB->pix_x; + for (v= by; v < by + step_v0; v += BLOCK_SIZE) + { + for (h = bx; h < bx + step_h0; h += BLOCK_SIZE) + { + diff = diff16; + calcDifference(cur_img, pic_pix_x+h, pic_pix_y+v, mb_pred, h,v, 4, 4, diff); + mcost += p_Vid->distortion4x4 (diff16, DISTBLK_MAX); + } + } + } + else + { + short diff64[64]; + short *diff; + + pic_pix_y = (short) currMB->opix_y; + pic_pix_x = (short) currMB->pix_x; + for (v= by; v < by + step_v0; v += BLOCK_SIZE_8x8) + { + for (h = bx; h < bx + step_h0; h += BLOCK_SIZE_8x8) + { + diff = diff64; + calcDifference(cur_img, pic_pix_x+h, pic_pix_y+v, mb_pred, h, v, 8, 8, diff); + mcost += p_Vid->distortion8x8(diff64, DISTBLK_MAX); + } + } + } + + return mcost; +} + +/*! + ************************************************************************ + * \brief + * Get cost for skip mode for an macroblock + ************************************************************************ + */ +static distblk GetSkipCostMB (Macroblock *currMB, int lambda) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + distblk cost = 0; + + int block; + imgpel **mb_pred = currSlice->mb_pred[0]; + char cur_ref[2] = {0, 0}; + int list_mode[2] = {0, 0}; + + //===== prediction of 16x16 skip block ===== + p_Dpb->pf_luma_prediction (currMB, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE, 0, list_mode, cur_ref, 0); + + if (p_Inp->Transform8x8Mode == 0) + { + short diff16[16]; + short *diff; + int block_y, block_x;//, i, j; + int mb_x, mb_y; + + int pic_pix_y = currMB->opix_y; + int pic_pix_x = currMB->pix_x; + + for(block = 0;block < 4; block++) + { + mb_y = (block >> 1)<<3; + mb_x = (block & 0x01)<<3; + for (block_y = mb_y; block_y < mb_y + 8; block_y += 4) + { + for (block_x = mb_x; block_x < mb_x + 8; block_x += 4) + { + diff = diff16; + //===== get displaced frame difference ====== + calcDifference(p_Vid->pCurImg, pic_pix_x+block_x, pic_pix_y+block_y, mb_pred, block_x, block_y, 4, 4, diff); + cost += p_Vid->distortion4x4 (diff16, DISTBLK_MAX); + } + } + } + } + else + { + short diff64[64]; + short *diff; + //int i, j; + int mb_x, mb_y; + + int pic_pix_y = currMB->opix_y; + int pic_pix_x = currMB->pix_x; + + for(block = 0;block < 4;block++) + { + mb_y = (block >> 1)<<3; + mb_x = (block & 0x01)<<3; + + //===== get displaced frame difference ====== + diff = diff64; + calcDifference(p_Vid->pCurImg, pic_pix_x+mb_x, pic_pix_y+mb_y, mb_pred, mb_x, mb_y, 8, 8, diff); + cost += p_Vid->distortion8x8 (diff64, DISTBLK_MAX); + } + } + + //cost -= ((lambda_factor[Q_PEL] + 4096) >> 13); + cost -= weight_cost(lambda, 8); + + return cost; +} + +/*! + ************************************************************************ + * \brief + * Find motion vector for the Skip mode + ************************************************************************ + */ +void FindSkipModeMotionVector (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int bx, by; + MotionVector **all_mv = currSlice->all_mv[0][0][0]; + + MotionVector pmv; + + int zeroMotionAbove; + int zeroMotionLeft; + PixelPos mb[4]; + int a_mv_y = 0; + int a_ref_idx = 0; + int b_mv_y = 0; + int b_ref_idx = 0; + + get_neighbors(currMB, mb, 0, 0, 16); + + if (mb[0].available) + { + a_mv_y = motion[mb[0].pos_y][mb[0].pos_x].mv[LIST_0].mv_y; + a_ref_idx = motion[mb[0].pos_y][mb[0].pos_x].ref_idx[LIST_0]; + + if (currMB->mb_field && !p_Vid->mb_data[mb[0].mb_addr].mb_field) + { + a_mv_y /=2; + a_ref_idx *=2; + } + if (!currMB->mb_field && p_Vid->mb_data[mb[0].mb_addr].mb_field) + { + a_mv_y *= 2; + a_ref_idx >>=1; + } + } + + if (mb[1].available) + { + b_mv_y = motion[mb[1].pos_y][mb[1].pos_x].mv[LIST_0].mv_y; + b_ref_idx = motion[mb[1].pos_y][mb[1].pos_x].ref_idx[LIST_0]; + + if (currMB->mb_field && !p_Vid->mb_data[mb[1].mb_addr].mb_field) + { + b_mv_y /=2; + b_ref_idx *=2; + } + if (!currMB->mb_field && p_Vid->mb_data[mb[1].mb_addr].mb_field) + { + b_mv_y *=2; + b_ref_idx >>=1; + } + } + + zeroMotionLeft = !mb[0].available ? 1 : a_ref_idx==0 && motion[mb[0].pos_y][mb[0].pos_x].mv[LIST_0].mv_x ==0 && a_mv_y==0 ? 1 : 0; + zeroMotionAbove = !mb[1].available ? 1 : b_ref_idx==0 && motion[mb[1].pos_y][mb[1].pos_x].mv[LIST_0].mv_x ==0 && b_mv_y==0 ? 1 : 0; + + if (zeroMotionAbove || zeroMotionLeft) + { + memset(&all_mv [0][0], 0, 16 * sizeof(MotionVector)); // 4 * 4 + } + else + { + currMB->GetMVPredictor (currMB, mb, &pmv, 0, motion, LIST_0, 0, 0, 16, 16); + + for (by = 0;by < 4;by++) + for (bx = 0;bx < 4;bx++) + { + all_mv [by][bx] = pmv; + } + } +} + +/*! + ************************************************************************ + * \brief + * Get cost for direct mode for an 8x8 block + ************************************************************************ + */ +distblk GetDirectCost8x8 (Macroblock *currMB, int block, distblk *cost8x8) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + int pic_pix_y, pic_pix_x, i, j; + + distblk cost = 0; + int mb_y = (block >> 1)<<3; + int mb_x = (block & 0x01)<<3; + imgpel **mb_pred = currSlice->mb_pred[0]; + int list_mode[2] = {0, 0}; + + // Check if valid + for (j=(currMB->opix_y + mb_y) >> 2; j < (currMB->opix_y + mb_y + 8) >> 2; j++) + { + for (i=(currMB->pix_x + mb_x) >> 2; i < (currMB->pix_x + mb_x + 8) >> 2; i++) + { + if (currSlice->direct_pdir[j][i] < 0) + { + *cost8x8 = DISTBLK_MAX; + return DISTBLK_MAX; //mode not allowed + } + } + } + + //===== Generate direct prediction ===== + for (j = mb_y; j < mb_y + 8; j += 4) + { + pic_pix_y = (currMB->opix_y + j) >> 2; + for (i = mb_x; i < mb_x + 8; i += 4) + { + pic_pix_x = (currMB->pix_x + i) >> 2; + p_Dpb->pf_luma_prediction (currMB, i, j, 4, 4, currSlice->direct_pdir[pic_pix_y][pic_pix_x], + list_mode, currSlice->direct_ref_idx[pic_pix_y][pic_pix_x], 0); + } + } + + if(p_Inp->Transform8x8Mode) + { + short diff16[4][16]; + short diff64[64]; + short *tmp64 = diff64; + short *tmp16[4]; //{diff16[0], diff16[1], diff16[2], diff16[3]}; + int index; + + tmp16[0] = diff16[0]; + tmp16[1] = diff16[1]; + tmp16[2] = diff16[2]; + tmp16[3] = diff16[3]; + + pic_pix_y = currMB->opix_y; + pic_pix_x = currMB->pix_x; + //===== get displaced frame difference ====== + //p_Dpb->pf_calcDifference(p_Vid->pCurImg, pic_pix_x+mb_x, pic_pix_y+mb_y, mb_pred, mb_x, mb_y, 8, 8, tmp64); + for (j = mb_y; j < 8 + mb_y; j++) + { + for (i = mb_x; i < 8 + mb_x; i++) + { + index = 2 * ((j - mb_y)> 3) + ((i - mb_x)> 3); + *tmp64++ = *(tmp16[index])++ = (short) (p_Vid->pCurImg[pic_pix_y + j][pic_pix_x + i] - mb_pred[j][i]); + } + } + + cost += p_Vid->distortion4x4 (diff16[0], DISTBLK_MAX); + cost += p_Vid->distortion4x4 (diff16[1], DISTBLK_MAX); + cost += p_Vid->distortion4x4 (diff16[2], DISTBLK_MAX); + cost += p_Vid->distortion4x4 (diff16[3], DISTBLK_MAX); + *cost8x8 += p_Vid->distortion8x8 (diff64, DISTBLK_MAX); + } + else + { + int block_y, block_x; + short diff16[16]; + short *diff; + + for (block_y=mb_y; block_y < mb_y + 8; block_y += 4) + { + pic_pix_y = currMB->opix_y + block_y; + + for (block_x=mb_x; block_xpix_x + block_x; + diff = diff16; + + //===== get displaced frame difference ====== + calcDifference(p_Vid->pCurImg, pic_pix_x, pic_pix_y, mb_pred, block_x, block_y, 4, 4, diff); + cost += p_Vid->distortion4x4 (diff16, DISTBLK_MAX); + } + } + } + + return cost; +} + + + +/*! + ************************************************************************ + * \brief + * Get cost for direct mode for an macroblock + ************************************************************************ + */ +distblk GetDirectCostMB (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + InputParameters *p_Inp = currSlice->p_Inp; + int i; + distblk cost = 0; + distblk cost8x8 = 0; + int bslice = currSlice->slice_type == B_SLICE; +#if (MVC_EXTENSION_ENABLE) + int *InterSearch = p_Inp->InterSearch[(currSlice->p_Vid->num_of_layers > 1) ? currSlice->view_id : 0][bslice]; +#else + int *InterSearch = p_Inp->InterSearch[0][bslice]; +#endif + + for (i=0; i<4; i++) + { + cost += GetDirectCost8x8 (currMB, i, &cost8x8); + if (cost8x8 == DISTBLK_MAX) return DISTBLK_MAX; + } + + switch(p_Inp->Transform8x8Mode) + { + case 1: // Mixture of 8x8 & 4x4 transform + if((cost8x8 < cost)|| + !(InterSearch[5] && + InterSearch[6] && + InterSearch[7]) + ) + { + cost = cost8x8; //return 8x8 cost + } + break; + case 2: // 8x8 Transform only + cost = cost8x8; + break; + default: // 4x4 Transform only + break; + } + + return cost; +} + +/*! + ************************************************************************ + * \brief + * Motion search for a macroblock partition + ************************************************************************ + */ +void PartitionMotionSearch (Macroblock *currMB, + int blocktype, + int block8x8, + int *lambda_factor) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + +#if GET_METIME + TIME_T me_time_start; + TIME_T me_time_end; + int64 me_tmp_time; + gettime( &me_time_start ); // start time ms +#endif + + if (currSlice->rdoq_motion_copy == 1) + { + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + short by = by0[blocktype][block8x8]; + short bx = bx0[blocktype][block8x8]; + short step_h = (part_size[blocktype][0]); + short step_v = (part_size[blocktype][1]); + + short pic_block_y = currMB->block_y + by; + short pic_block_x = currMB->block_x + bx; + int list_offset = currMB->list_offset; + int numlists = (currSlice->slice_type == B_SLICE) ? 2 : 1; + distblk *m_cost; + + short list = LIST_0; + short ref = 0; + + //===== LOOP OVER REFERENCE FRAMES ===== + for (list = 0; list < numlists; list++) + { + for (ref=0; ref < currSlice->listXsize[list+list_offset]; ref++) + { + m_cost = &p_Vid->motion_cost[blocktype][list][ref][block8x8]; + + //===== LOOP OVER SUB MACRO BLOCK partitions + updateMV_mp(currMB, m_cost, ref, list, bx, by, blocktype, block8x8); + set_me_parameters(motion, &currSlice->all_mv[list][ref][blocktype][by][bx], list, (char) ref, step_h, step_v, pic_block_y, pic_block_x); + } + } + } + else + { + InputParameters *p_Inp = currMB->p_Inp; + short by = by0[blocktype][block8x8]; + short bx = bx0[blocktype][block8x8]; + short step_h = (part_size[blocktype][0]); + short step_v = (part_size[blocktype][1]); + + short pic_block_y = currMB->block_y + by; + short pic_block_x = currMB->block_x + bx; + int list_offset = currMB->list_offset; + int numlists = (currSlice->slice_type == B_SLICE) ? 2 : 1; + short list = LIST_0; + short ref = 0; + MEBlock mv_block; + distblk *m_cost; + + + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + // Set flag for 8x8 Hadamard consideration for SATD (only used when 8x8 integer transform is used for encoding) + mv_block.test8x8 = p_Inp->Transform8x8Mode; + + init_mv_block(currMB, &mv_block, (short) blocktype, list, (char) ref, bx, by); + + if (p_Inp->SearchMode[p_Vid->view_id] == EPZS) + { + if (p_Inp->EPZSSubPelGrid) + currMB->IntPelME = EPZS_integer_motion_estimation; + else + currMB->IntPelME = EPZS_motion_estimation; + } + + get_original_block(p_Vid, &mv_block); + + //--- motion search for block --- + { + //===== LOOP OVER REFERENCE FRAMES ===== + for (list = 0; list < numlists; list++) + { + //----- set arrays ----- + mv_block.list = (char) list; + for (ref=0; ref < currSlice->listXsize[list+list_offset]; ref++) + { + mv_block.ref_idx = (char) ref; + m_cost = &p_Vid->motion_cost[blocktype][list][ref][block8x8]; + + { + //----- set search range --- + get_search_range(&mv_block, p_Inp, ref, blocktype); + + //===== LOOP OVER MACROBLOCK partitions + *m_cost = BlockMotionSearch (currMB, &mv_block, bx<<2, by<<2, lambda_factor); + } + //--- set motion vectors and reference frame --- + set_me_parameters(motion, &currSlice->all_mv[list][ref][blocktype][by][bx], list, (char) ref, step_h, step_v, pic_block_y, pic_block_x); + } + } + } + + free_mv_block(&mv_block); + } + +#if GET_METIME + gettime(&me_time_end); // end time ms + me_tmp_time = timediff (&me_time_start, &me_time_end); + p_Vid->me_tot_time += me_tmp_time; + p_Vid->me_time += me_tmp_time; +#endif +} + +/*! + ************************************************************************ + * \brief + * Motion search for a submacroblock partition + ************************************************************************ + */ +void SubPartitionMotionSearch (Macroblock *currMB, + int blocktype, + int block8x8, + int *lambda_factor) + +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + +#if GET_METIME + TIME_T me_time_start; + TIME_T me_time_end; + int64 me_tmp_time; + gettime( &me_time_start ); // start time ms +#endif + + if (currSlice->rdoq_motion_copy == 1) + { + int parttype = 4; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + short by = by0[parttype][block8x8]; + short bx = bx0[parttype][block8x8]; + short step_h = (part_size[blocktype][0]); + short step_v = (part_size[blocktype][1]); + int list_offset = currMB->list_offset; + int numlists = (currSlice->slice_type == B_SLICE) ? 2 : 1; + distblk *m_cost; + MotionVector *all_mv; + short list = LIST_0; + short ref = 0; + + short step_h0 = (part_size[ parttype][0]); + short step_v0 = (part_size[ parttype][1]); + + int v, h; + int pic_block_y; + + //===== LOOP OVER REFERENCE FRAMES ===== + for (list = 0; list < numlists; list++) + { + for (ref=0; ref < currSlice->listXsize[list+list_offset]; ref++) + { + m_cost = &p_Vid->motion_cost[blocktype][list][ref][block8x8]; + + //===== LOOP OVER SUB MACRO BLOCK partitions + for (v=by; vblock_y + v; + for (h=bx; hall_mv[list][ref][blocktype][v][h]; + + updateMV_mp(currMB, m_cost, ref, list, h, v, blocktype, block8x8); + + //--- set motion vectors and reference frame (for motion vector prediction) --- + set_me_parameters(motion, all_mv, list, (char) ref, step_h, step_v, pic_block_y, currMB->block_x + h); + } // h + } // v + } + } + } + else + { + InputParameters *p_Inp = currMB->p_Inp; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int parttype = 4; + short by = by0[parttype][block8x8]; + short bx = bx0[parttype][block8x8]; + short step_h0 = (part_size[ parttype][0]); + short step_v0 = (part_size[ parttype][1]); + short step_h = (part_size[blocktype][0]); + short step_v = (part_size[blocktype][1]); + int list_offset = currMB->list_offset; + int numlists = (currSlice->slice_type == B_SLICE) ? 2 : 1; + MotionVector *all_mv; + short list = LIST_0; + short ref = 0; + MEBlock mv_block; + distblk *m_cost; + distblk mcost; + int v, h; + int pic_block_y; + + // Set if 8x8 transform will be used if SATD is used + mv_block.test8x8 = p_Inp->Transform8x8Mode && blocktype == 4; + + if (p_Inp->SearchMode[p_Vid->view_id] == EPZS) + { + if (p_Inp->EPZSSubPelGrid) + { + if (blocktype > 4) + currMB->IntPelME = EPZS_integer_subMB_motion_estimation; + else + currMB->IntPelME = EPZS_integer_motion_estimation; + } + else + { + if (blocktype > 4) + currMB->IntPelME = EPZS_subMB_motion_estimation; + else + currMB->IntPelME = EPZS_motion_estimation; + } + } + + init_mv_block(currMB, &mv_block, (short) blocktype, list, (char) ref, bx, by); + + if (blocktype == 4) + get_original_block(p_Vid, &mv_block); + + //===== LOOP OVER REFERENCE FRAMES ===== + for (list=0; listlistXsize[list+list_offset]; ref++) + { + mv_block.ref_idx = (char) ref; + m_cost = &p_Vid->motion_cost[blocktype][list][ref][block8x8]; + //----- set search range --- + get_search_range(&mv_block, p_Inp, ref, blocktype); + + //----- init motion cost ----- + *m_cost = 0; + + //===== LOOP OVER SUB MACRO BLOCK partitions + for (v=by; vblock_y + v; + + for (h=bx; hall_mv[list][ref][blocktype][v][h]; + + //--- motion search for block --- + update_mv_block(currMB, &mv_block, h, v); + { + //----- set search range --- + get_search_range(&mv_block, p_Inp, ref, blocktype); + + mcost = BlockMotionSearch (currMB, &mv_block, h<<2, v<<2, lambda_factor); + + *m_cost += mcost; + } + //--- set motion vectors and reference frame (for motion vector prediction) --- + set_me_parameters(motion, all_mv, list, (char) ref, step_h, step_v, pic_block_y, currMB->block_x + h); + } + } + + if ((p_Inp->Transform8x8Mode == 1) && p_Inp->RDOQ_CP_MV && (blocktype == 4)) + { + if (currMB->luma_transform_size_8x8_flag) + { + currSlice->tmp_mv8[list][ref][by][bx] = currSlice->all_mv[list][ref][blocktype][by][bx]; + currSlice->motion_cost8[list][ref][block8x8] = *m_cost; + } + else + { + currSlice->tmp_mv4[list][ref][by][bx] = currSlice->all_mv[list][ref][blocktype][by][bx]; + currSlice->motion_cost4[list][ref][block8x8] = *m_cost; + } + } + } + + } + + free_mv_block(&mv_block); + } + +#if GET_METIME + gettime(&me_time_end); // end time ms + me_tmp_time = timediff (&me_time_start, &me_time_end); + p_Vid->me_tot_time += me_tmp_time; + p_Vid->me_time += me_tmp_time; +#endif +} + + diff --git a/lencod/src/nal.c b/lencod/src/nal.c new file mode 100644 index 0000000..fc2f35a --- /dev/null +++ b/lencod/src/nal.c @@ -0,0 +1,145 @@ + +/*! + ************************************************************************************** + * \file + * nal.c + * \brief + * Handles the operations on converting String of Data Bits (SODB) + * to Raw Byte Sequence Payload (RBSP), and then + * onto Encapsulate Byte Sequence Payload (EBSP). + * \date 14 June 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Shankar Regunathan + * - Stephan Wenger + *************************************************************************************** + */ + +#include "contributors.h" +#include "global.h" +#include "enc_statistics.h" +#include "biariencode.h" +#include "nal.h" + +static const int MbWidthC [4]= { 0, 8, 8, 16}; +static const int MbHeightC [4]= { 0, 8, 16, 16}; + + /*! + ************************************************************************ + * \brief + * Converts String Of Data Bits (SODB) to Raw Byte Sequence + * Packet (RBSP) + * \param currStream + * Bitstream which contains data bits. + * \return None + * \note currStream is byte-aligned at the end of this function + * + ************************************************************************ +*/ + +void SODBtoRBSP(Bitstream *currStream) +{ + currStream->byte_buf <<= 1; + currStream->byte_buf |= 1; + currStream->bits_to_go--; + currStream->byte_buf <<= currStream->bits_to_go; + currStream->streamBuffer[currStream->byte_pos++] = currStream->byte_buf; + currStream->bits_to_go = 8; + currStream->byte_buf = 0; +} + + +/*! +************************************************************************ +* \brief +* This function add emulation_prevention_three_byte for all occurrences +* of the following byte sequences in the stream +* 0x000000 -> 0x00000300 +* 0x000001 -> 0x00000301 +* 0x000002 -> 0x00000302 +* 0x000003 -> 0x00000303 +* +* \param NaluBuffer +* pointer to target buffer +* \param rbsp +* pointer to source buffer +* \param rbsp_size +* Size of source +* \return +* Size target buffer after emulation prevention. +* +************************************************************************ +*/ + +int RBSPtoEBSP(byte *NaluBuffer, unsigned char *rbsp, int rbsp_size) +{ + int j = 0; + int count = 0; + int i; + + for(i = 0; i < rbsp_size; i++) + { + if(count == ZEROBYTES_SHORTSTARTCODE && !(rbsp[i] & 0xFC)) + { + NaluBuffer[j] = 0x03; + j++; + count = 0; + } + NaluBuffer[j] = rbsp[i]; + if(rbsp[i] == 0x00) + count++; + else + count = 0; + j++; + } + + return j; +} + +/*! +************************************************************************ +* \brief +* This function adds cabac_zero_word syntax elements at the end of the +* NAL unit to +* +* \param p_Vid +* VideoParameters structure +* \param nalu +* target NAL unit +* \param cur_stats +* currently used statistics parameters +* \return +* number of added bytes +* +************************************************************************ +*/ +int addCabacZeroWords(VideoParameters *p_Vid, NALU_t *nalu, StatParameters *cur_stats) +{ + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int stuffing_bytes = 0; + int i = 0; + + byte *buf = &nalu->buf[nalu->len]; + + int RawMbBits = 256 * p_Vid->bitdepth_luma + 2 * MbWidthC[active_sps->chroma_format_idc] * MbHeightC[active_sps->chroma_format_idc] * p_Vid->bitdepth_chroma; + int min_num_bytes = ((96 * get_pic_bin_count(p_Vid)) - (RawMbBits * (int)p_Vid->PicSizeInMbs *3) + 1023) / 1024; + + if (min_num_bytes > p_Vid->bytes_in_picture) + { + stuffing_bytes = min_num_bytes - p_Vid->bytes_in_picture; + printf ("Inserting %d/%d cabac_zero_word syntax elements/bytes (Clause 7.4.2.10)\n", ((stuffing_bytes + 2)/3), stuffing_bytes); + + for (i = 0; i < stuffing_bytes; i+=3 ) + { + *buf++ = 0x00; // CABAC zero word + *buf++ = 0x00; + *buf++ = 0x03; + } + cur_stats->bit_use_stuffing_bits[p_Vid->type] += (i<<3); + nalu->len += i; + } + + return i; +} + diff --git a/lencod/src/nalu.c b/lencod/src/nalu.c new file mode 100644 index 0000000..01c4619 --- /dev/null +++ b/lencod/src/nalu.c @@ -0,0 +1,164 @@ + +/*! + ************************************************************************ + * \file nalu.c + * + * \brief + * Common NALU support functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + ************************************************************************ + */ + +#include "global.h" +#include "nalu.h" +#include "nal.h" + +/*! + ************************************************************************************* + * \brief + * Converts an RBSP to a NALU + * + * \param rbsp + * byte buffer with the rbsp + * \param nalu + * nalu structure to be filled + * \param rbsp_size + * size of the rbsp in bytes + * \param nal_unit_type + * as in JVT doc + * \param nal_reference_idc + * as in JVT doc + * \param UseAnnexbLongStartcode + * some incomprehensible CABAC stuff + * \param UseAnnexbLongStartcode + * when 1 and when using AnnexB bytestreams, then use a long startcode prefix + * + * \return + * length of the NALU in bytes + ************************************************************************************* + */ + +int RBSPtoNALU (unsigned char *rbsp, NALU_t *nalu, int rbsp_size, int nal_unit_type, int nal_reference_idc, int UseAnnexbLongStartcode) +{ + int len; + + assert (nalu != NULL); + assert (nal_reference_idc <=3 && nal_reference_idc >=0); +#if (MVC_EXTENSION_ENABLE) + assert (nal_unit_type > 0 && nal_unit_type <= NALU_TYPE_SLC_EXT); +#else + assert (nal_unit_type > 0 && nal_unit_type <= NALU_TYPE_FILL); +#endif + assert (rbsp_size < MAXRBSPSIZE); + + nalu->startcodeprefix_len = UseAnnexbLongStartcode ? 4 : 3; + nalu->forbidden_bit = 0; + nalu->nal_reference_idc = (NalRefIdc) nal_reference_idc; + nalu->nal_unit_type = (NaluType) nal_unit_type; + +#if (MVC_EXTENSION_ENABLE) + if(nal_unit_type==NALU_TYPE_PREFIX || nal_unit_type==NALU_TYPE_SLC_EXT) + { + nalu->svc_extension_flag = 0; + //nalu->non_idr_flag = (nal_reference_idc==NALU_PRIORITY_HIGHEST) ? 0:1; + nalu->reserved_one_bit = 1; + + } + else + nalu->svc_extension_flag = 0; +#endif + + + len = RBSPtoEBSP (nalu->buf, rbsp, rbsp_size); + nalu->len = len; + + return len; +} + +/*! + ************************************************************************ + * \brief + * write AUD NALU + ************************************************************************ + */ + +int Write_AUD_NALU( VideoParameters *p_Vid ) +{ + int RBSPlen = 0; + int len; + byte rbsp[MAXRBSPSIZE]; + NALU_t *nalu = AllocNALU( MAXNALUSIZE ); + + switch( p_Vid->type ) + { + case I_SLICE: + p_Vid->primary_pic_type = 0; + break; + case P_SLICE: + p_Vid->primary_pic_type = 1; + break; + case B_SLICE: + p_Vid->primary_pic_type = 2; + break; + } + RBSPlen = 1; + rbsp[0] = (byte) (p_Vid->primary_pic_type << 5); + rbsp[0] |= (1 << 4); + + // write RBSP into NALU + RBSPtoNALU( rbsp, nalu, RBSPlen, NALU_TYPE_AUD, NALU_PRIORITY_DISPOSABLE, 1 ); + // write NALU into bitstream + len = p_Vid->WriteNALU( p_Vid, nalu, p_Vid->f_out ); + + FreeNALU( nalu ); + + return len; +} + +/*! + ************************************************************************ + * \brief + * write Filler Data NALU (results to num_bytes + 4 bytes written) + ************************************************************************ + */ + +int Write_Filler_Data_NALU( VideoParameters *p_Vid, int num_bytes ) +{ + int RBSPlen = num_bytes - 1; + int len, bytes_written = 0; + byte rbsp[MAXRBSPSIZE]; + byte filler_byte = (byte)0xFF; + byte trailing_byte = (byte)0x80; + NALU_t *nalu = AllocNALU( MAXNALUSIZE ); + + num_bytes = iClip3( 1, (MAXRBSPSIZE - 2), num_bytes ); + assert( num_bytes > 0 && num_bytes < (MAXRBSPSIZE - 1) ); + + num_bytes = imax( 2, num_bytes ); // one byte for the NAL header and one for the rbsp trailing byte + + if ( RBSPlen > 1 ) + { + while ( bytes_written < (RBSPlen - 1) ) + { + rbsp[ bytes_written++ ] = filler_byte; + } + } + rbsp[ bytes_written++ ] = trailing_byte; // rbsp_trailing_bits + assert( num_bytes == (bytes_written + 1) ); + + // write RBSP into NALU + RBSPtoNALU( rbsp, nalu, RBSPlen, NALU_TYPE_FILL, NALU_PRIORITY_DISPOSABLE, 1 ); + // write NALU into bitstream + len = p_Vid->WriteNALU( p_Vid, nalu, p_Vid->f_out ); + p_Vid->bytes_in_picture += (nalu->len + 1); + + FreeNALU( nalu ); + + return len; +} + + + diff --git a/lencod/src/output.c b/lencod/src/output.c new file mode 100644 index 0000000..a493f85 --- /dev/null +++ b/lencod/src/output.c @@ -0,0 +1,556 @@ + +/*! + ************************************************************************ + * \file output.c + * + * \brief + * Output an image and Trance support + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + ************************************************************************ + */ + +#include "contributors.h" +#include "global.h" +#include "image.h" +#include "input.h" +#include "output.h" + +/*! + ************************************************************************ + * \brief + * Convert image plane to temporary buffer for file writing + * \param imgX + * Pointer to image plane + * \param buf + * Buffer for file output + * \param size_x + * horizontal size + * \param size_y + * vertical size + * \param symbol_size_in_bytes + * number of bytes used per pel + * \param crop_left + * pixels to crop from left + * \param crop_right + * pixels to crop from right + * \param crop_top + * pixels to crop from top + * \param crop_bottom + * pixels to crop from bottom + ************************************************************************ + */ +void img2buf (imgpel** imgX, unsigned char* buf, int size_x, int size_y, int symbol_size_in_bytes, int crop_left, int crop_right, int crop_top, int crop_bottom) +{ + int i,j; + + int twidth = size_x - crop_left - crop_right; + int theight = size_y - crop_top - crop_bottom; + int size = 0; + unsigned char ui8; + uint16 tmp16, ui16; + unsigned long tmp32, ui32; + + if (( sizeof(char) == sizeof (imgpel)) && ( sizeof(char) == symbol_size_in_bytes)) + { + // imgpel == pixel_in_file == 1 byte -> simple copy + if (crop_left == 0 && crop_top == 0 && crop_right == 0 && crop_bottom == 0) + { + //memcpy(buf,&(imgX[0][0]), twidth * theight); + for(j=0; j sizeof(char) + if (testEndian()) + { + // big endian + switch (symbol_size_in_bytes) + { + case 1: + { + for(i=crop_top;i> 8) | ((tmp16&0xFF)<<8); + memcpy(buf+((j-crop_left+((i-crop_top)*(twidth)))*2),&(ui16), 2); + } + break; + } + case 4: + { + for(i=crop_top;i>8) | ((tmp32&0xFF000000)>>24); + memcpy(buf+((j-crop_left+((i-crop_top)*(twidth)))*4),&(ui32), 4); + } + break; + } + default: + { + error ("writing only to formats of 8, 16 or 32 bit allowed on big endian architecture", 500); + break; + } + } + + } + else + { + // little endian + if (sizeof (imgpel) < symbol_size_in_bytes) + { + // this should not happen. we should not have smaller imgpel than our source material. + size = sizeof (imgpel); + // clear buffer + memset (buf, 0, (twidth*theight*symbol_size_in_bytes)); + } + else + { + size = symbol_size_in_bytes; + } + + for(i=crop_top;ipic_unit_size_shift3; + Boolean rgb_output = (Boolean) (output->color_model != CM_YUV && output->yuv_format == YUV444); + unsigned char *buf; + + if (p->non_existing) + return; + + if (p_out == -1) + return; + + if (p->frame_cropping_flag) + { + crop_left = SubWidthC[p->chroma_format_idc] * p->frame_crop_left_offset; + crop_right = SubWidthC[p->chroma_format_idc] * p->frame_crop_right_offset; + crop_top = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + + //printf ("write frame size: %dx%d\n", p->size_x-crop_left-crop_right,p->size_y-crop_top-crop_bottom ); + + // KS: this buffer should actually be allocated only once, but this is still much faster than the previous version + buf = malloc (p->size_x * p->size_y * symbol_size_in_bytes); + if (NULL==buf) + { + no_mem_exit("write_out_picture: buf"); + } + + if(rgb_output) + { + crop_left = p->frame_crop_left_offset; + crop_right = p->frame_crop_right_offset; + crop_top = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + + img2buf (p->imgUV[1], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to RGB output file.", 500); + } + + if (p->frame_cropping_flag) + { + crop_left = SubWidthC[p->chroma_format_idc] * p->frame_crop_left_offset; + crop_right = SubWidthC[p->chroma_format_idc] * p->frame_crop_right_offset; + crop_top = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = SubHeightC[p->chroma_format_idc]*( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + } + else + { + crop_left = crop_right = crop_top = crop_bottom = 0; + } + } + + img2buf (p->imgY, buf, p->size_x, p->size_y, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y-crop_bottom-crop_top)*(p->size_x-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y-crop_bottom-crop_top)*(p->size_x-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV output file.", 500); + } + + if (p->chroma_format_idc != YUV400) + { + crop_left = p->frame_crop_left_offset; + crop_right = p->frame_crop_right_offset; + crop_top = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_top_offset; + crop_bottom = ( 2 - p->frame_mbs_only_flag ) * p->frame_crop_bottom_offset; + + img2buf (p->imgUV[0], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)* symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)* symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV output file.", 500); + } + + if (!rgb_output) + { + img2buf (p->imgUV[1], buf, p->size_x_cr, p->size_y_cr, symbol_size_in_bytes, crop_left, crop_right, crop_top, crop_bottom); + ret = write(p_out, buf, (p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes); + if (ret != ((p->size_y_cr-crop_bottom-crop_top)*(p->size_x_cr-crop_right-crop_left)*symbol_size_in_bytes)) + { + error ("write_out_picture: error writing to YUV output file.", 500); + } + } + } + + free(buf); + +// fsync(p_out); +} + +/*! + ************************************************************************ + * \brief + * Initialize output buffer for direct output + ************************************************************************ + */ +void init_out_buffer(VideoParameters *p_Vid) +{ + p_Vid->out_buffer = alloc_frame_store(); +} + +/*! + ************************************************************************ + * \brief + * Uninitialize output buffer for direct output + ************************************************************************ + */ +void uninit_out_buffer(VideoParameters *p_Vid) +{ + free_frame_store(p_Vid, p_Vid->out_buffer); + p_Vid->out_buffer=NULL; +} + +/*! + ************************************************************************ + * \brief + * Initialize picture memory with (Y:0,U:128,V:128) + ************************************************************************ + */ +void clear_picture(VideoParameters *p_Vid, StorablePicture *p) +{ + int i; + + if (p_Vid->bitdepth_luma == 8) + { + // this does not seem to be right since it seems to work only for imgpel == byte + // should be fixed + for(i=0;isize_y;i++) + memset(p->imgY[i], p_Vid->dc_pred_value_comp[0], p->size_x*sizeof(imgpel)); + } + else + { + int j; + for(i=0;i < p->size_y; i++) + for(j=0;j < p->size_x; j++) + p->imgY[i][j] = (imgpel) p_Vid->dc_pred_value_comp[0]; + } + + if (p_Vid->bitdepth_chroma == 8) + { + for(i=0;isize_y_cr;i++) + memset(p->imgUV[0][i], p_Vid->dc_pred_value_comp[1], p->size_x_cr*sizeof(imgpel)); + for(i=0;isize_y_cr;i++) + memset(p->imgUV[1][i], p_Vid->dc_pred_value_comp[2], p->size_x_cr*sizeof(imgpel)); + } + else + { + int k, j; + for (k = 0; k < 2; k++) + { + for(i=0;isize_y_cr;i++) + for(j=0;j < p->size_x_cr; j++) + p->imgUV[k][i][j] = (imgpel) p_Vid->dc_pred_value_comp[1]; + } + } +} + +/*! + ************************************************************************ + * \brief + * Write out not paired direct output fields. A second empty field is generated + * and combined into the frame buffer. + * \param p_Vid + * point to VideoParameters + * \param fs + * FrameStore that contains a single field + * \param output + * Frame format to + * \param p_out + * Output file + ************************************************************************ + */ +void write_unpaired_field(VideoParameters *p_Vid, FrameStore* fs, FrameFormat *output, int p_out) +{ + StorablePicture *p; + assert (fs->is_used<3); + if(fs->is_used &1) + { + // we have a top field + // construct an empty bottom field + p = fs->top_field; + fs->bottom_field = alloc_storable_picture(p_Vid, BOTTOM_FIELD, p->size_x, p->size_y, p->size_x_cr, p->size_y_cr); + fs->bottom_field->chroma_format_idc = p->chroma_format_idc; + fs->bottom_field->chroma_mask_mv_x = p->chroma_mask_mv_x; + fs->bottom_field->chroma_mask_mv_y = p->chroma_mask_mv_y; + fs->bottom_field->chroma_shift_x = p->chroma_shift_x; + fs->bottom_field->chroma_shift_y = p->chroma_shift_y; + + clear_picture(p_Vid, fs->bottom_field); + dpb_combine_field_yuv(p_Vid, fs); + write_picture (fs->frame, output, p_out); + } + + if(fs->is_used &2) + { + // we have a bottom field + // construct an empty top field + p = fs->bottom_field; + fs->top_field = alloc_storable_picture(p_Vid, TOP_FIELD, p->size_x, p->size_y, p->size_x_cr, p->size_y_cr); + clear_picture(p_Vid, fs->top_field); + fs->top_field->chroma_format_idc = p->chroma_format_idc; + fs->top_field->chroma_mask_mv_x = p->chroma_mask_mv_x; + fs->top_field->chroma_mask_mv_y = p->chroma_mask_mv_y; + fs->top_field->chroma_shift_x = p->chroma_shift_x; + fs->top_field->chroma_shift_y = p->chroma_shift_y; + + clear_picture(p_Vid, fs->top_field); + fs ->top_field->frame_cropping_flag = fs->bottom_field->frame_cropping_flag; + if(fs ->top_field->frame_cropping_flag) + { + fs ->top_field->frame_crop_top_offset = fs->bottom_field->frame_crop_top_offset; + fs ->top_field->frame_crop_bottom_offset = fs->bottom_field->frame_crop_bottom_offset; + fs ->top_field->frame_crop_left_offset = fs->bottom_field->frame_crop_left_offset; + fs ->top_field->frame_crop_right_offset = fs->bottom_field->frame_crop_right_offset; + } + dpb_combine_field_yuv(p_Vid, fs); + write_picture (fs->frame, output, p_out); + } + + fs->is_used=3; +} + +/*! + ************************************************************************ + * \brief + * Write out unpaired fields from output buffer. + * \param p_Vid + * VideoParameters structure + * \param output + * FrameFormat structure for output + * \param p_out + * Output file + ************************************************************************ + */ +void flush_direct_output(VideoParameters *p_Vid, FrameFormat *output, int p_out) +{ + write_unpaired_field(p_Vid, p_Vid->out_buffer, output, p_out); + + free_storable_picture(p_Vid, p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; +} + + +/*! + ************************************************************************ + * \brief + * Write a frame (from FrameStore) + * \param p_Vid + * VideoParameters structure + * \param fs + * FrameStore containing the frame + * \param output + * Frame format for output + * \param p_out + * Output file + ************************************************************************ + */ +void write_stored_frame( VideoParameters *p_Vid, FrameStore *fs, FrameFormat *output, int p_out) +{ + // make sure no direct output field is pending + flush_direct_output(p_Vid, output, p_out); + + if (fs->is_used<3) + { + write_unpaired_field(p_Vid, fs, output, p_out); + } + else + { + write_picture(fs->frame, output, p_out); + } + + fs->is_output = 1; +} + + +/*! + ************************************************************************ + * \brief + * Directly output a picture without storing it in the DPB. Fields + * are buffered before they are written to the file. + * \param p_Vid + * VideoParameters structure + * \param p + * Picture for output + * \param output + * Frame format for output + * \param p_out + * Output file + ************************************************************************ + */ +void direct_output(VideoParameters *p_Vid, StorablePicture *p, FrameFormat *output, int p_out) +{ + switch ( p->structure ) + { + case FRAME: + // we have a frame (or complementary field pair) + // so output it directly + flush_direct_output(p_Vid, output, p_out); + write_picture (p, output, p_out); + free_storable_picture(p_Vid, p); + return; + break; + case TOP_FIELD: + if (p_Vid->out_buffer->is_used &1) + flush_direct_output(p_Vid, output, p_out); + p_Vid->out_buffer->top_field = p; + p_Vid->out_buffer->is_used |= 1; + break; + case BOTTOM_FIELD: + if (p_Vid->out_buffer->is_used &2) + flush_direct_output(p_Vid, output, p_out); + p_Vid->out_buffer->bottom_field = p; + p_Vid->out_buffer->is_used |= 2; + break; + default: + printf("invalid picture type\n"); + break; + } + + if (p_Vid->out_buffer->is_used == 3) + { + // we have both fields, so output them + dpb_combine_field_yuv(p_Vid, p_Vid->out_buffer); + write_picture (p_Vid->out_buffer->frame, output, p_out); + free_storable_picture(p_Vid, p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; + } +} + + +/*! +************************************************************************ +* \brief +* For adaptive frame/field coding remove dangling top field from direct +* output frame version instead. +* \param p_Vid +* Picture for output +* \param p +* Picture for output +* \param output +* Frame format for output +* \param p_out +* Output file +************************************************************************ +*/ +void direct_output_paff(VideoParameters *p_Vid, StorablePicture *p, FrameFormat *output, int p_out) +{ + printf("Warning!!! Frame can't fit in DPB. Displayed out of sequence.\n"); + free_storable_picture(p_Vid, p_Vid->out_buffer->frame); + p_Vid->out_buffer->frame = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->top_field); + p_Vid->out_buffer->top_field = NULL; + free_storable_picture(p_Vid, p_Vid->out_buffer->bottom_field); + p_Vid->out_buffer->bottom_field = NULL; + p_Vid->out_buffer->is_used = 0; + + direct_output(p_Vid, p, output, p_out); +} diff --git a/lencod/src/parset.c b/lencod/src/parset.c new file mode 100644 index 0000000..de9bcbe --- /dev/null +++ b/lencod/src/parset.c @@ -0,0 +1,1453 @@ +/*! + ************************************************************************************** + * \file + * parset.c + * \brief + * Picture and Sequence Parameter set generation and handling + * \date 25 November 2002 + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Stephan Wenger + * + ************************************************************************************** + */ + +#include +#include + +#include "global.h" + +#include "contributors.h" +#include "nal.h" +#include "mbuffer.h" +#include "parset.h" +#include "vlc.h" +#include "q_matrix.h" + +// Local helpers +static int identify_profile(InputParameters *p_Inp); +static int identify_level(InputParameters *p_Inp); +static int GenerateVUI_parameters_rbsp(seq_parameter_set_rbsp_t *sps, Bitstream *bitstream); + +static const byte ZZ_SCAN[16] = +{ + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + +static const byte ZZ_SCAN8[64] = +{ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + + +/*! + ************************************************************************************* + * \brief + * generates a sequence and picture parameter set and stores these in global + * active_sps and active_pps + * + * \return + * A NALU containing the Sequence ParameterSet + * + ************************************************************************************* +*/ +void generate_parameter_sets (VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i; + seq_parameter_set_rbsp_t *sps = NULL; + + sps = AllocSPS(); + + for (i=0; iPicParSet[i] = NULL; + } + + GenerateSequenceParameterSet(sps, p_Vid, 0); + + if (p_Inp->GenerateMultiplePPS) + { + p_Vid->PicParSet[0] = AllocPPS(); + p_Vid->PicParSet[1] = AllocPPS(); + p_Vid->PicParSet[2] = AllocPPS(); + + if (is_FREXT_profile(sps->profile_idc)) + { + GeneratePictureParameterSet( p_Vid->PicParSet[0], sps, p_Vid, p_Inp, 0, 0, 0, p_Inp->cb_qp_index_offset, p_Inp->cr_qp_index_offset); + GeneratePictureParameterSet( p_Vid->PicParSet[1], sps, p_Vid, p_Inp, 1, 1, 1, p_Inp->cb_qp_index_offset, p_Inp->cr_qp_index_offset); + GeneratePictureParameterSet( p_Vid->PicParSet[2], sps, p_Vid, p_Inp, 2, 1, 2, p_Inp->cb_qp_index_offset, p_Inp->cr_qp_index_offset); + } + else + { + GeneratePictureParameterSet( p_Vid->PicParSet[0], sps, p_Vid, p_Inp, 0, 0, 0, p_Inp->chroma_qp_index_offset, 0); + GeneratePictureParameterSet( p_Vid->PicParSet[1], sps, p_Vid, p_Inp, 1, 1, 1, p_Inp->chroma_qp_index_offset, 0); + GeneratePictureParameterSet( p_Vid->PicParSet[2], sps, p_Vid, p_Inp, 2, 1, 2, p_Inp->chroma_qp_index_offset, 0); + } + } + else + { + p_Vid->PicParSet[0] = AllocPPS(); + if (is_FREXT_profile(sps->profile_idc)) + GeneratePictureParameterSet( p_Vid->PicParSet[0], sps, p_Vid, p_Inp, 0, p_Inp->WeightedPrediction, p_Inp->WeightedBiprediction, + p_Inp->cb_qp_index_offset, p_Inp->cr_qp_index_offset); + else + GeneratePictureParameterSet( p_Vid->PicParSet[0], sps, p_Vid, p_Inp, 0, p_Inp->WeightedPrediction, p_Inp->WeightedBiprediction, + p_Inp->chroma_qp_index_offset, 0); + } + + p_Vid->active_sps = sps; + p_Vid->active_pps = p_Vid->PicParSet[0]; + // + p_Vid->sps[0] = sps; + if(p_Vid->num_of_layers == 2) + { + p_Vid->sps[1] = AllocSPS(); + *(p_Vid->sps[1]) = *sps; + } + else + p_Vid->sps[1] = NULL; +} + +/*! +************************************************************************************* +* \brief +* frees global parameter sets active_sps and active_pps +* +* \return +* A NALU containing the Sequence ParameterSet +* +************************************************************************************* +*/ +void FreeParameterSets (VideoParameters *p_Vid) +{ + int i; + for (i=0; iPicParSet[i]) + { + FreePPS(p_Vid->PicParSet[i]); + p_Vid->PicParSet[i] = NULL; + } + } + for(i=0; inum_of_layers; i++) + if(p_Vid->sps[i]) + { + FreeSPS(p_Vid->sps[i]); + p_Vid->sps[i] = NULL; + } + p_Vid->active_sps = NULL; +} + +/*! +************************************************************************************* +* \brief +* int GenerateSeq_parameter_set_NALU (VideoParameters *p_Vid); +* +* \note +* Uses the global variables through GenerateSequenceParameterSet() +* and GeneratePictureParameterSet +* \param p_Vid +* VideoParameters structure +* \return +* A NALU containing the Sequence ParameterSet +* +************************************************************************************* +*/ + +NALU_t *GenerateSeq_parameter_set_NALU (VideoParameters *p_Vid) +{ + NALU_t *n = AllocNALU(MAXNALUSIZE); + int RBSPlen = 0; + byte rbsp[MAXRBSPSIZE]; + +#if (MVC_EXTENSION_ENABLE) + RBSPlen = GenerateSeq_parameter_set_rbsp (p_Vid, p_Vid->sps[0]/*p_Vid->active_sps*/, rbsp, 0); +#else + RBSPlen = GenerateSeq_parameter_set_rbsp (p_Vid, p_Vid->active_sps, rbsp); +#endif + RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_SPS, NALU_PRIORITY_HIGHEST, 1); + n->startcodeprefix_len = 4; + + return n; +} + +#if (MVC_EXTENSION_ENABLE) +/*! +************************************************************************************* +* \brief +* int GenerateSubsetSeq_parameter_set_NALU (VideoParameters *p_Vid); +* +* \note +* Uses the global variables through GenerateSequenceParameterSet() +* and GeneratePictureParameterSet +* \param p_Vid +* VideoParameters structure +* \return +* A NALU containing the Sequence ParameterSet +* +************************************************************************************* +*/ + +NALU_t *GenerateSubsetSeq_parameter_set_NALU (VideoParameters *p_Vid) +{ + NALU_t *n = AllocNALU(MAXNALUSIZE); + int RBSPlen = 0; + byte rbsp[MAXRBSPSIZE]; + + RBSPlen = GenerateSeq_parameter_set_rbsp (p_Vid, p_Vid->sps[1]/*p_Vid->active_sps*/, rbsp, 1); + RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_SUB_SPS, NALU_PRIORITY_HIGHEST, 1); + n->startcodeprefix_len = 4; + + return n; +} +#endif + +/*! +************************************************************************************* +* \brief +* NALU_t *GeneratePic_parameter_set_NALU (VideoParameters *p_Vid, int PPS_id); +* +* \note +* Uses the global variables through GenerateSequenceParameterSet() +* and GeneratePictureParameterSet +* +* \return +* A NALU containing the Picture Parameter Set +* +************************************************************************************* +*/ + +NALU_t *GeneratePic_parameter_set_NALU(VideoParameters *p_Vid, int PPS_id) +{ + NALU_t *n = AllocNALU(MAXNALUSIZE); + int RBSPlen = 0; + byte rbsp[MAXRBSPSIZE]; + + RBSPlen = GeneratePic_parameter_set_rbsp (p_Vid, p_Vid->PicParSet[PPS_id], rbsp); + RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_PPS, NALU_PRIORITY_HIGHEST, 1); + n->startcodeprefix_len = 4; + + return n; +} + + +/*! + ************************************************************************ + * \brief + * GenerateSequenceParameterSet: extracts info from global variables and + * generates sequence parameter set structure + * \param sps + * Sequence Parameter Set to be filled + * \param p_Vid + * VideoParameters for encoding + * \param SPS_id + * SPS ID + * + * \par + * Function reads all kinds of values from several global variables, + * including p_Inp-> and image-> and fills in the sps. Many + * values are current hard-coded to defaults. + * + ************************************************************************ + */ + +void GenerateSequenceParameterSet( seq_parameter_set_rbsp_t *sps, //!< Sequence Parameter Set to be filled + VideoParameters *p_Vid, //!< VideoParameters for encoding + int SPS_id //!< SPS ID + ) +{ + static const int SubWidthC [4]= { 1, 2, 2, 1}; + static const int SubHeightC [4]= { 1, 2, 1, 1}; + unsigned i; + unsigned n_ScalingList; + InputParameters *p_Inp = p_Vid->p_Inp; + + int frext_profile = ((identify_profile(p_Inp)==FREXT_HP) || + (identify_profile(p_Inp)==FREXT_Hi10P) || + (identify_profile(p_Inp)==FREXT_Hi422) || + (identify_profile(p_Inp)==FREXT_Hi444) || + (identify_profile(p_Inp)==FREXT_CAVLC444) +#if (MVC_EXTENSION_ENABLE) + || (identify_profile(p_Inp)==MULTIVIEW_HIGH) + || (identify_profile(p_Inp)==STEREO_HIGH) +#endif + ); + // ************************************************************************* + // Sequence Parameter Set + // ************************************************************************* + assert (sps != NULL); + // Profile and Level should be calculated using the info from the config + // file. Calculation is hidden in identify_profile() and identify_level() + sps->profile_idc = identify_profile(p_Inp); + sps->level_idc = identify_level(p_Inp); + + // needs to be set according to profile + sps->constrained_set0_flag = FALSE; + sps->constrained_set1_flag = FALSE; + sps->constrained_set2_flag = FALSE; + + if ( (sps->level_idc == 9) && !is_FREXT_profile(sps->profile_idc) ) // Level 1.b + { + sps->constrained_set3_flag = TRUE; + sps->level_idc = 11; + } + else if (frext_profile && p_Inp->IntraProfile) + { + sps->constrained_set3_flag = TRUE; + } + else + { + sps->constrained_set3_flag = FALSE; + } + + // Parameter Set ID hard coded to zero + sps->seq_parameter_set_id = SPS_id; + + // Fidelity Range Extensions stuff + sps->bit_depth_luma_minus8 = p_Inp->output.bit_depth[0] - 8; + sps->bit_depth_chroma_minus8 = p_Inp->output.bit_depth[1] - 8; + sps->lossless_qpprime_flag = p_Inp->LosslessCoding & + (sps->profile_idc==FREXT_Hi444 || sps->profile_idc==FREXT_CAVLC444); + + //! POC stuff: + //! The following values are hard-coded in init_poc(). Apparently, + //! the poc implementation covers only a subset of the poc functionality. + //! Here, the same subset is implemented. Changes in the POC stuff have + //! also to be reflected here + sps->log2_max_frame_num_minus4 = p_Vid->log2_max_frame_num_minus4; + sps->log2_max_pic_order_cnt_lsb_minus4 = p_Vid->log2_max_pic_order_cnt_lsb_minus4; + + sps->pic_order_cnt_type = p_Inp->pic_order_cnt_type; + sps->num_ref_frames_in_pic_order_cnt_cycle = p_Vid->num_ref_frames_in_pic_order_cnt_cycle; + sps->delta_pic_order_always_zero_flag = p_Vid->delta_pic_order_always_zero_flag; + sps->offset_for_non_ref_pic = p_Vid->offset_for_non_ref_pic; + sps->offset_for_top_to_bottom_field = p_Vid->offset_for_top_to_bottom_field; + + for (i=0; inum_ref_frames_in_pic_order_cnt_cycle; i++) + { + sps->offset_for_ref_frame[i] = p_Vid->offset_for_ref_frame[i]; + } + // End of POC stuff + + // Number of Reference Frames + sps->num_ref_frames = (unsigned char) p_Inp->num_ref_frames; + + //required_frame_num_update_behaviour_flag hardcoded to zero + sps->gaps_in_frame_num_value_allowed_flag = FALSE; // double check + + sps->frame_mbs_only_flag = (Boolean) !(p_Inp->PicInterlace || p_Inp->MbInterlace); + + // Picture size, finally a simple one :-) + sps->pic_width_in_mbs_minus1 = (( p_Inp->output.width[0] + p_Vid->auto_crop_right) >> 4) -1; + sps->pic_height_in_map_units_minus1 = (((p_Inp->output.height[0] + p_Vid->auto_crop_bottom) >> 4)/ (2 - sps->frame_mbs_only_flag)) - 1; + + // a couple of flags, simple + sps->mb_adaptive_frame_field_flag = (Boolean) (FRAME_CODING != p_Inp->MbInterlace); + sps->direct_8x8_inference_flag = (Boolean) p_Inp->directInferenceFlag; + + // Sequence VUI not implemented, signalled as not present + sps->vui_parameters_present_flag = (Boolean) ((p_Inp->output.color_model != CM_YUV && p_Inp->output.yuv_format == YUV444) || p_Inp->EnableVUISupport); + sps->chroma_format_idc = p_Inp->output.yuv_format; + sps->separate_colour_plane_flag = ( sps->chroma_format_idc == YUV444 ) ? p_Inp->separate_colour_plane_flag : 0; + + if ( sps->vui_parameters_present_flag ) + GenerateVUIParameters(sps, p_Inp); + + // Fidelity Range Extensions stuff + if(frext_profile) + { + sps->seq_scaling_matrix_present_flag = (Boolean) (p_Inp->ScalingMatrixPresentFlag&1); + n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12; + for(i=0; iseq_scaling_list_present_flag[i] = (p_Inp->ScalingListPresentFlag[i]&1); + else + { + if(p_Inp->Transform8x8Mode) + sps->seq_scaling_list_present_flag[i] = (p_Inp->ScalingListPresentFlag[i]&1); + else + sps->seq_scaling_list_present_flag[i] = 0; + } + if( sps->seq_scaling_matrix_present_flag == FALSE ) + sps->seq_scaling_list_present_flag[i] = 0; + } + } + else + { + sps->seq_scaling_matrix_present_flag = FALSE; + for(i=0; i<12; i++) + sps->seq_scaling_list_present_flag[i] = 0; + + } + + + if (p_Vid->auto_crop_right || p_Vid->auto_crop_bottom) + { + sps->frame_cropping_flag = TRUE; + sps->frame_crop_left_offset=0; + sps->frame_crop_top_offset=0; + sps->frame_crop_right_offset= (p_Vid->auto_crop_right / SubWidthC[sps->chroma_format_idc]); + sps->frame_crop_bottom_offset= (p_Vid->auto_crop_bottom / (SubHeightC[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag))); + if (p_Vid->auto_crop_right % SubWidthC[sps->chroma_format_idc]) + { + error("automatic frame cropping (width) not possible",500); + } + if (p_Vid->auto_crop_bottom % (SubHeightC[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag))) + { + error("automatic frame cropping (height) not possible",500); + } + } + else + { + sps->frame_cropping_flag = FALSE; + } + +} + +/*! + ************************************************************************ + * \brief + * GeneratePictureParameterSet: + * Generates a Picture Parameter Set structure + * \par + * Regarding the QP + * The previous software versions coded the absolute QP only in the + * slice header. This is kept, and the offset in the PPS is coded + * even if we could save bits by intelligently using this field. + * + ************************************************************************ + */ +void GeneratePictureParameterSet( pic_parameter_set_rbsp_t *pps, //!< Picture Parameter Set to be filled + seq_parameter_set_rbsp_t *sps, //!< used Sequence Parameter Set + VideoParameters *p_Vid, //!< the image pointer + InputParameters *p_Inp, //!< Input configuration parameters + int PPS_id, //!< PPS ID + int WeightedPrediction, //!< value of weighted_pred_flag + int WeightedBiprediction, //!< value of weighted_bipred_idc + int cb_qp_index_offset, //!< value of cb_qp_index_offset + int cr_qp_index_offset //!< value of cr_qp_index_offset + ) + +{ + unsigned i; + unsigned n_ScalingList; + unsigned FrameSizeInMapUnits = 0; + + int frext_profile = ((identify_profile(p_Inp)==FREXT_HP) || + (identify_profile(p_Inp)==FREXT_Hi10P) || + (identify_profile(p_Inp)==FREXT_Hi422) || + (identify_profile(p_Inp)==FREXT_Hi444) || + (identify_profile(p_Inp)==FREXT_CAVLC444) +#if (MVC_EXTENSION_ENABLE) + || (identify_profile(p_Inp)==MULTIVIEW_HIGH) + || (identify_profile(p_Inp)==STEREO_HIGH) +#endif + ); + + // ************************************************************************* + // Picture Parameter Set + // ************************************************************************* + + pps->seq_parameter_set_id = sps->seq_parameter_set_id; + pps->pic_parameter_set_id = PPS_id; + pps->entropy_coding_mode_flag = (p_Inp->symbol_mode == CAVLC ? FALSE : TRUE); + // Fidelity Range Extensions stuff + if(frext_profile) + { + pps->transform_8x8_mode_flag = (p_Inp->Transform8x8Mode ? TRUE:FALSE); + pps->pic_scaling_matrix_present_flag = (Boolean) ((p_Inp->ScalingMatrixPresentFlag&2)>>1); + n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12; + for(i=0; ipic_scaling_list_present_flag[i] = (p_Inp->ScalingListPresentFlag[i]&2)>>1; + else + { + if(pps->transform_8x8_mode_flag) + pps->pic_scaling_list_present_flag[i] = (p_Inp->ScalingListPresentFlag[i]&2)>>1; + else + pps->pic_scaling_list_present_flag[i] = 0; + } + if( pps->pic_scaling_matrix_present_flag == FALSE ) + pps->pic_scaling_list_present_flag[i] = 0; + } + } + else + { + pps->pic_scaling_matrix_present_flag = FALSE; + for(i=0; i<12; i++) + pps->pic_scaling_list_present_flag[i] = 0; + + pps->transform_8x8_mode_flag = FALSE; + p_Inp->Transform8x8Mode = 0; + } + + // JVT-Fxxx (by Stephan Wenger, make this flag unconditional + pps->bottom_field_pic_order_in_frame_present_flag = p_Vid->bottom_field_pic_order_in_frame_present_flag; + + // Begin FMO stuff + pps->num_slice_groups_minus1 = p_Inp->num_slice_groups_minus1; + + //! Following set the parameter for different slice group types + if (pps->num_slice_groups_minus1 > 0) + { + if ((pps->slice_group_id = calloc ((sps->pic_height_in_map_units_minus1+1)*(sps->pic_width_in_mbs_minus1+1), sizeof(byte))) == NULL) + no_mem_exit ("GeneratePictureParameterSet: slice_group_id"); + + switch (p_Inp->slice_group_map_type) + { + case 0: + pps->slice_group_map_type = 0; + for(i=0; i<=pps->num_slice_groups_minus1; i++) + { + pps->run_length_minus1[i]=p_Inp->run_length_minus1[i]; + } + break; + case 1: + pps->slice_group_map_type = 1; + break; + case 2: + // i loops from 0 to num_slice_groups_minus1-1, because no info for background needed + pps->slice_group_map_type = 2; + FrameSizeInMapUnits = (sps->pic_height_in_map_units_minus1) * (sps->pic_width_in_mbs_minus1 + 1); + for(i=0; inum_slice_groups_minus1; i++) + { + // make sure the macroblock map does not lie outside the picture + pps->top_left[i] = imin (p_Inp->top_left[i], FrameSizeInMapUnits); + pps->bottom_right[i] = imin (p_Inp->bottom_right[i], FrameSizeInMapUnits); + } + break; + case 3: + case 4: + case 5: + pps->slice_group_map_type = p_Inp->slice_group_map_type; + pps->slice_group_change_direction_flag = (Boolean) p_Inp->slice_group_change_direction_flag; + pps->slice_group_change_rate_minus1 = p_Inp->slice_group_change_rate_minus1; + break; + case 6: + pps->slice_group_map_type = 6; + pps->pic_size_in_map_units_minus1 = + (((p_Inp->output.height[0] + p_Vid->auto_crop_bottom)/MB_BLOCK_SIZE)/(2-sps->frame_mbs_only_flag)) + *((p_Inp->output.width[0] + p_Vid->auto_crop_right)/MB_BLOCK_SIZE) -1; + + for (i=0;i<=pps->pic_size_in_map_units_minus1; i++) + pps->slice_group_id[i] = p_Inp->slice_group_id[i]; + + break; + default: + printf ("Parset.c: slice_group_map_type invalid, default\n"); + assert (0==1); + } + } +// End FMO stuff + + pps->num_ref_idx_l0_default_active_minus1 = sps->frame_mbs_only_flag ? (sps->num_ref_frames - 1) : (2 * sps->num_ref_frames - 1) ; // set defaults + pps->num_ref_idx_l1_default_active_minus1 = sps->frame_mbs_only_flag ? (sps->num_ref_frames - 1) : (2 * sps->num_ref_frames - 1) ; // set defaults + + pps->weighted_pred_flag = (byte) WeightedPrediction; + pps->weighted_bipred_idc = (byte) WeightedBiprediction; + + pps->pic_init_qp_minus26 = 0; // hard coded to zero, QP lives in the slice header + pps->pic_init_qs_minus26 = 0; + + pps->chroma_qp_index_offset = cb_qp_index_offset; + if (frext_profile) + { + pps->cb_qp_index_offset = cb_qp_index_offset; + pps->cr_qp_index_offset = cr_qp_index_offset; + } + else + pps->cb_qp_index_offset = pps->cr_qp_index_offset = pps->chroma_qp_index_offset; + + pps->deblocking_filter_control_present_flag = (Boolean) ((p_Inp->DFSendParameters != 0) || (p_Inp->RDPictureDeblocking != 0)); + + pps->constrained_intra_pred_flag = (Boolean) p_Inp->UseConstrainedIntraPred; + + // if redundant slice is in use. + pps->redundant_pic_cnt_present_flag = (Boolean) p_Inp->redundant_pic_flag; +} + +/*! + ************************************************************************************* + * \brief + * syntax for scaling list matrix values + * + * \param scalingListinput + * input scaling list + * \param scalingList + * scaling list to be used + * \param sizeOfScalingList + * size of the scaling list + * \param UseDefaultScalingMatrix + * usage of default Scaling Matrix + * \param bitstream + * target bitstream for writing syntax + * + * \return + * size of the RBSP in bytes + * + ************************************************************************************* + */ +int Scaling_List(short *scalingListinput, short *scalingList, int sizeOfScalingList, short *UseDefaultScalingMatrix, Bitstream *bitstream) +{ + int j, scanj; + int len=0; + int delta_scale, lastScale, nextScale; + + lastScale = 8; + nextScale = 8; + + for(j=0; j127) + delta_scale=delta_scale-256; + else if(delta_scale<-128) + delta_scale=delta_scale+256; + + len+=write_se_v (" : delta_sl ", delta_scale, bitstream); + nextScale = scalingListinput[scanj]; + *UseDefaultScalingMatrix|=(scanj==0 && nextScale==0); // Check first matrix value for zero + } + + scalingList[scanj] = (short) ((nextScale==0) ? lastScale:nextScale); // Update the actual scalingList matrix with the correct values + lastScale = scalingList[scanj]; + } + + return len; +} + + +/*! + ************************************************************************************* + * \brief + * int GenerateSeq_parameter_set_rbsp (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps, char *rbsp); + * + * \param p_Vid + * Image parameters structure + * \param sps + * sequence parameter structure + * \param rbsp + * buffer to be filled with the rbsp, size should be at least MAXIMUMPARSETRBSPSIZE + * \return + * size of the RBSP in bytes + * + * \note + * Sequence Parameter VUI function is called, but the function implements + * an exit (-1) + ************************************************************************************* + */ +#if (MVC_EXTENSION_ENABLE) +int GenerateSeq_parameter_set_rbsp (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps, byte *rbsp, short Is_Subset) +#else +int GenerateSeq_parameter_set_rbsp (VideoParameters *p_Vid, seq_parameter_set_rbsp_t *sps, byte *rbsp) +#endif +{ + Bitstream *bitstream; + int len = 0, LenInBytes; + unsigned i; + unsigned n_ScalingList; + + assert (rbsp != NULL); + + if ((bitstream=calloc(1, sizeof(Bitstream)))==NULL) no_mem_exit("SeqParameterSet:bitstream"); + + // .. and use the rbsp provided (or allocated above) for the data + bitstream->streamBuffer = rbsp; + bitstream->bits_to_go = 8; + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->p_Inp->num_of_views==2) + { + if(Is_Subset==1) + { + assert(sps->profile_idc==MULTIVIEW_HIGH || sps->profile_idc==STEREO_HIGH); + len+=write_u_v (8, "SPS: profile_idc", sps->profile_idc, bitstream); + } + else + len+=write_u_v (8, "SPS: profile_idc", 100, bitstream); + } + else +#endif + len+=write_u_v (8, "SPS: profile_idc", sps->profile_idc, bitstream); + + len+=write_u_1 ("SPS: constrained_set0_flag", sps->constrained_set0_flag, bitstream); + len+=write_u_1 ("SPS: constrained_set1_flag", sps->constrained_set1_flag, bitstream); + len+=write_u_1 ("SPS: constrained_set2_flag", sps->constrained_set2_flag, bitstream); + len+=write_u_1 ("SPS: constrained_set3_flag", sps->constrained_set3_flag, bitstream); + len+=write_u_v (4, "SPS: reserved_zero_4bits", 0, bitstream); + + len+=write_u_v (8, "SPS: level_idc", sps->level_idc, bitstream); + + len+=write_ue_v ("SPS: seq_parameter_set_id", sps->seq_parameter_set_id, bitstream); + + // Fidelity Range Extensions stuff + if( is_FREXT_profile(sps->profile_idc) ) + { + len+=write_ue_v ("SPS: chroma_format_idc", sps->chroma_format_idc, bitstream); + if(sps->chroma_format_idc == YUV444) //if(p_Vid->yuv_format == YUV444) + len+=write_u_1 ("SPS: separate_colour_plane_flag", sps->separate_colour_plane_flag, bitstream); + len+=write_ue_v ("SPS: bit_depth_luma_minus8", sps->bit_depth_luma_minus8, bitstream); + len+=write_ue_v ("SPS: bit_depth_chroma_minus8", sps->bit_depth_chroma_minus8, bitstream); + + len+=write_u_1 ("SPS: lossless_qpprime_y_zero_flag", sps->lossless_qpprime_flag, bitstream); + //other chroma info to be added in the future + + len+=write_u_1 ("SPS: seq_scaling_matrix_present_flag", sps->seq_scaling_matrix_present_flag, bitstream); + + if(sps->seq_scaling_matrix_present_flag) + { + ScaleParameters *p_QScale = p_Vid->p_QScale; + n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12; + for(i=0; iseq_scaling_list_present_flag[i], bitstream); + if(sps->seq_scaling_list_present_flag[i]) + { + if(i<6) + len+=Scaling_List(p_QScale->ScalingList4x4input[i], p_QScale->ScalingList4x4[i], 16, &p_QScale->UseDefaultScalingMatrix4x4Flag[i], bitstream); + else + len+=Scaling_List(p_QScale->ScalingList8x8input[i-6], p_QScale->ScalingList8x8[i-6], 64, &p_QScale->UseDefaultScalingMatrix8x8Flag[i-6], bitstream); + } + } + } + } + + len+=write_ue_v ("SPS: log2_max_frame_num_minus4", sps->log2_max_frame_num_minus4, bitstream); + len+=write_ue_v ("SPS: pic_order_cnt_type", sps->pic_order_cnt_type, bitstream); + + if (sps->pic_order_cnt_type == 0) + len+=write_ue_v ("SPS: log2_max_pic_order_cnt_lsb_minus4", sps->log2_max_pic_order_cnt_lsb_minus4, bitstream); + else if (sps->pic_order_cnt_type == 1) + { + len+=write_u_1 ("SPS: delta_pic_order_always_zero_flag", sps->delta_pic_order_always_zero_flag, bitstream); + len+=write_se_v ("SPS: offset_for_non_ref_pic", sps->offset_for_non_ref_pic, bitstream); + len+=write_se_v ("SPS: offset_for_top_to_bottom_field", sps->offset_for_top_to_bottom_field, bitstream); + len+=write_ue_v ("SPS: num_ref_frames_in_pic_order_cnt_cycle", sps->num_ref_frames_in_pic_order_cnt_cycle, bitstream); + for (i=0; inum_ref_frames_in_pic_order_cnt_cycle; i++) + len+=write_se_v ("SPS: offset_for_ref_frame", sps->offset_for_ref_frame[i], bitstream); + } + len+=write_ue_v ("SPS: num_ref_frames", sps->num_ref_frames, bitstream); + len+=write_u_1 ("SPS: gaps_in_frame_num_value_allowed_flag", sps->gaps_in_frame_num_value_allowed_flag, bitstream); + len+=write_ue_v ("SPS: pic_width_in_mbs_minus1", sps->pic_width_in_mbs_minus1, bitstream); + len+=write_ue_v ("SPS: pic_height_in_map_units_minus1", sps->pic_height_in_map_units_minus1, bitstream); + len+=write_u_1 ("SPS: frame_mbs_only_flag", sps->frame_mbs_only_flag, bitstream); + if (!sps->frame_mbs_only_flag) + { + len+=write_u_1 ("SPS: mb_adaptive_frame_field_flag", sps->mb_adaptive_frame_field_flag, bitstream); + } + len+=write_u_1 ("SPS: direct_8x8_inference_flag", sps->direct_8x8_inference_flag, bitstream); + + len+=write_u_1 ("SPS: frame_cropping_flag", sps->frame_cropping_flag, bitstream); + if (sps->frame_cropping_flag) + { + len+=write_ue_v ("SPS: frame_crop_left_offset", sps->frame_crop_left_offset, bitstream); + len+=write_ue_v ("SPS: frame_crop_right_offset", sps->frame_crop_right_offset, bitstream); + len+=write_ue_v ("SPS: frame_crop_top_offset", sps->frame_crop_top_offset, bitstream); + len+=write_ue_v ("SPS: frame_crop_bottom_offset", sps->frame_crop_bottom_offset, bitstream); + } + + len+=write_u_1 ("SPS: vui_parameters_present_flag", sps->vui_parameters_present_flag, bitstream); + + if (sps->vui_parameters_present_flag) + len+=GenerateVUI_parameters_rbsp(sps, bitstream); // currently a dummy, asserting + +#if (MVC_EXTENSION_ENABLE) + if(Is_Subset==1) + { + // profile_idc fixed to 118 only + len+=write_u_1 ("SPS: bit_equal_to_one", 1, bitstream); + + // fixed to 2 views only + { + len+=write_ue_v ("SPS: num_views_minus1", 1, bitstream); + if ( p_Vid->p_Inp->MVCFlipViews ) + { + len+=write_ue_v ("SPS: view_id[ 0 ]", 1, bitstream); + len+=write_ue_v ("SPS: view_id[ 1 ]", 0, bitstream); + + len+=write_ue_v ("SPS: num_anchor_refs_l0[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: anchor_ref_l0[ 1 ][ 0 ]", 1, bitstream); + len+=write_ue_v ("SPS: num_anchor_refs_l1[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: anchor_ref_l1[ 1 ][ 0 ]", 1, bitstream); + + len+=write_ue_v ("SPS: num_non_anchor_refs_l0[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: non_anchor_ref_l0[ 1 ][ 0 ]", 1, bitstream); + len+=write_ue_v ("SPS: num_non_anchor_refs_l1[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: non_anchor_ref_l1[ 1 ][ 0 ]", 1, bitstream); + } + else + { + len+=write_ue_v ("SPS: view_id[ 0 ]", 0, bitstream); + len+=write_ue_v ("SPS: view_id[ 1 ]", 1, bitstream); + + len+=write_ue_v ("SPS: num_anchor_refs_l0[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: anchor_ref_l0[ 1 ][ 0 ]", 0, bitstream); + len+=write_ue_v ("SPS: num_anchor_refs_l1[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: anchor_ref_l1[ 1 ][ 0 ]", 0, bitstream); + + len+=write_ue_v ("SPS: num_non_anchor_refs_l0[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: non_anchor_ref_l0[ 1 ][ 0 ]", 0, bitstream); + len+=write_ue_v ("SPS: num_non_anchor_refs_l1[ 1 ]", 1, bitstream); + len+=write_ue_v ("SPS: non_anchor_ref_l1[ 1 ][ 0 ]", 0, bitstream); + } + + len+=write_ue_v ("SPS: num_level_values_signalled_minus1", 0, bitstream); + len+=write_u_v (8, "SPS: level_idc[ 0 ]", sps->level_idc, bitstream); + len+=write_ue_v ("SPS: num_applicable_ops_minus1[ 0 ]", 0, bitstream); + len+=write_u_v (3, "SPS: applicable_op_temporal_id[ 0 ][ 0 ]", 0, bitstream); + len+=write_ue_v ("SPS: applicable_op_num_target_views_minus1[ 0 ][ 0 ]", 0, bitstream); + len+=write_ue_v ("SPS: applicable_op_target_view_id[ 0 ][ 0 ][ 0 ]", 0, bitstream); + len+=write_ue_v ("SPS: applicable_op_num_views_minus1[ 0 ][ 0 ]", 0, bitstream); + } + + len+=write_u_1 ("SPS: mvc_vui_parameters_present_flag", sps->vui_parameters_present_flag, bitstream); + { + if(sps->vui_parameters_present_flag) + { + len+=write_ue_v ( "SPS: vui_mvc_num_ops_minus1", 0, bitstream); + len+=write_u_v ( 3, "SPS: vui_mvc_temporal_id[ 0 ]", 0, bitstream); + len+=write_ue_v ( "SPS: vui_mvc_num_target_output_views_minus1[ 0 ]", 0, bitstream); + len+=write_ue_v ( "SPS: vui_mvc_view_id[ 0 ][ 0 ]", 0, bitstream); + len+=write_u_1 ( "SPS: vui_mvc_timing_info_present_flag[ 0 ]", sps->vui_parameters_present_flag, bitstream); + len+=write_u_v (32, "SPS: vui_mvc_num_units_in_tick[ 0 ]", sps->vui_seq_parameters.num_units_in_tick, bitstream); + len+=write_u_v (32, "SPS: vui_mvc_time_scale[ 0 ]", sps->vui_seq_parameters.time_scale, bitstream); + len+=write_u_1 ( "SPS: vui_mvc_fixed_frame_rate_flag[ 0 ]", sps->vui_seq_parameters.fixed_frame_rate_flag, bitstream); + len+=write_u_1 ( "SPS: vui_mvc_nal_hrd_parameters_present_flag[ 0 ]", sps->vui_seq_parameters.nal_hrd_parameters_present_flag, bitstream); + if(sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + { + len += WriteHRDParameters(sps, bitstream); + } + len+=write_u_1 ("SPS: vui_mvc_vcl_hrd_parameters_present_flag[ 0 ]", sps->vui_seq_parameters.vcl_hrd_parameters_present_flag, bitstream); + if ( sps->vui_seq_parameters.vcl_hrd_parameters_present_flag ) + { + len += WriteHRDParameters(sps, bitstream); + } + if ( sps->vui_seq_parameters.nal_hrd_parameters_present_flag || sps->vui_seq_parameters.vcl_hrd_parameters_present_flag ) + { + len+=write_u_1 ("SPS: vui_mvc_low_delay_hrd_flag[ 0 ]", sps->vui_seq_parameters.low_delay_hrd_flag, bitstream ); + } + len+=write_u_1 ("SPS: vui_mvc_pic_struct_present_flag[ 0 ]", sps->vui_seq_parameters.pic_struct_present_flag, bitstream); + } + } + + len+=write_u_1 ("SPS: additional_extension2_flag", 0, bitstream); + } +#endif + + SODBtoRBSP(bitstream); // copies the last couple of bits into the byte buffer + + LenInBytes=bitstream->byte_pos; + + free (bitstream); + + return LenInBytes; +} + + +/*! + *********************************************************************************************** + * \brief + * int GeneratePic_parameter_set_rbsp (VideoParameters *p_Vid, pic_parameter_set_rbsp_t *pps, char *rbsp); + * + * \param p_Vid + * picture parameter structure + * \param pps + * picture parameter structure + * \param rbsp + * buffer to be filled with the rbsp, size should be at least MAXIMUMPARSETRBSPSIZE + * + * \return + * size of the RBSP in bytes, negative in case of an error + * + * \note + * Picture Parameter VUI function is called, but the function implements + * an exit (-1) + ************************************************************************************************ + */ + +int GeneratePic_parameter_set_rbsp (VideoParameters *p_Vid, pic_parameter_set_rbsp_t *pps, byte *rbsp) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + Bitstream *bitstream; + int len = 0, LenInBytes; + unsigned i; + int profile_idc; + + assert (rbsp != NULL); + + if ((bitstream=calloc(1, sizeof(Bitstream)))==NULL) no_mem_exit("PicParameterSet:bitstream"); + + // .. and use the rbsp provided (or allocated above) for the data + bitstream->streamBuffer = rbsp; + bitstream->bits_to_go = 8; + + pps->bottom_field_pic_order_in_frame_present_flag = p_Vid->bottom_field_pic_order_in_frame_present_flag; + + len += write_ue_v ("PPS: pic_parameter_set_id", pps->pic_parameter_set_id, bitstream); + len += write_ue_v ("PPS: seq_parameter_set_id", pps->seq_parameter_set_id, bitstream); + len += write_u_1 ("PPS: entropy_coding_mode_flag", pps->entropy_coding_mode_flag, bitstream); + len += write_u_1 ("PPS: bottom_field_pic_order_in_frame_present_flag", pps->bottom_field_pic_order_in_frame_present_flag, bitstream); + len += write_ue_v ("PPS: num_slice_groups_minus1", pps->num_slice_groups_minus1, bitstream); + + // FMO stuff + if(pps->num_slice_groups_minus1 > 0 ) + { + len += write_ue_v ("PPS: slice_group_map_type", pps->slice_group_map_type, bitstream); + if (pps->slice_group_map_type == 0) + for (i=0; i<=pps->num_slice_groups_minus1; i++) + len += write_ue_v ("PPS: run_length_minus1[i]", pps->run_length_minus1[i], bitstream); + else if (pps->slice_group_map_type==2) + { + for (i=0; inum_slice_groups_minus1; i++) + { + len += write_ue_v ("PPS: top_left[i]", pps->top_left[i], bitstream); + len += write_ue_v ("PPS: bottom_right[i]", pps->bottom_right[i], bitstream); + } + } + else if (pps->slice_group_map_type == 3 || + pps->slice_group_map_type == 4 || + pps->slice_group_map_type == 5) + { + len += write_u_1 ("PPS: slice_group_change_direction_flag", pps->slice_group_change_direction_flag, bitstream); + len += write_ue_v ("PPS: slice_group_change_rate_minus1", pps->slice_group_change_rate_minus1, bitstream); + } + else if (pps->slice_group_map_type == 6) + { + unsigned NumberBitsPerSliceGroupId = 0; + + if (pps->num_slice_groups_minus1>=4) + NumberBitsPerSliceGroupId=3; + else if (pps->num_slice_groups_minus1>=2) + NumberBitsPerSliceGroupId=2; + else if (pps->num_slice_groups_minus1>=1) + NumberBitsPerSliceGroupId=1; + + len += write_ue_v ("PPS: pic_size_in_map_units_minus1", pps->pic_size_in_map_units_minus1, bitstream); + for(i = 0; i <= pps->pic_size_in_map_units_minus1; i++) + len += write_u_v (NumberBitsPerSliceGroupId, "PPS: >slice_group_id[i]", pps->slice_group_id[i], bitstream); + } + } + // End of FMO stuff + + len += write_ue_v ("PPS: num_ref_idx_l0_default_active_minus1", pps->num_ref_idx_l0_default_active_minus1, bitstream); + len += write_ue_v ("PPS: num_ref_idx_l1_default_active_minus1", pps->num_ref_idx_l1_default_active_minus1, bitstream); + len += write_u_1 ("PPS: weighted_pred_flag", pps->weighted_pred_flag, bitstream); + len += write_u_v (2, "PPS: weighted_bipred_idc", pps->weighted_bipred_idc, bitstream); + len += write_se_v ("PPS: pic_init_qp_minus26", pps->pic_init_qp_minus26, bitstream); + len += write_se_v ("PPS: pic_init_qs_minus26", pps->pic_init_qs_minus26, bitstream); + + profile_idc = identify_profile(p_Inp); + if( is_FREXT_profile(profile_idc) ) + len += write_se_v ("PPS: chroma_qp_index_offset", pps->cb_qp_index_offset, bitstream); + else + len += write_se_v ("PPS: chroma_qp_index_offset", pps->chroma_qp_index_offset, bitstream); + + len += write_u_1 ("PPS: deblocking_filter_control_present_flag", pps->deblocking_filter_control_present_flag, bitstream); + len += write_u_1 ("PPS: constrained_intra_pred_flag", pps->constrained_intra_pred_flag, bitstream); + len += write_u_1 ("PPS: redundant_pic_cnt_present_flag", pps->redundant_pic_cnt_present_flag, bitstream); + + // Fidelity Range Extensions stuff + if( is_FREXT_profile(profile_idc) ) + { + len += write_u_1 ("PPS: transform_8x8_mode_flag", pps->transform_8x8_mode_flag, bitstream); + len += write_u_1 ("PPS: pic_scaling_matrix_present_flag", pps->pic_scaling_matrix_present_flag, bitstream); + + if(pps->pic_scaling_matrix_present_flag) + { + ScaleParameters *p_QScale = p_Vid->p_QScale; + unsigned n_ScalingList = 6 + ((p_Vid->active_sps->chroma_format_idc != 3) ? 2 : 6) * pps->transform_8x8_mode_flag; + + for(i=0; ipic_scaling_list_present_flag[i], bitstream); + + if(pps->pic_scaling_list_present_flag[i]) + { + if(i < 6) + len += Scaling_List(p_QScale->ScalingList4x4input[i], p_QScale->ScalingList4x4[i], 16, &p_QScale->UseDefaultScalingMatrix4x4Flag[i], bitstream); + else + len += Scaling_List(p_QScale->ScalingList8x8input[i-6], p_QScale->ScalingList8x8[i-6], 64, &p_QScale->UseDefaultScalingMatrix8x8Flag[i-6], bitstream); + } + } + } + len += write_se_v ("PPS: second_chroma_qp_index_offset", pps->cr_qp_index_offset, bitstream); + } + + SODBtoRBSP(bitstream); // copies the last couple of bits into the byte buffer + + LenInBytes = bitstream->byte_pos; + + // Get rid of the helper structures + free (bitstream); + + return LenInBytes; +} + + + +/*! + ************************************************************************************* + * \brief + * Returns the Profile + * + * \return + * Profile according to Annex A + * + * \note + * Function is currently a dummy. Should "calculate" the profile from those + * config file parameters. E.g. + * + * Profile = Baseline; + * if (CABAC Used || Interlace used) Profile=Main; + * if (!Cabac Used) && (Bframes | SPframes) Profile = Streaming; + * + ************************************************************************************* + */ +int identify_profile(InputParameters *p_Inp) +{ + return p_Inp->ProfileIDC; +} + +/*! + ************************************************************************************* + * \brief + * Returns the Level + * + * \return + * Level according to Annex A + * + * \note + * This function is currently a dummy, but should calculate the level out of + * the config file parameters (primarily the picture size) + ************************************************************************************* + */ +int identify_level(InputParameters *p_Inp) +{ + return p_Inp->LevelIDC; +} + + +/*! + ************************************************************************************* + * \brief + * Function body for VUI Parameter generation (to be done) + * + * \return + * exits with error message + ************************************************************************************* + */ +static int GenerateVUI_parameters_rbsp(seq_parameter_set_rbsp_t *sps, Bitstream *bitstream) +{ + int len=0; + vui_seq_parameters_t *vui_seq_parameters = &(sps->vui_seq_parameters); + + len+=write_u_1 ("VUI: aspect_ratio_info_present_flag", vui_seq_parameters->aspect_ratio_info_present_flag, bitstream); + if (vui_seq_parameters->aspect_ratio_info_present_flag) + { + len+=write_u_v (8,"VUI: aspect_ratio_idc", vui_seq_parameters->aspect_ratio_idc, bitstream); + if (vui_seq_parameters->aspect_ratio_idc == 255) + { + len+=write_u_v (16,"VUI: sar_width", vui_seq_parameters->sar_width, bitstream); + len+=write_u_v (16,"VUI: sar_height", vui_seq_parameters->sar_height, bitstream); + } + } + + len+=write_u_1 ("VUI: overscan_info_present_flag", vui_seq_parameters->overscan_info_present_flag, bitstream); + if (vui_seq_parameters->overscan_info_present_flag) + { + len+=write_u_1 ("VUI: overscan_appropriate_flag", vui_seq_parameters->overscan_appropriate_flag, bitstream); + } + + len+=write_u_1 ("VUI: video_signal_type_present_flag", vui_seq_parameters->video_signal_type_present_flag, bitstream); + if (vui_seq_parameters->video_signal_type_present_flag) + { + len+=write_u_v (3,"VUI: video_format", vui_seq_parameters->video_format, bitstream); + len+=write_u_1 ("VUI: video_full_range_flag", vui_seq_parameters->video_full_range_flag, bitstream); + len+=write_u_1 ("VUI: colour_description_present_flag", vui_seq_parameters->colour_description_present_flag, bitstream); + if (vui_seq_parameters->colour_description_present_flag) + { + len+=write_u_v (8,"VUI: colour_primaries", vui_seq_parameters->colour_primaries, bitstream); + len+=write_u_v (8,"VUI: transfer_characteristics", vui_seq_parameters->transfer_characteristics, bitstream); + len+=write_u_v (8,"VUI: matrix_coefficients", vui_seq_parameters->matrix_coefficients, bitstream); + } + } + + len+=write_u_1 ("VUI: chroma_loc_info_present_flag", vui_seq_parameters->chroma_location_info_present_flag, bitstream); + if (vui_seq_parameters->chroma_location_info_present_flag) + { + len+=write_ue_v ("VUI: chroma_sample_loc_type_top_field", vui_seq_parameters->chroma_sample_loc_type_top_field, bitstream); + len+=write_ue_v ("VUI: chroma_sample_loc_type_bottom_field", vui_seq_parameters->chroma_sample_loc_type_bottom_field, bitstream); + } + + len+=write_u_1 ("VUI: timing_info_present_flag", vui_seq_parameters->timing_info_present_flag, bitstream); + // timing parameters + if (vui_seq_parameters->timing_info_present_flag) + { + len+=write_u_v (32,"VUI: num_units_in_tick", vui_seq_parameters->num_units_in_tick, bitstream); + len+=write_u_v (32,"VUI: time_scale", vui_seq_parameters->time_scale, bitstream); + len+=write_u_1 ("VUI: fixed_frame_rate_flag", vui_seq_parameters->fixed_frame_rate_flag, bitstream); + } + // end of timing parameters + // nal_hrd_parameters_present_flag + len+=write_u_1 ("VUI: nal_hrd_parameters_present_flag", vui_seq_parameters->nal_hrd_parameters_present_flag, bitstream); + if ( vui_seq_parameters->nal_hrd_parameters_present_flag ) + { + len += WriteHRDParameters(sps, bitstream); + } + // vcl_hrd_parameters_present_flag + len+=write_u_1 ("VUI: vcl_hrd_parameters_present_flag", vui_seq_parameters->vcl_hrd_parameters_present_flag, bitstream); + if ( vui_seq_parameters->vcl_hrd_parameters_present_flag ) + { + len += WriteHRDParameters(sps, bitstream); + } + if ( vui_seq_parameters->nal_hrd_parameters_present_flag || vui_seq_parameters->vcl_hrd_parameters_present_flag ) + { + len+=write_u_1 ("VUI: low_delay_hrd_flag", vui_seq_parameters->low_delay_hrd_flag, bitstream ); + } + len+=write_u_1 ("VUI: pic_struct_present_flag", vui_seq_parameters->pic_struct_present_flag, bitstream); + + len+=write_u_1 ("VUI: bitstream_restriction_flag", vui_seq_parameters->bitstream_restriction_flag, bitstream); + if (vui_seq_parameters->bitstream_restriction_flag) + { + len+=write_u_1 ("VUI: motion_vectors_over_pic_boundaries_flag", vui_seq_parameters->motion_vectors_over_pic_boundaries_flag, bitstream); + len+=write_ue_v ("VUI: max_bytes_per_pic_denom", vui_seq_parameters->max_bytes_per_pic_denom, bitstream); + len+=write_ue_v ("VUI: max_bits_per_mb_denom", vui_seq_parameters->max_bits_per_mb_denom, bitstream); + len+=write_ue_v ("VUI: log2_max_mv_length_horizontal", vui_seq_parameters->log2_max_mv_length_horizontal, bitstream); + len+=write_ue_v ("VUI: log2_max_mv_length_vertical", vui_seq_parameters->log2_max_mv_length_vertical, bitstream); + len+=write_ue_v ("VUI: num_reorder_frames", vui_seq_parameters->num_reorder_frames, bitstream); + len+=write_ue_v ("VUI: max_dec_frame_buffering", vui_seq_parameters->max_dec_frame_buffering, bitstream); + } + + return len; +} + +/*! + ************************************************************************************* + * \brief + * Function body for SEI message NALU generation + * + * \return + * A NALU containing the SEI messages + * + ************************************************************************************* + */ +NALU_t *GenerateSEImessage_NALU(InputParameters *p_Inp) +{ + NALU_t *n = AllocNALU(MAXNALUSIZE); + int RBSPlen = 0; + byte rbsp[MAXRBSPSIZE]; + + RBSPlen = GenerateSEImessage_rbsp (p_Inp, NORMAL_SEI, rbsp); + RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_SEI, NALU_PRIORITY_DISPOSABLE, 1); + n->startcodeprefix_len = 4; + + return n; +} + + +/*! + ************************************************************************************* + * \brief + * int GenerateSEImessage_rbsp (int, bufferingperiod_information_struct*, char*) + * + * + * \return + * size of the RBSP in bytes, negative in case of an error + * + * \note + ************************************************************************************* + */ +int GenerateSEImessage_rbsp (InputParameters *p_Inp, int id, byte *rbsp) +{ + Bitstream *bitstream; + + int len = 0, LenInBytes; + assert (rbsp != NULL); + + if ((bitstream=calloc(1, sizeof(Bitstream)))==NULL) + no_mem_exit("SeqParameterSet:bitstream"); + + // .. and use the rbsp provided (or allocated above) for the data + bitstream->streamBuffer = rbsp; + bitstream->bits_to_go = 8; + + { + char sei_message[500] = ""; + char uuid_message[9] = "Random"; // This is supposed to be Random + unsigned int i, message_size = (unsigned int) strlen(p_Inp->SEIMessageText); + TIME_T start_time; + gettime(&start_time); // start time + + if (message_size == 0) + { + message_size = 13; + strncpy(sei_message,"Empty Message",message_size); + } + else + strncpy(sei_message,p_Inp->SEIMessageText,message_size); + + len+=write_u_v (8,"SEI: last_payload_type_byte", 5, bitstream); + message_size += 17; + while (message_size > 254) + { + len+=write_u_v (8,"SEI: ff_byte",255, bitstream); + message_size -= 255; + } + len+=write_u_v (8,"SEI: last_payload_size_byte",message_size, bitstream); + + // Lets randomize uuid based on time +#ifdef _WIN32 + len+=write_u_v (32,"SEI: uuid_iso_iec_11578",(int) start_time.HighPart, bitstream); + len+=write_u_v (32,"SEI: uuid_iso_iec_11578",(int) start_time.QuadPart, bitstream); +#else + len+=write_u_v (32,"SEI: uuid_iso_iec_11578",(int) start_time.tv_sec, bitstream); + len+=write_u_v (32,"SEI: uuid_iso_iec_11578",(int) start_time.tv_usec, bitstream); +#endif + len+=write_u_v (32,"SEI: uuid_iso_iec_11578",(int) (uuid_message[0] << 24) + (uuid_message[1] << 16) + (uuid_message[2] << 8) + (uuid_message[3] << 0), bitstream); + len+=write_u_v (32,"SEI: uuid_iso_iec_11578",(int) (uuid_message[4] << 24) + (uuid_message[5] << 16) + (uuid_message[6] << 8) + (uuid_message[7] << 0), bitstream); + for (i = 0; i < strlen(sei_message); i++) + len+=write_u_v (8,"SEI: user_data_payload_byte",sei_message[i], bitstream); + + len+=write_u_v (8,"SEI: user_data_payload_byte", 0, bitstream); + } + SODBtoRBSP(bitstream); // copies the last couple of bits into the byte buffer + + LenInBytes=bitstream->byte_pos; + + free(bitstream); + return LenInBytes; +} + +/*! + ************************************************************************************* + * \brief + * int WriteHRDParameters((seq_parameter_set_rbsp_t *sps, Bitstream *bitstream) + * + * + * \return + * size of the RBSP in bytes, negative in case of an error + * + * \note + ************************************************************************************* + */ + +int WriteHRDParameters(seq_parameter_set_rbsp_t *sps, Bitstream *bitstream) +{ + // hrd_parameters() + int len = 0; + unsigned int SchedSelIdx = 0; + hrd_parameters_t *hrd = &(sps->vui_seq_parameters.nal_hrd_parameters); + + len+=write_ue_v ("VUI: cpb_cnt_minus1", hrd->cpb_cnt_minus1, bitstream); + len+=write_u_v (4, "VUI: bit_rate_scale", hrd->bit_rate_scale, bitstream); + len+=write_u_v (4, "VUI: cpb_size_scale", hrd->cpb_size_scale, bitstream); + + for( SchedSelIdx = 0; SchedSelIdx <= (hrd->cpb_cnt_minus1); SchedSelIdx++ ) + { + len+=write_ue_v ("VUI: bit_rate_value_minus1", hrd->bit_rate_value_minus1[SchedSelIdx], bitstream); + len+=write_ue_v ("VUI: cpb_size_value_minus1", hrd->cpb_size_value_minus1[SchedSelIdx], bitstream); + len+=write_u_1 ("VUI: cbr_flag", hrd->cbr_flag[SchedSelIdx], bitstream); + } + + len+=write_u_v (5, "VUI: initial_cpb_removal_delay_length_minus1", hrd->initial_cpb_removal_delay_length_minus1, bitstream); + len+=write_u_v (5, "VUI: cpb_removal_delay_length_minus1", hrd->cpb_removal_delay_length_minus1, bitstream); + len+=write_u_v (5, "VUI: dpb_output_delay_length_minus1", hrd->dpb_output_delay_length_minus1, bitstream); + len+=write_u_v (5, "VUI: time_offset_length", hrd->time_offset_length, bitstream); + + return len; +} + +/*! + ************************************************************************ + * \brief + * Returns the size of the dpb depending on level and picture size + * + * + ************************************************************************ + */ +static int getMaxDpbSize(seq_parameter_set_rbsp_t *active_sps) +{ + int pic_size = (active_sps->pic_width_in_mbs_minus1 + 1) * (active_sps->pic_height_in_map_units_minus1 + 1) * (active_sps->frame_mbs_only_flag?1:2) * 384; + + int size = 0; + + switch (active_sps->level_idc) + { + case 9: + size = 152064; + break; + case 10: + size = 152064; + break; + case 11: + if (!is_FREXT_profile(active_sps->profile_idc) && (active_sps->constrained_set3_flag == 1)) + size = 152064; + else + size = 345600; + break; + case 12: + size = 912384; + break; + case 13: + size = 912384; + break; + case 20: + size = 912384; + break; + case 21: + size = 1824768; + break; + case 22: + size = 3110400; + break; + case 30: + size = 3110400; + break; + case 31: + size = 6912000; + break; + case 32: + size = 7864320; + break; + case 40: + size = 12582912; + break; + case 41: + size = 12582912; + break; + case 42: + size = 13369344; + break; + case 50: + size = 42393600; + break; + case 51: + size = 70778880; + break; + default: + error ("undefined level", 500); + break; + } + + size /= pic_size; + size = imin( size, 16); + + return size; +} + +/*! + ************************************************************************************* + * \brief + * void GenerateVUIParameters(seq_parameter_set_rbsp_t *sps, InputParameters *p_Inp) + * + * + * \return + * none + * + * \note + ************************************************************************************* + */ + +void GenerateVUIParameters(seq_parameter_set_rbsp_t *sps, InputParameters *p_Inp) +{ + unsigned int SchedSelIdx; + hrd_parameters_t *nal_hrd = &(sps->vui_seq_parameters.nal_hrd_parameters); + hrd_parameters_t *vcl_hrd = &(sps->vui_seq_parameters.vcl_hrd_parameters); + vui_seq_parameters_t *vui = &(sps->vui_seq_parameters); + VUIParameters *iVui = &p_Inp->VUI; + + vui->aspect_ratio_info_present_flag = (Boolean) iVui->aspect_ratio_info_present_flag; + vui->aspect_ratio_idc = (unsigned int) iVui->aspect_ratio_idc; + vui->sar_width = (unsigned short) iVui->sar_width; + vui->sar_height = (unsigned short) iVui->sar_height; + vui->overscan_info_present_flag = (Boolean) iVui->overscan_info_present_flag; + vui->overscan_appropriate_flag = (Boolean) iVui->overscan_appropriate_flag; + vui->video_signal_type_present_flag = (Boolean) iVui->video_signal_type_present_flag; + vui->video_format = (unsigned int) iVui->video_format; + vui->video_full_range_flag = (Boolean) iVui->video_full_range_flag; + vui->colour_description_present_flag = (Boolean) iVui->colour_description_present_flag; + vui->colour_primaries = (unsigned int) iVui->colour_primaries; + vui->transfer_characteristics = (unsigned int) iVui->transfer_characteristics; + vui->matrix_coefficients = (unsigned int) iVui->matrix_coefficients; + vui->chroma_location_info_present_flag = (Boolean) iVui->chroma_location_info_present_flag; + vui->chroma_sample_loc_type_top_field = (unsigned int) iVui->chroma_sample_loc_type_top_field; + vui->chroma_sample_loc_type_bottom_field = (unsigned int) iVui->chroma_sample_loc_type_bottom_field; + vui->timing_info_present_flag = (Boolean) iVui->timing_info_present_flag; + vui->num_units_in_tick = (unsigned int) iVui->num_units_in_tick; + vui->time_scale = (unsigned int) iVui->time_scale; + vui->fixed_frame_rate_flag = (Boolean) iVui->fixed_frame_rate_flag; + + // NAL HRD parameters + vui->nal_hrd_parameters_present_flag = (Boolean) iVui->nal_hrd_parameters_present_flag; + nal_hrd->cpb_cnt_minus1 = (unsigned int) iVui->nal_cpb_cnt_minus1; + nal_hrd->bit_rate_scale = (unsigned int) iVui->nal_bit_rate_scale; + nal_hrd->cpb_size_scale = (unsigned int) iVui->nal_cpb_size_scale; + for ( SchedSelIdx = 0; SchedSelIdx <= nal_hrd->cpb_cnt_minus1; SchedSelIdx++ ) + { + nal_hrd->bit_rate_value_minus1[SchedSelIdx] = (unsigned int) iVui->nal_bit_rate_value_minus1; + nal_hrd->cpb_size_value_minus1[SchedSelIdx] = (unsigned int) iVui->nal_cpb_size_value_minus1; + nal_hrd->cbr_flag[SchedSelIdx] = (unsigned int) iVui->nal_vbr_cbr_flag; + } + nal_hrd->initial_cpb_removal_delay_length_minus1 = (unsigned int) iVui->nal_initial_cpb_removal_delay_length_minus1; + nal_hrd->cpb_removal_delay_length_minus1 = (unsigned int) iVui->nal_cpb_removal_delay_length_minus1; + nal_hrd->dpb_output_delay_length_minus1 = (unsigned int) iVui->nal_dpb_output_delay_length_minus1; + nal_hrd->time_offset_length = (unsigned int) iVui->nal_time_offset_length; + + // VCL HRD parameters + vui->vcl_hrd_parameters_present_flag = (Boolean) iVui->vcl_hrd_parameters_present_flag; + vcl_hrd->cpb_cnt_minus1 = (unsigned int) iVui->vcl_cpb_cnt_minus1; + vcl_hrd->bit_rate_scale = (unsigned int) iVui->vcl_bit_rate_scale; + vcl_hrd->cpb_size_scale = (unsigned int) iVui->vcl_cpb_size_scale; + for ( SchedSelIdx = 0; SchedSelIdx <= vcl_hrd->cpb_cnt_minus1; SchedSelIdx++ ) + { + vcl_hrd->bit_rate_value_minus1[SchedSelIdx] = (unsigned int) iVui->vcl_bit_rate_value_minus1; + vcl_hrd->cpb_size_value_minus1[SchedSelIdx] = (unsigned int) iVui->vcl_cpb_size_value_minus1; + vcl_hrd->cbr_flag[SchedSelIdx] = (unsigned int) iVui->vcl_vbr_cbr_flag; + } + vcl_hrd->initial_cpb_removal_delay_length_minus1 = (unsigned int) iVui->vcl_initial_cpb_removal_delay_length_minus1; + vcl_hrd->cpb_removal_delay_length_minus1 = (unsigned int) iVui->vcl_cpb_removal_delay_length_minus1; + vcl_hrd->dpb_output_delay_length_minus1 = (unsigned int) iVui->vcl_dpb_output_delay_length_minus1; + vcl_hrd->time_offset_length = (unsigned int) iVui->vcl_time_offset_length; + + vui->low_delay_hrd_flag = (Boolean) iVui->low_delay_hrd_flag; + vui->pic_struct_present_flag = (Boolean) iVui->pic_struct_present_flag; + vui->bitstream_restriction_flag = (Boolean) iVui->bitstream_restriction_flag; + vui->motion_vectors_over_pic_boundaries_flag = (Boolean) iVui->motion_vectors_over_pic_boundaries_flag; + vui->max_bytes_per_pic_denom = (unsigned int) iVui->max_bytes_per_pic_denom; + vui->max_bits_per_mb_denom = (unsigned int) iVui->max_bits_per_mb_denom; + vui->log2_max_mv_length_horizontal = (unsigned int) iVui->log2_max_mv_length_horizontal; + vui->log2_max_mv_length_vertical = (unsigned int) iVui->log2_max_mv_length_vertical; + vui->max_dec_frame_buffering = (unsigned int) imin( iVui->max_dec_frame_buffering, getMaxDpbSize(sps) ); + vui->num_reorder_frames = (unsigned int) imin( iVui->num_reorder_frames, (int)vui->max_dec_frame_buffering ); + + // special case to signal the RGB format + if (p_Inp->output.color_model != CM_YUV && p_Inp->output.yuv_format == YUV444) + { + printf ("VUI: writing Sequence Parameter VUI to signal RGB format\n"); + + vui->aspect_ratio_info_present_flag = FALSE; + vui->overscan_info_present_flag = FALSE; + vui->video_signal_type_present_flag = TRUE; + vui->video_format = 2; + vui->video_full_range_flag = TRUE; + vui->colour_description_present_flag = TRUE; + vui->colour_primaries = 2; + vui->transfer_characteristics = 2; + vui->matrix_coefficients = 0; + vui->chroma_location_info_present_flag = FALSE; + vui->timing_info_present_flag = FALSE; + vui->nal_hrd_parameters_present_flag = FALSE; + vui->vcl_hrd_parameters_present_flag = FALSE; + vui->pic_struct_present_flag = FALSE; + vui->bitstream_restriction_flag = FALSE; + } +} diff --git a/lencod/src/pred_struct.c b/lencod/src/pred_struct.c new file mode 100644 index 0000000..a840ade --- /dev/null +++ b/lencod/src/pred_struct.c @@ -0,0 +1,2602 @@ +/*! + *************************************************************************** + * \file + * pred_struct.c + * + * \author + * Athanasios Leontaris + * + * \date + * June 8, 2009 + * + * \brief + * Source file for prediction structure function + ************************************************************************** + */ + +#include "pred_struct.h" +#include "explicit_seq.h" + +#define DEBUG_PRED_STRUCT 0 + +static inline void pop_pred_struct_frm( PredStructFrm *p_dst, int slice_type, int nal_ref_idc, int disp_offset, int layer, int slice_qp_off, + int random_access, int temporal_layer ); +static void init_gop_struct( InputParameters *p_Inp, SeqStructure *p_seq_struct, int is_idr, int *memory_size ); +static void free_gop_struct( SeqStructure *p_seq_struct ); +static void init_pred_struct( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, int *memory_size ); +static void free_pred_struct( SeqStructure *p_seq_struct ); +static PicStructure * alloc_pic_struct( int num_slices, int *memory_size ); +static void free_pic_struct( PicStructure *p_pic ); +static FrameUnitStruct * alloc_frame_buffer( InputParameters *p_Inp, int num_frames, int num_slices, int *memory_size ); +static void free_frame_buffer( FrameUnitStruct *p_frm_struct, int num_frames ); + +static int rand_acc_test_range( int curr_frame, int offset, int idr_period ); +static inline int check_power_of_two( int number ); +static int establish_random_access( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames, int sim ); +static int establish_intra( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames, int sim ); +static int establish_sp( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames, int sim ); +static int get_fixed_frame( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames ); +static int get_prd_index( InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_frames ); +static int get_idr_index( InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_frames ); +static int get_intra_index( InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_frames ); +static void populate_frame( InputParameters *p_Inp, SeqStructure *p_seq_struct, FrameUnitStruct *p_frm_struct, PredStructAtom *p_cur_prd, + int curr_frame, int pred_frame, int idx, int num_slices, int no_rnd_acc ); +static void update_frame_indices( SeqStructure *p_seq_struct, FrameUnitStruct *p_frm_struct, int curr_frame, int pred_frame ); +static int populate_reg_pred_struct_atom( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, + int curr_frame, int proc_frames, int *terminate_pop ); +static int populate_rnd_acc_pred_struct_atom( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, + int curr_frame, int proc_frames, int *terminate_pop, int is_idr, int no_rnd_acc ); +#if (MVC_EXTENSION_ENABLE) +static void copy_frame_mvc( InputParameters *p_Inp, FrameUnitStruct *p_src, FrameUnitStruct *p_dst, int num_slices, int view_id ); +#endif + +/*! + *********************************************************************** + * \brief + * Derivation of Picture Order Count Type 0 + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_frm_struct + * pointer to the cyclical frame unit buffer + *********************************************************************** + */ + +void get_poc_type_zero( VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_frm_struct ) +{ + FrameUnitStruct *p_cur = p_frm_struct; // + (curr_frm_idx % p_Vid->frm_struct_buffer); + int last_disp_order; + + if ( p_Vid->last_idr_code_order > p_Vid->last_mmco_5_code_order ) + { + last_disp_order = p_Vid->last_idr_disp_order; + } + else + { + last_disp_order = p_Vid->last_mmco_5_disp_order; + } + + if ( p_cur->idr_flag ) + { + p_Vid->toppoc = 0; + } + else + { + p_Vid->toppoc = (p_cur->frame_no - last_disp_order) << 1; + } + // frame_skip consideration + p_Vid->toppoc = (1 + p_Inp->frame_skip) * p_Vid->toppoc; + + if ( p_Inp->PicInterlace == FRAME_CODING && p_Inp->MbInterlace == FRAME_CODING ) + { + p_Vid->bottompoc = p_Vid->toppoc; // progressive + } + else + { + p_Vid->bottompoc = p_Vid->toppoc + 1; // hard coded + } + + p_Vid->framepoc = imin( p_Vid->toppoc, p_Vid->bottompoc ); +} + +/*! + *********************************************************************** + * \brief + * Derivation of Picture Order Count Type 1 + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_frm_struct + * pointer to the cyclical frame unit buffer + *********************************************************************** + */ + +void get_poc_type_one( VideoParameters *p_Vid, InputParameters *p_Inp, FrameUnitStruct *p_frm_struct ) +{ + FrameUnitStruct *p_cur = p_frm_struct; // + curr_frm_idx; + int i; + int AbsFrameNum; + int ExpectedDeltaPerPicOrderCntCycle; + int PicOrderCntCycleCnt; + int FrameNumInPicOrderCntCycle; + int ExpectedPicOrderCnt; + CodingParameters *p_EncodePar = p_Vid->p_EncodePar[p_Vid->dpb_layer_id]; + + // we need to get type 0 values first and then estimate delta_pic_order_cnt with respect to those + get_poc_type_zero( p_Vid, p_Inp, p_frm_struct ); + + // next we use the decoder POC Type 1 code to determine the delta_pic_order_cnt + + // derive p_Vid->FrameNumOffset + if ( p_cur->idr_flag ) + { + p_Vid->FrameNumOffset = 0; + p_Vid->delta_pic_order_cnt[0] = 0; + } + else + { + if ( p_Vid->last_has_mmco_5 ) + { + p_EncodePar->prevFrameNumOffset = 0; + p_EncodePar->prevFrameNum = 0; + } + if ( p_Vid->frame_num < p_EncodePar->prevFrameNum ) + { + p_Vid->FrameNumOffset = p_EncodePar->prevFrameNumOffset + p_Vid->max_frame_num; + } + else + { + p_Vid->FrameNumOffset = p_EncodePar->prevFrameNumOffset; + } + } + + // derive AbsFrameNum + if ( p_Vid->num_ref_frames_in_pic_order_cnt_cycle ) + { + AbsFrameNum = p_Vid->FrameNumOffset + p_Vid->frame_num; + } + else + { + AbsFrameNum=0; + } + if ( !(p_cur->nal_ref_idc) && AbsFrameNum > 0 ) + { + AbsFrameNum--; + } + + // derive ExpectedPicOrderCnt + ExpectedDeltaPerPicOrderCntCycle=0; + if ( p_Vid->num_ref_frames_in_pic_order_cnt_cycle ) + { + for( i = 0; i < (int) p_Vid->num_ref_frames_in_pic_order_cnt_cycle; i++ ) + { + ExpectedDeltaPerPicOrderCntCycle += p_Vid->offset_for_ref_frame[i]; + } + } + + if ( AbsFrameNum ) + { + PicOrderCntCycleCnt = (AbsFrameNum - 1) / p_Vid->num_ref_frames_in_pic_order_cnt_cycle; + FrameNumInPicOrderCntCycle = (AbsFrameNum - 1) % p_Vid->num_ref_frames_in_pic_order_cnt_cycle; + + ExpectedPicOrderCnt = PicOrderCntCycleCnt * ExpectedDeltaPerPicOrderCntCycle; + for ( i = 0; i <= (int)FrameNumInPicOrderCntCycle; i++ ) + { + ExpectedPicOrderCnt += p_Vid->offset_for_ref_frame[i]; + } + } + else + { + ExpectedPicOrderCnt = 0; + } + + if ( !(p_cur->nal_ref_idc) ) + { + ExpectedPicOrderCnt += p_Vid->offset_for_non_ref_pic; + } + + p_Vid->delta_pic_order_cnt[0] = p_Vid->toppoc - ExpectedPicOrderCnt; + p_Vid->delta_pic_order_cnt[1] = 0; + + // update parameters + p_Vid->prevFrameNum = p_EncodePar->prevFrameNum = p_Vid->frame_num; + p_Vid->prevFrameNumOffset = p_EncodePar->prevFrameNumOffset = p_Vid->FrameNumOffset; +} + +/*! + *********************************************************************** + * \brief + * Initializes POC type 0 and 1: POC type 1 simulates the decoder's behavior and sets values \n + * given the POCs calculated for POC type 0; needs to be tested + * \param p_Vid + * pointer to the VideoParameters structure + *********************************************************************** + */ + +void init_poc(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + // general parameters + p_Vid->pic_order_cnt_type = p_Inp->pic_order_cnt_type; + if ((p_Inp->PicInterlace == FRAME_CODING) && (p_Inp->MbInterlace == FRAME_CODING)) + { + p_Vid->bottom_field_pic_order_in_frame_present_flag = FALSE; + } + else + { + p_Vid->bottom_field_pic_order_in_frame_present_flag = TRUE; + } + + // POC type 0 + if ((p_Inp->PicInterlace==FRAME_CODING) && (p_Inp->MbInterlace==FRAME_CODING)) + { + p_Vid->delta_pic_order_cnt_bottom = 0; + } + else + { + p_Vid->delta_pic_order_cnt_bottom = 1; + } + + // POC type 1 (parameters need to be *optimized* for the prediction structure) + // should be good enough for now + p_Vid->delta_pic_order_always_zero_flag = FALSE; + p_Vid->num_ref_frames_in_pic_order_cnt_cycle = 1; + + // these initialization have to depend more on the structure + if (p_Inp->BRefPictures == 1) + { + p_Vid->offset_for_non_ref_pic = 0; + p_Vid->offset_for_ref_frame[0] = 2; + } + else + { + p_Vid->offset_for_non_ref_pic = -2*(p_Inp->NumberBFrames); + p_Vid->offset_for_ref_frame[0] = 2*(p_Inp->NumberBFrames + 1); + } + + if ((p_Inp->PicInterlace==FRAME_CODING) && (p_Inp->MbInterlace==FRAME_CODING)) + { + p_Vid->offset_for_top_to_bottom_field = 0; + } + else + { + p_Vid->offset_for_top_to_bottom_field = 1; + } +} + +/*! + *********************************************************************** + * \brief + * Allocate picture structure + * \param num_slices + * max number of slices used to code the current picture + * \param memory_size + * pointer to the memory_size variable to count the number of bytes allocated + * \return + * pointer to the allocated PicStructure + *********************************************************************** + */ + +static PicStructure * alloc_pic_struct( int num_slices, int *memory_size ) +{ + PicStructure *p_pic = (PicStructure *)malloc( sizeof( PicStructure ) ); + if ( p_pic == NULL ) + { + fprintf(stdout, "\nNot enough memory or error during memory allocation: alloc_pic_struct()"); + exit(1); + } + *memory_size += sizeof( PicStructure ); + + p_pic->num_slices = num_slices; // this could also be set on a frame basis + p_pic->p_Slice = (SliceStructure *)malloc( num_slices * sizeof( SliceStructure ) ); + if ( p_pic->p_Slice == NULL ) + { + fprintf(stdout, "\nNot enough memory or error during memory allocation: alloc_pic_struct()"); + exit(1); + } + *memory_size += (num_slices * sizeof( SliceStructure )); + + return p_pic; +} + +/*! + *********************************************************************** + * \brief + * Free picture structure + * \param p_pic + * pointer to the picture structure that we wish to deallocate + *********************************************************************** + */ + +static void free_pic_struct( PicStructure *p_pic ) +{ + if ( p_pic != NULL ) + { + if ( p_pic->p_Slice != NULL ) + { + free( p_pic->p_Slice ); + p_pic->p_Slice = NULL; + } + free( p_pic ); + } +} + +/*! + *********************************************************************** + * \brief + * Allocate frame buffer + * \param p_Inp + * pointer to the InputParameters structure + * \param num_frames + * number of frames/length of the cyclical frame buffer + * \param num_slices + * max number of slices used to code each frame unit in the cyclical frame buffer + * \param memory_size + * pointer to the memory_size variable to count the number of bytes allocated + * \return + * pointer to the allocated FrameUnitStruct + *********************************************************************** + */ + +static FrameUnitStruct * alloc_frame_buffer( InputParameters *p_Inp, int num_frames, int num_slices, int *memory_size ) +{ + int idx; + + // FrameUnitStruct + FrameUnitStruct *p_frm_struct = (FrameUnitStruct *)malloc( num_frames * sizeof( FrameUnitStruct ) ); + FrameUnitStruct *p_frm_tmp; + + if ( p_frm_struct == NULL ) + { + fprintf(stdout, "\nNot enough memory or error during memory allocation: alloc_frame_buffer()"); + exit(1); + } + *memory_size += num_frames * sizeof( FrameUnitStruct ); + + for ( idx = 0; idx < num_frames; idx++ ) + { + p_frm_tmp = p_frm_struct + idx; + + switch( p_Inp->PicInterlace ) + { + default: + case FRAME_CODING: + p_frm_tmp->field_pic_flag = 0; + p_frm_tmp->p_top_fld_pic = NULL; + p_frm_tmp->p_bot_fld_pic = NULL; + p_frm_tmp->p_frame_pic = alloc_pic_struct( num_slices, memory_size ); + break; + case FIELD_CODING: + p_frm_tmp->field_pic_flag = 1; + p_frm_tmp->p_top_fld_pic = alloc_pic_struct( num_slices, memory_size ); + p_frm_tmp->p_bot_fld_pic = alloc_pic_struct( num_slices, memory_size ); + p_frm_tmp->p_frame_pic = NULL; + break; + case ADAPTIVE_CODING: + p_frm_tmp->p_top_fld_pic = alloc_pic_struct( num_slices, memory_size ); + p_frm_tmp->p_bot_fld_pic = alloc_pic_struct( num_slices, memory_size ); + p_frm_tmp->p_frame_pic = alloc_pic_struct( num_slices, memory_size ); + break; + } + } + + return p_frm_struct; +} + +/*! + *********************************************************************** + * \brief + * Free frame buffer + * \param p_frm_struct + * pointer to the cyclical frame buffer + * \param num_frames + * number of frames in the cyclical frame buffer + *********************************************************************** + */ + +static void free_frame_buffer( FrameUnitStruct *p_frm_struct, int num_frames ) +{ + int idx; + FrameUnitStruct *p_frm_tmp; + + if ( p_frm_struct != NULL ) + { + for ( idx = 0; idx < num_frames; idx++ ) + { + p_frm_tmp = p_frm_struct + idx; + + free_pic_struct( p_frm_tmp->p_top_fld_pic ); + p_frm_tmp->p_top_fld_pic = NULL; + + free_pic_struct( p_frm_tmp->p_bot_fld_pic ); + p_frm_tmp->p_bot_fld_pic = NULL; + + free_pic_struct( p_frm_tmp->p_frame_pic ); + p_frm_tmp->p_frame_pic = NULL; + } + + free( p_frm_struct ); + } +} + +/*! + *********************************************************************** + * \brief + * Initialize sequence structure + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param memory_size + * pointer to the memory_size variable that stores the number of bytes allocated so far + * \return + * pointer to SeqStructure + *********************************************************************** + */ + +SeqStructure * init_seq_structure( VideoParameters *p_Vid, InputParameters *p_Inp, int *memory_size ) +{ +#if (MVC_EXTENSION_ENABLE) + int start, end; +#endif + SeqStructure *p_seq_struct = (SeqStructure *)malloc( sizeof( SeqStructure ) ); + int frames_to_pop; + + if ( p_seq_struct == NULL ) + { + fprintf(stdout, "\nNot enough memory or error during memory allocation: init_seq_structure()"); + exit(1); + } + + // set length of frame buffer + p_Inp->FrmStructBufferLength = imax( p_Inp->FrmStructBufferLength, imax( p_Inp->idr_period, p_Inp->intra_period ) + p_Inp->NumberBFrames + p_Inp->intra_delay + 2 ); + p_Vid->frm_struct_buffer = p_Inp->FrmStructBufferLength; + p_Vid->frm_struct_buffer = imin( p_Vid->frm_struct_buffer, p_Inp->no_frames ); + p_Inp->FrmStructBufferLength = imin( p_Inp->FrmStructBufferLength, p_Inp->no_frames ); + + p_Inp->FrmStructBufferLength = p_Inp->no_frames; + p_Vid->frm_struct_buffer = p_Inp->no_frames; + + *memory_size += sizeof( SeqStructure ); + + p_seq_struct->max_num_slices = (p_Inp->slice_mode == 1) ? imax(1, p_Vid->FrameSizeInMbs / p_Inp->slice_argument) : 1; + p_seq_struct->num_frames = p_Vid->frm_struct_buffer; + p_seq_struct->p_frm = alloc_frame_buffer( p_Inp, p_seq_struct->num_frames, p_seq_struct->max_num_slices, memory_size ); + p_seq_struct->last_random_access_frame = 0; + p_seq_struct->last_idr_frame = 0; + p_seq_struct->last_intra_frame = 0; + p_seq_struct->last_mmco_5_frame = -1; + p_seq_struct->curr_num_to_populate = p_Vid->frm_struct_buffer; + p_seq_struct->pop_start_frame = 0; + p_seq_struct->last_rand_access_disp = 0; + p_seq_struct->last_idr_disp = 0; + p_seq_struct->last_intra_disp = 0; + p_seq_struct->last_bl_frm_disposable = 0; + p_seq_struct->last_sp_frame = 0; + p_seq_struct->last_sp_disp = 0; + p_seq_struct->pop_flag = 0; + +#if (MVC_EXTENSION_ENABLE) + p_seq_struct->num_frames_mvc = p_seq_struct->num_frames * p_Inp->num_of_views; // two views hence twice the buffer size + p_seq_struct->p_frm_mvc = alloc_frame_buffer( p_Inp, p_seq_struct->num_frames_mvc, p_seq_struct->max_num_slices, memory_size ); +#endif + + // initialize prediction structures + init_pred_struct( p_Vid, p_Inp, p_seq_struct, memory_size ); + init_gop_struct ( p_Inp, p_seq_struct, 1, memory_size ); // IDR GOPs + init_gop_struct ( p_Inp, p_seq_struct, 0, memory_size ); // Intra GOPs + + frames_to_pop = p_Vid->frm_struct_buffer; + + // populate frames +#if (MVC_EXTENSION_ENABLE) + start = p_seq_struct->pop_start_frame; + populate_frm_struct( p_Vid, p_Inp, p_seq_struct, frames_to_pop, p_Inp->no_frames ); + + if ( p_Inp->num_of_views > 1 ) + { + assert( p_Inp->num_of_views < 4 ); + end = p_seq_struct->pop_start_frame; + populate_frm_struct_mvc( p_Vid, p_Inp, p_seq_struct, start, end ); + } +#else + populate_frm_struct( p_Vid, p_Inp, p_seq_struct, frames_to_pop, p_Inp->no_frames ); +#endif + + return p_seq_struct; +} + +/*! + *********************************************************************** + * \brief + * Free sequence structure + * \param p_seq_struct + * pointer to the sequence structure we wish to deallocate + *********************************************************************** + */ + +void free_seq_structure( SeqStructure *p_seq_struct ) +{ + free_frame_buffer( p_seq_struct->p_frm, p_seq_struct->num_frames ); + p_seq_struct->p_frm = NULL; +#if (MVC_EXTENSION_ENABLE) + free_frame_buffer( p_seq_struct->p_frm_mvc, p_seq_struct->num_frames_mvc ); + p_seq_struct->p_frm_mvc = NULL; +#endif + free_gop_struct( p_seq_struct ); + p_seq_struct->p_gop = NULL; + free_pred_struct( p_seq_struct ); + p_seq_struct->p_prd = NULL; + + if ( p_seq_struct != NULL ) + { + free( p_seq_struct ); + } +} + +/*! + *********************************************************************** + * \brief + * Establish whether the frame with coding order "curr_frame" will be coded as an IDR picture + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * coding order of the current frame + * \param avail_frames + * frames available for population + * \param sim + * simulate the insertion: this disables checks about available frames ;) + * \return + * returns 1 when current frame will be a random access frame \n + * if PreferDispOrder == 1 then it returns 1 + disp_offset (for the random access frame) + *********************************************************************** + */ + +static int establish_random_access( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames, int sim ) +{ + int delta; + int is_random_access = 0; + + if ( !curr_frame ) // first frame in coding order + { + if ( !(p_Inp->PreferDispOrder) ) // coding order + { + is_random_access = 1; + } + else + { + int idx; + PredStructAtom *p_cur_gop; + + // test each random access prediction structure, starting from the longest one + // if random access is established then break from this loop and prepare output parameter + for ( idx = (p_seq_struct->num_gops - 1); idx >= 0; idx-- ) + { + p_cur_gop = p_seq_struct->p_gop + idx; + // check if length of structure overflows the available frame number + if ( sim ) + { + if ( (curr_frame + p_cur_gop->length) <= p_Inp->no_frames ) + { + is_random_access = 1 + idx; + break; + } + } + else + { + if ( p_cur_gop->length <= avail_frames ) + { + is_random_access = 1 + idx; + break; + } + } + } + } + } + else if ( p_Inp->idr_period ) + { + if ( !(p_Inp->PreferDispOrder) ) // coding order + { + switch ( p_Inp->adaptive_idr_period ) + { + default: + case 0: + if ( curr_frame % p_Inp->idr_period == 0 ) + { + is_random_access = 1; + } + break; + case 1: + delta = curr_frame - p_seq_struct->last_random_access_frame; + if ( delta >= p_Inp->idr_period && delta >= p_Inp->MinIDRDistance ) + { + is_random_access = 1; + } + break; + case 2: + delta = curr_frame - imax( p_seq_struct->last_random_access_frame, p_seq_struct->last_intra_frame); + if ( delta >= p_Inp->idr_period && delta >= p_Inp->MinIDRDistance ) + { + is_random_access = 1; + } + break; + } + } + else // display order (insertion) + { + int idx; + int offset; + PredStructAtom *p_cur_gop; + + // test each random access prediction structure, starting from the longest one + // if random access is established then break from this loop and prepare output parameter + for ( idx = (p_seq_struct->num_gops - 1); idx >= 0; idx-- ) + { + p_cur_gop = p_seq_struct->p_gop + idx; + // check if length of structure overflows the available frame number + if ( sim ) + { + if ( (curr_frame + p_cur_gop->length) > p_Inp->no_frames ) + { + continue; + } + } + else + { + if ( p_cur_gop->length > avail_frames ) + { + continue; + } + } + // recall that frame "0" is the random access frame in those prediction structures + offset = p_cur_gop->p_frm[0].disp_offset; + + // now test if random access conditions are satisfied + switch ( p_Inp->adaptive_idr_period ) + { + default: + case 0: + if ( !curr_frame || (curr_frame + offset - p_Inp->intra_delay) % p_Inp->idr_period == 0 ) + { + is_random_access = 1 + idx; + } + break; + case 1: + delta = (curr_frame + offset) - p_seq_struct->last_rand_access_disp; + if ( !curr_frame || (delta >= p_Inp->idr_period && delta >= p_Inp->MinIDRDistance) ) + { + is_random_access = 1 + idx; + } + break; + case 2: + delta = (curr_frame + offset) - imax( p_seq_struct->last_rand_access_disp, p_seq_struct->last_intra_disp); + if ( !curr_frame || (delta >= p_Inp->idr_period && delta >= p_Inp->MinIDRDistance) ) + { + is_random_access = 1 + idx; + } + break; + } + if ( is_random_access ) + { + break; + } + } + } + } + // additional case can be added to insert IDR based on *pre-analysis* and other "pre-scient" tools + + return is_random_access; +} + +/*! + *********************************************************************** + * \brief + * Test if IDR is placed between curr_frame and curr_frame + offset inclusive + *********************************************************************** + */ + +static int rand_acc_test_range( int curr_frame, int offset, int idr_period ) +{ + int idx; + int no_rnd_acc = 1; + + if ( idr_period > 0 ) + { + for ( idx = curr_frame; idx <= (curr_frame + offset); idx++ ) + { + if ( idx % idr_period == 0 ) + { + no_rnd_acc = 0; + break; + } + } + } + + return no_rnd_acc; +} + +/*! + *********************************************************************** + * \brief + * Establish whether the frame with coding order "curr_frame" will be coded as an INTRA picture + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * coding order of the current frame + * \param avail_frames + * frames available for population + * \return + * returns 1 when current frame will be an intra frame \n + * if PreferDispOrder == 1 then it returns 1 + disp_offset (for the intra frame) + *********************************************************************** + */ + +static int establish_intra( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames, int sim ) +{ + int is_intra = 0; + + if ( !curr_frame ) // first frame in coding order + { + is_intra = 1; + } + else if ( p_Inp->intra_period ) + { + if ( !(p_Inp->PreferDispOrder) ) // coding order + { + switch ( p_Inp->adaptive_intra_period ) + { + default: + case 0: + if ( curr_frame % p_Inp->intra_period == 0 ) + { + is_intra = 1; + } + break; + case 1: + if ( (curr_frame - imax( p_seq_struct->last_idr_frame, p_seq_struct->last_intra_frame)) % p_Inp->intra_period == 0 ) + { + is_intra = 1; + } + break; + } + } + else // display order (insertion) + { + int idx; + int offset; + PredStructAtom *p_cur_gop; + + // test each random access prediction structure, staring from the longest one + // if random access is established then break from this loop and prepare output parameter + for ( idx = (p_seq_struct->num_intra_gops - 1); idx >= 0; idx-- ) + { + p_cur_gop = p_seq_struct->p_intra_gop + idx; + // check if length of structure overflows the available frame number + if ( sim ) + { + if ( (curr_frame + p_cur_gop->length) > p_Inp->no_frames ) + { + continue; + } + } + else + { + if ( p_cur_gop->length > avail_frames ) + { + continue; + } + } + // recall that frame "0" is the random access frame in those prediction structures + offset = p_cur_gop->p_frm[0].disp_offset; + + // now test if random access conditions are satisfied + switch ( p_Inp->adaptive_intra_period ) + { + default: + case 0: + // intra_period operates as if EnableIDRGOP=0 which means that the criteria for its insertion, when inserting based on display order + // may be satisfied before (in terms of coding order) an IDR_period with EnableIDRGOP=1 (for 0 there is no issue) + // this code ensures that IDRPeriod always takes precedence over IntraPeriod + if ( (curr_frame + offset) % p_Inp->intra_period == 0 && rand_acc_test_range( curr_frame, offset, p_Inp->idr_period ) ) + { + is_intra = 1 + idx; + } + break; + case 2: + // see comment above + if ( ((curr_frame + offset) - imax( p_seq_struct->last_idr_disp, p_seq_struct->last_intra_disp)) % p_Inp->intra_period == 0 + && rand_acc_test_range( curr_frame - imax( p_seq_struct->last_idr_disp, p_seq_struct->last_intra_disp), offset, p_Inp->idr_period ) ) + { + is_intra = 1 + idx; + } + break; + } + if ( is_intra ) + { + break; + } + } + } + } + // additional case can be added to insert IDR based on *pre-analysis* and other "pre-scient" tools + + return is_intra; +} + +/*! + *********************************************************************** + * \brief + * Establish whether the frame with coding order "curr_frame" will be coded as an SP picture + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * coding order of the current frame + * \param avail_frames + * frames available for population + * \return + * returns 1 when current frame will be an SP frame \n + * if PreferDispOrder == 1 then it returns 1 + disp_offset (for the SP frame) + *********************************************************************** + */ + +static int establish_sp( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames, int sim ) +{ + int is_sp = 0; + + if ( p_Inp->sp_periodicity ) + { + if ( !(p_Inp->PreferDispOrder) ) // coding order + { + if ( (curr_frame - p_seq_struct->last_sp_frame) % p_Inp->sp_periodicity == 0 ) + { + is_sp = 1; + } + } + else // display order (insertion) + { + int idx; + int offset; + PredStructAtom *p_cur_gop; + + // test each random access prediction structure, staring from the longest one + // if random access is established then break from this loop and prepare output parameter + for ( idx = (p_seq_struct->num_gops - 1); idx >= 0; idx-- ) + { + p_cur_gop = p_seq_struct->p_gop + idx; + // check if length of structure overflows the available frame number + if ( sim ) + { + if ( (curr_frame + p_cur_gop->length) > p_Inp->no_frames ) + { + continue; + } + } + else + { + if ( p_cur_gop->length > avail_frames ) + { + continue; + } + } + + // recall that frame "0" is the random access frame in those prediction structures + offset = p_cur_gop->p_frm[0].disp_offset; + + // now test if random access conditions are satisfied + if ( (curr_frame + offset - p_seq_struct->last_sp_disp) % p_Inp->sp_periodicity == 0 ) + { + is_sp = 1 + idx; + break; + } + } + } + } + + return is_sp; +} + +/*! + *********************************************************************** + * \brief + * Find closest fixed frame (IDR, intra, or slice set through some pre-analysis tool) + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * coding order of the current frame + * \param avail_frames + * frames available for population + * \return + * returns the coding order of the first "fixed" frame, if none then -1 + *********************************************************************** + */ + +static int get_fixed_frame( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames ) +{ + int idx = 0; + int is_rnd_acc = 0; + int is_intra = 0; + int is_sp = 0; + + while ( idx < avail_frames ) + { + is_rnd_acc = establish_random_access( p_Inp, p_seq_struct, curr_frame + idx, avail_frames - idx, 1 ); + is_intra = establish_intra( p_Inp, p_seq_struct, curr_frame + idx, avail_frames - idx, 1 ); + is_sp = establish_sp( p_Inp, p_seq_struct, curr_frame + idx, avail_frames - idx, 1 ); + if ( is_rnd_acc || is_intra || is_sp ) + { + return idx; + } + idx++; + } + // signal that there is no fixed frame in the processed frames buffer (functions have to interpret the negative output here) + return -1; +} + +/*! + *********************************************************************** + * \brief + * Find closest fixed frame (IDR, intra, or slice set through some pre-analysis tool) + * for regular prediction structures and then try place the longest possible structure... + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * coding order of the current frame + * \param avail_frames + * frames available for population + * \return + * returns the coding order of the first "fixed" frame, if none then -1 + *********************************************************************** + */ + +static int get_fixed_frame_for_prd( InputParameters *p_Inp, SeqStructure *p_seq_struct, int curr_frame, int avail_frames ) +{ + int idx = 0; + int is_rnd_acc = 0; + int is_intra = 0; + int is_sp = 0; + PredStructAtom *p_longest_prd = p_seq_struct->p_prd + p_seq_struct->num_prds - 1; + + while ( idx < avail_frames ) + { + // IDRs + is_rnd_acc = establish_random_access( p_Inp, p_seq_struct, curr_frame + idx, avail_frames - idx, 1 ); + if ( is_rnd_acc ) + { + if ( p_Inp->PreferDispOrder && !(p_Inp->EnableIDRGOP) ) + { + int gop_length; + PredStructAtom *p_curr_gop; + + // decode is_intra + if ( is_rnd_acc > 1 ) + { + p_curr_gop = p_seq_struct->p_gop + is_rnd_acc - 1; + gop_length = p_curr_gop->length; + } + else + { + gop_length = 1; + } + // consider the case where even though there were enough available frames to a large structure, these slots + // instead were allocated to a very long intra structure, which reduces compression efficiency + if ( (idx % p_longest_prd->length) < p_longest_prd->length ) + { + p_seq_struct->pop_flag = POP_IDR; + return ( imin( p_longest_prd->length, idx + gop_length - 1 ) ); + } + else + { + return idx; + } + } + else + { + return idx; + } + } + // Intras + is_intra = establish_intra( p_Inp, p_seq_struct, curr_frame + idx, avail_frames - idx, 1 ); + if ( is_intra ) + { + if ( p_Inp->PreferDispOrder ) + { + int gop_length; + PredStructAtom *p_curr_gop; + + // decode is_intra + if ( is_intra > 1 ) + { + p_curr_gop = p_seq_struct->p_intra_gop + is_intra - 1; + gop_length = p_curr_gop->length; + } + else + { + gop_length = 1; + } + // consider the case where even though there were enough available frames to a large structure, these slots + // instead were allocated to a very long intra structure, which reduces compression efficiency + if ( (idx % p_longest_prd->length) < p_longest_prd->length ) + { + p_seq_struct->pop_flag = POP_INTRA; + return ( imin( p_longest_prd->length, idx + gop_length - 1 ) ); + } + else + { + return idx; + } + } + else + { + return idx; + } + } + // SP/SIs + is_sp = establish_sp( p_Inp, p_seq_struct, curr_frame + idx, avail_frames - idx, 1 ); + if ( is_sp ) + { + if ( p_Inp->PreferDispOrder && !(p_Inp->EnableIDRGOP) ) + { + int gop_length; + PredStructAtom *p_curr_gop; + + // decode is_intra + if ( is_sp > 1 ) + { + p_curr_gop = p_seq_struct->p_gop + is_sp - 1; + gop_length = p_curr_gop->length; + } + else + { + gop_length = 1; + } + // consider the case where even though there were enough available frames to a large structure, these slots + // instead were allocated to a very long intra structure, which reduces compression efficiency + if ( (idx % p_longest_prd->length) < p_longest_prd->length ) + { + p_seq_struct->pop_flag = POP_SP; + return ( imin( p_longest_prd->length, idx + gop_length - 1 ) ); + } + else + { + return idx; + } + } + else + { + return idx; + } + } + idx++; + } + // signal that there is no fixed frame in the processed frames buffer (functions have to interpret the negative output here) + return -1; +} + +/*! + *********************************************************************** + * \brief + * Check if "number" is a power of two + * \param number + * input value + * \return + * 1 if power of two, 0 otherwise + *********************************************************************** + */ + +static inline int check_power_of_two( int number ) +{ + return (((~((~number) + 1)) & number ) == 0) ? 1 : 0; +} + +/*! + *********************************************************************** + * \brief + * Select index to pred structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param num_frames + * frames available for population + * \return + * returns the index to the selected prediction structure + *********************************************************************** + */ + +static int get_prd_index( InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_frames ) +{ + int curr_prd; + PredStructAtom *p_cur_prd; + + // allocate atoms + for ( curr_prd = (p_seq_struct->num_prds - 1); curr_prd >= 0; curr_prd-- ) + { + p_cur_prd = p_seq_struct->p_prd + curr_prd; + if ( p_Inp->PreferPowerOfTwo && curr_prd != (p_seq_struct->num_prds - 1) && !check_power_of_two( p_cur_prd->length ) ) + { + continue; + } + if ( p_cur_prd->length <= num_frames ) + { + return curr_prd; + } + } + return 0; +} + +/*! + *********************************************************************** + * \brief + * Select index to random access structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param num_frames + * frames available for population + * \return + * returns the index to the selected prediction structure + *********************************************************************** + */ + +static int get_idr_index( InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_frames ) +{ + int curr_gop; + PredStructAtom *p_cur_gop; + + // allocate atoms + for ( curr_gop = (p_seq_struct->num_gops - 1); curr_gop >= 0; curr_gop-- ) + { + p_cur_gop = p_seq_struct->p_gop + curr_gop; + if ( p_Inp->PreferPowerOfTwo && curr_gop != (p_seq_struct->num_gops - 1) && !check_power_of_two( p_cur_gop->length ) ) + { + continue; + } + if ( p_cur_gop->length <= num_frames ) + { + return curr_gop; + } + } + return 0; +} + +/*! + *********************************************************************** + * \brief + * Select index to intra structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param num_frames + * frames available for population + * \return + * returns the index to the selected prediction structure + *********************************************************************** + */ + +static int get_intra_index( InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_frames ) +{ + int curr_gop; + PredStructAtom *p_cur_gop; + + // allocate atoms + for ( curr_gop = (p_seq_struct->num_intra_gops - 1); curr_gop >= 0; curr_gop-- ) + { + p_cur_gop = p_seq_struct->p_intra_gop + curr_gop; + if ( p_Inp->PreferPowerOfTwo && curr_gop != (p_seq_struct->num_intra_gops - 1) && !check_power_of_two( p_cur_gop->length ) ) + { + continue; + } + if ( p_cur_gop->length <= num_frames ) + { + return curr_gop; + } + } + return 0; +} + +/*! + *********************************************************************** + * \brief + * Populate a PredStructFrm object + * \param p_dst + * Pointer to the object to be populated with the args of this func. + *********************************************************************** + */ + +static inline void pop_pred_struct_frm( PredStructFrm *p_dst, int slice_type, int nal_ref_idc, int disp_offset, int layer, int slice_qp_off, + int random_access, int temporal_layer ) +{ + p_dst->slice_type = slice_type; + p_dst->nal_ref_idc = nal_ref_idc; + p_dst->disp_offset = disp_offset; + p_dst->layer = layer; + p_dst->slice_qp_off = slice_qp_off; + p_dst->random_access = random_access; + p_dst->temporal_layer = temporal_layer; +} + +/*! + *********************************************************************** + * \brief + * Create random access prediction structures + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param memory_size + * frames available for population + * \param is_idr + * initialize an IDR GOP list as opposed to an Intra GOP list + * \return + * returns the index to the selected prediction structure + *********************************************************************** + */ + +static void init_gop_struct( InputParameters *p_Inp, SeqStructure *p_seq_struct, int is_idr, int *memory_size ) +{ + int idx; + int length; + PredStructAtom *p_cur_gop, *p_cur_prd, *p_cur_prd_tail = NULL, *p_gop; + PredStructFrm *p_dst, *p_src; + + if ( is_idr ) + { + // derive number of gop atoms + if ( p_Inp->idr_period == 1 || p_Inp->intra_period == 1 ) + { + p_seq_struct->num_gops = 1; + } + else if ( p_Inp->intra_delay && !p_Inp->EnableIDRGOP ) + { + p_seq_struct->num_gops = 3; + } + else if ( p_Inp->intra_delay || !p_Inp->EnableIDRGOP ) + { + p_seq_struct->num_gops = !p_Inp->EnableIDRGOP ? p_seq_struct->num_prds : 2; + } + else + { + p_seq_struct->num_gops = !p_Inp->EnableIDRGOP ? p_seq_struct->num_prds : 1; + } + + // we assume that intra_delay is ALWAYS lesser than the idr_period + if ( p_Inp->idr_period ) + { + assert( p_Inp->intra_delay < p_Inp->idr_period ); + } + + p_seq_struct->p_gop = (PredStructAtom *)malloc( p_seq_struct->num_gops * sizeof( PredStructAtom ) ); + *memory_size += ( p_seq_struct->num_gops * sizeof( PredStructAtom ) ); + + p_gop = p_seq_struct->p_gop; + } + else // intra GOP + { + // derive number of gop atoms + if ( p_Inp->intra_period == 1 ) + { + p_seq_struct->num_intra_gops = 1; + } + else if ( p_Inp->intra_delay ) + { + p_seq_struct->num_intra_gops = 3; + } + else + { + p_seq_struct->num_intra_gops = p_seq_struct->num_prds; + } + + // we assume that intra_delay is ALWAYS lesser than the intra_period + if ( p_Inp->intra_period ) + { + assert( p_Inp->intra_delay < p_Inp->intra_period ); + } + + p_seq_struct->p_intra_gop = (PredStructAtom *)malloc( p_seq_struct->num_intra_gops * sizeof( PredStructAtom ) ); + *memory_size += ( p_seq_struct->num_intra_gops * sizeof( PredStructAtom ) ); + + p_gop = p_seq_struct->p_intra_gop; + } + + // default IDR GOP + length = 1; + p_cur_gop = p_gop; + p_cur_gop->length = length; + p_cur_gop->p_frm = (PredStructFrm *)malloc( length * sizeof( PredStructFrm ) ); + *memory_size += length * sizeof( PredStructFrm ); + + // initialize atoms + p_cur_gop = p_gop; + p_dst = p_cur_gop->p_frm + 0; + pop_pred_struct_frm( p_dst, I_SLICE, NALU_PRIORITY_HIGHEST, 0, 0, 0, 1, 0 ); + + // intra-delayed IDR GOP + if ( p_Inp->intra_delay && p_Inp->intra_period != 1 && p_Inp->idr_period != 1 ) + { + int proc_frames = 0; + int start_frame = p_Inp->intra_delay - 1; + int idr_idx = 0; + int curr_prd; + + // allocate atoms + length = p_Inp->intra_delay + 1; + p_cur_gop = p_gop + 1; + p_cur_gop->length = length; + p_cur_gop->gop_levels = 1; + p_cur_gop->p_frm = (PredStructFrm *)malloc( length * sizeof( PredStructFrm ) ); + *memory_size += length * sizeof( PredStructFrm ); + + // IDR picture + p_cur_gop = p_gop + 1; + p_dst = p_cur_gop->p_frm + idr_idx; + pop_pred_struct_frm( p_dst, I_SLICE, NALU_PRIORITY_HIGHEST, p_Inp->intra_delay, 0, 0, 1, 0 ); + + idr_idx++; + + while ( proc_frames < p_Inp->intra_delay ) + { + // given the available slots select the index to the pred structure to use for current segment + curr_prd = get_prd_index( p_Inp, p_seq_struct, p_Inp->intra_delay - proc_frames ); + p_cur_prd = p_seq_struct->p_prd + curr_prd; + // set gop_levels + p_cur_gop->gop_levels = p_cur_prd->gop_levels; + // populate gop structure from selected structure + for ( idx = 0; idx < p_cur_prd->length; idx++, idr_idx++, proc_frames++ ) + { + p_dst = p_cur_gop->p_frm + idr_idx; + p_src = p_cur_prd->p_frm + idx; + + pop_pred_struct_frm( p_dst, p_src->slice_type, p_src->nal_ref_idc, start_frame - p_src->disp_offset, p_src->layer, + p_src->slice_qp_off, 0, p_src->temporal_layer ); + } + // update start_frame + start_frame -= p_cur_prd->length; + } + + // a separate case + if ( !p_Inp->EnableIDRGOP || !is_idr ) // an additional atom: the longest one + { + proc_frames = 0; + start_frame = p_Inp->intra_delay - 1; + idr_idx = 0; + + // longest structure + p_cur_prd_tail = p_seq_struct->p_prd + p_seq_struct->num_prds - 1; + + // allocate atoms + length = p_Inp->intra_delay + 1 + (p_cur_prd_tail->length - 1); + p_cur_gop = p_gop + 2; + p_cur_gop->length = length; + p_cur_gop->gop_levels = 1; + p_cur_gop->p_frm = (PredStructFrm *)malloc( length * sizeof( PredStructFrm ) ); + *memory_size += length * sizeof( PredStructFrm ); + idr_idx = 0; + + // IDR picture + p_cur_gop = p_gop + 2; + p_dst = p_cur_gop->p_frm + idr_idx; + pop_pred_struct_frm( p_dst, I_SLICE, NALU_PRIORITY_HIGHEST, p_Inp->intra_delay, 0, 0, 1, 0 ); + + idr_idx++; + + while ( proc_frames < p_Inp->intra_delay ) + { + // given the available slots select the index to the pred structure to use for current segment + curr_prd = get_prd_index( p_Inp, p_seq_struct, p_Inp->intra_delay - proc_frames ); + p_cur_prd = p_seq_struct->p_prd + curr_prd; + // set gop_levels + p_cur_gop->gop_levels = p_cur_prd->gop_levels; + // populate gop structure from selected structure + for ( idx = 0; idx < p_cur_prd->length; idx++, idr_idx++, proc_frames++ ) + { + p_dst = p_cur_gop->p_frm + idr_idx; + p_src = p_cur_prd->p_frm + idx; + + pop_pred_struct_frm( p_dst, p_src->slice_type, p_src->nal_ref_idc, start_frame - p_src->disp_offset, + p_src->layer, p_src->slice_qp_off, 0, p_src->temporal_layer ); + } + // update start_frame + start_frame -= p_cur_prd->length; + } + + // add an offset to the display offsets + for ( idr_idx = 0; idr_idx < (p_Inp->intra_delay + 1); idr_idx++ ) + { + p_cur_gop->p_frm[idr_idx].disp_offset += (p_cur_prd_tail->length - 1); + } + p_cur_gop->gop_levels = imax( p_cur_gop->gop_levels, p_cur_prd_tail->gop_levels ); + // and now place the prd struct *before* them in display order (set idx to 1 to avoid copying the I/P frame, we only seek the hierarchy if it exists) + for ( idx = 1; idx < p_cur_prd_tail->length; idx++, idr_idx++ ) + { + p_dst = p_cur_gop->p_frm + idr_idx; + p_src = p_cur_prd_tail->p_frm + idx; + + pop_pred_struct_frm( p_dst, p_src->slice_type, p_src->nal_ref_idc, p_src->disp_offset, + p_src->layer, p_src->slice_qp_off, 0, p_src->temporal_layer ); + } + } + } + else if ( !(p_Inp->intra_delay) && ((!p_Inp->EnableIDRGOP || !is_idr) && p_Inp->intra_period != 1 && p_Inp->idr_period != 1) ) + { + int gop_idx; + int idr_idx = 0; + + for ( gop_idx = 1; gop_idx < p_seq_struct->num_prds; gop_idx++ ) + { + // set structure + p_cur_prd = p_seq_struct->p_prd + gop_idx; + + // allocate atoms + length = p_cur_prd->length; + p_cur_gop = p_gop + gop_idx; + p_cur_gop->length = length; + p_cur_gop->p_frm = (PredStructFrm *)malloc( length * sizeof( PredStructFrm ) ); + *memory_size += length * sizeof( PredStructFrm ); + idr_idx = 0; + + // IDR picture + p_cur_gop->gop_levels = p_cur_prd->gop_levels; + p_dst = p_cur_gop->p_frm + idr_idx; + pop_pred_struct_frm( p_dst, I_SLICE, NALU_PRIORITY_HIGHEST, p_cur_prd->p_frm[0].disp_offset, 0, 0, 1, 0 ); + idr_idx++; + + // populate gop structure from selected structure + for ( idx = 1; idx < p_cur_prd->length; idx++, idr_idx++ ) + { + p_dst = p_cur_gop->p_frm + idr_idx; + p_src = p_cur_prd->p_frm + idx; + + pop_pred_struct_frm( p_dst, p_src->slice_type, p_src->nal_ref_idc, p_src->disp_offset, + p_src->layer, p_src->slice_qp_off, 0, p_src->temporal_layer ); + } + } // gop_idx + } +} + +/*! + *********************************************************************** + * \brief + * Create non-random access prediction structures + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param memory_size + * frames available for population + *********************************************************************** + */ + +static void init_pred_struct( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, int *memory_size ) +{ + int curr_prd, idx; + int frm, sum, layer, order; + int length, length2, pred_mode; + PredStructAtom *p_cur_prd; + PredStructFrm *p_dst; + + p_seq_struct->num_prds = (p_Inp->idr_period == 1 || p_Inp->intra_period == 1) ? 1 : (p_Inp->NumberBFrames + 1); + + p_seq_struct->p_prd = (PredStructAtom *)malloc( p_seq_struct->num_prds * sizeof( PredStructAtom ) ); + *memory_size += p_seq_struct->num_prds * sizeof( PredStructAtom ); + + // allocate atoms + for ( curr_prd = (p_seq_struct->num_prds - 1); curr_prd >= 0; curr_prd-- ) + { + // length of prediction structure + length = curr_prd + 1; + + p_cur_prd = p_seq_struct->p_prd + curr_prd; + p_cur_prd->length = length; + p_cur_prd->p_frm = (PredStructFrm *)malloc( length * sizeof( PredStructFrm ) ); + *memory_size += length * sizeof( PredStructFrm ); + } + + // initialize atoms + for ( curr_prd = (p_seq_struct->num_prds - 1); curr_prd >= 0; curr_prd-- ) + { + // length of prediction structure + length = curr_prd + 1; + + switch ( p_Inp->HierarchicalCoding ) + { + default: + case 0: + pred_mode = 0; + break; + case 1: + pred_mode = 1; + break; + case 2: + // check if power of two + pred_mode = check_power_of_two( length ) ? 2 : ( length > 4 ? 1 : 0 ); + break; + case 3: + // check again if power of two + if ( p_Inp->LowDelay ) + { + pred_mode = 3; + } + else + { + pred_mode = (length == (p_Inp->NumberBFrames + 1)) ? 3 : (check_power_of_two( length ) ? 2 : ( length > 4 ? 1 : 0 )); + } + break; + } + + p_cur_prd = p_seq_struct->p_prd + curr_prd; + p_cur_prd->gop_levels = 0; + switch ( pred_mode ) + { + default: + case 0: // disposable B-pics of equal priority + p_dst = p_cur_prd->p_frm + 0; + + p_dst->slice_type = ( p_Inp->BRefPictures == 2 ) ? B_SLICE : P_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_HIGH; + p_dst->disp_offset = length - 1; + p_dst->layer = 0; + p_dst->slice_qp_off = ( p_Inp->BRefPictures == 2 ) ? (p_Inp->qp[P_SLICE] - p_Inp->qp[B_SLICE]) : 0; // ensure all types of frames have identical QP (modifiers) + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + + for ( idx = 1; idx < length; idx++ ) + { + p_dst = p_cur_prd->p_frm + idx; + + p_dst->slice_type = ( p_Inp->PReplaceBSlice ) ? P_SLICE : B_SLICE; + p_dst->nal_ref_idc = ( p_Inp->BRefPictures == 1 && p_dst->slice_type == B_SLICE ) ? NALU_PRIORITY_LOW : NALU_PRIORITY_DISPOSABLE; + p_dst->disp_offset = idx - 1; + p_dst->layer = 2; + p_dst->slice_qp_off = ( p_Inp->PReplaceBSlice ) ? (p_Inp->qp[B_SLICE] - p_Inp->qp[P_SLICE]) : (p_dst->nal_ref_idc ? p_Inp->qpBRSOffset : 0); //2; 2 when depends on QPPSlice (highest layer QP) + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + } + if ( length > 1 ) + { + p_cur_prd->gop_levels = 1; + } + break; + case 1: // even/odd hierarchy + length2 = ((length - 1) >> 1) + 1; + + p_dst = p_cur_prd->p_frm + 0; + + p_dst->slice_type = ( p_Inp->BRefPictures == 2 ) ? B_SLICE : P_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_HIGH; + p_dst->disp_offset = length - 1; + p_dst->layer = 0; + p_dst->slice_qp_off = ( p_Inp->BRefPictures == 2 ) ? (p_Inp->qp[B_SLICE] - p_Inp->qp[P_SLICE]) : 0; // ensure all types of frames have identical QP (modifiers) + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + + for ( idx = 1; idx < length2; idx++ ) + { + p_dst = p_cur_prd->p_frm + idx; + + p_dst->slice_type = ( p_Inp->PReplaceBSlice ) ? P_SLICE : B_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_LOW; + p_dst->disp_offset = 2*(idx - 1) + 1; + p_dst->layer = 1; + p_dst->slice_qp_off = p_dst->slice_type == B_SLICE ? + (p_Inp->HierarchyLevelQPEnable ? -1: p_Inp->qpBRSOffset) : (p_Inp->HierarchyLevelQPEnable ? 1 : 0); // 1 + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + } + for ( idx = length2; idx < length; idx++ ) + { + p_dst = p_cur_prd->p_frm + idx; + + p_dst->slice_type = ( p_Inp->PReplaceBSlice ) ? P_SLICE : B_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_DISPOSABLE; + p_dst->disp_offset = (idx - length2) * 2; + p_dst->layer = 2; + p_dst->slice_qp_off = p_dst->slice_type == B_SLICE ? 0 : 2;//2; + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + } + if ( length > 1 ) + { + p_cur_prd->gop_levels = 2; + } + break; + case 2: // full binary decomposition + p_dst = p_cur_prd->p_frm + 0; + + p_dst->slice_type = ( p_Inp->BRefPictures == 2 ) ? B_SLICE : P_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_HIGH; + p_dst->disp_offset = length - 1; + p_dst->layer = 0; + p_dst->slice_qp_off = ( p_Inp->BRefPictures == 2 ) ? (p_Inp->qp[B_SLICE] - p_Inp->qp[P_SLICE]) : 0; // ensure all types of frames have identical QP (modifiers) + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + + if ( length > 3 ) + { + int GOPlevels = 1; + + // determine number of levels + while ((length >> GOPlevels) > 1) + { + GOPlevels ++; + } + p_cur_prd->gop_levels = GOPlevels; + + // hierarchical layer (from highest priority to lowest priority) + for ( layer = 1, order = 1, sum = 0, frm = 1; sum < (length - 1); frm = (frm << 1), sum += frm, layer++ ) + { + // layer frames (in *coding* order) + for ( idx = 0; idx < frm; idx++, order++ ) + { + p_dst = p_cur_prd->p_frm + order; + + p_dst->slice_type = ( p_Inp->PReplaceBSlice ) ? P_SLICE : B_SLICE; + p_dst->nal_ref_idc = (frm == (length >> 1)) ? NALU_PRIORITY_DISPOSABLE : NALU_PRIORITY_LOW; + p_dst->disp_offset = ((length - 1) >> layer) + idx * (length >> (layer - 1)); + p_dst->layer = layer; + p_dst->slice_qp_off = p_dst->slice_type == B_SLICE ? + (p_Inp->HierarchyLevelQPEnable ? (-GOPlevels + layer): (p_dst->nal_ref_idc != NALU_PRIORITY_DISPOSABLE ? p_Inp->qpBRSOffset : 0)) : (p_Inp->HierarchyLevelQPEnable ? layer : 0); // layer + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + } + } + } + else + { + for ( idx = 1; idx < length; idx++ ) + { + p_dst = p_cur_prd->p_frm + idx; + + p_dst->slice_type = ( p_Inp->PReplaceBSlice ) ? P_SLICE : B_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_DISPOSABLE; + p_dst->disp_offset = idx - 1; + p_dst->layer = 2; + p_dst->slice_qp_off = 0; //2; + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + } + if ( length > 1 ) + { + p_cur_prd->gop_levels = 1; + } + } + break; + case 3: // explicit structure + { + int max_layer = 0; + + // encode without delay + if ( p_Inp->LowDelay ) + { + for ( idx = 0; idx < (length - 1); idx++ ) + { + p_dst = p_cur_prd->p_frm + idx; + + p_dst->slice_type = p_Vid->gop_structure[idx].slice_type; + p_dst->nal_ref_idc = p_Vid->gop_structure[idx].reference_idc; + p_dst->disp_offset = p_Vid->gop_structure[idx].display_no; + p_dst->layer = ((p_Vid->gop_structure[idx].hierarchy_layer == 1) ? 0 : 1) + 1; // invert in new notation + p_dst->slice_qp_off = p_Vid->gop_structure[idx].slice_qp_off; + p_dst->random_access = 0; + + p_dst->temporal_layer = p_Vid->gop_structure[idx].temporal_layer; + + if ( p_Vid->gop_structure[idx - 1].hierarchy_layer > max_layer ) + { + max_layer = p_Vid->gop_structure[idx - 1].hierarchy_layer; + } + } + p_dst = p_cur_prd->p_frm + idx; + p_dst->slice_type = ( p_Inp->BRefPictures == 2 ) ? B_SLICE : P_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_HIGH; + p_dst->disp_offset = length - 1; + p_dst->layer = 0; + p_dst->slice_qp_off = ( p_Inp->BRefPictures == 2 ) ? (p_Inp->qp[B_SLICE] - p_Inp->qp[P_SLICE]) : 0; // ensure all types of frames have identical QP (modifiers) + p_dst->random_access = 0; + + p_dst->temporal_layer = 0; + } + else + { + p_dst = p_cur_prd->p_frm + 0; + + p_dst->slice_type = ( p_Inp->BRefPictures == 2 ) ? B_SLICE : P_SLICE; + p_dst->nal_ref_idc = NALU_PRIORITY_HIGH; + p_dst->disp_offset = length - 1; + p_dst->layer = 0; + p_dst->slice_qp_off = ( p_Inp->BRefPictures == 2 ) ? (p_Inp->qp[B_SLICE] - p_Inp->qp[P_SLICE]) : 0; // ensure all types of frames have identical QP (modifiers) + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + + for ( idx = 1; idx < length; idx++ ) + { + p_dst = p_cur_prd->p_frm + idx; + + p_dst->slice_type = p_Vid->gop_structure[idx - 1].slice_type; + p_dst->nal_ref_idc = p_Vid->gop_structure[idx - 1].reference_idc; + p_dst->disp_offset = p_Vid->gop_structure[idx - 1].display_no; + p_dst->layer = ((p_Vid->gop_structure[idx - 1].hierarchy_layer == 1) ? 0 : 1) + 1; // invert in new notation + p_dst->slice_qp_off = p_Vid->gop_structure[idx - 1].slice_qp_off; + p_dst->random_access = 0; + p_dst->temporal_layer = 0; + + if ( p_Vid->gop_structure[idx - 1].hierarchy_layer > max_layer ) + { + max_layer = p_Vid->gop_structure[idx - 1].hierarchy_layer; + } + } + } + p_cur_prd->gop_levels = max_layer + 1; + } + break; + } + } +} + +/*! + *********************************************************************** + * \brief + * Populate frame structure + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param num_to_populate + * number of frame unit structures to populate + *********************************************************************** + */ + +void populate_frm_struct( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, int num_to_populate, int init_frames_to_code ) +{ + // case 5: read explicit seq info and store it in the frm_struct + int curr_frame; // in coding order + int proc_frames; + int is_idr; + int is_intra; + int is_sp; + int terminate_pop = 0; + + p_seq_struct->curr_num_to_populate = imin( num_to_populate, init_frames_to_code - p_seq_struct->pop_start_frame ); + curr_frame = p_seq_struct->pop_start_frame; + proc_frames = 0; + + while ( proc_frames < p_seq_struct->curr_num_to_populate ) + { + is_idr = 0; + is_intra = 0; + is_sp = 0; + + // we have to check here for inserted frames (e.g. due to pre-analysis) and assign them to the structure (future work) + + // establish if it is an IDR frame + is_idr = establish_random_access( p_Inp, p_seq_struct, curr_frame, p_seq_struct->curr_num_to_populate - proc_frames, 0 ); + if ( is_idr && p_seq_struct->pop_flag != POP_INTRA && p_seq_struct->pop_flag != POP_SP ) + { + // random access structure + int gop_frame = populate_rnd_acc_pred_struct_atom( p_Vid, p_Inp, p_seq_struct, curr_frame, proc_frames, &terminate_pop, is_idr, 0 ); + // update counters + curr_frame += gop_frame; + proc_frames += gop_frame; + if ( terminate_pop ) + { + terminate_pop = 0; + break; // the proc_frames main loop + } + } + else // INTRA frames check (non-IDR) + { + is_intra = establish_intra( p_Inp, p_seq_struct, curr_frame, p_seq_struct->curr_num_to_populate - proc_frames, 0 ); + if ( is_intra && p_seq_struct->pop_flag != POP_SP ) + { + // intra structure (not random access) + int gop_frame = populate_rnd_acc_pred_struct_atom( p_Vid, p_Inp, p_seq_struct, curr_frame, proc_frames, &terminate_pop, is_intra, 1 ); + // update counters + proc_frames += gop_frame; + curr_frame += gop_frame; + if ( terminate_pop ) + { + terminate_pop = 0; + break; // the proc_frames main loop + } + } + else // SP frames check + { + is_sp = establish_sp( p_Inp, p_seq_struct, curr_frame, p_seq_struct->curr_num_to_populate - proc_frames, 0 ); + if ( is_sp ) + { + // intra structure (not random access) + int gop_frame = populate_rnd_acc_pred_struct_atom( p_Vid, p_Inp, p_seq_struct, curr_frame, proc_frames, &terminate_pop, is_sp, 2 ); + // update counters + proc_frames += gop_frame; + curr_frame += gop_frame; + if ( terminate_pop ) + { + terminate_pop = 0; + break; // the proc_frames main loop + } + } + } + } + + if ( !is_idr && !is_intra && !is_sp ) + { + int pred_frame = populate_reg_pred_struct_atom( p_Vid, p_Inp, p_seq_struct, curr_frame, proc_frames, &terminate_pop ); + // update counters + curr_frame += pred_frame; + proc_frames += pred_frame; + if ( terminate_pop ) + { + terminate_pop = 0; + break; // the proc_frames main loop + } + } // is_idr is_intra is_sp + } // proc_frames loop + // update pop_start_frame for subsequent run of this function ;) + p_seq_struct->pop_start_frame = curr_frame; +} + +/*! + *********************************************************************** + * \brief + * Set parameters for a single coded picture (frame/field) + * \param p_Inp + * pointer to the InputParameters structure + * \param p_pic + * pointer to the current picture structure + * \param p_frm_struct + * pointer to the current frame unit structure + * \param num_slices + * number of slices for the current picture + * \param is_bot_fld + * bottom field flag + *********************************************************************** + */ + +void populate_reg_pic( InputParameters *p_Inp, PicStructure *p_pic, FrameUnitStruct *p_frm_struct, int num_slices, int is_bot_fld ) +{ + int slice; + int slice_type = (is_bot_fld && p_frm_struct->type == I_SLICE) ? ( p_Inp->IntraBottom ? I_SLICE : (p_Inp->BRefPictures == 2 ? B_SLICE : P_SLICE) ) : p_frm_struct->type; + int deblock = p_Inp->DFSendParameters ? + (!(p_Inp->DFDisableIdc[p_frm_struct->nal_ref_idc][p_frm_struct->type])) : 1; + int weighted_pred = (slice_type == P_SLICE) ? + p_Inp->WeightedPrediction : ((slice_type == B_SLICE) ? + p_Inp->WeightedBiprediction : 0); + SliceStructure *p_Slice; + + // if bottom field picture idr_flag has to be 0 (even when an IDR top field pic precedes it) + p_pic->idr_flag = !is_bot_fld ? p_frm_struct->idr_flag : 0; + p_pic->random_access = !is_bot_fld ? p_frm_struct->random_access : 0; + p_pic->nal_ref_idc = p_frm_struct->nal_ref_idc; + p_pic->num_slices = num_slices; + + for ( slice = 0; slice < p_pic->num_slices; slice++ ) + { + // Slice Structure + p_Slice = p_pic->p_Slice + slice; + + p_Slice->type = slice_type; + p_Slice->deblock = deblock; + p_Slice->weighted_pred = weighted_pred; + p_Slice->num_refs = p_frm_struct->num_refs; + p_Slice->qp = p_frm_struct->qp; + } +} + +/*! + *********************************************************************** + * \brief + * Set parameters for a single frame unit + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param p_frm_struct + * pointer to the current frame unit structure + * \param p_cur_prd + * pointer to the current prediction structure + * \param curr_frame + * global (sequence-level) coding order of the first frame (in coding order) in the PredStructAtom + * \param pred_frame + * coding order with respect to "curr_frame" (pred_frame + curr_frame + idx yields the absolute coding order of the current frame) + * \param idx + * local (PredStructAtom-level) coding order with respect to the start of the current PredStructAtom + * \param num_slices + * number of slices for the current picture + * \param no_rnd_acc + * if 1 the first frame in the Atom is not a random access frame: Intra \n + * if 2 it is an SP frame + *********************************************************************** + */ + +static void populate_frame( InputParameters *p_Inp, SeqStructure *p_seq_struct, FrameUnitStruct *p_frm_struct, PredStructAtom *p_cur_prd, + int curr_frame, int pred_frame, int idx, int num_slices, int no_rnd_acc ) +{ + PredStructFrm *p_src = p_cur_prd->p_frm + idx; + + // Frame Unit Structure + p_frm_struct->type = p_src->slice_type; + p_frm_struct->random_access = p_src->random_access; + p_frm_struct->num_refs = p_Inp->num_ref_frames; + p_frm_struct->layer = p_src->layer; + p_frm_struct->mod_qp = p_src->slice_qp_off; + p_frm_struct->field_pic_flag = 0; // need to add better support for field coded pictures + p_frm_struct->frame_no = curr_frame + pred_frame + p_src->disp_offset; + + p_frm_struct->temporal_layer = p_src->temporal_layer; + + if ( !(curr_frame + pred_frame + idx) ) + { + // first frame in the sequence + p_frm_struct->type = I_SLICE; + p_frm_struct->idr_flag = 1; + p_frm_struct->nal_ref_idc = NALU_PRIORITY_HIGHEST; + } + // disposable P/B frames + else if ( p_Inp->DisposableP && p_frm_struct->type != I_SLICE && !p_frm_struct->layer ) // this way it will also apply to B_SLICEs in layer 0 + { + if ( !(p_seq_struct->last_bl_frm_disposable) ) + { + p_frm_struct->nal_ref_idc = NALU_PRIORITY_DISPOSABLE; + p_frm_struct->mod_qp += p_Inp->DispPQPOffset; + } + else + { + p_frm_struct->nal_ref_idc = p_src->nal_ref_idc; + } + p_frm_struct->idr_flag = (p_src->nal_ref_idc == NALU_PRIORITY_HIGHEST) ? 1 : 0; + } + else if ( no_rnd_acc == 1 && !idx ) // no random access frame and frame first in the struct (hence I_SLICE) + { + p_frm_struct->idr_flag = 0; + p_frm_struct->nal_ref_idc = NALU_PRIORITY_HIGH; + p_frm_struct->random_access = p_Inp->EnableOpenGOP ? 1 : 0; + } + else if ( no_rnd_acc == 2 && !idx ) // no random access frame and frame first in the struct (hence SP_SLICE) + { + p_frm_struct->type = p_Inp->si_frame_indicator ? SI_SLICE : SP_SLICE; + p_frm_struct->idr_flag = 0; + p_frm_struct->nal_ref_idc = NALU_PRIORITY_HIGH; + p_frm_struct->random_access = 0; + } + else + { + p_frm_struct->idr_flag = (p_src->nal_ref_idc == NALU_PRIORITY_HIGHEST) ? 1 : 0; + p_frm_struct->nal_ref_idc = p_src->nal_ref_idc; + } + // final QP (w/o RC) set here to ensure "mod_qp" and "type" have been *finalized* + p_frm_struct->qp = p_frm_struct->mod_qp + p_Inp->qp[p_frm_struct->type]; +#if (DEBUG_PRED_STRUCT) + fprintf( stdout, "\n\n Frame Population Stats for Frame %5d in coding order", curr_frame + pred_frame + idx ); + switch ( p_frm_struct->type ) + { + default: + case I_SLICE: + fprintf( stdout, "\n Slice Type: I_SLICE " ); + break; + case P_SLICE: + fprintf( stdout, "\n Slice Type: P_SLICE " ); + break; + case B_SLICE: + fprintf( stdout, "\n Slice Type: B_SLICE " ); + break; + case SP_SLICE: + fprintf( stdout, "\n Slice Type: SP_SLICE " ); + break; + case SI_SLICE: + fprintf( stdout, "\n Slice Type: SI_SLICE " ); + break; + } + fprintf( stdout, "\n IDR picture: %d ", p_frm_struct->idr_flag ); + switch( p_frm_struct->nal_ref_idc ) + { + default: + case NALU_PRIORITY_HIGHEST: + fprintf( stdout, "\n NAL_reference_idc: NALU_PRIORITY_HIGHEST "); + break; + case NALU_PRIORITY_HIGH: + fprintf( stdout, "\n NAL_reference_idc: NALU_PRIORITY_HIGH "); + break; + case NALU_PRIORITY_LOW: + fprintf( stdout, "\n NAL_reference_idc: NALU_PRIORITY_LOW "); + break; + case NALU_PRIORITY_DISPOSABLE: + fprintf( stdout, "\n NAL_reference_idc: NALU_PRIORITY_DISPOSABLE "); + break; + } + fprintf( stdout, "\n Random Access: %d ", p_frm_struct->random_access ); + fprintf( stdout, "\n Number of References: %2d ", p_frm_struct->num_refs ); + fprintf( stdout, "\n Hierarchy Layer: %d ", p_frm_struct->layer ); + fprintf( stdout, "\n QP Modifier: %2d ", p_frm_struct->qp ); + fprintf( stdout, "\n Field Coding: %d ", p_frm_struct->field_pic_flag ); + fprintf( stdout, "\n Display Order: %5d ", p_frm_struct->frame_no ); +#endif + + // store a pointer to the prediction structure + p_frm_struct->p_atom = p_cur_prd; + p_frm_struct->atom_idx = idx; +#if (MVC_EXTENSION_ENABLE) + p_frm_struct->view_id = 0; +#endif + + // Picture Structure + switch( p_Inp->PicInterlace ) + { + default: + case FRAME_CODING: + // frame + populate_reg_pic( p_Inp, p_frm_struct->p_frame_pic, p_frm_struct, num_slices, 0 ); + break; + case FIELD_CODING: + // top field + populate_reg_pic( p_Inp, p_frm_struct->p_top_fld_pic, p_frm_struct, num_slices, 0 ); + // bottom field + populate_reg_pic( p_Inp, p_frm_struct->p_bot_fld_pic, p_frm_struct, num_slices, 1 ); + break; + case ADAPTIVE_CODING: + // frame + populate_reg_pic( p_Inp, p_frm_struct->p_frame_pic, p_frm_struct, num_slices, 0 ); + // top field + populate_reg_pic( p_Inp, p_frm_struct->p_top_fld_pic, p_frm_struct, num_slices, 0 ); + // bottom field + populate_reg_pic( p_Inp, p_frm_struct->p_bot_fld_pic, p_frm_struct, num_slices, 1 ); + break; + } +} + +/*! + *********************************************************************** + * \brief + * Update frame indices + * \param p_seq_struct + * pointer to the sequence structure + * \param p_frm_struct + * pointer to the current frame unit structure + * \param curr_frame + * global (sequence-level) coding order of the first frame (in coding order) in the PredStructAtom + * \param pred_frame + * coding order with respect to "curr_frame" (pred_frame + curr_frame yields the absolute coding order of the current frame) + *********************************************************************** + */ + +static void update_frame_indices( SeqStructure *p_seq_struct, FrameUnitStruct *p_frm_struct, int curr_frame, int pred_frame ) +{ + if ( p_frm_struct->idr_flag ) + { + // coding order + p_seq_struct->last_intra_frame = curr_frame + pred_frame; + p_seq_struct->last_idr_frame = curr_frame + pred_frame; + p_seq_struct->last_random_access_frame = curr_frame + pred_frame; + // display order + p_seq_struct->last_intra_disp = p_frm_struct->frame_no; + p_seq_struct->last_idr_frame = p_frm_struct->frame_no; + p_seq_struct->last_rand_access_disp = p_frm_struct->frame_no; + // sp frame counter (no need to send SP frames if random access frames) + // coding order + p_seq_struct->last_sp_frame = curr_frame + pred_frame; + // display order + p_seq_struct->last_sp_disp = p_frm_struct->frame_no; + } + else if ( p_frm_struct->type == I_SLICE ) + { + // coding order + p_seq_struct->last_intra_frame = curr_frame + pred_frame; + // display order + p_seq_struct->last_intra_disp = p_frm_struct->frame_no; + if ( p_frm_struct->random_access ) + { + // coding order + p_seq_struct->last_random_access_frame = curr_frame + pred_frame; + // display order + p_seq_struct->last_rand_access_disp = p_frm_struct->frame_no; + } + } + else if ( p_frm_struct->type == SP_SLICE || p_frm_struct->type == SI_SLICE ) + { + // coding order + p_seq_struct->last_sp_frame = curr_frame + pred_frame; + // display order + p_seq_struct->last_sp_disp = p_frm_struct->frame_no; + } + if ( p_frm_struct->layer == 0 ) // support for p_Inp->DisposableP + { + if ( p_frm_struct->nal_ref_idc == NALU_PRIORITY_DISPOSABLE ) + { + p_seq_struct->last_bl_frm_disposable = 1; + } + else + { + p_seq_struct->last_bl_frm_disposable = 0; + } + } +} + +/*! + *********************************************************************** + * \brief + * Populate regular prediction structure atom + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * global (sequence-level) coding order of the first frame (in coding order) in the PredStructAtom + * \param proc_frames + * frames that have been populated so far out of the "num_to_populate" frames + * \param terminate_pop + * pointer to the terminate_pop variable that signals termination of the frame population loop + * \return + * number of frames that have been populated by this function run + *********************************************************************** + */ + +static int populate_reg_pred_struct_atom( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, + int curr_frame, int proc_frames, int *terminate_pop ) +{ + int idx; + int fixed_idx; + int avail_frames; + int pred_frame = 0; + int pred_idx; + + FrameUnitStruct *p_frm_struct; + PredStructAtom *p_cur_prd; + + // regular prediction structure (*in-between* idr and intra frames though) + // first determine how many frames are available to be used to place our prediction structures + // this finds the next place for a fixed (IDR/intra/SP/SI) frame *after* current_frame (hence counts from current_frame + 1 on) + if ( !(p_Inp->intra_delay) ) + { + fixed_idx = get_fixed_frame_for_prd( p_Inp, p_seq_struct, curr_frame, p_seq_struct->curr_num_to_populate - proc_frames ); + } + else + { + // IntraDelay currently does not support the improved prediction structure allocation (get_fixed_frame_for_prd) + fixed_idx = get_fixed_frame( p_Inp, p_seq_struct, curr_frame, p_seq_struct->curr_num_to_populate - proc_frames ); + } + if ( fixed_idx == -1 ) + { + avail_frames = p_seq_struct->curr_num_to_populate - proc_frames; + } + else + { + avail_frames = fixed_idx; // frames including "curr_frame" + } + // in the future we have to take care of the avail_frames = 0 case + if ( !avail_frames ) + { + *terminate_pop = 1; + } + + // loop through these frames and apply the appropriate prediction structure (p_prd) + while ( pred_frame < avail_frames ) + { + pred_idx = get_prd_index( p_Inp, p_seq_struct, avail_frames - pred_frame ); + // check here whether the prediction structure does not fit even if there is no fixed frame detected; + // if we proceed we will allocate an inefficient pred structure; better to terminate the frame population here + if ( fixed_idx == -1 && (curr_frame + avail_frames) < p_Inp->no_frames ) + { + if ( (p_seq_struct->num_prds - 1) != pred_idx ) + { + *terminate_pop = 1; + break; // the pred_frame loop + } + } + // prediction structure pointer + p_cur_prd = p_seq_struct->p_prd + pred_idx; + // populate gop structure from selected structure + // "idx" is internal pred struct idx + // "pred_frame" is general index for the current frame starting from "curr_frame" (it is zero for "curr_frame") + for ( idx = 0; idx < p_cur_prd->length; idx++ )//, pred_frame++ ) + { + // set pointer + p_frm_struct = p_seq_struct->p_frm + ((curr_frame + pred_frame + idx) % p_Vid->frm_struct_buffer); + + // assign values + populate_frame( p_Inp, p_seq_struct, p_frm_struct, p_cur_prd, curr_frame, pred_frame, idx, p_seq_struct->max_num_slices, 0 ); + + // update IDR and intra frame counters + update_frame_indices( p_seq_struct, p_frm_struct, curr_frame, pred_frame + idx ); + } + pred_frame += idx; + } + return pred_frame; // number of frames that have been populated by this function run +} + +/*! + *********************************************************************** + * \brief + * Populate intra-coded/random access prediction structure atom + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param curr_frame + * global (sequence-level) coding order of the first frame (in coding order) in the PredStructAtom + * \param proc_frames + * frames that have been populated so far out of the "num_to_populate" frames + * \param terminate_pop + * pointer to the terminate_pop variable that signals termination of the frame population loop + * \param is_idr + * first frame of the atom will be IDR if > 0. is_idr - 1 is equal to the index of the Atom used to populate the frames + * \param no_rnd_acc + * if 1, then the first frame in the (given) Atom is not a random access frame: Intra \n + * if 2, then it is an SP frame + * \return + * number of frames that have been populated by this function run + *********************************************************************** + */ + +static int populate_rnd_acc_pred_struct_atom( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, + int curr_frame, int proc_frames, int *terminate_pop, int is_idr, int no_rnd_acc ) +{ + // insert IDR pred structure (can be *more* than one frame) + int idx; + int fixed_idx; + int avail_frames; + int gop_frame = 0; + int gop_idx; + int num_gops; + + FrameUnitStruct *p_frm_struct; + PredStructAtom *p_cur_gop; + PredStructAtom *p_gop; + int (*get_rand_acc_index)( InputParameters *, SeqStructure *, int ); + + if ( no_rnd_acc == 1 ) // intra + { + p_gop = p_seq_struct->p_intra_gop; + num_gops = p_seq_struct->num_intra_gops; + get_rand_acc_index = get_intra_index; + } + else + { + p_gop = p_seq_struct->p_gop; + num_gops = p_seq_struct->num_gops; + get_rand_acc_index = get_idr_index; + } + + // regular prediction structure (*in-between* idr and intra frames though) + // first determine how many frames are available to be used to place our prediction structures + // this finds the next place for a fixed (IDR/intra/SP/SI) frame *after* current_frame (hence counts from current_frame + 1 on) + fixed_idx = get_fixed_frame( p_Inp, p_seq_struct, curr_frame + 1, p_seq_struct->curr_num_to_populate - proc_frames - 1 ); + if ( fixed_idx == -1 ) + { + avail_frames = p_seq_struct->curr_num_to_populate - proc_frames; + } + else + { + avail_frames = fixed_idx + 1; // frames including "curr_frame" + } + // in the future we have to take care of the avail_frames = 0 case + + // select prediction structure for random access + if ( !curr_frame && !(p_Inp->EnableIDRGOP) && !(p_Inp->intra_delay) ) + { + gop_idx = 0; // force shortest IDR pred struct for first frame + } + else if ( !curr_frame && !(p_Inp->EnableIDRGOP) && p_Inp->intra_delay ) + { + gop_idx = 1; // force middle IDR pred struct (2 corresponds to the longest that is though reserved for within the sequence) + } + else + { + if ( !(p_Inp->PreferDispOrder) ) // coding order + { + // bias in favor of longest *available* and *possible* structure + gop_idx = get_rand_acc_index( p_Inp, p_seq_struct, avail_frames ); + } + else // display order + { + // selection here is *fixed* and is signaled within is_idr + gop_idx = is_idr - 1; + } + // check here whether the prediction structure does not fit even if there is no fixed frame detected; if we proceed we will allocate an inefficient pred structure; better to terminate the frame population here + if ( fixed_idx == -1 && (curr_frame + avail_frames) < p_Inp->no_frames ) + { + if ( (num_gops - 1) != gop_idx && !p_seq_struct->pop_flag ) + { + *terminate_pop = 1; + return 0; + } + } + } + + // reset flag + if ( p_seq_struct->pop_flag ) + { + p_seq_struct->pop_flag = 0; + } + + // prediction structure pointer + p_cur_gop = p_gop + gop_idx; + // populate gop structure from selected structure + for ( idx = 0; idx < p_cur_gop->length; idx++ )//, gop_frame++ ) + { + // set pointer + p_frm_struct = p_seq_struct->p_frm + ((curr_frame + gop_frame + idx) % p_Vid->frm_struct_buffer); + + // assign values + populate_frame( p_Inp, p_seq_struct, p_frm_struct, p_cur_gop, curr_frame, gop_frame, idx, p_seq_struct->max_num_slices, no_rnd_acc ); + + // update IDR and intra frame counters + update_frame_indices( p_seq_struct, p_frm_struct, curr_frame, gop_frame + idx ); + } + gop_frame += idx; + + return gop_frame; // populated frames +} + +/*! + *********************************************************************** + * \brief + * Free random access prediction structures + * \param p_seq_struct + * pointer to the sequence structure + *********************************************************************** + */ + +static void free_gop_struct( SeqStructure *p_seq_struct ) +{ + int idx; + PredStructAtom *p_cur_gop; + + // IDR GOPs + for ( idx = 0; idx < p_seq_struct->num_gops; idx++ ) + { + p_cur_gop = p_seq_struct->p_gop + idx; + free( p_cur_gop->p_frm ); + } + free( p_seq_struct->p_gop ); + // Intra GOPs + for ( idx = 0; idx < p_seq_struct->num_intra_gops; idx++ ) + { + p_cur_gop = p_seq_struct->p_intra_gop + idx; + free( p_cur_gop->p_frm ); + } + free( p_seq_struct->p_intra_gop ); +} + +/*! + *********************************************************************** + * \brief + * Free non-random access prediction structures + * \param p_seq_struct + * pointer to the sequence structure + *********************************************************************** + */ + +static void free_pred_struct( SeqStructure *p_seq_struct ) +{ + int idx; + PredStructAtom *p_cur_prd; + + // free pred structures + for ( idx = 0; idx < p_seq_struct->num_prds; idx++ ) + { + p_cur_prd = p_seq_struct->p_prd + idx; + free( p_cur_prd->p_frm ); + } + free( p_seq_struct->p_prd ); +} + +/*! + *********************************************************************** + * \brief + * Set parameters for a single frame from the explicit structure + * \param info + * pointer to the Explicit Structure information for the current frame + * \param p_Inp + * pointer to the InputParameters structure + * \param p_frm_struct + * pointer to the current frame structure + * \param num_slices + * number of slices used to code this picture + *********************************************************************** + */ + +void populate_frame_explicit( ExpFrameInfo *info, InputParameters *p_Inp, FrameUnitStruct *p_frm_struct, int num_slices ) +{ + // Frame Unit Structure + p_frm_struct->idr_flag = info->is_idr; + p_frm_struct->nal_ref_idc = info->reference_idc; + p_frm_struct->type = info->slice_type; + p_frm_struct->random_access = info->is_idr; + p_frm_struct->num_refs = p_Inp->num_ref_frames; + p_frm_struct->layer = info->reference_idc ? 0 : 1; + p_frm_struct->mod_qp = 0; + p_frm_struct->field_pic_flag = 0; + p_frm_struct->frame_no = info->seq_number; + p_frm_struct->qp = p_frm_struct->mod_qp + p_Inp->qp[p_frm_struct->type]; + + // Picture Structure + switch( p_Inp->PicInterlace ) + { + default: + case FRAME_CODING: + // frame + populate_reg_pic( p_Inp, p_frm_struct->p_frame_pic, p_frm_struct, num_slices, 0 ); + break; + case FIELD_CODING: + // top field + populate_reg_pic( p_Inp, p_frm_struct->p_top_fld_pic, p_frm_struct, num_slices, 0 ); + // bottom field + populate_reg_pic( p_Inp, p_frm_struct->p_bot_fld_pic, p_frm_struct, num_slices, 1 ); + break; + case ADAPTIVE_CODING: + // frame + populate_reg_pic( p_Inp, p_frm_struct->p_frame_pic, p_frm_struct, num_slices, 0 ); + // top field + populate_reg_pic( p_Inp, p_frm_struct->p_top_fld_pic, p_frm_struct, num_slices, 0 ); + // bottom field + populate_reg_pic( p_Inp, p_frm_struct->p_bot_fld_pic, p_frm_struct, num_slices, 1 ); + break; + } +} + +/*! + *********************************************************************** + * \brief + * Set parameters for a single frame during RD-picture decision + * \param p_Inp + * pointer to the InputParameters structure + * \param p_frm_struct + * pointer to the current frame structure + * \param slice_type + * NEW slice type that is set + * \param num_slices + * number of slices used to code this picture + *********************************************************************** + */ + +void populate_frame_slice_type( InputParameters *p_Inp, FrameUnitStruct *p_frm_struct, int slice_type, int num_slices ) +{ + p_frm_struct->type = slice_type; + + // frame (RDPictureDecision only called for frame pictures so no need to check here) + populate_reg_pic( p_Inp, p_frm_struct->p_frame_pic, p_frm_struct, num_slices, 0 ); +} + +#if (MVC_EXTENSION_ENABLE) +/*! + *********************************************************************** + * \brief + * Populate frame structure + * \param p_Vid + * pointer to the VideoParameters structure + * \param p_Inp + * pointer to the InputParameters structure + * \param p_seq_struct + * pointer to the sequence structure + * \param start + * starting number of frame unit structures to populate + * \param end + * starting number of frame unit structures to populate + *********************************************************************** + */ + +void populate_frm_struct_mvc( VideoParameters *p_Vid, InputParameters *p_Inp, SeqStructure *p_seq_struct, int start, int end ) +{ + int view_id; + int idx; + FrameUnitStruct *p_curr_frm, *p_frm = p_seq_struct->p_frm; + FrameUnitStruct *p_curr_frm_mvc, *p_frm_mvc = p_seq_struct->p_frm_mvc; + + if ( p_Inp->num_of_views == 2 ) + { + for ( idx = start; idx < end; idx++ ) + { + p_curr_frm = p_frm + (idx % p_Vid->frm_struct_buffer); + + // view 0 + p_curr_frm_mvc = p_frm_mvc + ((idx << 1) % p_seq_struct->num_frames_mvc); + copy_frame_mvc( p_Inp, p_curr_frm, p_curr_frm_mvc, p_seq_struct->max_num_slices, 0 ); + // view 1 + p_curr_frm_mvc = p_frm_mvc + (((idx << 1) + 1) % p_seq_struct->num_frames_mvc); + copy_frame_mvc( p_Inp, p_curr_frm, p_curr_frm_mvc, p_seq_struct->max_num_slices, 1 ); + } + } + else + { + assert( p_Inp->num_of_views > 2 ); + for ( idx = start; idx < end; idx++ ) + { + p_curr_frm = p_frm + (idx % p_Vid->frm_struct_buffer); + + for ( view_id = 0; view_id < p_Inp->num_of_views; view_id++ ) + { + // view "view_id" + p_curr_frm_mvc = p_frm_mvc + (((idx * p_Inp->num_of_views) + view_id) % p_seq_struct->num_frames_mvc); + copy_frame_mvc( p_Inp, p_curr_frm, p_curr_frm_mvc, p_seq_struct->max_num_slices, view_id ); + } + } + } +} + + +/*! + *********************************************************************** + * \brief + * Set parameters for a single frame unit for MVC compression + * \param p_Inp + * pointer to the InputParameters structure + * \param p_src + * pointer to the source frame unit structure + * \param p_dst + * pointer to the destination frame unit structure + * \param num_slices + * number of slices for the current picture + * \param view_id + * view id + *********************************************************************** + */ + + +static void copy_frame_mvc( InputParameters *p_Inp, FrameUnitStruct *p_src, FrameUnitStruct *p_dst, int num_slices, int view_id ) +{ + // Frame Unit Structure + + //! Edited by Joao Carreira + if( p_Inp->PFramesOnlyView1 && view_id ) + p_dst->type = P_SLICE; + else + p_dst->type = view_id ? p_Inp->MVCInterViewForceB != 0? B_SLICE : (p_src->type == I_SLICE ? (p_Inp->BRefPictures == 2 ? B_SLICE : P_SLICE) : p_src->type) : p_src->type; + + p_dst->random_access = p_src->random_access; + p_dst->num_refs = p_src->num_refs; + p_dst->layer = p_src->layer; + p_dst->mod_qp = p_src->mod_qp; + p_dst->field_pic_flag = p_src->field_pic_flag; + p_dst->frame_no = p_src->frame_no; + p_dst->idr_flag = view_id ? 0 : p_src->idr_flag; + p_dst->nal_ref_idc = view_id ? (p_src->idr_flag ? NALU_PRIORITY_HIGH : p_src->nal_ref_idc) : p_src->nal_ref_idc; + p_dst->qp = p_src->qp; + p_dst->p_atom = p_src->p_atom; + p_dst->atom_idx = p_src->atom_idx; + p_dst->view_id = view_id; + + // Picture Structure + switch( p_Inp->PicInterlace ) + { + default: + case FRAME_CODING: + // frame + populate_reg_pic( p_Inp, p_dst->p_frame_pic, p_dst, num_slices, 0 ); + break; + case FIELD_CODING: + // top field + populate_reg_pic( p_Inp, p_dst->p_top_fld_pic, p_dst, num_slices, 0 ); + // bottom field + populate_reg_pic( p_Inp, p_dst->p_bot_fld_pic, p_dst, num_slices, 1 ); + break; + case ADAPTIVE_CODING: + // frame + populate_reg_pic( p_Inp, p_dst->p_frame_pic, p_dst, num_slices, 0 ); + // top field + populate_reg_pic( p_Inp, p_dst->p_top_fld_pic, p_dst, num_slices, 0 ); + // bottom field + populate_reg_pic( p_Inp, p_dst->p_bot_fld_pic, p_dst, num_slices, 1 ); + break; + } +} +#endif diff --git a/lencod/src/q_around.c b/lencod/src/q_around.c new file mode 100644 index 0000000..aaaf30c --- /dev/null +++ b/lencod/src/q_around.c @@ -0,0 +1,295 @@ + +/*! + ************************************************************************************* + * \file q_around.c + * + * \brief + * Quantization Adaptive Rounding (JVT-N011) + * \author + * - Alexis Michael Tourapis + * - Ehsan Maani + * + ************************************************************************************* + */ + +#include "global.h" +#include "memalloc.h" +#include "q_offsets.h" +#include "q_around.h" + +static const int AdaptRndCrPos[2][5] = +{ + // P, B, I, SP, SI + { 4, 7, 1, 4, 1}, // Intra MB + { 10, 13, 10, 10, 10} // Inter MB +}; + +static const int AdaptRndPos[4][5] = +{ + // P, B, I, SP, SI + { 3, 6, 0, 3, 0}, // 4x4 Intra MB + { 1, 2, 0, 1, 2}, // 8x8 Intra MB + { 9, 12, 9, 9, 9}, // 4x4 Inter MB + { 3, 4, 3, 3, 3}, // 8x8 Inter MB +}; + + +/*! +************************************************************************ +* \brief +* copy data from to a temporary location +************************************************************************ +*/ +void store_adaptive_rounding_4x4 (VideoParameters *p_Vid, int****ARCofAdj, int mode, int block_y, int block_x) +{ + int j; + + for (j = block_y; j < block_y + 4; j++) + memcpy(&ARCofAdj[0][DUMMY][j][block_x], &ARCofAdj[0][mode][j][block_x], BLOCK_SIZE * sizeof(int)); + + if (p_Vid->P444_joined) + { + for (j = block_y; j < block_y + 4; j++) + { + memcpy(&ARCofAdj[1][DUMMY][j][block_x],&ARCofAdj[1][mode][j][block_x], BLOCK_SIZE * sizeof(int)); + } + for (j = block_y; j < block_y + 4; j++) + { + memcpy(&ARCofAdj[2][DUMMY][j][block_x],&ARCofAdj[2][mode][j][block_x], BLOCK_SIZE * sizeof(int)); + } + } +} + + +/*! +************************************************************************ +* \brief +* copy data from a temporary location to the actual location +************************************************************************ +*/ +void update_adaptive_rounding_4x4 (VideoParameters *p_Vid, int****ARCofAdj , int mode, int block_y, int block_x) +{ + int j; + + for (j = block_y; j < block_y + BLOCK_SIZE; j++) + memcpy (&ARCofAdj[0][mode][j][block_x],&ARCofAdj[0][DUMMY][j][block_x], BLOCK_SIZE * sizeof(int)); + + if (p_Vid->P444_joined) + { + for (j = 0; j < block_y + BLOCK_SIZE; j++) + { + memcpy (&ARCofAdj[1][mode][j][block_x], &ARCofAdj[1][DUMMY][j][block_x], BLOCK_SIZE * sizeof(int)); + } + for (j = 0; j < block_y + BLOCK_SIZE; j++) + { + memcpy (&ARCofAdj[2][mode][j][block_x], &ARCofAdj[2][DUMMY][j][block_x], BLOCK_SIZE * sizeof(int)); + } + } +} + +/*! +************************************************************************ +* \brief +* copy data from to a temporary location +************************************************************************ +*/ +void store_adaptive_rounding_16x16 (VideoParameters *p_Vid, int****ARCofAdj, int mode) +{ + memcpy(&ARCofAdj[0][DUMMY][0][0], &ARCofAdj[0][mode][0][0], MB_PIXELS * sizeof(int)); + if (p_Vid->P444_joined) + { + memcpy(&ARCofAdj[1][DUMMY][0][0], &ARCofAdj[1][mode][0][0], MB_PIXELS * sizeof(int)); + memcpy(&ARCofAdj[2][DUMMY][0][0], &ARCofAdj[2][mode][0][0], MB_PIXELS * sizeof(int)); + } +} + + +/*! +************************************************************************ +* \brief +* copy data from a temporary location to the actual location +************************************************************************ +*/ +void update_adaptive_rounding_16x16(VideoParameters *p_Vid, int****ARCofAdj , int mode) +{ + memcpy (&ARCofAdj[0][mode][0][0],&ARCofAdj[0][DUMMY][0][0], MB_PIXELS * sizeof(int)); + if (p_Vid->P444_joined) + { + memcpy (&ARCofAdj[1][mode][0][0], &ARCofAdj[1][DUMMY][0][0], MB_PIXELS * sizeof(int)); + memcpy (&ARCofAdj[2][mode][0][0], &ARCofAdj[2][DUMMY][0][0], MB_PIXELS * sizeof(int)); + } +} + + + + +/*! +************************************************************************ +* \brief +* update rounding offsets based on JVT-N011 +************************************************************************ +*/ +void update_offset_params(Macroblock *currMB, int mode, byte luma_transform_size_8x8_flag) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + int is_inter = (mode != I4MB)&&(mode != I16MB) && (mode != I8MB); + int luma_pos = AdaptRndPos[(is_inter<<1) + luma_transform_size_8x8_flag][p_Vid->type]; + int i,j; + int qp = currMB->qp + p_Vid->bitdepth_luma_qp_scale; + int cur_qp = p_Inp->AdaptRoundingFixed ? 0 : qp; + int temp = 0; + QuantParameters *p_Quant = p_Vid->p_Quant; + int offsetRange = 1 << (OffsetBits - 1); + int blk_mask = 0x03 + (luma_transform_size_8x8_flag<<2); + int blk_shift = 2 + luma_transform_size_8x8_flag; + short **offsetList = luma_transform_size_8x8_flag ? p_Quant->OffsetList8x8[cur_qp] : p_Quant->OffsetList4x4[cur_qp]; + short *cur_offset_list = offsetList[luma_pos]; + + int **fAdjust = luma_transform_size_8x8_flag ? p_Vid->ARCofAdj8x8[0][mode] : p_Vid->ARCofAdj4x4[0][mode]; + + if (mode == IPCM) return; + + if( (p_Vid->active_sps->chroma_format_idc == YUV444) && (p_Inp->separate_colour_plane_flag != 0) ) + { + if( luma_transform_size_8x8_flag ) // 8x8 + luma_pos += 5 * p_Vid->colour_plane_id; + else // 4x4 + luma_pos += p_Vid->colour_plane_id; + cur_offset_list = offsetList[luma_pos]; + } + + for (j=0; j < MB_BLOCK_SIZE; j++) + { + int j_pos = ((j & blk_mask)<P444_joined) + { + int **fAdjustCbCr; + int uv; + + for(uv = 0; uv < 2; uv++) + { + luma_pos = AdaptRndPos[(is_inter<<1) + luma_transform_size_8x8_flag][p_Vid->type]; + fAdjustCbCr = luma_transform_size_8x8_flag ? p_Vid->ARCofAdj8x8[uv + 1][mode] : p_Vid->ARCofAdj4x4[uv + 1][mode]; + if(luma_transform_size_8x8_flag ) // 8x8 + luma_pos += 5 * (uv+1); + else // 4x4 + luma_pos += (uv+1); + cur_offset_list = offsetList[luma_pos]; + for (j=0; j < MB_BLOCK_SIZE; j++) + { + int j_pos = ((j & blk_mask)<AdaptRndChroma) && (p_Vid->yuv_format == YUV420 || p_Vid->yuv_format == YUV422 )) + { + int u_pos = AdaptRndCrPos[is_inter][p_Vid->type]; + int v_pos = u_pos + 1; + int k, jpos, uv = 1; + + for (k = u_pos; k <= v_pos; k++) + { + int **fAdjustChroma = (luma_transform_size_8x8_flag && mode == P8x8 )? p_Vid->ARCofAdj4x4[uv][4] : p_Vid->ARCofAdj4x4[uv][mode]; + uv++; + cur_offset_list = p_Quant->OffsetList4x4[cur_qp][k]; + + for (j = 0; j < p_Vid->mb_cr_size_y; j++) + { + jpos = ((j & 0x03)<<2); + for (i = 0; i < p_Vid->mb_cr_size_x; i++) + { + temp = jpos + (i & 0x03); + cur_offset_list[temp] = (short) iClip3(0, offsetRange, cur_offset_list[temp] + (short) fAdjustChroma[j][i]); + } + } + } + } +} + + +/*! +************************************************************************ +* \brief +* resets adaptive rounding p_Inp to zero +************************************************************************ +*/ +void reset_adaptive_rounding(VideoParameters *p_Vid) +{ + int maxplane; + maxplane = (p_Vid->yuv_format == YUV400)? 1 : 3; + memset(&p_Vid->ARCofAdj4x4[0][0][0][0], 0, maxplane * MAXMODE * MB_PIXELS * sizeof (int)); + if (p_Vid->p_Inp->Transform8x8Mode) + { + maxplane = (p_Vid->yuv_format == YUV400)? 1 : (p_Vid->P444_joined ? 3 : 1); + memset(&p_Vid->ARCofAdj8x8[0][0][0][0], 0, maxplane * MAXMODE * MB_PIXELS * sizeof (int)); + } +} + +/*! +************************************************************************ +* \brief +* resets adaptive rounding p_Inp for the direct mode to zero +************************************************************************ +*/ +void reset_adaptive_rounding_direct(VideoParameters *p_Vid) +{ + int maxplane, pl; + maxplane = (p_Vid->yuv_format == YUV400)? 1 : 3; + for (pl = 0; pl < maxplane; pl++) + memset(&p_Vid->ARCofAdj4x4[pl][DUMMY][0][0], 0, MB_PIXELS * sizeof (int)); + + if (p_Vid->p_Inp->Transform8x8Mode) + { + maxplane = (p_Vid->yuv_format == YUV400)? 1 : (p_Vid->P444_joined ? 3 : 1); + for (pl = 0; pl < maxplane; pl++) + memset(&p_Vid->ARCofAdj8x8[pl][DUMMY][0][0], 0, MB_PIXELS * sizeof (int)); + } + +} + +/*! +************************************************************************ +* \brief +* copy data from a temporary location to the actual location for mode P8x8 +************************************************************************ +*/ +void update_adaptive_rounding_8x8(VideoParameters *p_Vid, InputParameters *p_Inp, RD_8x8DATA* dataTr, int**** ARCofAdj) +{ + int b8, pl, plane, j0, i0, j; + + if (p_Inp->AdaptiveRounding) + { + plane = (p_Vid->P444_joined) ? 3 : 1; + for (pl = 0; pl < plane; pl++) + { + for (b8 = 0; b8 < 4; b8++) + { + j0 = 8*(b8 >> 1); + i0 = 8*(b8 & 0x01); + if (dataTr->part[b8].mode > 0) + { + for (j = j0; j < j0 + BLOCK_SIZE_8x8; j++) + { + memcpy(&ARCofAdj[pl][P8x8][j][i0], &ARCofAdj[pl][(short) dataTr->part[b8].mode][j][i0], BLOCK_SIZE_8x8 * sizeof(int)); + } + } + } + } + } +} + + diff --git a/lencod/src/q_matrix.c b/lencod/src/q_matrix.c new file mode 100644 index 0000000..28c9ee8 --- /dev/null +++ b/lencod/src/q_matrix.c @@ -0,0 +1,901 @@ + +/*! + ************************************************************************************* + * \file q_matrix.c + * + * \brief + * read q_matrix parameters from input file: q_matrix.cfg + * + ************************************************************************************* + */ + +#include "global.h" +#include "memalloc.h" +#include "q_matrix.h" + +extern char *GetConfigFileContent (char *Filename, int error_type); + +#define MAX_ITEMS_TO_PARSE 1000 + +static const int quant_coef[6][4][4] = { + {{13107, 8066,13107, 8066},{ 8066, 5243, 8066, 5243},{13107, 8066,13107, 8066},{ 8066, 5243, 8066, 5243}}, + {{11916, 7490,11916, 7490},{ 7490, 4660, 7490, 4660},{11916, 7490,11916, 7490},{ 7490, 4660, 7490, 4660}}, + {{10082, 6554,10082, 6554},{ 6554, 4194, 6554, 4194},{10082, 6554,10082, 6554},{ 6554, 4194, 6554, 4194}}, + {{ 9362, 5825, 9362, 5825},{ 5825, 3647, 5825, 3647},{ 9362, 5825, 9362, 5825},{ 5825, 3647, 5825, 3647}}, + {{ 8192, 5243, 8192, 5243},{ 5243, 3355, 5243, 3355},{ 8192, 5243, 8192, 5243},{ 5243, 3355, 5243, 3355}}, + {{ 7282, 4559, 7282, 4559},{ 4559, 2893, 4559, 2893},{ 7282, 4559, 7282, 4559},{ 4559, 2893, 4559, 2893}} +}; + +const int dequant_coef[6][4][4] = { + {{10, 13, 10, 13},{ 13, 16, 13, 16},{10, 13, 10, 13},{ 13, 16, 13, 16}}, + {{11, 14, 11, 14},{ 14, 18, 14, 18},{11, 14, 11, 14},{ 14, 18, 14, 18}}, + {{13, 16, 13, 16},{ 16, 20, 16, 20},{13, 16, 13, 16},{ 16, 20, 16, 20}}, + {{14, 18, 14, 18},{ 18, 23, 18, 23},{14, 18, 14, 18},{ 18, 23, 18, 23}}, + {{16, 20, 16, 20},{ 20, 25, 20, 25},{16, 20, 16, 20},{ 20, 25, 20, 25}}, + {{18, 23, 18, 23},{ 23, 29, 23, 29},{18, 23, 18, 23},{ 23, 29, 23, 29}} +}; + +static const int quant_coef8[6][8][8] = +{ + { + {13107, 12222, 16777, 12222, 13107, 12222, 16777, 12222}, + {12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428}, + {16777, 15481, 20972, 15481, 16777, 15481, 20972, 15481}, + {12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428}, + {13107, 12222, 16777, 12222, 13107, 12222, 16777, 12222}, + {12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428}, + {16777, 15481, 20972, 15481, 16777, 15481, 20972, 15481}, + {12222, 11428, 15481, 11428, 12222, 11428, 15481, 11428} + }, + { + {11916, 11058, 14980, 11058, 11916, 11058, 14980, 11058}, + {11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826}, + {14980, 14290, 19174, 14290, 14980, 14290, 19174, 14290}, + {11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826}, + {11916, 11058, 14980, 11058, 11916, 11058, 14980, 11058}, + {11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826}, + {14980, 14290, 19174, 14290, 14980, 14290, 19174, 14290}, + {11058, 10826, 14290, 10826, 11058, 10826, 14290, 10826} + }, + { + {10082, 9675, 12710, 9675, 10082, 9675, 12710, 9675}, + {9675, 8943, 11985, 8943, 9675, 8943, 11985, 8943}, + {12710, 11985, 15978, 11985, 12710, 11985, 15978, 11985}, + {9675, 8943, 11985, 8943, 9675, 8943, 11985, 8943}, + {10082, 9675, 12710, 9675, 10082, 9675, 12710, 9675}, + {9675, 8943, 11985, 8943, 9675, 8943, 11985, 8943}, + {12710, 11985, 15978, 11985, 12710, 11985, 15978, 11985}, + {9675, 8943, 11985, 8943, 9675, 8943, 11985, 8943} + }, + { + {9362, 8931, 11984, 8931, 9362, 8931, 11984, 8931}, + {8931, 8228, 11259, 8228, 8931, 8228, 11259, 8228}, + {11984, 11259, 14913, 11259, 11984, 11259, 14913, 11259}, + {8931, 8228, 11259, 8228, 8931, 8228, 11259, 8228}, + {9362, 8931, 11984, 8931, 9362, 8931, 11984, 8931}, + {8931, 8228, 11259, 8228, 8931, 8228, 11259, 8228}, + {11984, 11259, 14913, 11259, 11984, 11259, 14913, 11259}, + {8931, 8228, 11259, 8228, 8931, 8228, 11259, 8228} + }, + { + {8192, 7740, 10486, 7740, 8192, 7740, 10486, 7740}, + {7740, 7346, 9777, 7346, 7740, 7346, 9777, 7346}, + {10486, 9777, 13159, 9777, 10486, 9777, 13159, 9777}, + {7740, 7346, 9777, 7346, 7740, 7346, 9777, 7346}, + {8192, 7740, 10486, 7740, 8192, 7740, 10486, 7740}, + {7740, 7346, 9777, 7346, 7740, 7346, 9777, 7346}, + {10486, 9777, 13159, 9777, 10486, 9777, 13159, 9777}, + {7740, 7346, 9777, 7346, 7740, 7346, 9777, 7346} + }, + { + {7282, 6830, 9118, 6830, 7282, 6830, 9118, 6830}, + {6830, 6428, 8640, 6428, 6830, 6428, 8640, 6428}, + {9118, 8640, 11570, 8640, 9118, 8640, 11570, 8640}, + {6830, 6428, 8640, 6428, 6830, 6428, 8640, 6428}, + {7282, 6830, 9118, 6830, 7282, 6830, 9118, 6830}, + {6830, 6428, 8640, 6428, 6830, 6428, 8640, 6428}, + {9118, 8640, 11570, 8640, 9118, 8640, 11570, 8640}, + {6830, 6428, 8640, 6428, 6830, 6428, 8640, 6428} + } +}; + + + +static const int dequant_coef8[6][8][8] = +{ + { + {20, 19, 25, 19, 20, 19, 25, 19}, + {19, 18, 24, 18, 19, 18, 24, 18}, + {25, 24, 32, 24, 25, 24, 32, 24}, + {19, 18, 24, 18, 19, 18, 24, 18}, + {20, 19, 25, 19, 20, 19, 25, 19}, + {19, 18, 24, 18, 19, 18, 24, 18}, + {25, 24, 32, 24, 25, 24, 32, 24}, + {19, 18, 24, 18, 19, 18, 24, 18} + }, + { + {22, 21, 28, 21, 22, 21, 28, 21}, + {21, 19, 26, 19, 21, 19, 26, 19}, + {28, 26, 35, 26, 28, 26, 35, 26}, + {21, 19, 26, 19, 21, 19, 26, 19}, + {22, 21, 28, 21, 22, 21, 28, 21}, + {21, 19, 26, 19, 21, 19, 26, 19}, + {28, 26, 35, 26, 28, 26, 35, 26}, + {21, 19, 26, 19, 21, 19, 26, 19} + }, + { + {26, 24, 33, 24, 26, 24, 33, 24}, + {24, 23, 31, 23, 24, 23, 31, 23}, + {33, 31, 42, 31, 33, 31, 42, 31}, + {24, 23, 31, 23, 24, 23, 31, 23}, + {26, 24, 33, 24, 26, 24, 33, 24}, + {24, 23, 31, 23, 24, 23, 31, 23}, + {33, 31, 42, 31, 33, 31, 42, 31}, + {24, 23, 31, 23, 24, 23, 31, 23} + }, + { + {28, 26, 35, 26, 28, 26, 35, 26}, + {26, 25, 33, 25, 26, 25, 33, 25}, + {35, 33, 45, 33, 35, 33, 45, 33}, + {26, 25, 33, 25, 26, 25, 33, 25}, + {28, 26, 35, 26, 28, 26, 35, 26}, + {26, 25, 33, 25, 26, 25, 33, 25}, + {35, 33, 45, 33, 35, 33, 45, 33}, + {26, 25, 33, 25, 26, 25, 33, 25} + }, + { + {32, 30, 40, 30, 32, 30, 40, 30}, + {30, 28, 38, 28, 30, 28, 38, 28}, + {40, 38, 51, 38, 40, 38, 51, 38}, + {30, 28, 38, 28, 30, 28, 38, 28}, + {32, 30, 40, 30, 32, 30, 40, 30}, + {30, 28, 38, 28, 30, 28, 38, 28}, + {40, 38, 51, 38, 40, 38, 51, 38}, + {30, 28, 38, 28, 30, 28, 38, 28} + }, + { + {36, 34, 46, 34, 36, 34, 46, 34}, + {34, 32, 43, 32, 34, 32, 43, 32}, + {46, 43, 58, 43, 46, 43, 58, 43}, + {34, 32, 43, 32, 34, 32, 43, 32}, + {36, 34, 46, 34, 36, 34, 46, 34}, + {34, 32, 43, 32, 34, 32, 43, 32}, + {46, 43, 58, 43, 46, 43, 58, 43}, + {34, 32, 43, 32, 34, 32, 43, 32} + } +}; + + +int matrix4x4_check[6] = {0, 0, 0, 0, 0, 0}; +int matrix8x8_check[6] = {0, 0, 0, 0, 0, 0}; + +static const char MatrixType4x4[6][20] = +{ + "INTRA4X4_LUMA", + "INTRA4X4_CHROMAU", + "INTRA4X4_CHROMAV", + "INTER4X4_LUMA", + "INTER4X4_CHROMAU", + "INTER4X4_CHROMAV" +}; + +static const char MatrixType8x8[6][20] = +{ + "INTRA8X8_LUMA", + "INTER8X8_LUMA", + "INTRA8X8_CHROMAU", // only for 4:4:4 + "INTER8X8_CHROMAU", // only for 4:4:4 + "INTRA8X8_CHROMAV", // only for 4:4:4 + "INTER8X8_CHROMAV" // only for 4:4:4 +}; + + +static const short Quant_intra_default[16] = +{ + 6,13,20,28, +13,20,28,32, +20,28,32,37, +28,32,37,42 +}; + +static const short Quant_inter_default[16] = +{ +10,14,20,24, +14,20,24,27, +20,24,27,30, +24,27,30,34 +}; + +static const short Quant8_intra_default[64] = +{ + 6,10,13,16,18,23,25,27, +10,11,16,18,23,25,27,29, +13,16,18,23,25,27,29,31, +16,18,23,25,27,29,31,33, +18,23,25,27,29,31,33,36, +23,25,27,29,31,33,36,38, +25,27,29,31,33,36,38,40, +27,29,31,33,36,38,40,42 +}; + +static const short Quant8_inter_default[64] = +{ + 9,13,15,17,19,21,22,24, +13,13,17,19,21,22,24,25, +15,17,19,21,22,24,25,27, +17,19,21,22,24,25,27,28, +19,21,22,24,25,27,28,30, +21,22,24,25,27,28,30,32, +22,24,25,27,28,30,32,33, +24,25,27,28,30,32,33,35 +}; + + +/*! + *********************************************************************** + * \brief + * Check the parameter name. + * \param s + * parameter name string + * \param type + * 4x4 or 8x8 matrix type + * \return + * the index number if the string is a valid parameter name, \n + * -1 for error + *********************************************************************** + */ +static int CheckParameterName (char *s, int *type) +{ + int i = 0; + + *type = 0; + while ((MatrixType4x4[i] != NULL) && (i<6)) + { + if (0==strcmp (MatrixType4x4[i], s)) + return i; + else + i++; + } + + i = 0; + *type = 1; + while ((MatrixType8x8[i] != NULL) && (i<6)) + { + if (0==strcmp (MatrixType8x8[i], s)) + return i; + else + i++; + } + + return -1; +} + +/*! + *********************************************************************** + * \brief + * Parse the Q matrix values read from cfg file. + * \param p_Vid + * current video parameters + * \param buf + * buffer to be parsed + * \param bufsize + * buffer size of buffer + *********************************************************************** + */ +static void ParseMatrix (VideoParameters *p_Vid, char *buf, int bufsize) +{ + ScaleParameters *p_QScale = p_Vid->p_QScale; + char *items[MAX_ITEMS_TO_PARSE] = {NULL}; + int MapIdx; + int item = 0; + int InString = 0, InItem = 0; + char *p = buf; + char *bufend = &buf[bufsize]; + int IntContent; + int i, j, range, type, cnt; + short *ScalingList; + + while (p < bufend) + { + switch (*p) + { + case 13: + p++; + break; + case '#': // Found comment + *p = '\0'; // Replace '#' with '\0' in case of comment immediately following integer or string + while (*p != '\n' && p < bufend) // Skip till EOL or EOF, whichever comes first + p++; + InString = 0; + InItem = 0; + break; + case '\n': + InItem = 0; + InString = 0; + *p++='\0'; + break; + case ' ': + case '\t': // Skip whitespace, leave state unchanged + if (InString) + p++; + else + { // Terminate non-strings once whitespace is found + *p++ = '\0'; + InItem = 0; + } + break; + + case '"': // Begin/End of String + *p++ = '\0'; + if (!InString) + { + items[item++] = p; + InItem = ~InItem; + } + else + InItem = 0; + InString = ~InString; // Toggle + break; + + case ',': + p++; + InItem = 0; + break; + + default: + if (!InItem) + { + items[item++] = p; + InItem = ~InItem; + } + p++; + } + } + + item--; + + for (i=0; i (MapIdx = CheckParameterName (items[i+cnt], &type))) + { + snprintf (errortext, ET_SIZE, " Parsing error in quantization matrix config file: Parameter Name '%s' not recognized.", items[i+cnt]); + error (errortext, 300); + } + cnt++; + if (strcmp ("=", items[i+cnt])) + { + snprintf (errortext, ET_SIZE, " Parsing error in quantization matrix config file: '=' expected as the second token in each item."); + error (errortext, 300); + } + cnt++; + + if (!type) //4x4 Matrix + { + range = 16; + ScalingList = p_QScale->ScalingList4x4input[MapIdx]; + matrix4x4_check[MapIdx] = 1; //to indicate matrix found in cfg file + } + else //8x8 matrix + { + range = 64; + ScalingList = p_QScale->ScalingList8x8input[MapIdx]; + matrix8x8_check[MapIdx] = 1; //to indicate matrix found in cfg file + } + + for(j=0; jp_QScale; + short *ScalingList; + int i, cnt, fail; + + for(i=0; i<6; i++) + { + if(p_Inp->ScalingListPresentFlag[i]) + { + ScalingList = p_QScale->ScalingList4x4input[i]; + if(matrix4x4_check[i]) + { + fail=0; + for(cnt=0; cnt<16; cnt++) + { + if(ScalingList[cnt]<0 || ScalingList[cnt]>255) // ScalingList[0]=0 to indicate use default matrix + { + fail=1; + break; + } + } + + if(fail) //value of matrix exceed range + { + printf("\n%s value exceed range. (Value must be 1 to 255)\n", MatrixType4x4[i]); + printf("Setting default values for this matrix."); + if(i>2) + memcpy(ScalingList, Quant_inter_default, sizeof(short)*16); + else + memcpy(ScalingList, Quant_intra_default, sizeof(short)*16); + } + } + else //matrix not found, pad with default value + { + printf("\n%s matrix definition not found. Setting default values.", MatrixType4x4[i]); + if(i>2) + memcpy(ScalingList, Quant_inter_default, sizeof(short)*16); + else + memcpy(ScalingList, Quant_intra_default, sizeof(short)*16); + } + } + + if(p_Inp->ScalingListPresentFlag[i+6]) + { + ScalingList = p_QScale->ScalingList8x8input[i]; + if(matrix8x8_check[i]) + { + fail=0; + for(cnt=0; cnt<64; cnt++) + { + if(ScalingList[cnt]<0 || ScalingList[cnt]>255) // ScalingList[0]=0 to indicate use default matrix + { + fail=1; + break; + } + } + + if(fail) //value of matrix exceed range + { + printf("\n%s value exceed range. (Value must be 1 to 255)\n", MatrixType8x8[i]); + printf("Setting default values for this matrix."); + if(i==1 || i==3 || i==5) + memcpy(ScalingList, Quant8_inter_default, sizeof(short)*64); + else + memcpy(ScalingList, Quant8_intra_default, sizeof(short)*64); + } + } + else //matrix not found, pad with default value + { + printf("\n%s matrix definition not found. Setting default values.", MatrixType8x8[i]); + if(i==1 || i==3 || i==5) + memcpy(ScalingList, Quant8_inter_default, sizeof(short)*64); + else + memcpy(ScalingList, Quant8_intra_default, sizeof(short)*64); + } + } + } +} + +/*! + *********************************************************************** + * \brief + * Allocate Q matrix arrays + *********************************************************************** + */ +static void allocate_QMatrix (QuantParameters *p_Quant, InputParameters *p_Inp) +{ + int max_bitdepth = imax(p_Inp->output.bit_depth[0], p_Inp->output.bit_depth[1]); + int max_qp = (3 + 6*(max_bitdepth)); + + int bitdepth_qp_scale = 6*(p_Inp->output.bit_depth[0] - 8); + int i; + + get_mem5Dquant(&p_Quant->q_params_4x4, 3, 2, max_qp + 1, 4, 4); + get_mem5Dquant(&p_Quant->q_params_8x8, 3, 2, max_qp + 1, 8, 8); + + if ((p_Quant->qp_per_matrix = (int*)malloc((MAX_QP + 1 + bitdepth_qp_scale)*sizeof(int))) == NULL) + no_mem_exit("allocate_QMatrix: p_Quant->qp_per_matrix"); + if ((p_Quant->qp_rem_matrix = (int*)malloc((MAX_QP + 1 + bitdepth_qp_scale)*sizeof(int))) == NULL) + no_mem_exit("allocate_QMatrix: p_Quant->qp_per_matrix"); + + for (i = 0; i < MAX_QP + bitdepth_qp_scale + 1; i++) + { + p_Quant->qp_per_matrix[i] = i / 6; + p_Quant->qp_rem_matrix[i] = i % 6; + } +} + +/*! + *********************************************************************** + * \brief + * Free Q matrix arrays + *********************************************************************** + */ +void free_QMatrix (QuantParameters *p_Quant) +{ + free_mem5Dquant(p_Quant->q_params_4x4); + free_mem5Dquant(p_Quant->q_params_8x8); + + free(p_Quant->qp_rem_matrix); + free(p_Quant->qp_per_matrix); +} + + +/*! + *********************************************************************** + * \brief + * Initialise Q matrix values. + *********************************************************************** + */ +void init_qmatrix (VideoParameters *p_Vid, InputParameters *p_Inp) +{ + QuantParameters *p_Quant = p_Vid->p_Quant; + ScaleParameters *p_QScale = p_Vid->p_QScale; + char *content; + + allocate_QMatrix (p_Quant, p_Inp); + + if(p_Inp->ScalingMatrixPresentFlag) + { + printf ("Parsing QMatrix file %s ", p_Inp->QmatrixFile); + content = GetConfigFileContent(p_Inp->QmatrixFile, 0); + if(content!='\0') + ParseMatrix(p_Vid, content, (int) strlen (content)); + else + printf("\nError: %s\nProceeding with default values for all matrices.", errortext); + + PatchMatrix(p_Vid, p_Inp); + printf("\n"); + + memset(p_QScale->UseDefaultScalingMatrix4x4Flag, 0, 6 * sizeof(short)); + memset(p_QScale->UseDefaultScalingMatrix8x8Flag, 0, 6 * sizeof(short)); + + free(content); + } +} + +static void set_default_quant4x4(LevelQuantParams **q_params_4x4, const int (*quant)[4], const int (*dequant)[4]) +{ + int i, j; + for(j=0; j<4; j++) + { + for(i=0; i<4; i++) + { + q_params_4x4[j][i].ScaleComp = quant[j][i]; + q_params_4x4[j][i].InvScaleComp = dequant[j][i]<<4; + } + } +} + +/*! + ************************************************************************ + * \brief + * For calculating the quantisation values at frame level + * + * \par Input: + * none + * + * \par Output: + * none + ************************************************************************ + */ +void CalculateQuant4x4Param(VideoParameters *p_Vid) +{ + QuantParameters *p_Quant = p_Vid->p_Quant; + ScaleParameters *p_QScale = p_Vid->p_QScale; + + pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int i, j, k, temp; + int k_mod; + int present[6]; + int no_q_matrix=FALSE; + + int max_bitdepth = imax(p_Vid->bitdepth_luma, p_Vid->bitdepth_chroma); + int max_qp = (3 + 6*(max_bitdepth)); + + + if(!active_sps->seq_scaling_matrix_present_flag && !active_pps->pic_scaling_matrix_present_flag) //set to no q-matrix + no_q_matrix=TRUE; + else + { + memset(present, 0, 6 * sizeof(int)); + + if(active_sps->seq_scaling_matrix_present_flag) + for(i=0; i<6; i++) + present[i] = active_sps->seq_scaling_list_present_flag[i]; + + if(active_pps->pic_scaling_matrix_present_flag) + for(i=0; i<6; i++) + { + if((i==0) || (i==3)) + present[i] |= active_pps->pic_scaling_list_present_flag[i]; + else + present[i] = active_pps->pic_scaling_list_present_flag[i]; + } + } + + if(no_q_matrix==TRUE) + { + for(k_mod=0; k_modq_params_4x4[0][0][k_mod], quant_coef[k], dequant_coef[k]); + set_default_quant4x4(p_Quant->q_params_4x4[0][1][k_mod], quant_coef[k], dequant_coef[k]); + set_default_quant4x4(p_Quant->q_params_4x4[1][0][k_mod], quant_coef[k], dequant_coef[k]); + set_default_quant4x4(p_Quant->q_params_4x4[1][1][k_mod], quant_coef[k], dequant_coef[k]); + set_default_quant4x4(p_Quant->q_params_4x4[2][0][k_mod], quant_coef[k], dequant_coef[k]); + set_default_quant4x4(p_Quant->q_params_4x4[2][1][k_mod], quant_coef[k], dequant_coef[k]); + } + } + else + { + for(k_mod=0; k_modUseDefaultScalingMatrix4x4Flag[0]) + { + p_Quant->q_params_4x4[0][1][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/Quant_intra_default[temp]; + p_Quant->q_params_4x4[0][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*Quant_intra_default[temp]; + } + else + { + p_Quant->q_params_4x4[0][1][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/p_QScale->ScalingList4x4[0][temp]; + p_Quant->q_params_4x4[0][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*p_QScale->ScalingList4x4[0][temp]; + } + + if(!present[1]) + { + p_Quant->q_params_4x4[1][1][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[0][1][k_mod][j][i].ScaleComp; + p_Quant->q_params_4x4[1][1][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[0][1][k_mod][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_4x4[1][1][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[1] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[1][temp]); + p_Quant->q_params_4x4[1][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[1] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[1][temp]); + } + + if(!present[2]) + { + p_Quant->q_params_4x4[2][1][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[1][1][k_mod][j][i].ScaleComp; + p_Quant->q_params_4x4[2][1][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[1][1][k_mod][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_4x4[2][1][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[2] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[2][temp]); + p_Quant->q_params_4x4[2][1][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[2] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[2][temp]); + } + + if((!present[3]) || p_QScale->UseDefaultScalingMatrix4x4Flag[3]) + { + p_Quant->q_params_4x4[0][0][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/Quant_inter_default[temp]; + p_Quant->q_params_4x4[0][0][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*Quant_inter_default[temp]; + } + else + { + p_Quant->q_params_4x4[0][0][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/p_QScale->ScalingList4x4[3][temp]; + p_Quant->q_params_4x4[0][0][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*p_QScale->ScalingList4x4[3][temp]; + } + + if(!present[4]) + { + p_Quant->q_params_4x4[1][0][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[0][0][k_mod][j][i].ScaleComp; + p_Quant->q_params_4x4[1][0][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[0][0][k_mod][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_4x4[1][0][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[4] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[4][temp]); + p_Quant->q_params_4x4[1][0][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[4] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[4][temp]); + } + + if(!present[5]) + { + p_Quant->q_params_4x4[2][0][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[1][0][k_mod][j][i].ScaleComp; + p_Quant->q_params_4x4[2][0][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[1][0][k_mod][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_4x4[2][0][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix4x4Flag[5] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[5][temp]); + p_Quant->q_params_4x4[2][0][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[5] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[5][temp]); + } + } + } + } + } +} + +/*! + ************************************************************************ + * \brief + * Calculate the quantisation and inverse quantisation parameters + * + ************************************************************************ + */ +void CalculateQuant8x8Param(VideoParameters *p_Vid) +{ + QuantParameters *p_Quant = p_Vid->p_Quant; + ScaleParameters *p_QScale = p_Vid->p_QScale; + + pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int i, j, k, temp; + int k_mod; + int n_ScalingList8x8; + int present[6]; + int no_q_matrix=FALSE; + int max_bitdepth = imax(p_Vid->bitdepth_luma, p_Vid->bitdepth_chroma); + int max_qp = (3 + 6*(max_bitdepth)); + + + // maximum number of valid 8x8 scaling lists + n_ScalingList8x8 = ( active_sps->chroma_format_idc != 3 ) ? 2 : 6; + + if(!active_sps->seq_scaling_matrix_present_flag && !active_pps->pic_scaling_matrix_present_flag) //set to default matrix + no_q_matrix=TRUE; + else + { + memset(present, 0, sizeof(int)*n_ScalingList8x8); + + if(active_sps->seq_scaling_matrix_present_flag) + { + for(i=0; iseq_scaling_list_present_flag[i+6]; + } + + if(active_pps->pic_scaling_matrix_present_flag) + { + for(i=0; ipic_scaling_list_present_flag[i+6]; + else + present[i] = active_pps->pic_scaling_list_present_flag[i+6]; + } + } + } + + if(no_q_matrix==TRUE) + { + for(k = 0; k < max_qp; k++) + { + k_mod = k %6; + for(j=0; j<8; j++) + { + for(i=0; i<8; i++) + { + // intra Y + p_Quant->q_params_8x8[0][1][k][j][i].ScaleComp = quant_coef8[k_mod][j][i]; + p_Quant->q_params_8x8[0][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]<<4; + + // inter Y + p_Quant->q_params_8x8[0][0][k][j][i].ScaleComp = quant_coef8[k_mod][j][i]; + p_Quant->q_params_8x8[0][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]<<4; + + if( n_ScalingList8x8 > 2 ) // 4:4:4 case only + { + // intra U + p_Quant->q_params_8x8[1][1][k][j][i].ScaleComp = quant_coef8[k_mod][j][i]; + p_Quant->q_params_8x8[1][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]<<4; + + // intra V + p_Quant->q_params_8x8[2][1][k][j][i].ScaleComp = quant_coef8[k_mod][j][i]; + p_Quant->q_params_8x8[2][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]<<4; + + // inter U + p_Quant->q_params_8x8[1][0][k][j][i].ScaleComp = quant_coef8[k_mod][j][i]; + p_Quant->q_params_8x8[1][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]<<4; + + // inter V + p_Quant->q_params_8x8[2][0][k][j][i].ScaleComp = quant_coef8[k_mod][j][i]; + p_Quant->q_params_8x8[2][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]<<4; + + } + } + } + } + } + else + { + for(k = 0; k < max_qp; k++) + { + k_mod = k %6; + for(j=0; j<8; j++) + { + for(i=0; i<8; i++) + { + temp = (j<<3)+i; + if((!present[0]) || p_QScale->UseDefaultScalingMatrix8x8Flag[0]) + { + p_Quant->q_params_8x8[0][1][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/Quant8_intra_default[temp]; + p_Quant->q_params_8x8[0][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*Quant8_intra_default[temp]; + } + else + { + p_Quant->q_params_8x8[0][1][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/p_QScale->ScalingList8x8[0][temp]; + p_Quant->q_params_8x8[0][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*p_QScale->ScalingList8x8[0][temp]; + } + + if((!present[1]) || p_QScale->UseDefaultScalingMatrix8x8Flag[1]) + { + p_Quant->q_params_8x8[0][0][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/Quant8_inter_default[temp]; + p_Quant->q_params_8x8[0][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*Quant8_inter_default[temp]; + } + else + { + p_Quant->q_params_8x8[0][0][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/p_QScale->ScalingList8x8[1][temp]; + p_Quant->q_params_8x8[0][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*p_QScale->ScalingList8x8[1][temp]; + } + + if( n_ScalingList8x8 > 2 ) + { + + // Intra U + if(!present[2]) + { + p_Quant->q_params_8x8[1][1][k][j][i].ScaleComp = p_Quant->q_params_8x8[0][1][k][j][i].ScaleComp; + p_Quant->q_params_8x8[1][1][k][j][i].InvScaleComp = p_Quant->q_params_8x8[0][1][k][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_8x8[1][1][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix8x8Flag[2] ? Quant8_intra_default[temp]:p_QScale->ScalingList8x8[2][temp]); + p_Quant->q_params_8x8[1][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*(p_QScale->UseDefaultScalingMatrix8x8Flag[2] ? Quant8_intra_default[temp]:p_QScale->ScalingList8x8[2][temp]); + } + + // Inter U + if(!present[3]) + { + p_Quant->q_params_8x8[1][0][k][j][i].ScaleComp = p_Quant->q_params_8x8[0][0][k][j][i].ScaleComp; + p_Quant->q_params_8x8[1][0][k][j][i].InvScaleComp = p_Quant->q_params_8x8[0][0][k][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_8x8[1][0][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix8x8Flag[3] ? Quant8_inter_default[temp]:p_QScale->ScalingList8x8[3][temp]); + p_Quant->q_params_8x8[1][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*(p_QScale->UseDefaultScalingMatrix8x8Flag[3] ? Quant8_inter_default[temp]:p_QScale->ScalingList8x8[3][temp]); + } + + // Intra V + if(!present[4]) + { + p_Quant->q_params_8x8[2][1][k][j][i].ScaleComp = p_Quant->q_params_8x8[1][1][k][j][i].ScaleComp; + p_Quant->q_params_8x8[2][1][k][j][i].InvScaleComp = p_Quant->q_params_8x8[1][1][k][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_8x8[2][1][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix8x8Flag[4] ? Quant8_intra_default[temp]:p_QScale->ScalingList8x8[4][temp]); + p_Quant->q_params_8x8[2][1][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i]*(p_QScale->UseDefaultScalingMatrix8x8Flag[4] ? Quant8_intra_default[temp]:p_QScale->ScalingList8x8[4][temp]); + } + + // Inter V + if(!present[5]) + { + p_Quant->q_params_8x8[2][0][k][j][i].ScaleComp = p_Quant->q_params_8x8[1][0][k][j][i].ScaleComp; + p_Quant->q_params_8x8[2][0][k][j][i].InvScaleComp = p_Quant->q_params_8x8[1][0][k][j][i].InvScaleComp; + } + else + { + p_Quant->q_params_8x8[2][0][k][j][i].ScaleComp = (quant_coef8[k_mod][j][i]<<4)/(p_QScale->UseDefaultScalingMatrix8x8Flag[5] ? Quant8_inter_default[temp]:p_QScale->ScalingList8x8[5][temp]); + p_Quant->q_params_8x8[2][0][k][j][i].InvScaleComp = dequant_coef8[k_mod][j][i] * (p_QScale->UseDefaultScalingMatrix8x8Flag[5] ? Quant8_inter_default[temp]:p_QScale->ScalingList8x8[5][temp]); + } + } + } + } + } + } +} + diff --git a/lencod/src/q_offsets.c b/lencod/src/q_offsets.c new file mode 100644 index 0000000..01fa3b3 --- /dev/null +++ b/lencod/src/q_offsets.c @@ -0,0 +1,636 @@ + +/*! + ************************************************************************************* + * \file q_offsets.c + * + * \brief + * read Quantization Offset matrix parameters from input file: q_OffsetMatrix.cfg + * + ************************************************************************************* + */ + +#include "global.h" +#include "memalloc.h" +#include "q_matrix.h" +#include "q_offsets.h" + +extern char *GetConfigFileContent (char *Filename, int error_type); + +#define MAX_ITEMS_TO_PARSE 2000 + +int offset4x4_check[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int offset8x8_check[15] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static const char OffsetType4x4[15][24] = { + "INTRA4X4_LUMA_INTRA", + "INTRA4X4_CHROMAU_INTRA", + "INTRA4X4_CHROMAV_INTRA", + "INTRA4X4_LUMA_INTERP", + "INTRA4X4_CHROMAU_INTERP", + "INTRA4X4_CHROMAV_INTERP", + "INTRA4X4_LUMA_INTERB", + "INTRA4X4_CHROMAU_INTERB", + "INTRA4X4_CHROMAV_INTERB", + "INTER4X4_LUMA_INTERP", + "INTER4X4_CHROMAU_INTERP", + "INTER4X4_CHROMAV_INTERP", + "INTER4X4_LUMA_INTERB", + "INTER4X4_CHROMAU_INTERB", + "INTER4X4_CHROMAV_INTERB" +}; + +static const char OffsetType8x8[15][24] = { + "INTRA8X8_LUMA_INTRA", + "INTRA8X8_LUMA_INTERP", + "INTRA8X8_LUMA_INTERB", + "INTER8X8_LUMA_INTERP", + "INTER8X8_LUMA_INTERB", + "INTRA8X8_CHROMAU_INTRA", + "INTRA8X8_CHROMAU_INTERP", + "INTRA8X8_CHROMAU_INTERB", + "INTER8X8_CHROMAU_INTERP", + "INTER8X8_CHROMAU_INTERB", + "INTRA8X8_CHROMAV_INTRA", + "INTRA8X8_CHROMAV_INTERP", + "INTRA8X8_CHROMAV_INTERB", + "INTER8X8_CHROMAV_INTERP", + "INTER8X8_CHROMAV_INTERB" +}; + +static const short Offset_intra_default_intra[16] = { + 682, 682, 682, 682, + 682, 682, 682, 682, + 682, 682, 682, 682, + 682, 682, 682, 682 +}; + +static const short Offset_intra_default_chroma[16] = { + 682, 682, 682, 682, + 682, 682, 682, 682, + 682, 682, 682, 682, + 682, 682, 682, 682 +}; + + +static const short Offset_intra_default_inter[16] = { + 342, 342, 342, 342, + 342, 342, 342, 342, + 342, 342, 342, 342, + 342, 342, 342, 342, +}; + +static const short Offset_inter_default[16] = { + 342, 342, 342, 342, + 342, 342, 342, 342, + 342, 342, 342, 342, + 342, 342, 342, 342, +}; + +static const short Offset8_intra_default_intra[64] = { + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682 +}; + +static const short Offset8_intra_default_chroma[64] = { + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682, + 682, 682, 682, 682, 682, 682, 682, 682 +}; + +static const short Offset8_intra_default_inter[64] = { + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342 +}; + +static const short Offset8_inter_default[64] = { + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342, + 342, 342, 342, 342, 342, 342, 342, 342 +}; + + +// Function prototypes +void InitOffsetParam (QuantParameters *p_Quant, InputParameters *p_Inp); +/*! + *********************************************************************** + * \brief + * Allocate Q matrix arrays + *********************************************************************** + */ +static void allocate_QOffsets (QuantParameters *p_Quant, InputParameters *p_Inp) +{ + int max_bitdepth = imax(p_Inp->output.bit_depth[0], p_Inp->output.bit_depth[1]); + int max_qp = (3 + 6*(max_bitdepth)); + + + if (p_Inp->AdaptRoundingFixed) + { + get_mem3Dshort(&p_Quant->OffsetList4x4, 1, 25, 16); + get_mem3Dshort(&p_Quant->OffsetList8x8, 1, 15, 64); + } + else + { + get_mem3Dshort(&p_Quant->OffsetList4x4, max_qp + 1, 25, 16); + get_mem3Dshort(&p_Quant->OffsetList8x8, max_qp + 1, 15, 64); + } + + get_mem2Dshort(&p_Quant->OffsetList4x4input, 25, 16); + get_mem2Dshort(&p_Quant->OffsetList8x8input, 15, 64); +} + +static inline void update_q_offset4x4(LevelQuantParams **q_params, short *offsetList, int q_bits) +{ + int i, j; + short *p_list = &offsetList[0]; + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + q_params[j][i].OffsetComp = (int) *p_list++ << q_bits; + } + } +} + +static inline void update_q_offset8x8(LevelQuantParams **q_params, short *offsetList, int q_bits) +{ + int i, j; + short *p_list; + for (j = 0; j < 8; j++) + { + p_list = &offsetList[j << 3]; + for (i = 0; i < 8; i++) + { + q_params[j][i].OffsetComp = (int) *p_list++ << q_bits; + } + } +} + +/*! + *********************************************************************** + * \brief + * Free Q matrix arrays + *********************************************************************** + */ +void free_QOffsets (QuantParameters *p_Quant, InputParameters *p_Inp) +{ + free_mem3Dshort(p_Quant->OffsetList8x8); + free_mem3Dshort(p_Quant->OffsetList4x4); + free_mem2Dshort(p_Quant->OffsetList8x8input); + free_mem2Dshort(p_Quant->OffsetList4x4input); +} + + +/*! + *********************************************************************** + * \brief + * Check the parameter name. + * \param s + * parameter name string + * \param type + * 4x4 or 8x8 offset matrix type + * \return + * the index number if the string is a valid parameter name, \n + * -1 for error + *********************************************************************** + */ + +int CheckOffsetParameterName (char *s, int *type) +{ + int i = 0; + + *type = 0; + while ((OffsetType4x4[i] != NULL) && (i < 15)) + { + if (0 == strcmp (OffsetType4x4[i], s)) + return i; + else + i++; + } + + i = 0; + *type = 1; + while ((OffsetType8x8[i] != NULL) && (i < 15)) + { + if (0 == strcmp (OffsetType8x8[i], s)) + return i; + else + i++; + } + + return -1; +} + +/*! + *********************************************************************** + * \brief + * Parse the Q Offset Matrix values read from cfg file. + * \param p_Quant + * quantization parameters + * \param buf + * buffer to be parsed + * \param bufsize + * buffer size of buffer + *********************************************************************** + */ +void ParseQOffsetMatrix (QuantParameters *p_Quant, char *buf, int bufsize) +{ + char *items[MAX_ITEMS_TO_PARSE] = {NULL}; + int MapIdx; + int item = 0; + int InString = 0, InItem = 0; + char *p = buf; + char *bufend = &buf[bufsize]; + int IntContent; + int i, j, range, type, cnt; + short *OffsetList; + + while (p < bufend) + { + switch (*p) + { + //case 13: + //p++; + //break; + case '#': // Found comment + *p = '\0'; // Replace '#' with '\0' in case of comment immediately following integer or string + while ((*p != '\n' && *p != '\r') && p < bufend) // Skip till EOL or EOF, whichever comes first + p++; + InString = 0; + InItem = 0; + break; + case '\n': + case '\r': + InItem = 0; + InString = 0; + *p++ = '\0'; + break; + case ' ': + case '\t': // Skip whitespace, leave state unchanged + if (InString) + p++; + else + { // Terminate non-strings once whitespace is found + *p++ = '\0'; + InItem = 0; + } + break; + + case '"': // Begin/End of String + *p++ = '\0'; + if (!InString) + { + items[item++] = p; + InItem = ~InItem; + } + else + InItem = 0; + InString = ~InString; // Toggle + break; + + case ',': + p++; + InItem = 0; + break; + + default: + if (!InItem) + { + items[item++] = p; + InItem = ~InItem; + } + p++; + } + } + + item--; + + for (i = 0; i < item; i += cnt) + { + cnt = 0; + if (0 > (MapIdx = CheckOffsetParameterName (items[i + cnt], &type))) + { + snprintf (errortext, ET_SIZE, + " Parsing error in quantization offset config file: Parameter Name '%s' not recognized.", + items[i + cnt]); + error (errortext, 300); + } + cnt++; + if (strcmp ("=", items[i + cnt])) + { + snprintf (errortext, ET_SIZE, + " Parsing error in quantization offset config file: '=' expected as the second token in each item."); + error (errortext, 300); + } + cnt++; + + if (!type) //4x4 Matrix + { + range = 16; + OffsetList = p_Quant->OffsetList4x4input[MapIdx]; + offset4x4_check[MapIdx] = 1; //to indicate matrix found in cfg file + } + else //8x8 matrix + { + range = 64; + OffsetList = p_Quant->OffsetList8x8input[MapIdx]; + offset8x8_check[MapIdx] = 1; //to indicate matrix found in cfg file + } + + for (j = 0; j < range; j++) + { + if (1 != sscanf (items[i + cnt + j], "%d", &IntContent)) + { + snprintf (errortext, ET_SIZE, + " Parsing error in quantization offset file: Expected numerical value for Parameter of %s, found '%s'.", + items[i], items[i + cnt + j]); + error (errortext, 300); + } + + OffsetList[j] = (short) IntContent; //save value in matrix + } + cnt += j; + printf ("."); + } +} + + +/*! + *********************************************************************** + * \brief + * Initialise Q offset matrix values. + *********************************************************************** + */ +void init_qoffset (VideoParameters *p_Vid) +{ + char *content; + InputParameters *p_Inp = p_Vid->p_Inp; + + allocate_QOffsets (p_Vid->p_Quant, p_Inp); + + if (p_Inp->OffsetMatrixPresentFlag) + { + printf ("Parsing Quantization Offset Matrix file %s ", + p_Inp->QOffsetMatrixFile); + content = GetConfigFileContent (p_Inp->QOffsetMatrixFile, 0); + if (content != '\0') + ParseQOffsetMatrix (p_Vid->p_Quant, content, (int) strlen (content)); + else + { + printf ("\nError: %s\nProceeding with default values for all matrices.", errortext); + p_Inp->OffsetMatrixPresentFlag = 0; + } + + printf ("\n"); + + free (content); + } + //! Now set up all offset p_Inp. This process could be reused if we wish to re-init offsets + InitOffsetParam (p_Vid->p_Quant, p_Inp); +} + +/*! + ************************************************************************ + * \brief + * Init quantization offset parameters + * + * \par Input: + * none + * + * \par Output: + * none + ************************************************************************ + */ + +void InitOffsetParam (QuantParameters *p_Quant, InputParameters *p_Inp) +{ + int i, k; + int max_qp_luma = (4 + 6*(p_Inp->output.bit_depth[0])); + int max_qp_cr = (4 + 6*(p_Inp->output.bit_depth[1])); + + for (i = 0; i < (p_Inp->AdaptRoundingFixed ? 1 : imax(max_qp_luma, max_qp_cr)); i++) + { + if (p_Inp->OffsetMatrixPresentFlag) + { + memcpy(&(p_Quant->OffsetList4x4[i][0][0]),&(p_Quant->OffsetList4x4input[0][0]), 400 * sizeof(short)); // 25 * 16 + memcpy(&(p_Quant->OffsetList8x8[i][0][0]),&(p_Quant->OffsetList8x8input[0][0]), 960 * sizeof(short)); // 15 * 64 + } + else + { + // 0 (INTRA4X4_LUMA_INTRA) + memcpy(&(p_Quant->OffsetList4x4[i][0][0]),&(Offset_intra_default_intra[0]), 16 * sizeof(short)); + for (k = 1; k < 3; k++) // 1,2 (INTRA4X4_CHROMA_INTRA) + memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_default_chroma[0]), 16 * sizeof(short)); + for (k = 3; k < 9; k++) // 3,4,5,6,7,8 (INTRA4X4_LUMA/CHROMA_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_intra_default_inter[0]), 16 * sizeof(short)); + for (k = 9; k < 25; k++) // 9,10,11,12,13,14 (INTER4X4) + memcpy(&(p_Quant->OffsetList4x4[i][k][0]),&(Offset_inter_default[0]), 16 * sizeof(short)); + + // 0 (INTRA8X8_LUMA_INTRA) + memcpy(&(p_Quant->OffsetList8x8[i][0][0]),&(Offset8_intra_default_intra[0]), 64 * sizeof(short)); + for (k = 1; k < 3; k++) // 1,2 (INTRA8X8_LUMA_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]), 64 * sizeof(short)); + for (k = 3; k < 5; k++) // 3,4 (INTER8X8_LUMA_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]), 64 * sizeof(short)); + + // 5 (INTRA8X8_CHROMAU_INTRA) + memcpy(&(p_Quant->OffsetList8x8[i][5][0]),&(Offset8_intra_default_chroma[0]), 64 * sizeof(short)); + for (k = 6; k < 8; k++) // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]), 64 * sizeof(short)); + for (k = 8; k < 10; k++) // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]), 64 * sizeof(short)); + + // 10 (INTRA8X8_CHROMAV_INTRA) + memcpy(&(p_Quant->OffsetList8x8[i][10][0]),&(Offset8_intra_default_chroma[0]), 64 * sizeof(short)); + for (k = 11; k < 13; k++) // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_intra_default_inter[0]), 64 * sizeof(short)); + for (k = 13; k < 15; k++) // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB) + memcpy(&(p_Quant->OffsetList8x8[i][k][0]),&(Offset8_inter_default[0]), 64 * sizeof(short)); + } + } +} + + +/*! + ************************************************************************ + * \brief + * Calculation of the quantization offset parameters at the frame level + * + * \par Input: + * none + * + * \par Output: + * none + ************************************************************************ + */ +void CalculateOffset4x4Param (VideoParameters *p_Vid) +{ + QuantParameters *p_Quant = p_Vid->p_Quant; + int k; + int qp_per, qp; + int img_type = ((p_Vid->type == SI_SLICE) ? I_SLICE : (p_Vid->type == SP_SLICE ? P_SLICE : p_Vid->type)); + + int max_qp_scale = imax(p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_chroma_qp_scale); + int max_qp = 51 + max_qp_scale; + InputParameters *p_Inp = p_Vid->p_Inp; + + p_Vid->AdaptRndWeight = p_Inp->AdaptRndWFactor [p_Vid->nal_reference_idc != 0][img_type]; + p_Vid->AdaptRndCrWeight = p_Inp->AdaptRndCrWFactor[p_Vid->nal_reference_idc != 0][img_type]; + + if (img_type == I_SLICE ) + { + for (qp = 0; qp < max_qp + 1; qp++) + { + k = p_Quant->qp_per_matrix [qp]; + qp_per = Q_BITS + k - OffsetBits; + k = p_Inp->AdaptRoundingFixed ? 0 : qp; + + // Intra4x4 luma + update_q_offset4x4(p_Quant->q_params_4x4[0][1][qp], p_Quant->OffsetList4x4[k][ 0], qp_per); + // Intra4x4 chroma u + update_q_offset4x4(p_Quant->q_params_4x4[1][1][qp], p_Quant->OffsetList4x4[k][ 1], qp_per); + // Intra4x4 chroma v + update_q_offset4x4(p_Quant->q_params_4x4[2][1][qp], p_Quant->OffsetList4x4[k][ 2], qp_per); + } + } + else if (img_type == B_SLICE) + { + for (qp = 0; qp < max_qp + 1; qp++) + { + k = p_Quant->qp_per_matrix [qp]; + qp_per = Q_BITS + k - OffsetBits; + k = p_Inp->AdaptRoundingFixed ? 0 : qp; + + // Inter4x4 luma + update_q_offset4x4(p_Quant->q_params_4x4[0][0][qp], p_Quant->OffsetList4x4[k][12], qp_per); + // Intra4x4 luma + update_q_offset4x4(p_Quant->q_params_4x4[0][1][qp], p_Quant->OffsetList4x4[k][ 6], qp_per); + // Inter4x4 chroma u + update_q_offset4x4(p_Quant->q_params_4x4[1][0][qp], p_Quant->OffsetList4x4[k][13], qp_per); + // Intra4x4 chroma u + update_q_offset4x4(p_Quant->q_params_4x4[1][1][qp], p_Quant->OffsetList4x4[k][ 7], qp_per); + // Inter4x4 chroma v + update_q_offset4x4(p_Quant->q_params_4x4[2][0][qp], p_Quant->OffsetList4x4[k][14], qp_per); + // Intra4x4 chroma v + update_q_offset4x4(p_Quant->q_params_4x4[2][1][qp], p_Quant->OffsetList4x4[k][ 8], qp_per); + } + } + else + { + for (qp = 0; qp < max_qp + 1; qp++) + { + k = p_Quant->qp_per_matrix [qp]; + qp_per = Q_BITS + k - OffsetBits; + k = p_Inp->AdaptRoundingFixed ? 0 : qp; + + // Inter4x4 luma + update_q_offset4x4(p_Quant->q_params_4x4[0][0][qp], p_Quant->OffsetList4x4[k][ 9], qp_per); + // Intra4x4 luma + update_q_offset4x4(p_Quant->q_params_4x4[0][1][qp], p_Quant->OffsetList4x4[k][ 3], qp_per); + // Inter4x4 chroma u + update_q_offset4x4(p_Quant->q_params_4x4[1][0][qp], p_Quant->OffsetList4x4[k][10], qp_per); + // Intra4x4 chroma u + update_q_offset4x4(p_Quant->q_params_4x4[1][1][qp], p_Quant->OffsetList4x4[k][ 4], qp_per); + // Inter4x4 chroma v + update_q_offset4x4(p_Quant->q_params_4x4[2][0][qp], p_Quant->OffsetList4x4[k][11], qp_per); + // Intra4x4 chroma v + update_q_offset4x4(p_Quant->q_params_4x4[2][1][qp], p_Quant->OffsetList4x4[k][ 5], qp_per); + } + } +} + +/*! + ************************************************************************ + * \brief + * Calculate the quantisation offset parameters + * + ************************************************************************ +*/ +void CalculateOffset8x8Param (VideoParameters *p_Vid) +{ + QuantParameters *p_Quant = p_Vid->p_Quant; + int k; + int q_bits, qp; + + int max_qp_scale = imax(p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_chroma_qp_scale); + int max_qp = 51 + max_qp_scale; + InputParameters *p_Inp = p_Vid->p_Inp; + + if (p_Vid->type == I_SLICE || p_Vid->type == SI_SLICE ) + { + for (qp = 0; qp < max_qp + 1; qp++) + { + q_bits = Q_BITS_8 + p_Quant->qp_per_matrix[qp] - OffsetBits; + k = p_Inp->AdaptRoundingFixed ? 0 : qp; + // INTRA8X8 + update_q_offset8x8(p_Quant->q_params_8x8[0][1][qp], p_Quant->OffsetList8x8[k][0], q_bits); + // INTRA8X8 CHROMAU + update_q_offset8x8(p_Quant->q_params_8x8[1][1][qp], p_Quant->OffsetList8x8[k][5], q_bits); + // INTRA8X8 CHROMAV + update_q_offset8x8(p_Quant->q_params_8x8[2][1][qp], p_Quant->OffsetList8x8[k][10], q_bits); + } + } + else if ((p_Vid->type == P_SLICE) || (p_Vid->type == SP_SLICE)) + { + for (qp = 0; qp < max_qp + 1; qp++) + { + q_bits = Q_BITS_8 + p_Quant->qp_per_matrix[qp] - OffsetBits; + k = p_Inp->AdaptRoundingFixed ? 0 : qp; + + // INTER8X8 + update_q_offset8x8(p_Quant->q_params_8x8[0][0][qp], p_Quant->OffsetList8x8[k][3], q_bits); + // INTRA8X8 + update_q_offset8x8(p_Quant->q_params_8x8[0][1][qp], p_Quant->OffsetList8x8[k][1], q_bits); + // INTER8X8 CHROMAU + update_q_offset8x8(p_Quant->q_params_8x8[1][0][qp], p_Quant->OffsetList8x8[k][8], q_bits); + // INTRA8X8 CHROMAU + update_q_offset8x8(p_Quant->q_params_8x8[1][1][qp], p_Quant->OffsetList8x8[k][6], q_bits); + // INTER8X8 CHROMAV + update_q_offset8x8(p_Quant->q_params_8x8[2][0][qp], p_Quant->OffsetList8x8[k][13], q_bits); + // INTRA8X8 CHROMAV + update_q_offset8x8(p_Quant->q_params_8x8[2][1][qp], p_Quant->OffsetList8x8[k][11], q_bits); + } + } + else + { + for (qp = 0; qp < max_qp + 1; qp++) + { + q_bits = Q_BITS_8 + p_Quant->qp_per_matrix[qp] - OffsetBits; + k = p_Inp->AdaptRoundingFixed ? 0 : qp; + + // INTER8X8 + update_q_offset8x8(p_Quant->q_params_8x8[0][0][qp], p_Quant->OffsetList8x8[k][4], q_bits); + // INTRA8X8 + update_q_offset8x8(p_Quant->q_params_8x8[0][1][qp], p_Quant->OffsetList8x8[k][2], q_bits); + // INTER8X8 CHROMAU + update_q_offset8x8(p_Quant->q_params_8x8[1][0][qp], p_Quant->OffsetList8x8[k][9], q_bits); + // INTRA8X8 CHROMAU + update_q_offset8x8(p_Quant->q_params_8x8[1][1][qp], p_Quant->OffsetList8x8[k][7], q_bits); + // INTER8X8 CHROMAV + update_q_offset8x8(p_Quant->q_params_8x8[2][0][qp], p_Quant->OffsetList8x8[k][14], q_bits); + // INTRA8X8 CHROMAV + update_q_offset8x8(p_Quant->q_params_8x8[2][1][qp], p_Quant->OffsetList8x8[k][12], q_bits); + } + } +} diff --git a/lencod/src/quant4x4.c b/lencod/src/quant4x4.c new file mode 100644 index 0000000..ad8297e --- /dev/null +++ b/lencod/src/quant4x4.c @@ -0,0 +1,66 @@ + +/*! + ************************************************************************************* + * \file quant4x4.c + * + * \brief + * Quantization process for a 4x4 block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" +#include "global.h" +#include "quant4x4.h" + +/*! +************************************************************************ +* \brief +* Quantization initialization function +* +************************************************************************ +*/ +void init_quant_4x4(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + if (currSlice->UseRDOQuant == 1) + { + currSlice->quant_4x4 = quant_4x4_trellis; + if (p_Inp->RDOQ_DC == 1) + currSlice->quant_dc4x4 = quant_dc4x4_trellis; + else + currSlice->quant_dc4x4 = quant_dc4x4_normal; + currSlice->quant_ac4x4 = quant_ac4x4_trellis; + if (currSlice->symbol_mode == CAVLC) + { + currSlice->rdoq_4x4 = rdoq_4x4_CAVLC; + currSlice->rdoq_dc = rdoq_dc_CAVLC; + currSlice->rdoq_ac4x4 = rdoq_ac4x4_CAVLC; + } + else + { + currSlice->rdoq_4x4 = rdoq_4x4_CABAC; + currSlice->rdoq_dc = rdoq_dc_CABAC; + currSlice->rdoq_ac4x4 = rdoq_ac4x4_CABAC; + } + } + else if (p_Vid->AdaptiveRounding) + { + currSlice->quant_4x4 = quant_4x4_around; + currSlice->quant_dc4x4 = quant_dc4x4_normal; + currSlice->quant_ac4x4 = quant_ac4x4_around; + } + else + { + currSlice->quant_4x4 = quant_4x4_normal; + currSlice->quant_dc4x4 = quant_dc4x4_normal; + currSlice->quant_ac4x4 = quant_ac4x4_normal; + } +} + diff --git a/lencod/src/quant4x4_2step.c b/lencod/src/quant4x4_2step.c new file mode 100644 index 0000000..4b5d375 --- /dev/null +++ b/lencod/src/quant4x4_2step.c @@ -0,0 +1,300 @@ + +/*! + ************************************************************************************* + * \file quant4x4_2step.c + * + * \brief + * Quantization process for a 4x4 block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant4x4.h" + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 block + * + ************************************************************************ + */ +int quant_4x4_2step(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + Slice *currSlice = currMB->p_Slice; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + + int block_x = q_method->block_x; + int qp = q_method->qp; + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + + LevelQuantParams *q_params = NULL; + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + const byte *p_scan = &pos_scan[0][0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (*m7 != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *m7 = 0; + ++run; + } + } + else + { + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +int quant_ac4x4_2step(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + int block_x = q_method->block_x; + + int qp = q_method->qp; + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + LevelQuantParams *q_params = NULL; + + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + const byte *p_scan1 = &pos_scan[1][0]; + const byte *p_scan = &pos_scan[1][0]; + int temp_block[16][16]; + + int qp_per2 = p_Quant->qp_per_matrix[51]; + int q_bits2 = Q_BITS + qp_per2; + int coeff; + + + // First pass quantization + for (coeff_ctr = 1; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan1++; // horizontal position + j = *p_scan1++; // vertical position + + coeff = tblock[j][block_x + i]; + m7 = &temp_block[j][block_x + i]; + if (coeff != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (coeff); + level = (scaled_coeff * q_params->ScaleComp) >> q_bits2; + //level = (scaled_coeff) >> q_bits2; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, coeff); + *m7 = (level << q_bits2) / q_params->ScaleComp; + //*m7 = (level << q_bits2); + } + else + { + *m7 = 0; + } + } + else + *m7 = 0; + } + + // Quantization + for (coeff_ctr = 1; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + coeff = temp_block[j][block_x + i]; + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (coeff) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, coeff); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *m7 = 0; + ++run; + } + } + else + { + *m7 = 0; + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 DC block + * + ************************************************************************ + */ +int quant_dc4x4_2step(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + *m7 = level; + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + ++run; + *m7 = 0; + } + } + else + { + ++run; + } + } + + *DCL = 0; + + return nonzero; +} diff --git a/lencod/src/quant4x4_around.c b/lencod/src/quant4x4_around.c new file mode 100644 index 0000000..faee08f --- /dev/null +++ b/lencod/src/quant4x4_around.c @@ -0,0 +1,279 @@ + +/*! + ************************************************************************************* + * \file quant4x4_around.c + * + * \brief + * Quantization process for a 4x4 block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Limin Liu + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant4x4.h" + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 block + * + ************************************************************************ + */ +int quant_4x4_around(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + Slice *currSlice = currMB->p_Slice; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + + int AdaptRndWeight = p_Vid->AdaptRndWeight; + + int block_x = q_method->block_x; + int qp = q_method->qp; + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + + LevelQuantParams *q_params = NULL; + int **fadjust4x4 = q_method->fadjust; + + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + const byte *p_scan = &pos_scan[0][0]; + + int* padjust4x4; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + padjust4x4 = &fadjust4x4[j][block_x + i]; + m7 = &tblock[j][block_x + i]; + + if (*m7 != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *padjust4x4 = rshift_rnd_sf((AdaptRndWeight * (scaled_coeff - (level << q_bits))), q_bits + 1); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *padjust4x4 = 0; + *m7 = 0; + ++run; + } + } + else + { + *padjust4x4 = 0; + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +int quant_ac4x4_around(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + int block_x = q_method->block_x; + + int qp = q_method->qp; + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + LevelQuantParams **q_params_4x4 = q_method->q_params; + int **fadjust4x4 = q_method->fadjust; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + int AdaptRndWeight = p_Vid->AdaptRndWeight; + LevelQuantParams *q_params = NULL; + + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + const byte *p_scan = &pos_scan[1][0]; + int* padjust4x4; + + // Quantization + for (coeff_ctr = 1; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + padjust4x4 = &fadjust4x4[j][block_x + i]; + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *padjust4x4 = rshift_rnd_sf((AdaptRndWeight * (scaled_coeff - (level << q_bits))), (q_bits + 1)); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *padjust4x4 = 0; + *m7 = 0; + ++run; + } + } + else + { + *padjust4x4 = 0; + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 DC block + * + ************************************************************************ + */ +int quant_dc4x4_around(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + *m7 = level; + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + ++run; + *m7 = 0; + } + } + else + { + ++run; + } + } + + *DCL = 0; + + return nonzero; +} diff --git a/lencod/src/quant4x4_normal.c b/lencod/src/quant4x4_normal.c new file mode 100644 index 0000000..1f23aa5 --- /dev/null +++ b/lencod/src/quant4x4_normal.c @@ -0,0 +1,259 @@ + +/*! + ************************************************************************************* + * \file quant4x4_normal.c + * + * \brief + * Quantization process for a 4x4 block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * - Limin Liu + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant4x4.h" + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 block + * + ************************************************************************ + */ +int quant_4x4_normal(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + Slice *currSlice = currMB->p_Slice; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + + int block_x = q_method->block_x; + int qp = q_method->qp; + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + + LevelQuantParams *q_params = NULL; + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + const byte *p_scan = &pos_scan[0][0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (*m7 != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *m7 = 0; + ++run; + } + } + else + { + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +int quant_ac4x4_normal(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + int block_x = q_method->block_x; + + int qp = q_method->qp; + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + LevelQuantParams *q_params = NULL; + + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per; + const byte *p_scan = &pos_scan[1][0]; + + // Quantization + for (coeff_ctr = 1; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + q_params = &q_params_4x4[j][i]; + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params->InvScaleComp),4-qp_per) : (level*q_params->InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *m7 = 0; + ++run; + } + } + else + { + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 DC block + * + ************************************************************************ + */ +int quant_dc4x4_normal(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + *m7 = level; + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + ++run; + *m7 = 0; + } + } + else + { + ++run; + } + } + + *DCL = 0; + + return nonzero; +} diff --git a/lencod/src/quant4x4_trellis.c b/lencod/src/quant4x4_trellis.c new file mode 100644 index 0000000..d4b43b4 --- /dev/null +++ b/lencod/src/quant4x4_trellis.c @@ -0,0 +1,433 @@ + +/*! + ************************************************************************************* + * \file quant4x4_trellis.c + * + * \brief + * Quantization process for a 4x4 block using trellis based quantization + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Qualcomm + * - Limin Liu + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant4x4.h" +#include "rdoq.h" + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 block + * + ************************************************************************ + */ +int quant_4x4_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + int block_x = q_method->block_x; + + int* ACL = &q_method->ACLevel[0]; + int* ACR = &q_method->ACRun[0]; + Slice *currSlice = currMB->p_Slice; + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + int qp = q_method->qp; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + + int i,j, coeff_ctr; + + int *m7; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + const byte *p_scan = &pos_scan[0][0]; + + int levelTrellis[16]; + + currSlice->rdoq_4x4(currMB, tblock, q_method, levelTrellis); + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (*m7 != 0) + { + /* + scaled_coeff = iabs (*m7) * q_params_4x4[j][i].ScaleComp; + level = (scaled_coeff + q_params_4x4[j][i].OffsetComp) >> q_bits; + */ + level = levelTrellis[coeff_ctr]; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_4x4[j][i].InvScaleComp) << qp_per), 4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + *m7 = 0; + ++run; + } + } + else + { + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a 4x4 block (CAVLC) +* +************************************************************************ +*/ +void rdoq_4x4_CAVLC(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int block_x = q_method->block_x; + int block_y = q_method->block_y; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *p_scan = &pos_scan[0][0]; + int qp = q_method->qp; + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + + levelDataStruct levelData[16]; + double lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + int type = LUMA_4x4; + int pos_x = block_x >> BLOCK_SHIFT; + int pos_y = block_y >> BLOCK_SHIFT; + int b8 = 2*(pos_y >> 1) + (pos_x >> 1); + int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01); + + init_trellis_data_4x4_CAVLC(currMB, tblock, block_x, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0], type); + est_RunLevel_CAVLC(currMB, levelData, levelTrellis, LUMA, b8, b4, 16, lambda_md); +} +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a 4x4 block (CABAC) +* +************************************************************************ +*/ +void rdoq_4x4_CABAC(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *p_scan = &pos_scan[0][0]; + + levelDataStruct levelData[16]; + int kStart=0, kStop=0, noCoeff = 0, estBits; + + double lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + noCoeff = init_trellis_data_4x4_CABAC(currMB, tblock, q_method, p_scan, &levelData[0], &kStart, &kStop, LUMA_4x4); + estBits = est_write_and_store_CBP_block_bit(currMB, LUMA_4x4); + est_writeRunLevel_CABAC(currMB, levelData, levelTrellis, LUMA_4x4, lambda_md, kStart, kStop, noCoeff, estBits); +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 block (LUMA_16AC or CHROMA_AC) + * + ************************************************************************ + */ +int quant_ac4x4_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + int block_x = q_method->block_x; + + int* ACLevel = q_method->ACLevel; + int* ACRun = q_method->ACRun; + int qp = q_method->qp; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + Slice *currSlice = currMB->p_Slice; + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + const byte *p_scan = &pos_scan[1][0]; + int* ACL = &ACLevel[0]; + int* ACR = &ACRun[0]; + + int levelTrellis[16]; + + currSlice->rdoq_ac4x4(currMB, tblock, q_method, levelTrellis); + + // Quantization + for (coeff_ctr = 1; coeff_ctr < 16; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + /* + scaled_coeff = iabs (*m7) * q_params_4x4[j][i].ScaleComp; + level = (scaled_coeff + q_params_4x4[j][i].OffsetComp) >> q_bits; + */ + level=levelTrellis[coeff_ctr - 1]; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_4x4[j][i].InvScaleComp) << qp_per), 4); + // inverse scale can be alternative performed as follows to ensure 16bit + // arithmetic is satisfied. + // *m7 = (qp_per<4) ? rshift_rnd_sf((level*q_params_4x4[j][i].InvScaleComp),4-qp_per) : (level*q_params_4x4[j][i].InvScaleComp)<<(qp_per-4); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a 4x4 block (CAVLC) +* +************************************************************************ +*/ +void rdoq_ac4x4_CAVLC(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int block_x = q_method->block_x; + int block_y = q_method->block_y; + LevelQuantParams **q_params_4x4 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + int qp = q_method->qp; + int type = q_method->type; + QuantParameters *p_Quant = p_Vid->p_Quant; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + + const byte *p_scan = &pos_scan[1][0]; + levelDataStruct levelData[16]; + double lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + int pos_x = block_x >> BLOCK_SHIFT; + int pos_y = block_y >> BLOCK_SHIFT; + int b8 = 2*(pos_y >> 1) + (pos_x >> 1); + int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01); + int block_type = ( (type == CHROMA_AC) ? CHROMA_AC : LUMA_INTRA16x16AC); + + init_trellis_data_4x4_CAVLC(currMB, tblock, block_x, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0], type); + est_RunLevel_CAVLC(currMB, levelData, levelTrellis, block_type, b8, b4, 15, lambda_md); +} +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a 4x4 block (LUMA_16AC or CHROMA_AC) - CABAC +* +************************************************************************ +*/ +void rdoq_ac4x4_CABAC(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int levelTrellis[]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + + const byte (*pos_scan)[2] = q_method->pos_scan; + int type = q_method->type; + + const byte *p_scan = &pos_scan[1][0]; + levelDataStruct levelData[16]; + double lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + int kStart = 0, kStop = 0, noCoeff = 0, estBits; + + noCoeff = init_trellis_data_4x4_CABAC(currMB, tblock, q_method, p_scan, &levelData[0], &kStart, &kStop, type); + estBits = est_write_and_store_CBP_block_bit(currMB, type); + est_writeRunLevel_CABAC(currMB, levelData, levelTrellis, type, lambda_md, kStart, kStop, noCoeff, estBits); +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 4x4 DC block + * + ************************************************************************ + */ +int quant_dc4x4_trellis(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2]) +{ + Slice *currSlice = currMB->p_Slice; + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + int levelTrellis[16]; + + currSlice->rdoq_dc(currMB, tblock, qp_per, qp_rem, q_params_4x4, pos_scan, levelTrellis, LUMA_16DC); + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 16; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + level = levelTrellis[coeff_ctr]; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + *m7 = level; + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *DCL = 0; + + return nonzero; +} + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a luma DC block +* +************************************************************************ +*/ +void rdoq_dc_CAVLC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, + const byte (*pos_scan)[2], int levelTrellis[], int type) +{ + VideoParameters *p_Vid = currMB->p_Vid; + const byte *p_scan = &pos_scan[0][0]; + levelDataStruct levelData[16]; + double lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + init_trellis_data_DC_CAVLC(currMB, tblock, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0]); + est_RunLevel_CAVLC(currMB, levelData, levelTrellis, LUMA_INTRA16x16DC, 0, 0, 16, lambda_md); +} + + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a luma DC block +* +************************************************************************ +*/ +void rdoq_dc_CABAC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2], int levelTrellis[], int type) +{ + VideoParameters *p_Vid = currMB->p_Vid; + const byte *p_scan = &pos_scan[0][0]; + levelDataStruct levelData[16]; + double lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + int kStart = 0, kStop = 0, noCoeff = 0, estBits; + + noCoeff = init_trellis_data_DC_CABAC(currMB, tblock, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0], &kStart, &kStop); + estBits = est_write_and_store_CBP_block_bit(currMB, type); + est_writeRunLevel_CABAC(currMB, levelData, levelTrellis, type, lambda_md, kStart, kStop, noCoeff, estBits); +} + diff --git a/lencod/src/quant8x8.c b/lencod/src/quant8x8.c new file mode 100644 index 0000000..b0c2379 --- /dev/null +++ b/lencod/src/quant8x8.c @@ -0,0 +1,51 @@ + +/*! + ************************************************************************************* + * \file quant8x8.c + * + * \brief + * Quantization process for a 8x8 block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "quant8x8.h" + + +/*! +************************************************************************ +* \brief +* Quantization initialization function +* +************************************************************************ +*/ +void init_quant_8x8(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + // We may wish to have all these parameters switched at the slice level for speed up. + if (currSlice->UseRDOQuant == 1) + { + currSlice->quant_8x8 = quant_8x8_trellis; + currSlice->quant_8x8cavlc = quant_8x8cavlc_trellis; + } + else if (p_Vid->AdaptiveRounding) + { + currSlice->quant_8x8 = quant_8x8_around; + currSlice->quant_8x8cavlc = quant_8x8cavlc_around; + } + else + { + currSlice->quant_8x8 = quant_8x8_normal; + currSlice->quant_8x8cavlc = quant_8x8cavlc_normal; + } +} + diff --git a/lencod/src/quant8x8_around.c b/lencod/src/quant8x8_around.c new file mode 100644 index 0000000..6d4e31c --- /dev/null +++ b/lencod/src/quant8x8_around.c @@ -0,0 +1,223 @@ + +/*! + ************************************************************************************* + * \file quant8x8_around.c + * + * \brief + * Quantization process for a 8x8 block with adaptive rounding + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant8x8.h" + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 8x8 block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_8x8_around(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + int AdaptRndWeight = p_Vid->AdaptRndWeight; + + int block_x = q_method->block_x; + + int qp = q_method->qp; + int* ACLevel = q_method->ACLevel; + int* ACRun = q_method->ACRun; + LevelQuantParams **q_params_8x8 = q_method->q_params; + LevelQuantParams *q_params = NULL; + + int **fadjust8x8 = q_method->fadjust; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS_8 + qp_per; + const byte *p_scan = &pos_scan[0][0]; + int* ACL = &ACLevel[0]; + int* ACR = &ACRun[0]; + int* padjust8x8; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 64; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + padjust8x8 = &fadjust8x8[j][block_x + i]; + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + q_params = &q_params_8x8[j][i]; + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + level = (scaled_coeff + q_params->OffsetComp) >> q_bits; + + if (level != 0) + { + *padjust8x8 = rshift_rnd_sf((AdaptRndWeight * (scaled_coeff - (level << q_bits))), (q_bits + 1)); + + nonzero = TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params->InvScaleComp) << qp_per), 6); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + } + else + { + *padjust8x8 = 0; + ++run; + *m7 = 0; + } + } + else + { + *padjust8x8 = 0; + ++run; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 8x8 block + * CAVLC version + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_8x8cavlc_around(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC) +{ + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + int AdaptRndWeight = p_Vid->AdaptRndWeight; + int block_x = q_method->block_x; + + int qp = q_method->qp; + LevelQuantParams **q_params_8x8 = q_method->q_params; + int **fadjust8x8 = q_method->fadjust; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + int i,j, k, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, runs[4] = { 0 }; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS_8 + qp_per; + const byte *p_scan = &pos_scan[0][0]; + int* ACL[4]; + int* ACR[4]; + int* padjust8x8; + + for (k = 0; k < 4; ++k) + { + ACL[k] = &cofAC[k][0][0]; + ACR[k] = &cofAC[k][1][0]; + } + + // Quantization + for (k = 0; k < 4; ++k) + { + for (coeff_ctr = 0; coeff_ctr < 16; ++coeff_ctr) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + padjust8x8 = &fadjust8x8[j][block_x + i]; + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_8x8[j][i].ScaleComp; + level = (scaled_coeff + q_params_8x8[j][i].OffsetComp) >> q_bits; + + if (level != 0) + { + level = imin(level, CAVLC_LEVEL_LIMIT); + + *padjust8x8 = rshift_rnd_sf((AdaptRndWeight * (scaled_coeff - (level << q_bits))), (q_bits + 1)); + + nonzero=TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[runs[k]]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_8x8[j][i].InvScaleComp) << qp_per), 6); + + *(ACL[k])++ = level; + *(ACR[k])++ = runs[k]; + // reset zero level counter + runs[k] = 0; + } + else + { + *padjust8x8 = 0; + *m7 = 0; + ++runs[k]; + } + } + else + { + *padjust8x8 = 0; + ++runs[k]; + } + } + } + + for(k = 0; k < 4; ++k) + *(ACL[k]) = 0; + + return nonzero; +} + diff --git a/lencod/src/quant8x8_normal.c b/lencod/src/quant8x8_normal.c new file mode 100644 index 0000000..51c629c --- /dev/null +++ b/lencod/src/quant8x8_normal.c @@ -0,0 +1,202 @@ + +/*! + ************************************************************************************* + * \file quant8x8_normal.c + * + * \brief + * Quantization process for a 8x8 block without any adaptation + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant8x8.h" + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 8x8 block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_8x8_normal(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + VideoParameters *p_Vid = currMB->p_Vid; + QuantParameters *p_Quant = p_Vid->p_Quant; + int block_x = q_method->block_x; + int* ACLevel = q_method->ACLevel; + int* ACRun = q_method->ACRun; + int qp = q_method->qp; + LevelQuantParams **q_params_8x8 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS_8 + qp_per; + const byte *p_scan = &pos_scan[0][0]; + int* ACL = &ACLevel[0]; + int* ACR = &ACRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 64; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_8x8[j][i].ScaleComp; + level = (scaled_coeff + q_params_8x8[j][i].OffsetComp) >> q_bits; + + if (level != 0) + { + nonzero = TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_8x8[j][i].InvScaleComp) << qp_per), 6); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 8x8 block + * CAVLC version + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_8x8cavlc_normal(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + int block_x = q_method->block_x; + + int qp = q_method->qp; + LevelQuantParams **q_params_8x8 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + + int i,j, k, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, runs[4] = { 0 }; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS_8 + qp_per; + const byte *p_scan = &pos_scan[0][0]; + int* ACL[4]; + int* ACR[4]; + + for (k = 0; k < 4; k++) + { + ACL[k] = &cofAC[k][0][0]; + ACR[k] = &cofAC[k][1][0]; + } + + // Quantization + for (k = 0; k < 4; k++) + { + for (coeff_ctr = 0; coeff_ctr < 16; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_8x8[j][i].ScaleComp; + level = (scaled_coeff + q_params_8x8[j][i].OffsetComp) >> q_bits; + + if (level != 0) + { + level = imin(level, CAVLC_LEVEL_LIMIT); + + nonzero=TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[runs[k]]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_8x8[j][i].InvScaleComp) << qp_per), 6); + + *(ACL[k])++ = level; + *(ACR[k])++ = runs[k]; + // reset zero level counter + runs[k] = 0; + } + else + { + runs[k]++; + *m7 = 0; + } + } + else + { + runs[k]++; + } + } + } + + for(k = 0; k < 4; k++) + *(ACL[k]) = 0; + + return nonzero; +} + diff --git a/lencod/src/quant8x8_trellis.c b/lencod/src/quant8x8_trellis.c new file mode 100644 index 0000000..8a8377e --- /dev/null +++ b/lencod/src/quant8x8_trellis.c @@ -0,0 +1,247 @@ + +/*! + ************************************************************************************* + * \file quant8x8_trellis.c + * + * \brief + * Quantization process for a 4x4 block using trellis based quantization + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "image.h" +#include "mb_access.h" +#include "vlc.h" +#include "transform.h" +#include "mc_prediction.h" +#include "q_offsets.h" +#include "q_matrix.h" +#include "quant8x8.h" +#include "rdoq.h" + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a 8x8 block +* +************************************************************************ +*/ +static void rdoq_8x8_CABAC(Macroblock *currMB, int **tblock, int block_x,int qp_per, int qp_rem, + LevelQuantParams **q_params_8x8, const byte *p_scan, int levelTrellis[64]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + levelDataStruct levelData[64]; + double lambda_md = 0.0; + int kStart = 0, kStop = 0, noCoeff = 0; + + lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + noCoeff = init_trellis_data_8x8_CABAC(currMB, tblock, block_x, qp_per, qp_rem, q_params_8x8, p_scan, &levelData[0], &kStart, &kStop); + est_writeRunLevel_CABAC(currMB, levelData, levelTrellis, LUMA_8x8, lambda_md, kStart, kStop, noCoeff, 0); +} + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a 8x8 block +* +************************************************************************ +*/ +static void rdoq_8x8_CAVLC(Macroblock *currMB, int **tblock, int block_y, int block_x, int qp_per, int qp_rem, + LevelQuantParams **q_params_8x8, const byte *p_scan, int levelTrellis[4][16]) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int k; + levelDataStruct levelData[4][16]; + double lambda_md = 0.0; + + int b8 = ((block_y >> 3) << 1) + (block_x >> 3); + + lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + init_trellis_data_8x8_CAVLC (currMB, tblock, block_x, qp_per, qp_rem, q_params_8x8, p_scan, levelData); + + for (k = 0; k < 4; k++) + est_RunLevel_CAVLC(currMB, levelData[k], levelTrellis[k], LUMA, b8, k, 16, lambda_md); +} + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 8x8 block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_8x8_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + int block_x = q_method->block_x; + int qp = q_method->qp; + int* ACLevel = q_method->ACLevel; + int* ACRun = q_method->ACRun; + LevelQuantParams **q_params_8x8 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + int i,j, coeff_ctr; + + int *m7; + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + const byte *p_scan = &pos_scan[0][0]; + int* ACL = &ACLevel[0]; + int* ACR = &ACRun[0]; + int levelTrellis[64]; + + rdoq_8x8_CABAC(currMB, tblock, block_x, qp_per, qp_rem, q_params_8x8, p_scan, levelTrellis); + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 64; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + if (*m7 != 0) + { + level = levelTrellis[coeff_ctr]; + + if (level != 0) + { + nonzero = TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[run]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_8x8[j][i].InvScaleComp) << qp_per), 6); + *ACL++ = level; + *ACR++ = run; + // reset zero level counter + run = 0; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *ACL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 8x8 block + * CAVLC version + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_8x8cavlc_trellis(Macroblock *currMB, int **tblock, struct quant_methods *q_method, int*** cofAC) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + int block_x = q_method->block_x; + int block_y = q_method->block_y; + int qp = q_method->qp; + LevelQuantParams **q_params_8x8 = q_method->q_params; + const byte (*pos_scan)[2] = q_method->pos_scan; + const byte *c_cost = q_method->c_cost; + int *coeff_cost = q_method->coeff_cost; + + int i,j, k, coeff_ctr; + + int *m7; + int level, runs[4] = { 0 }; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + const byte *p_scan = &pos_scan[0][0]; + int* ACL[4]; + int* ACR[4]; + + int levelTrellis[4][16]; + + rdoq_8x8_CAVLC(currMB, tblock, block_y, block_x, qp_per, qp_rem, q_params_8x8, p_scan, levelTrellis); + + for (k = 0; k < 4; k++) + { + ACL[k] = &cofAC[k][0][0]; + ACR[k] = &cofAC[k][1][0]; + } + + // Quantization + for (k = 0; k < 4; k++) + { + for (coeff_ctr = 0; coeff_ctr < 16; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (m7 != 0) + { + level = levelTrellis[k][coeff_ctr]; + + if (level != 0) + { + nonzero=TRUE; + + *coeff_cost += (level > 1) ? MAX_VALUE : c_cost[runs[k]]; + + level = isignab(level, *m7); + *m7 = rshift_rnd_sf(((level * q_params_8x8[j][i].InvScaleComp) << qp_per), 6); + + *(ACL[k])++ = level; + *(ACR[k])++ = runs[k]; + // reset zero level counter + runs[k] = 0; + } + else + { + runs[k]++; + *m7 = 0; + } + } + else + { + runs[k]++; + } + } + } + + for(k = 0; k < 4; k++) + *(ACL[k]) = 0; + + return nonzero; +} + diff --git a/lencod/src/quantChroma.c b/lencod/src/quantChroma.c new file mode 100644 index 0000000..07ef9a3 --- /dev/null +++ b/lencod/src/quantChroma.c @@ -0,0 +1,74 @@ + +/*! + ************************************************************************************* + * \file quantChroma.c + * + * \brief + * Quantization initialization function for Chroma blocks + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include "global.h" +#include "quant4x4.h" +#include "quantChroma.h" + +/*! +************************************************************************ +* \brief +* Quantization initialization function +* +************************************************************************ +*/ +void init_quant_Chroma(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + if (p_Inp->UseRDOQuant == 1 && p_Inp->RDOQ_CR == 1) + { + currSlice->quant_ac4x4cr = quant_ac4x4_trellis; + if (p_Inp->RDOQ_DC_CR) + { + if (p_Vid->yuv_format == YUV422) + currSlice->quant_dc_cr = quant_dc4x2_trellis; + else + currSlice->quant_dc_cr = quant_dc2x2_trellis; + } + else + { + if (p_Vid->yuv_format == YUV422) + currSlice->quant_dc_cr = quant_dc4x2_normal; + else + currSlice->quant_dc_cr = quant_dc2x2_normal; + } + if (currSlice->symbol_mode == CABAC) + currSlice->rdoq_dc_cr = rdoq_dc_cr_CABAC; + else + currSlice->rdoq_dc_cr = rdoq_dc_cr_CAVLC; + } + else if (p_Inp->UseRDOQuant == 1 || (!(currSlice->p_Vid)->AdaptiveRounding)) + { + currSlice->quant_ac4x4cr = quant_ac4x4_normal; + if (p_Vid->yuv_format == YUV422) + currSlice->quant_dc_cr = quant_dc4x2_normal; + else + currSlice->quant_dc_cr = quant_dc2x2_normal; + } + else + { + currSlice->quant_ac4x4cr = quant_ac4x4_around; + if (p_Vid->yuv_format == YUV422) + currSlice->quant_dc_cr = quant_dc4x2_around; + else + currSlice->quant_dc_cr = quant_dc2x2_around; + } +} + + diff --git a/lencod/src/quantChroma_2step.c b/lencod/src/quantChroma_2step.c new file mode 100644 index 0000000..b134fc9 --- /dev/null +++ b/lencod/src/quantChroma_2step.c @@ -0,0 +1,173 @@ + +/*! + ************************************************************************************* + * \file quantChroma_2step.c + * + * \brief + * Quantization process for a Chroma block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "q_matrix.h" +#include "quant4x4.h" +#include "quantChroma.h" + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc2x2_2step(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + //const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + m7 = *tblock; + + // Quantization + for (coeff_ctr=0; coeff_ctr < 4; coeff_ctr++) + { + // we need to update q_params_4x4->OffsetComp to a 4x1 array that would contain offset info for + // every 2x2 DC position + if (*m7) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + + *m7++ = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7++ = 0; + } + } + else + { + run++; + m7++; + } + } + + *DCL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc4x2_2step(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 8; coeff_ctr++) + { + j = *p_scan++; // note that in this part, somehow coefficients were transposed from 2x4 to 4x2. + i = *p_scan++; + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + level = isignab(level, *m7); + + *m7 = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *DCL = 0; + + return nonzero; +} + + + diff --git a/lencod/src/quantChroma_around.c b/lencod/src/quantChroma_around.c new file mode 100644 index 0000000..9820f0a --- /dev/null +++ b/lencod/src/quantChroma_around.c @@ -0,0 +1,174 @@ + +/*! + ************************************************************************************* + * \file quantChroma_around.c + * + * \brief + * Quantization process for a Chroma block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "q_matrix.h" +#include "quant4x4.h" +#include "quantChroma.h" + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc2x2_around(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + //const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + m7 = *tblock; + + // Quantization + for (coeff_ctr=0; coeff_ctr < 4; ++coeff_ctr) + { + // we need to update q_params_4x4->OffsetComp to a 4x1 array that would contain offset info for + // every 2x2 DC position + if (*m7) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + + *m7++ = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + ++run; + *m7++ = 0; + } + } + else + { + ++run; + ++m7; + } + } + + *DCL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc4x2_around(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 8; ++coeff_ctr) + { + j = *p_scan++; // note that in this part, somehow coefficients were transposed from 2x4 to 4x2. + i = *p_scan++; + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + level = isignab(level, *m7); + + *m7 = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + ++run; + *m7 = 0; + } + } + else + { + ++run; + } + } + + *DCL = 0; + + return nonzero; +} + + + diff --git a/lencod/src/quantChroma_normal.c b/lencod/src/quantChroma_normal.c new file mode 100644 index 0000000..96ad627 --- /dev/null +++ b/lencod/src/quantChroma_normal.c @@ -0,0 +1,173 @@ + +/*! + ************************************************************************************* + * \file quantChroma_normal.c + * + * \brief + * Quantization process for a Chroma block + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "q_matrix.h" +#include "quant4x4.h" +#include "quantChroma.h" + + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc2x2_normal(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + //const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + m7 = *tblock; + + // Quantization + for (coeff_ctr=0; coeff_ctr < 4; coeff_ctr++) + { + // we need to update q_params_4x4->OffsetComp to a 4x1 array that would contain offset info for + // every 2x2 DC position + if (*m7) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + + *m7++ = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7++ = 0; + } + } + else + { + run++; + m7++; + } + } + + *DCL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc4x2_normal(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currMB->p_Slice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + int scaled_coeff; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int q_bits = Q_BITS + qp_per + 1; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + // Quantization + for (coeff_ctr = 0; coeff_ctr < 8; coeff_ctr++) + { + j = *p_scan++; // note that in this part, somehow coefficients were transposed from 2x4 to 4x2. + i = *p_scan++; + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + scaled_coeff = iabs (*m7) * q_params_4x4->ScaleComp; + level = (scaled_coeff + (q_params_4x4->OffsetComp << 1) ) >> q_bits; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + level = isignab(level, *m7); + + *m7 = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *DCL = 0; + + return nonzero; +} + + + diff --git a/lencod/src/quantChroma_trellis.c b/lencod/src/quantChroma_trellis.c new file mode 100644 index 0000000..e3d3751 --- /dev/null +++ b/lencod/src/quantChroma_trellis.c @@ -0,0 +1,223 @@ + +/*! + ************************************************************************************* + * \file quantChroma_trellis.c + * + * \brief + * Quantization process for a Chroma block (trellis based) + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Alexis Michael Tourapis + * + ************************************************************************************* + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "q_matrix.h" +#include "quant4x4.h" +#include "quantChroma.h" +#include "rdoq.h" + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc2x2_trellis(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + Slice *currSlice = currMB->p_Slice; + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int coeff_ctr; + + int *m7; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + //const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + int levelTrellis[16]; + + currSlice->rdoq_dc_cr(currMB, tblock,qp_per,qp_rem, q_params_4x4, pos_scan, levelTrellis, CHROMA_DC); + + m7 = *tblock; + + // Quantization + for (coeff_ctr=0; coeff_ctr < 4; coeff_ctr++) + { + // we need to update q_params_4x4->OffsetComp to a 4x1 array that would contain offset info for + // every 2x2 DC position + if (*m7) + { + level = levelTrellis[coeff_ctr]; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + + level = isignab(level, *m7); + + *m7++ = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7++ = 0; + } + } + else + { + run++; + m7++; + } + } + + *DCL = 0; + + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * Quantization process for All coefficients for a 2x2 DC block + * + * \par Input: + * + * \par Output: + * + ************************************************************************ + */ +int quant_dc4x2_trellis(Macroblock *currMB, int **tblock, int qp, int* DCLevel, int* DCRun, + LevelQuantParams *q_params_4x4, int **fadjust, const byte (*pos_scan)[2]) +{ + Slice *currSlice = currMB->p_Slice; + QuantParameters *p_Quant = currMB->p_Vid->p_Quant; + Boolean is_cavlc = (Boolean) (currSlice->symbol_mode == CAVLC); + int i,j, coeff_ctr; + + int *m7; + + int level, run = 0; + int nonzero = FALSE; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + const byte *p_scan = &pos_scan[0][0]; + int* DCL = &DCLevel[0]; + int* DCR = &DCRun[0]; + + int levelTrellis[16]; + + currSlice->rdoq_dc_cr(currMB, tblock,qp_per,qp_rem, q_params_4x4,pos_scan, levelTrellis, CHROMA_DC_2x4); + + for (coeff_ctr=0; coeff_ctr < 8; coeff_ctr++) + { + j = *p_scan++; // note that in this part, somehow coefficients were transposed from 2x4 to 4x2. + i = *p_scan++; + + m7 = &tblock[j][i]; + + if (*m7 != 0) + { + level = levelTrellis[coeff_ctr]; + + if (level != 0) + { + if (is_cavlc) + level = imin(level, CAVLC_LEVEL_LIMIT); + level = isignab(level, *m7); + + *m7 = ((level * q_params_4x4->InvScaleComp) << qp_per); + + *DCL++ = level; + *DCR++ = run; + // reset zero level counter + run = 0; + nonzero = TRUE; + } + else + { + run++; + *m7 = 0; + } + } + else + { + run++; + } + } + + *DCL = 0; + + return nonzero; +} + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a chroma DC block +* +************************************************************************ +*/ +void rdoq_dc_cr_CAVLC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2], int levelTrellis[], int type) +{ + VideoParameters *p_Vid = currMB->p_Vid; + + const byte *p_scan = &pos_scan[0][0]; + levelDataStruct levelData[16]; + double lambda_md = 0.0; + + lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + init_trellis_data_DC_cr_CAVLC(currMB, tblock, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0]); + est_RunLevel_CAVLC(currMB, levelData, levelTrellis, CHROMA_DC, 0, 0, p_Vid->num_cdc_coeff, lambda_md); +} + +/*! +************************************************************************ +* \brief +* Rate distortion optimized Quantization process for +* all coefficients in a chroma DC block +* +************************************************************************ +*/ +void rdoq_dc_cr_CABAC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, LevelQuantParams *q_params_4x4, const byte (*pos_scan)[2], int levelTrellis[], int type) +{ + VideoParameters *p_Vid = currMB->p_Vid; + const byte *p_scan = &pos_scan[0][0]; + levelDataStruct levelData[16]; + double lambda_md = 0.0; + int kStart=0, kStop=0, noCoeff = 0, estBits; + + lambda_md = p_Vid->lambda_rdoq[p_Vid->type][p_Vid->masterQP]; + + noCoeff = init_trellis_data_DC_cr_CABAC(currMB, tblock, qp_per, qp_rem, q_params_4x4, p_scan, &levelData[0], &kStart, &kStop); + estBits = est_write_and_store_CBP_block_bit(currMB, type); + est_writeRunLevel_CABAC(currMB, levelData, levelTrellis, type, lambda_md, kStart, kStop, noCoeff, estBits); +} + + diff --git a/lencod/src/ratectl.c b/lencod/src/ratectl.c new file mode 100644 index 0000000..f113b8e --- /dev/null +++ b/lencod/src/ratectl.c @@ -0,0 +1,406 @@ + +/*! + *************************************************************************** + * \file ratectl.c + * + * \brief + * Rate Control algorithm + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Siwei Ma + * - Zhengguo LI + * + * \date + * 16 Jan. 2003 + ************************************************************************** + */ + +#include +#include + +#include "global.h" +#include "ratectl.h" + + +/*! + ************************************************************************************* + * \brief + * Update Rate Control Parameters + ************************************************************************************* + */ +void rc_store_mad(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + RCGeneric *p_gen = p_Vid->p_rc_gen; + + p_gen->MADofMB[currMB->mbAddrX] = ComputeMBMAD(currMB->p_Slice->diffy); + + if(p_Inp->basicunit < p_Vid->FrameSizeInMbs) + { + p_gen->TotalMADBasicUnit += p_gen->MADofMB[currMB->mbAddrX]; + } +} + +/*! + ************************************************************************************* + * \brief + * map QP to Qstep + * + ************************************************************************************* +*/ +double QP2Qstep( int QP ) +{ + int i; + double Qstep; + static const double QP2QSTEP[6] = { 0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125 }; + + Qstep = QP2QSTEP[QP % 6]; + for( i=0; i<(QP/6); i++) + Qstep *= 2; + + return Qstep; +} + + +/*! + ************************************************************************************* + * \brief + * map Qstep to QP + * + ************************************************************************************* +*/ +int Qstep2QP( double Qstep, int qp_offset ) +{ + int q_per = 0, q_rem = 0; + + if( Qstep < QP2Qstep(MIN_QP)) + return MIN_QP; + else if (Qstep > QP2Qstep(MAX_QP + qp_offset) ) + return (MAX_QP + qp_offset); + + while( Qstep > QP2Qstep(5) ) + { + Qstep /= 2.0; + q_per++; + } + + if (Qstep <= 0.65625) + { + //Qstep = 0.625; + q_rem = 0; + } + else if (Qstep <= 0.75) + { + //Qstep = 0.6875; + q_rem = 1; + } + else if (Qstep <= 0.84375) + { + //Qstep = 0.8125; + q_rem = 2; + } + else if (Qstep <= 0.9375) + { + //Qstep = 0.875; + q_rem = 3; + } + else if (Qstep <= 1.0625) + { + //Qstep = 1.0; + q_rem = 4; + } + else + { + //Qstep = 1.125; + q_rem = 5; + } + + return (q_per * 6 + q_rem); +} + +/*! + ************************************************************************************ + * \brief + * calculate MAD for the current macroblock + * + * \return + * calculated MAD + * + ************************************************************************************* +*/ +int ComputeMBMAD(int diffy[16][16]) +{ + int k, l, sum = 0; + + for (k = 0; k < 16; k++) + for (l = 0; l < 16; l++) + sum += iabs(diffy[k][l]); + + return sum; +} + +/*! + ************************************************************************************* + * \brief + * Compute Frame MAD + * + ************************************************************************************* +*/ +double ComputeFrameMAD(VideoParameters *p_Vid) +{ + int64 TotalMAD = 0; + unsigned int i; + for(i = 0; i < p_Vid->FrameSizeInMbs; i++) + TotalMAD += p_Vid->p_rc_gen->MADofMB[i]; + return (double)TotalMAD / (256.0 * (double)p_Vid->FrameSizeInMbs); +} + + +/*! + ************************************************************************************* + * \brief + * Copy JVT rate control objects + * + ************************************************************************************* +*/ +void rc_copy_generic( VideoParameters *p_Vid, RCGeneric *dst, RCGeneric *src ) +{ + /* buffer original addresses for which memory has been allocated */ + int *tmpMADofMB = dst->MADofMB; + + /* copy object */ + + // This could be written as: *dst = *src; + memcpy( (void *)dst, (void *)src, sizeof(RCGeneric) ); + + /* restore original addresses */ + dst->MADofMB = tmpMADofMB; + + /* copy MADs */ + memcpy( (void *)dst->MADofMB, (void *)src->MADofMB, p_Vid->FrameSizeInMbs * sizeof (int) ); +} + +/*! + ************************************************************************************* + * \brief + * Dynamically allocate memory needed for generic rate control + * + ************************************************************************************* + */ +void rc_alloc_generic( VideoParameters *p_Vid, RCGeneric **p_quad ) +{ + *p_quad = (RCGeneric *) malloc ( sizeof( RCGeneric ) ); + if (NULL == *p_quad) + { + no_mem_exit("rc_alloc_generic: rc_alloc_generic"); + } + (*p_quad)->MADofMB = (int *) calloc (p_Vid->FrameSizeInMbs, sizeof (int)); + if (NULL == (*p_quad)->MADofMB) + { + no_mem_exit("rc_alloc_generic: (*p_quad)->MADofMB"); + } + (*p_quad)->FieldFrame = 1; +} + + +/*! + ************************************************************************************* + * \brief + * Free memory needed for generic rate control + * + ************************************************************************************* + */ +void rc_free_generic(RCGeneric **p_quad) +{ + if (NULL!=(*p_quad)->MADofMB) + { + free ((*p_quad)->MADofMB); + (*p_quad)->MADofMB = NULL; + } + if (NULL!=(*p_quad)) + { + free ((*p_quad)); + (*p_quad) = NULL; + } +} + +/*! + ************************************************************************************* + * \brief + * Initialize GOP Level Rate Control parameters + * + ************************************************************************************* + */ +void rc_init_gop_params(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int np, nb; + RCQuadratic *p_quad = p_Vid->p_rc_quad; + RCGeneric *p_gen = p_Vid->p_rc_gen; + + switch( p_Inp->RCUpdateMode ) + { + case RC_MODE_1: + case RC_MODE_3: + if ( !(p_Vid->curr_frm_idx) ) + { + /* number of P frames */ + np = (int) (p_Inp->no_frames + p_Inp->NumberBFrames) / (1 + p_Inp->NumberBFrames) - 1 + 1; // approximate but good enough (hack...) + /* number of B frames */ + nb = np * p_Inp->NumberBFrames; + + rc_init_GOP(p_Vid, p_Inp, p_quad, p_gen, np, nb); + } + break; + case RC_MODE_0: + case RC_MODE_2: + if (p_Inp->idr_period == 0) + { + if ( !(p_Vid->curr_frm_idx) ) + { + /* number of P frames */ + np = (int) (p_Inp->no_frames + p_Inp->NumberBFrames) / (1 + p_Inp->NumberBFrames) - 1 + 1; // approximate but good enough (hack...) + /* number of B frames */ + nb = np * p_Inp->NumberBFrames; + rc_init_GOP(p_Vid, p_Inp, p_quad, p_gen, np, nb); + } + } + else if ( p_Vid->p_curr_frm_struct->idr_flag ) + { + int M = p_Inp->NumberBFrames + 1; + int n = p_Inp->idr_period; + + /* last GOP may contain less frames */ + if ((p_Vid->curr_frm_idx / p_Inp->idr_period) >= (p_Inp->no_frames / p_Inp->idr_period)) + { + n = p_Inp->no_frames - p_Vid->curr_frm_idx; + } + + /* number of P frames */ + np = (p_Vid->curr_frm_idx == 0) ? 1 + ((n - 2) / M) : (n - 1) / M; + /* number of B frames */ + nb = n - np - 1; + rc_init_GOP(p_Vid, p_Inp, p_quad, p_gen, np, nb); + } + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * Initialize Frame Level Rate Control parameters + * + ************************************************************************************* + */ + +void rc_init_frame(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + switch( p_Inp->RCUpdateMode ) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + + // update the number of MBs in the basic unit for MBAFF coding + if( (p_Inp->MbInterlace) && (p_Inp->basicunit < p_Vid->FrameSizeInMbs) && (p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && p_Vid->number) ) ) + p_Vid->BasicUnit = p_Inp->basicunit << 1; + else + p_Vid->BasicUnit = p_Inp->basicunit; + + if ( p_Inp->RDPictureDecision ) + { + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad_init, p_Vid->p_rc_quad ); // store rate allocation quadratic... + rc_copy_generic( p_Vid, p_Vid->p_rc_gen_init, p_Vid->p_rc_gen ); // ...and generic model + } + p_Vid->rc_init_pict_ptr(p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_gen, 1,0,1, 1.0F); + + if( p_Vid->active_sps->frame_mbs_only_flag) + p_Vid->p_rc_gen->TopFieldFlag=0; + + p_Vid->p_curr_frm_struct->qp = p_Vid->qp = p_Vid->updateQP(p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_gen, 0) - p_Vid->p_rc_quad->bitdepth_qp_scale; + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * Initialize Sequence Level Rate Control parameters + * + ************************************************************************************* + */ + +void rc_init_sequence(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + switch( p_Inp->RCUpdateMode ) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + rc_init_seq(p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_gen); + break; + default: + break; + } +} + +void rc_store_slice_header_bits( VideoParameters *p_Vid, InputParameters *p_Inp, int len ) +{ + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + p_Vid->p_rc_gen->NumberofHeaderBits +=len; + + // basic unit layer rate control + if(p_Vid->BasicUnit < p_Vid->FrameSizeInMbs) + p_Vid->p_rc_gen->NumberofBasicUnitHeaderBits +=len; + break; + default: + break; + } +} + + +/*! +************************************************************************************* +* \brief +* Update Rate Control Difference +************************************************************************************* +*/ +void rc_store_diff(int diffy[16][16], imgpel **p_curImg, int cpix_x,imgpel **prediction) +{ + int i, j; + int *iDst; + imgpel *Src1, *Src2; + + for(j = 0; j < MB_BLOCK_SIZE; j++) + { + iDst = diffy[j]; + Src1 = &p_curImg[j][cpix_x]; + Src2 = prediction[j]; + for (i = 0; i < MB_BLOCK_SIZE; i++) + { + iDst[i] = Src1[i] - Src2[i]; + } + } +} + +void rc_store_diff_16b(int diffy[16][16], imgpel **p_curImg, int cpix_x,imgpel **prediction) +{ + int i, j; + int *iDst; + uint16 *Src1, *Src2; + + for(j = 0; j < MB_BLOCK_SIZE; j++) + { + iDst = diffy[j]; + Src1 = (uint16*)(p_curImg[j]) +cpix_x; + Src2 = (uint16*)(prediction[j]); + for (i = 0; i < MB_BLOCK_SIZE; i++) + { + iDst[i] = Src1[i] - Src2[i]; + } + } +} diff --git a/lencod/src/rc_quadratic.c b/lencod/src/rc_quadratic.c new file mode 100644 index 0000000..2fbd89f --- /dev/null +++ b/lencod/src/rc_quadratic.c @@ -0,0 +1,2754 @@ + +/*! + *************************************************************************** + * \file rc_quadratic.c + * + * \brief + * Rate Control algorithm + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Siwei Ma + * - Zhengguo LI + * - Athanasios Leontaris + * + * \date + * 16 Jan. 2003 + ************************************************************************** + */ + +#include +#include + +#include "global.h" +#include "ratectl.h" + + +static const float THETA = 1.3636F; +static const float OMEGA = 0.9F; +static const float MINVALUE = 4.0F; +/*! + ************************************************************************************* + * \brief + * Dynamically allocate memory needed for rate control + * + ************************************************************************************* + */ +void rc_alloc_quadratic( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic **p_quad ) +{ + int rcBufSize = p_Vid->FrameSizeInMbs / p_Inp->basicunit; + + RCQuadratic *lprc; + + (*p_quad) = (RCQuadratic *) malloc ( sizeof( RCQuadratic ) ); + if (NULL==(*p_quad)) + { + no_mem_exit("rc_alloc_quadratic: (*p_quad)"); + } + lprc = *p_quad; + + lprc->PreviousFrameMAD = 1.0; + lprc->CurrentFrameMAD = 1.0; + lprc->Pprev_bits = 0; + lprc->Target = 0; + lprc->TargetField = 0; + lprc->LowerBound = 0; + lprc->UpperBound1 = INT_MAX; + lprc->UpperBound2 = INT_MAX; + lprc->Wp = 0.0; + lprc->Wb = 0.0; + lprc->AveWb = 0.0; + lprc->PAveFrameQP = p_Inp->qp[I_SLICE] + p_Vid->bitdepth_luma_qp_scale; + lprc->m_Qc = lprc->PAveFrameQP; + lprc->FieldQPBuffer = lprc->PAveFrameQP; + lprc->FrameQPBuffer = lprc->PAveFrameQP; + lprc->PAverageQp = lprc->PAveFrameQP; + lprc->MyInitialQp = lprc->PAveFrameQP; + lprc->AveWb = 0.0; + + lprc->BUPFMAD = (double*) calloc ((rcBufSize), sizeof (double)); + if (NULL==lprc->BUPFMAD) + { + no_mem_exit("rc_alloc_quadratic: lprc->BUPFMAD"); + } + + lprc->BUCFMAD = (double*) calloc ((rcBufSize), sizeof (double)); + if (NULL==lprc->BUCFMAD) + { + no_mem_exit("rc_alloc_quadratic: lprc->BUCFMAD"); + } + + lprc->FCBUCFMAD = (double*) calloc ((rcBufSize), sizeof (double)); + if (NULL==lprc->FCBUCFMAD) + { + no_mem_exit("rc_alloc_quadratic: lprc->FCBUCFMAD"); + } + + lprc->FCBUPFMAD = (double*) calloc ((rcBufSize), sizeof (double)); + if (NULL==lprc->FCBUPFMAD) + { + no_mem_exit("rc_alloc_quadratic: lprc->FCBUPFMAD"); + } +} + +/*! + ************************************************************************************* + * \brief + * Copy JVT rate control objects + * + ************************************************************************************* + */ +void rc_copy_quadratic( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *dst, RCQuadratic *src ) +{ + int rcBufSize = p_Vid->FrameSizeInMbs / p_Inp->basicunit; + /* buffer original addresses for which memory has been allocated */ + double *tmpBUPFMAD = dst->BUPFMAD; + double *tmpBUCFMAD = dst->BUCFMAD; + double *tmpFCBUPFMAD = dst->FCBUPFMAD; + double *tmpFCBUCFMAD = dst->FCBUCFMAD; + + /* copy object */ + memcpy( (void *)dst, (void *)src, sizeof(RCQuadratic) ); + + /* restore original addresses */ + dst->BUPFMAD = tmpBUPFMAD; + dst->BUCFMAD = tmpBUCFMAD; + dst->FCBUPFMAD = tmpFCBUPFMAD; + dst->FCBUCFMAD = tmpFCBUCFMAD; + + /* copy MADs */ + memcpy( (void *)dst->BUPFMAD, (void *)src->BUPFMAD, (rcBufSize) * sizeof (double) ); + memcpy( (void *)dst->BUCFMAD, (void *)src->BUCFMAD, (rcBufSize) * sizeof (double) ); + memcpy( (void *)dst->FCBUPFMAD, (void *)src->FCBUPFMAD, (rcBufSize) * sizeof (double) ); + memcpy( (void *)dst->FCBUCFMAD, (void *)src->FCBUCFMAD, (rcBufSize) * sizeof (double) ); +} + +/*! + ************************************************************************************* + * \brief + * Free memory needed for rate control + * + ************************************************************************************* +*/ +void rc_free_quadratic(RCQuadratic **p_quad) +{ + if (NULL!=(*p_quad)->BUPFMAD) + { + free ((*p_quad)->BUPFMAD); + (*p_quad)->BUPFMAD = NULL; + } + if (NULL!=(*p_quad)->BUCFMAD) + { + free ((*p_quad)->BUCFMAD); + (*p_quad)->BUCFMAD = NULL; + } + if (NULL!=(*p_quad)->FCBUCFMAD) + { + free ((*p_quad)->FCBUCFMAD); + (*p_quad)->FCBUCFMAD = NULL; + } + if (NULL!=(*p_quad)->FCBUPFMAD) + { + free ((*p_quad)->FCBUPFMAD); + (*p_quad)->FCBUPFMAD = NULL; + } + if (NULL!=(*p_quad)) + { + free ((*p_quad)); + (*p_quad) = NULL; + } +} + + +/*! + ************************************************************************************* + * \brief + * Initialize rate control parameters + * + ************************************************************************************* +*/ +void rc_init_seq(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen) +{ + double L1,L2,L3,bpp; + int qp, i; + + switch ( p_Inp->RCUpdateMode ) + { + case RC_MODE_0: + p_Vid->updateQP = updateQPRC0; + break; + case RC_MODE_1: + p_Vid->updateQP = updateQPRC1; + break; + case RC_MODE_2: + p_Vid->updateQP = updateQPRC2; + break; + case RC_MODE_3: + p_Vid->updateQP = updateQPRC3; + break; + default: + p_Vid->updateQP = updateQPRC0; + break; + } + // set function pointers + p_Vid->rc_update_pict_frame_ptr = rc_update_pict_frame; + p_Vid->rc_update_picture_ptr = rc_update_picture; + p_Vid->rc_init_pict_ptr = rc_init_pict; + + p_quad->Xp=0; + p_quad->Xb=0; + + p_quad->bit_rate = (float) p_Inp->bit_rate; + p_quad->frame_rate = p_Vid->framerate; + p_quad->PrevBitRate = p_quad->bit_rate; + + /*compute the total number of MBs in a frame*/ + if(p_Inp->basicunit > p_Vid->FrameSizeInMbs) + p_Inp->basicunit = p_Vid->FrameSizeInMbs; + if(p_Inp->basicunit < p_Vid->FrameSizeInMbs) + p_quad->TotalNumberofBasicUnit = p_Vid->FrameSizeInMbs/p_Inp->basicunit; + else + p_quad->TotalNumberofBasicUnit = 1; + + /*initialize the parameters of fluid flow traffic model*/ + p_gen->CurrentBufferFullness = 0; + p_quad->GOPTargetBufferLevel = (double) p_gen->CurrentBufferFullness; + + /*initialize the previous window size*/ + p_quad->m_windowSize = 0; + p_quad->MADm_windowSize = 0; + p_gen->NumberofCodedBFrame = 0; + p_quad->NumberofCodedPFrame = 0; + p_gen->NumberofGOP = 0; + /*remaining # of bits in GOP */ + p_gen->RemainingBits = 0; + /*control parameter */ + if(p_Inp->NumberBFrames>0) + { + p_quad->GAMMAP=0.25; + p_quad->BETAP=0.9; + } + else + { + p_quad->GAMMAP=0.5; + p_quad->BETAP=0.5; + } + + /*quadratic rate-distortion model*/ + p_quad->PPreHeader=0; + + p_quad->Pm_X1 = p_quad->bit_rate * 1.0; + p_quad->Pm_X2 = 0.0; + /* linear prediction model for P picture*/ + p_quad->PMADPictureC1 = 1.0; + p_quad->PMADPictureC2 = 0.0; + + // Initialize values + for(i=0;i<21;i++) + { + p_quad->Pm_rgQp[i] = 0; + p_quad->Pm_rgRp[i] = 0.0; + p_quad->PPictureMAD[i] = 0.0; + } + + //Define the largest variation of quantization parameters + p_quad->PMaxQpChange = p_Inp->RCMaxQPChange; + + /*basic unit layer rate control*/ + p_quad->PAveHeaderBits1 = 0; + p_quad->PAveHeaderBits3 = 0; + p_quad->DDquant = (p_quad->TotalNumberofBasicUnit>=9 ? 1 : 2); + + p_quad->MBPerRow = p_Vid->PicWidthInMbs; + + /*adaptive field/frame coding*/ + p_gen->FieldControl=0; + + if (p_Inp->SeinitialQP==0) + { + /*compute the initial QP*/ + bpp = 1.0*p_quad->bit_rate /(p_quad->frame_rate*p_Vid->size); + + if (p_Vid->width == 176) + { + L1 = 0.1; + L2 = 0.3; + L3 = 0.6; + } + else if (p_Vid->width == 352) + { + L1 = 0.2; + L2 = 0.6; + L3 = 1.2; + } + else + { + L1 = 0.6; + L2 = 1.4; + L3 = 2.4; + } + if (bpp<= L1) + qp = 35; + else if(bpp<=L2) + qp = 25; + else if(bpp<=L3) + qp = 20; + else + qp = 10; + p_Inp->SeinitialQP = qp; + } + + // high bit-depth + p_quad->bitdepth_qp_scale = p_Vid->bitdepth_luma_qp_scale; +} + +/*! + ************************************************************************************* + * \brief + * Initialize one GOP + * + ************************************************************************************* +*/ +void rc_init_GOP(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int np, int nb) +{ + //int OverBits; + int GOPDquant; + int64 AllocatedBits; + + // bit allocation for RC_MODE_3 + switch( p_Inp->RCUpdateMode ) + { + case RC_MODE_3: + { + int sum = 0, tmp, level, levels = 0, num_frames[RC_MAX_TEMPORAL_LEVELS]; + float numer, denom; + int gop = p_Inp->NumberBFrames + 1; + int i_period = p_Inp->intra_period == 0 ? p_Inp->idr_period : (p_Inp->idr_period == 0 ? p_Inp->intra_period : imin(p_Inp->intra_period, p_Inp->idr_period) ); + + memset( num_frames, 0, RC_MAX_TEMPORAL_LEVELS * sizeof(int) ); + // are there any B frames? + if ( p_Inp->NumberBFrames ) + { + if ( p_Inp->HierarchicalCoding == 1 ) // two layers: even/odd + { + levels = 2; + num_frames[0] = p_Inp->NumberBFrames >> 1; + num_frames[1] = (p_Inp->NumberBFrames - num_frames[0]) >= 0 ? (p_Inp->NumberBFrames - num_frames[0]) : 0; + } + else if ( p_Inp->HierarchicalCoding == 2 ) // binary hierarchical structure + { + // check if gop is power of two + tmp = gop; + while ( tmp ) + { + sum += tmp & 1; + tmp >>= 1; + } + assert( sum == 1 ); + + // determine number of levels + levels = 0; + tmp = gop; + while ( tmp > 1 ) + { + tmp >>= 1; // divide by 2 + num_frames[levels] = 1 << levels; + levels++; + } + assert( levels >= 1 && levels <= RC_MAX_TEMPORAL_LEVELS ); + } + else if ( p_Inp->HierarchicalCoding == 3 ) + { + fprintf(stdout, "\n RCUpdateMode=3 and HierarchicalCoding == 3 are currently not supported"); // This error message should be moved elsewhere and have proper memory deallocation + exit(1); + } + else // all frames of the same priority - level + { + levels = 1; + num_frames[0] = p_Inp->NumberBFrames; + } + p_gen->temporal_levels = levels; + } + else + { + for ( level = 0; level < RC_MAX_TEMPORAL_LEVELS; level++ ) + { + p_Inp->RCBSliceBitRatio[level] = 0.0F; + } + p_gen->temporal_levels = 0; + } + // calculate allocated bits for each type of frame + numer = (float)(( (!i_period ? 1 : i_period) * gop) * ((double)p_Inp->bit_rate / p_Inp->source.frame_rate)); + denom = 0.0F; + + for ( level = 0; level < levels; level++ ) + { + denom += (float)(num_frames[level] * p_Inp->RCBSliceBitRatio[level]); + p_gen->hierNb[level] = num_frames[level] * np; + } + denom += 1.0F; + if ( i_period >= 1 ) + { + denom *= (float)i_period; + denom += (float)p_Inp->RCISliceBitRatio - 1.0F; + } + + // set bit targets for each type of frame + p_gen->RCPSliceBits = (int) floor( numer / denom + 0.5F ); + p_gen->RCISliceBits = i_period ? (int)(p_Inp->RCISliceBitRatio * p_gen->RCPSliceBits + 0.5) : 0; + + for ( level = 0; level < levels; level++ ) + { + p_gen->RCBSliceBits[level] = (int)floor(p_Inp->RCBSliceBitRatio[level] * p_gen->RCPSliceBits + 0.5); + } + + p_gen->NISlice = i_period ? ( p_Inp->no_frames / i_period ) : 0; + p_gen->NPSlice = (p_Inp->no_frames / (1 + p_Inp->NumberBFrames)) - p_gen->NISlice; // approximate but good enough for sufficient number of frames + } + break; + default: + break; + } + + /* check if the last GOP over uses its budget. If yes, the initial QP of the I frame in + the coming GOP will be increased.*/ + + //OverBits=-(int)(p_gen->RemainingBits); + + /*initialize the lower bound and the upper bound for the target bits of each frame, HRD consideration*/ + p_quad->LowerBound = (int)(p_gen->RemainingBits + p_quad->bit_rate / p_quad->frame_rate); + p_quad->UpperBound1 = (int)(p_gen->RemainingBits + (p_quad->bit_rate * 2.048)); + + /*compute the total number of bits for the current GOP*/ + AllocatedBits = (int64) floor((1 + np + nb) * p_quad->bit_rate / p_quad->frame_rate + 0.5); + p_gen->RemainingBits += AllocatedBits; + p_quad->Np = np; + p_quad->Nb = nb; + + p_quad->GOPOverdue=FALSE; + + /*field coding*/ + //p_gen->NoGranularFieldRC = ( p_Inp->PicInterlace || !p_Inp->MbInterlace || p_Inp->basicunit != p_Vid->FrameSizeInMbs ); + if ( !p_Inp->PicInterlace && p_Inp->MbInterlace && p_Inp->basicunit == p_Vid->FrameSizeInMbs ) + p_gen->NoGranularFieldRC = 0; + else + p_gen->NoGranularFieldRC = 1; + + /*Compute InitialQp for each GOP*/ + p_quad->TotalPFrame=np; + p_gen->NumberofGOP++; + if(p_gen->NumberofGOP==1) + { + p_quad->MyInitialQp = p_Inp->SeinitialQP + p_quad->bitdepth_qp_scale; + p_quad->CurrLastQP = p_quad->MyInitialQp - 1; //recent change -0; + p_quad->QPLastGOP = p_quad->MyInitialQp; + + p_quad->PAveFrameQP = p_quad->MyInitialQp; + p_quad->m_Qc = p_quad->PAveFrameQP; + p_quad->FieldQPBuffer = p_quad->PAveFrameQP; + p_quad->FrameQPBuffer = p_quad->PAveFrameQP; + p_quad->PAverageQp = p_quad->PAveFrameQP; + } + else + { + /*adaptive field/frame coding*/ + if( p_Inp->PicInterlace == ADAPTIVE_CODING || p_Inp->MbInterlace ) + { + if (p_gen->FieldFrame == 1) + { + p_quad->TotalQpforPPicture += p_quad->FrameQPBuffer; + p_quad->QPLastPFrame = p_quad->FrameQPBuffer; + } + else + { + p_quad->TotalQpforPPicture += p_quad->FieldQPBuffer; + p_quad->QPLastPFrame = p_quad->FieldQPBuffer; + } + } + /*compute the average QP of P frames in the previous GOP*/ + p_quad->PAverageQp=(int)(1.0 * p_quad->TotalQpforPPicture / p_quad->NumberofPPicture+0.5); + + GOPDquant=(int)((1.0*(np+nb+1)/15.0) + 0.5); + if(GOPDquant>2) + GOPDquant=2; + + p_quad->PAverageQp -= GOPDquant; + + if (p_quad->PAverageQp > (p_quad->QPLastPFrame - 2)) + p_quad->PAverageQp--; + + // QP is constrained by QP of previous GOP + p_quad->PAverageQp = iClip3(p_quad->QPLastGOP - 2, p_quad->QPLastGOP + 2, p_quad->PAverageQp); + // Also clipped within range. + p_quad->PAverageQp = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->PAverageQp); + + p_quad->MyInitialQp = p_quad->PAverageQp; + p_quad->Pm_Qp = p_quad->PAverageQp; + p_quad->PAveFrameQP = p_quad->PAverageQp; + p_quad->QPLastGOP = p_quad->MyInitialQp; + p_quad->PrevLastQP = p_quad->CurrLastQP; + p_quad->CurrLastQP = p_quad->MyInitialQp - 1; + } + + p_quad->TotalQpforPPicture=0; + p_quad->NumberofPPicture=0; + p_quad->NumberofBFrames=0; +} + + +/*! + ************************************************************************************* + * \brief + * Initialize one picture + * + ************************************************************************************* +*/ +void rc_init_pict(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int fieldpic,int topfield,int targetcomputation, float mult) +{ + int tmp_T; + + /* compute the total number of basic units in a frame */ + if(p_Inp->MbInterlace) + p_quad->TotalNumberofBasicUnit = p_Vid->FrameSizeInMbs / p_Vid->BasicUnit; + else + p_quad->TotalNumberofBasicUnit = p_Vid->FrameSizeInMbs / p_Inp->basicunit; + + p_Vid->NumberofCodedMacroBlocks = 0; + + /* Normally, the bandwidth for the VBR case is estimated by + a congestion control algorithm. A bandwidth curve can be predefined if we only want to + test the proposed algorithm */ + if(p_Inp->channel_type==1) + { + if(p_quad->NumberofCodedPFrame==58) + p_quad->bit_rate *= 1.5; + else if(p_quad->NumberofCodedPFrame==59) + p_quad->PrevBitRate = p_quad->bit_rate; + } + + /* predefine a target buffer level for each frame */ + if((fieldpic||topfield) && targetcomputation) + { + if ( p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number !=0)) ) + { + /* Since the available bandwidth may vary at any time, the total number of + bits is updated picture by picture*/ + if(p_quad->PrevBitRate!=p_quad->bit_rate) + p_gen->RemainingBits +=(int) floor((p_quad->bit_rate-p_quad->PrevBitRate)*(p_quad->Np + p_quad->Nb)/p_quad->frame_rate+0.5); + + /* predefine the target buffer level for each picture. + frame layer rate control */ + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs) + { + if(p_quad->NumberofPPicture==1) + { + p_quad->TargetBufferLevel = (double) p_gen->CurrentBufferFullness; + p_quad->DeltaP = (p_gen->CurrentBufferFullness - p_quad->GOPTargetBufferLevel) / (p_quad->TotalPFrame-1); + p_quad->TargetBufferLevel -= p_quad->DeltaP; + } + else if(p_quad->NumberofPPicture>1) + p_quad->TargetBufferLevel -= p_quad->DeltaP; + } + /* basic unit layer rate control */ + else + { + if(p_quad->NumberofCodedPFrame>0) + { + /* adaptive frame/field coding */ + if(((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace))&&(p_gen->FieldControl==1)) + memcpy((void *)p_quad->FCBUPFMAD,(void *)p_quad->FCBUCFMAD, p_quad->TotalNumberofBasicUnit * sizeof(double)); + else + memcpy((void *)p_quad->BUPFMAD,(void *)p_quad->BUCFMAD, p_quad->TotalNumberofBasicUnit * sizeof(double)); + } + + if(p_gen->NumberofGOP==1) + { + if(p_quad->NumberofPPicture==1) + { + p_quad->TargetBufferLevel = (double) p_gen->CurrentBufferFullness; + p_quad->DeltaP = (p_gen->CurrentBufferFullness - p_quad->GOPTargetBufferLevel)/(p_quad->TotalPFrame - 1); + p_quad->TargetBufferLevel -= p_quad->DeltaP; + } + else if(p_quad->NumberofPPicture>1) + p_quad->TargetBufferLevel -= p_quad->DeltaP; + } + else if(p_gen->NumberofGOP>1) + { + if(p_quad->NumberofPPicture==0) + { + p_quad->TargetBufferLevel = (double) p_gen->CurrentBufferFullness; + p_quad->DeltaP = (p_gen->CurrentBufferFullness - p_quad->GOPTargetBufferLevel) / p_quad->TotalPFrame; + p_quad->TargetBufferLevel -= p_quad->DeltaP; + } + else if(p_quad->NumberofPPicture>0) + p_quad->TargetBufferLevel -= p_quad->DeltaP; + } + } + + if(p_quad->NumberofCodedPFrame==1) + p_quad->AveWp = p_quad->Wp; + + if((p_quad->NumberofCodedPFrame<8)&&(p_quad->NumberofCodedPFrame>1)) + p_quad->AveWp = (p_quad->AveWp + p_quad->Wp * (p_quad->NumberofCodedPFrame-1))/p_quad->NumberofCodedPFrame; + else if(p_quad->NumberofCodedPFrame>1) + p_quad->AveWp = (p_quad->Wp + 7 * p_quad->AveWp) / 8; + + // compute the average complexity of B frames + if(p_Inp->NumberBFrames>0) + { + // compute the target buffer level + p_quad->TargetBufferLevel += (p_quad->AveWp * (p_Inp->NumberBFrames + 1)*p_quad->bit_rate\ + /(p_quad->frame_rate*(p_quad->AveWp+p_quad->AveWb*p_Inp->NumberBFrames))-p_quad->bit_rate/p_quad->frame_rate); + } + } + else if ( p_Vid->type == B_SLICE ) + { + /* update the total number of bits if the bandwidth is changed*/ + if(p_quad->PrevBitRate != p_quad->bit_rate) + p_gen->RemainingBits +=(int) floor((p_quad->bit_rate-p_quad->PrevBitRate) * (p_quad->Np + p_quad->Nb) / p_quad->frame_rate+0.5); + if(p_gen->NumberofCodedBFrame == 1) + { + if(p_quad->NumberofCodedPFrame == 1) + { + p_quad->AveWp = p_quad->Wp; + } + p_quad->AveWb = p_quad->Wb; + } + else if(p_gen->NumberofCodedBFrame > 1) + { + //compute the average weight + if(p_gen->NumberofCodedBFrame<8) + p_quad->AveWb = (p_quad->AveWb + p_quad->Wb*(p_gen->NumberofCodedBFrame-1)) / p_gen->NumberofCodedBFrame; + else + p_quad->AveWb = (p_quad->Wb + 7 * p_quad->AveWb) / 8; + } + } + /* Compute the target bit for each frame */ + if( p_Vid->type == P_SLICE || ( (p_Vid->number != 0) && (p_Inp->RCUpdateMode == RC_MODE_1 || p_Inp->RCUpdateMode == RC_MODE_3 ) ) ) + { + /* frame layer rate control */ + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs || (p_Inp->RCUpdateMode == RC_MODE_3) ) + { + if(p_quad->NumberofCodedPFrame>0) + { + if (p_Inp->RCUpdateMode == RC_MODE_3) + { + int level_idx = (p_Vid->type == B_SLICE && p_Inp->HierarchicalCoding) ? (p_Vid->p_curr_frm_struct->layer - 1) : 0; + int bitrate = (p_Vid->type == B_SLICE) ? p_gen->RCBSliceBits[ level_idx ] + : ( p_Vid->type == P_SLICE ? p_gen->RCPSliceBits : p_gen->RCISliceBits ); + int level, denom = p_gen->NISlice * p_gen->RCISliceBits + p_gen->NPSlice * p_gen->RCPSliceBits; + + if ( p_Inp->HierarchicalCoding ) + { + for ( level = 0; level < p_gen->temporal_levels; level++ ) + denom += p_gen->hierNb[ level ] * p_gen->RCBSliceBits[ level ]; + } + else + { + denom += p_gen->hierNb[0] * p_gen->RCBSliceBits[0]; + } + // target due to remaining bits + p_quad->Target = (int) floor( (float)(1.0 * bitrate * p_gen->RemainingBits) / (float)denom + 0.5F ); + // target given original taget rate and buffer considerations + tmp_T = imax(0, (int) floor( (double)bitrate - p_quad->GAMMAP * (p_gen->CurrentBufferFullness-p_quad->TargetBufferLevel) + 0.5) ); + // translate Target rate from B or I "domain" to P domain since the P RC model is going to be used to select the QP + // for hierarchical coding adjust the target QP to account for different temporal levels + switch( p_Vid->type ) + { + case B_SLICE: + p_quad->Target = (int) floor( (float)p_quad->Target / p_Inp->RCBoverPRatio + 0.5F); + break; + case I_SLICE: + p_quad->Target = (int) floor( (float)p_quad->Target / (p_Inp->RCIoverPRatio * 4.0) + 0.5F); // 4x accounts for the fact that header bits reduce the percentage of texture + break; + case P_SLICE: + default: + break; + } + } + else + { + p_quad->Target = (int) floor( p_quad->Wp * p_gen->RemainingBits / (p_quad->Np * p_quad->Wp + p_quad->Nb * p_quad->Wb) + 0.5); + tmp_T = imax(0, (int) floor(p_quad->bit_rate / p_quad->frame_rate - p_quad->GAMMAP * (p_gen->CurrentBufferFullness-p_quad->TargetBufferLevel) + 0.5)); + p_quad->Target = (int) floor(p_quad->BETAP * (p_quad->Target - tmp_T) + tmp_T + 0.5); + } + } + } + /* basic unit layer rate control */ + else + { + if(((p_gen->NumberofGOP == 1)&&(p_quad->NumberofCodedPFrame>0)) + || (p_gen->NumberofGOP > 1)) + { + p_quad->Target = (int) (floor( p_quad->Wp * p_gen->RemainingBits / (p_quad->Np * p_quad->Wp + p_quad->Nb * p_quad->Wb) + 0.5)); + tmp_T = imax(0, (int) (floor(p_quad->bit_rate / p_quad->frame_rate - p_quad->GAMMAP * (p_gen->CurrentBufferFullness-p_quad->TargetBufferLevel) + 0.5))); + p_quad->Target = (int) (floor(p_quad->BETAP * (p_quad->Target - tmp_T) + tmp_T + 0.5)); + } + } + p_quad->Target = (int)(mult * p_quad->Target); + + /* HRD consideration */ + if ( p_Inp->RCUpdateMode != RC_MODE_3 || p_Vid->type == P_SLICE ) + p_quad->Target = iClip3(p_quad->LowerBound, p_quad->UpperBound2, p_quad->Target); + if((topfield) || (fieldpic && ((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)))) + p_quad->TargetField=p_quad->Target; + } + } + + if(fieldpic || topfield) + { + /* frame layer rate control */ + p_gen->NumberofHeaderBits = 0; + p_gen->NumberofTextureBits = 0; + + /* basic unit layer rate control */ + if(p_Vid->BasicUnit < p_Vid->FrameSizeInMbs) + { + p_quad->TotalFrameQP = 0; + p_gen->NumberofBasicUnitHeaderBits = 0; + p_gen->NumberofBasicUnitTextureBits = 0; + p_gen->TotalMADBasicUnit = 0; + if(p_gen->FieldControl==0) + p_quad->NumberofBasicUnit = p_quad->TotalNumberofBasicUnit; + else + p_quad->NumberofBasicUnit = p_quad->TotalNumberofBasicUnit >> 1; + } + } + + if( ( p_Vid->type==P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number != 0)) ) && p_Vid->BasicUnit < p_Vid->FrameSizeInMbs && p_gen->FieldControl == 1 ) + { + /* top field at basic unit layer rate control */ + if(topfield) + { + p_quad->bits_topfield=0; + p_quad->Target=(int)(p_quad->TargetField*0.6); + } + /* bottom field at basic unit layer rate control */ + else + { + p_quad->Target=p_quad->TargetField-p_quad->bits_topfield; + p_gen->NumberofBasicUnitHeaderBits=0; + p_gen->NumberofBasicUnitTextureBits=0; + p_gen->TotalMADBasicUnit=0; + p_quad->NumberofBasicUnit=p_quad->TotalNumberofBasicUnit >> 1; + } + } +} + +/*! + ************************************************************************************* + * \brief + * update one picture after frame/field encoding + * + * \param p_Vid + * Image encoding parameters for picture + * \param p_Inp + * Input configuration parameters + * \param p_quad + * quadratic model + * \param p_gen + * generic rate control parameters + * \param nbits + * number of bits used for picture + * + ************************************************************************************* +*/ +void rc_update_pict(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int nbits) +{ + int delta_bits = (nbits - (int)floor(p_quad->bit_rate / p_quad->frame_rate + 0.5F) ); + // remaining # of bits in GOP + p_gen->RemainingBits -= nbits; + p_gen->CurrentBufferFullness += delta_bits; + + // update the lower bound and the upper bound for the target bits of each frame, HRD consideration + p_quad->LowerBound -= (int) delta_bits; + p_quad->UpperBound1 -= (int) delta_bits; + p_quad->UpperBound2 = (int)(OMEGA * p_quad->UpperBound1); + + // update the parameters of quadratic R-D model + if( p_Vid->type==P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && p_Vid->curr_frm_idx) ) + { + updateRCModel(p_Vid, p_Inp, p_quad, p_gen); + if ( p_Inp->RCUpdateMode == RC_MODE_3 ) + p_quad->PreviousWholeFrameMAD = ComputeFrameMAD(p_Vid); + } +} + +/*! + ************************************************************************************* + * \brief + * update one picture after coding + * + * \param p_Vid + * video parameters for current picture + * \param p_Inp + * input parameters from configuration + * \param bits + * number of bits used for picture + * + ************************************************************************************* +*/ + +void rc_update_picture( VideoParameters *p_Vid, InputParameters *p_Inp, int bits ) +{ + rc_update_pict(p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_gen, bits); +} + +int updateComplexity( VideoParameters *p_Vid, RCQuadratic *p_quad, RCGeneric *p_gen, Boolean is_updated, int nbits ) +{ + double Avem_Qc; + + /* frame layer rate control */ + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs) + return ((int) floor(nbits * p_quad->m_Qc + 0.5)); + /* basic unit layer rate control */ + else + { + if( is_updated ) + { + if( p_gen->NoGranularFieldRC == 0 || p_gen->FieldControl == 0 ) + { + Avem_Qc = (double)p_quad->TotalFrameQP / (double)p_quad->TotalNumberofBasicUnit; + return ((int)floor(nbits * Avem_Qc + 0.5)); + } + } + else if( p_Vid->type == B_SLICE ) + return ((int) floor(nbits * p_quad->m_Qc + 0.5)); + } + return 0; +} + +void updatePparams( RCQuadratic *p_quad, RCGeneric *p_gen, int complexity ) +{ + p_quad->Xp = complexity; + p_quad->Np--; + p_quad->Wp = p_quad->Xp; + p_quad->Pm_Hp = p_gen->NumberofHeaderBits; + p_quad->NumberofCodedPFrame++; + p_quad->NumberofPPicture++; +} + +void updateBparams( RCQuadratic *p_quad, RCGeneric *p_gen, int complexity ) +{ + p_quad->Xb = complexity; + p_quad->Nb--; + p_quad->Wb = p_quad->Xb / THETA; + p_quad->NumberofBFrames++; + p_gen->NumberofCodedBFrame++; +} + +/*! + ************************************************************************************* + * \brief + * update after frame encoding + * \param p_Vid + * Image encoding parameters for picture + * \param p_Inp + * Input configuration parameters + * \param p_quad + * quadratic model + * \param p_gen + * generic rate control parameters + * \param nbits + * number of bits used for frame + * + ************************************************************************************* +*/ +void rc_update_pict_frame(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int nbits) +{ + /* update the complexity weight of I, P, B frame */ + int complexity = 0; + + switch( p_Inp->RCUpdateMode ) + { + case RC_MODE_0: + case RC_MODE_2: + default: + complexity = updateComplexity( p_Vid, p_quad, p_gen, (Boolean) (p_Vid->type == P_SLICE), nbits ); + if ( p_Vid->type == P_SLICE ) + { + if( p_gen->NoGranularFieldRC == 0 || p_gen->FieldControl == 0 ) + updatePparams( p_quad, p_gen, complexity ); + else + p_gen->NoGranularFieldRC = 0; + } + else if ( p_Vid->type == B_SLICE ) + updateBparams( p_quad, p_gen, complexity ); + break; + case RC_MODE_1: + complexity = updateComplexity( p_Vid, p_quad, p_gen, (Boolean) (p_Vid->number != 0), nbits ); + if ( p_Vid->number != 0 ) + { + if( p_gen->NoGranularFieldRC == 0 || p_gen->FieldControl == 0 ) + updatePparams( p_quad, p_gen, complexity ); + else + p_gen->NoGranularFieldRC = 0; + } + break; + case RC_MODE_3: + complexity = updateComplexity( p_Vid, p_quad, p_gen, (Boolean) (p_Vid->type == P_SLICE), nbits ); + if (p_Vid->type == I_SLICE && (p_Vid->number != 0)) + p_gen->NISlice--; + + if ( p_Vid->type == P_SLICE ) + { + if( p_gen->NoGranularFieldRC == 0 || p_gen->FieldControl == 0 ) + { + updatePparams( p_quad, p_gen, complexity ); + p_gen->NPSlice--; + } + else + p_gen->NoGranularFieldRC = 0; + } + else if ( p_Vid->type == B_SLICE ) + { + updateBparams( p_quad, p_gen, complexity ); + p_gen->hierNb[ p_Inp->HierarchicalCoding ? (p_Vid->p_curr_frm_struct->layer - 1) : 0 ]--; + } + break; + } +} + + +/*! + ************************************************************************************* + * \brief + * update the parameters of quadratic R-D model + * + ************************************************************************************* +*/ +void updateRCModel (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen) +{ + int n_windowSize; + int i; + double std = 0.0, threshold; + int m_Nc = p_quad->NumberofCodedPFrame; + Boolean MADModelFlag = FALSE; + Boolean m_rgRejected[RC_MODEL_HISTORY]; + double error [RC_MODEL_HISTORY]; + + if( p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number != 0)) ) + { + /*frame layer rate control*/ + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs) + { + p_quad->CurrentFrameMAD = ComputeFrameMAD(p_Vid); + m_Nc=p_quad->NumberofCodedPFrame; + } + /*basic unit layer rate control*/ + else + { + /*compute the MAD of the current basic unit*/ + p_quad->CurrentFrameMAD = (double) ((p_gen->TotalMADBasicUnit >> 8)/p_Vid->BasicUnit); + p_gen->TotalMADBasicUnit=0; + + /* compute the average number of header bits*/ + p_quad->CodedBasicUnit=p_quad->TotalNumberofBasicUnit-p_quad->NumberofBasicUnit; + if(p_quad->CodedBasicUnit > 0) + { + p_quad->PAveHeaderBits1=(int)((double)(p_quad->PAveHeaderBits1*(p_quad->CodedBasicUnit-1)+ + p_gen->NumberofBasicUnitHeaderBits)/p_quad->CodedBasicUnit+0.5); + if(p_quad->PAveHeaderBits3 == 0) + p_quad->PAveHeaderBits2 = p_quad->PAveHeaderBits1; + else + { + p_quad->PAveHeaderBits2 = (int)((double)(p_quad->PAveHeaderBits1 * p_quad->CodedBasicUnit+ + p_quad->PAveHeaderBits3 * p_quad->NumberofBasicUnit)/p_quad->TotalNumberofBasicUnit+0.5); + } + } + + if ((p_quad->NumberofBasicUnit >= p_quad->TotalNumberofBasicUnit) || (p_quad->NumberofBasicUnit<0)) + { + fprintf(stdout, "Write into invalid memory in updateRCModel at frame %d, p_quad->NumberofBasicUnit %d\n", + p_Vid->framepoc, p_quad->NumberofBasicUnit); + } + + /*update the record of MADs for reference*/ + if(((p_Inp->PicInterlace == ADAPTIVE_CODING) || (p_Inp->MbInterlace)) && (p_gen->FieldControl == 1)) + p_quad->FCBUCFMAD[p_quad->TotalNumberofBasicUnit-1-p_quad->NumberofBasicUnit]=p_quad->CurrentFrameMAD; + else + p_quad->BUCFMAD[p_quad->TotalNumberofBasicUnit-1-p_quad->NumberofBasicUnit]=p_quad->CurrentFrameMAD; + + if(p_quad->NumberofBasicUnit != 0) + m_Nc = p_quad->NumberofCodedPFrame * p_quad->TotalNumberofBasicUnit + p_quad->CodedBasicUnit; + else + m_Nc = (p_quad->NumberofCodedPFrame-1) * p_quad->TotalNumberofBasicUnit + p_quad->CodedBasicUnit; + } + + if(m_Nc > 1) + MADModelFlag=TRUE; + + p_quad->PPreHeader = p_gen->NumberofHeaderBits; + for (i = (RC_MODEL_HISTORY-2); i > 0; i--) + {// update the history + p_quad->Pm_rgQp[i] = p_quad->Pm_rgQp[i - 1]; + p_quad->m_rgQp[i] = p_quad->Pm_rgQp[i]; + p_quad->Pm_rgRp[i] = p_quad->Pm_rgRp[i - 1]; + p_quad->m_rgRp[i] = p_quad->Pm_rgRp[i]; + } + p_quad->Pm_rgQp[0] = QP2Qstep(p_quad->m_Qc); //*1.0/p_quad->CurrentFrameMAD; + /*frame layer rate control*/ + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs) + p_quad->Pm_rgRp[0] = p_gen->NumberofTextureBits*1.0/p_quad->CurrentFrameMAD; + /*basic unit layer rate control*/ + else + p_quad->Pm_rgRp[0] = p_gen->NumberofBasicUnitTextureBits*1.0/p_quad->CurrentFrameMAD; + + p_quad->m_rgQp[0] = p_quad->Pm_rgQp[0]; + p_quad->m_rgRp[0] = p_quad->Pm_rgRp[0]; + p_quad->m_X1 = p_quad->Pm_X1; + p_quad->m_X2 = p_quad->Pm_X2; + + /*compute the size of window*/ + n_windowSize = (p_quad->CurrentFrameMAD>p_quad->PreviousFrameMAD) + ? (int)(p_quad->PreviousFrameMAD/p_quad->CurrentFrameMAD * (RC_MODEL_HISTORY-1) ) + : (int)(p_quad->CurrentFrameMAD/p_quad->PreviousFrameMAD *(RC_MODEL_HISTORY-1)); + n_windowSize=iClip3(1, m_Nc, n_windowSize); + n_windowSize=imin(n_windowSize,p_quad->m_windowSize+1); + n_windowSize=imin(n_windowSize,(RC_MODEL_HISTORY-1)); + + /*update the previous window size*/ + p_quad->m_windowSize=n_windowSize; + + for (i = 0; i < (RC_MODEL_HISTORY-1); i++) + { + m_rgRejected[i] = FALSE; + } + + // initial RD model estimator + RCModelEstimator (p_Vid, p_Inp, p_quad, n_windowSize, m_rgRejected); + + n_windowSize = p_quad->m_windowSize; + // remove outlier + + for (i = 0; i < (int) n_windowSize; i++) + { + error[i] = p_quad->m_X1 / p_quad->m_rgQp[i] + p_quad->m_X2 / (p_quad->m_rgQp[i] * p_quad->m_rgQp[i]) - p_quad->m_rgRp[i]; + std += error[i] * error[i]; + } + threshold = (n_windowSize == 2) ? 0 : sqrt (std / n_windowSize); + for (i = 0; i < (int) n_windowSize; i++) + { + if (fabs(error[i]) > threshold) + m_rgRejected[i] = TRUE; + } + // always include the last data point + m_rgRejected[0] = FALSE; + + // second RD model estimator + RCModelEstimator (p_Vid, p_Inp, p_quad, n_windowSize, m_rgRejected); + + if( MADModelFlag ) + updateMADModel(p_Vid, p_Inp, p_quad, p_gen); + else if( p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number != 0)) ) + p_quad->PPictureMAD[0] = p_quad->CurrentFrameMAD; + } +} + +/*! + ************************************************************************************* + * \brief + * Model Estimator + * + ************************************************************************************* +*/ +void RCModelEstimator (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, int n_windowSize, Boolean *m_rgRejected) +{ + int n_realSize = n_windowSize; + int i; + double oneSampleQ = 0; + double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0; + double MatrixValue; + Boolean estimateX2 = FALSE; + + for (i = 0; i < n_windowSize; i++) + {// find the number of samples which are not rejected + if (m_rgRejected[i]) + n_realSize--; + } + + // default RD model estimation results + p_quad->m_X1 = p_quad->m_X2 = 0.0; + + for (i = 0; i < n_windowSize; i++) + { + if (!m_rgRejected[i]) + oneSampleQ = p_quad->m_rgQp[i]; + } + for (i = 0; i < n_windowSize; i++) + {// if all non-rejected Q are the same, take 1st order model + if ((p_quad->m_rgQp[i] != oneSampleQ) && !m_rgRejected[i]) + estimateX2 = TRUE; + if (!m_rgRejected[i]) + p_quad->m_X1 += (p_quad->m_rgQp[i] * p_quad->m_rgRp[i]) / n_realSize; + } + + // take 2nd order model to estimate X1 and X2 + if ((n_realSize >= 1) && estimateX2) + { + for (i = 0; i < n_windowSize; i++) + { + if (!m_rgRejected[i]) + { + a00 = a00 + 1.0; + a01 += 1.0 / p_quad->m_rgQp[i]; + a10 = a01; + a11 += 1.0 / (p_quad->m_rgQp[i] * p_quad->m_rgQp[i]); + b0 += p_quad->m_rgQp[i] * p_quad->m_rgRp[i]; + b1 += p_quad->m_rgRp[i]; + } + } + // solve the equation of AX = B + MatrixValue=a00*a11-a01*a10; + if(fabs(MatrixValue) > 0.000001) + { + p_quad->m_X1 = (b0 * a11 - b1 * a01) / MatrixValue; + p_quad->m_X2 = (b1 * a00 - b0 * a10) / MatrixValue; + } + else + { + p_quad->m_X1 = b0 / a00; + p_quad->m_X2 = 0.0; + } + } + if( p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number != 0)) ) + { + p_quad->Pm_X1 = p_quad->m_X1; + p_quad->Pm_X2 = p_quad->m_X2; + } +} + +/*! + ************************************************************************************* + * \brief + * update the parameters of linear prediction model + * + ************************************************************************************* +*/ +void updateMADModel (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen) +{ + int n_windowSize; + int i; + double std = 0.0, threshold; + int m_Nc = p_quad->NumberofCodedPFrame; + Boolean PictureRejected[RC_MODEL_HISTORY]; + double error [RC_MODEL_HISTORY]; + + if(p_quad->NumberofCodedPFrame>0) + { + //assert (p_Vid->type!=P_SLICE); + /*frame layer rate control*/ + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs) + m_Nc = p_quad->NumberofCodedPFrame; + else // basic unit layer rate control + m_Nc=p_quad->NumberofCodedPFrame*p_quad->TotalNumberofBasicUnit+p_quad->CodedBasicUnit; + + for (i = (RC_MODEL_HISTORY-2); i > 0; i--) + {// update the history + p_quad->PPictureMAD[i] = p_quad->PPictureMAD[i - 1]; + p_quad->PictureMAD[i] = p_quad->PPictureMAD[i]; + p_quad->ReferenceMAD[i] = p_quad->ReferenceMAD[i-1]; + } + p_quad->PPictureMAD[0] = p_quad->CurrentFrameMAD; + p_quad->PictureMAD[0] = p_quad->PPictureMAD[0]; + + if(p_Vid->BasicUnit == p_Vid->FrameSizeInMbs) + p_quad->ReferenceMAD[0]=p_quad->PictureMAD[1]; + else + { + if(((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) &&(p_gen->FieldControl==1)) + p_quad->ReferenceMAD[0]=p_quad->FCBUPFMAD[p_quad->TotalNumberofBasicUnit-1-p_quad->NumberofBasicUnit]; + else + p_quad->ReferenceMAD[0]=p_quad->BUPFMAD[p_quad->TotalNumberofBasicUnit-1-p_quad->NumberofBasicUnit]; + } + p_quad->MADPictureC1 = p_quad->PMADPictureC1; + p_quad->MADPictureC2 = p_quad->PMADPictureC2; + + /*compute the size of window*/ + n_windowSize = (p_quad->CurrentFrameMAD > p_quad->PreviousFrameMAD) + ? (int) ((float)(RC_MODEL_HISTORY-1) * p_quad->PreviousFrameMAD / p_quad->CurrentFrameMAD) + : (int) ((float)(RC_MODEL_HISTORY-1) * p_quad->CurrentFrameMAD / p_quad->PreviousFrameMAD); + n_windowSize = iClip3(1, (m_Nc-1), n_windowSize); + n_windowSize=imin(n_windowSize, imin(20, p_quad->MADm_windowSize + 1)); + + /*update the previous window size*/ + p_quad->MADm_windowSize=n_windowSize; + + for (i = 0; i < (RC_MODEL_HISTORY-1); i++) + { + PictureRejected[i] = FALSE; + } + + //update the MAD for the previous frame + if( p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number != 0)) ) + p_quad->PreviousFrameMAD=p_quad->CurrentFrameMAD; + + // initial MAD model estimator + MADModelEstimator (p_Vid, p_Inp, p_quad, n_windowSize, PictureRejected); + + // remove outlier + for (i = 0; i < n_windowSize; i++) + { + error[i] = p_quad->MADPictureC1 * p_quad->ReferenceMAD[i] + p_quad->MADPictureC2 - p_quad->PictureMAD[i]; + std += (error[i] * error[i]); + } + + threshold = (n_windowSize == 2) ? 0 : sqrt (std / n_windowSize); + for (i = 0; i < n_windowSize; i++) + { + if (fabs(error[i]) > threshold) + PictureRejected[i] = TRUE; + } + // always include the last data point + PictureRejected[0] = FALSE; + + // second MAD model estimator + MADModelEstimator (p_Vid, p_Inp, p_quad, n_windowSize, PictureRejected); + } +} + + +/*! + ************************************************************************************* + * \brief + * MAD mode estimator + * + ************************************************************************************* +*/ +void MADModelEstimator (VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, int n_windowSize, Boolean *PictureRejected) +{ + int n_realSize = n_windowSize; + int i; + double oneSampleQ = 0.0; + double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0; + double MatrixValue; + Boolean estimateX2 = FALSE; + + for (i = 0; i < n_windowSize; i++) + {// find the number of samples which are not rejected + if (PictureRejected[i]) + n_realSize--; + } + + // default MAD model estimation results + p_quad->MADPictureC1 = p_quad->MADPictureC2 = 0.0; + + for (i = 0; i < n_windowSize; i++) + { + if (!PictureRejected[i]) + oneSampleQ = p_quad->PictureMAD[i]; + } + + for (i = 0; i < n_windowSize; i++) + {// if all non-rejected MAD are the same, take 1st order model + if ((p_quad->PictureMAD[i] != oneSampleQ) && !PictureRejected[i]) + estimateX2 = TRUE; + if (!PictureRejected[i]) + p_quad->MADPictureC1 += p_quad->PictureMAD[i] / (p_quad->ReferenceMAD[i]*n_realSize); + } + + // take 2nd order model to estimate X1 and X2 + if ((n_realSize >= 1) && estimateX2) + { + for (i = 0; i < n_windowSize; i++) + { + if (!PictureRejected[i]) + { + a00 = a00 + 1.0; + a01 += p_quad->ReferenceMAD[i]; + a10 = a01; + a11 += p_quad->ReferenceMAD[i] * p_quad->ReferenceMAD[i]; + b0 += p_quad->PictureMAD[i]; + b1 += p_quad->PictureMAD[i] * p_quad->ReferenceMAD[i]; + } + } + // solve the equation of AX = B + MatrixValue = a00 * a11 - a01 * a10; + if(fabs(MatrixValue) > 0.000001) + { + p_quad->MADPictureC2 = (b0 * a11 - b1 * a01) / MatrixValue; + p_quad->MADPictureC1 = (b1 * a00 - b0 * a10) / MatrixValue; + } + else + { + p_quad->MADPictureC1 = b0/a01; + p_quad->MADPictureC2 = 0.0; + } + } + if( p_Vid->type == P_SLICE || (p_Inp->RCUpdateMode == RC_MODE_1 && (p_Vid->number != 0)) ) + { + p_quad->PMADPictureC1 = p_quad->MADPictureC1; + p_quad->PMADPictureC2 = p_quad->MADPictureC2; + } +} + +/*! + ************************************************************************************* + * \brief + * compute a quantization parameter for each frame (RC_MODE_0) + * + ************************************************************************************* +*/ +int updateQPRC0(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield) +{ + int m_Bits; + int BFrameNumber; + int StepSize; + int SumofBasicUnit; + int MaxQpChange, m_Qp, m_Hp; + + /* frame layer rate control */ + if( p_Vid->BasicUnit == p_Vid->FrameSizeInMbs ) + { + /* fixed quantization parameter is used to coded I frame, the first P frame and the first B frame + the quantization parameter is adjusted according the available channel bandwidth and + the type of video */ + /*top field*/ + if((topfield) || (p_gen->FieldControl==0)) + { + if (p_Vid->type==I_SLICE) + { + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if(p_Vid->type == B_SLICE) + { + if(p_Inp->NumberBFrames==1) + { + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + + p_quad->m_Qc = imin(p_quad->PrevLastQP, p_quad->CurrLastQP) + 2; + p_quad->m_Qc = imax(p_quad->m_Qc, imax(p_quad->PrevLastQP, p_quad->CurrLastQP)); + p_quad->m_Qc = imax(p_quad->m_Qc, p_quad->CurrLastQP + 1); + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + else + { + BFrameNumber = (p_quad->NumberofBFrames + 1) % p_Inp->NumberBFrames; + if(BFrameNumber==0) + BFrameNumber = p_Inp->NumberBFrames; + + /*adaptive field/frame coding*/ + if(BFrameNumber==1) + { + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + } + + if((p_quad->CurrLastQP-p_quad->PrevLastQP)<=(-2*p_Inp->NumberBFrames-3)) + StepSize=-3; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames-2)) + StepSize=-2; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames-1)) + StepSize=-1; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames)) + StepSize=0; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames+1)) + StepSize=1; + else + StepSize=2; + + p_quad->m_Qc = p_quad->PrevLastQP + StepSize; + p_quad->m_Qc += iClip3( -2 * (BFrameNumber - 1), 2*(BFrameNumber-1), + (BFrameNumber-1)*(p_quad->CurrLastQP-p_quad->PrevLastQP)/(p_Inp->NumberBFrames-1)); + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + return p_quad->m_Qc; + } + else if( p_Vid->type == P_SLICE && p_quad->NumberofPPicture == 0 ) + { + p_quad->m_Qc=p_quad->MyInitialQp; + + if(p_gen->FieldControl==0) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + return p_quad->m_Qc; + } + else + { + /*adaptive field/frame coding*/ + if( ( p_Inp->PicInterlace == ADAPTIVE_CODING || p_Inp->MbInterlace ) && p_gen->FieldControl == 0 ) + updateQPInterlaceBU( p_quad, p_gen ); + + p_quad->m_X1 = p_quad->Pm_X1; + p_quad->m_X2 = p_quad->Pm_X2; + p_quad->MADPictureC1 = p_quad->PMADPictureC1; + p_quad->MADPictureC2 = p_quad->PMADPictureC2; + p_quad->PreviousPictureMAD = p_quad->PPictureMAD[0]; + + MaxQpChange = p_quad->PMaxQpChange; + m_Qp = p_quad->Pm_Qp; + m_Hp = p_quad->PPreHeader; + + /* predict the MAD of current picture*/ + p_quad->CurrentFrameMAD = p_quad->MADPictureC1*p_quad->PreviousPictureMAD + p_quad->MADPictureC2; + + /*compute the number of bits for the texture*/ + if(p_quad->Target < 0) + { + p_quad->m_Qc=m_Qp+MaxQpChange; + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + else + { + m_Bits = p_quad->Target-m_Hp; + m_Bits = imax(m_Bits, (int)(p_quad->bit_rate/(MINVALUE*p_quad->frame_rate))); + + updateModelQPFrame( p_quad, m_Bits ); + + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // clipping + p_quad->m_Qc = iClip3(m_Qp-MaxQpChange, m_Qp+MaxQpChange, p_quad->m_Qc); // control variation + } + + if( p_gen->FieldControl == 0 ) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + + return p_quad->m_Qc; + } + } + /*bottom field*/ + else + { + if( p_Vid->type == P_SLICE && p_gen->NoGranularFieldRC == 0 ) + updateBottomField( p_Inp, p_quad ); + return p_quad->m_Qc; + } + } + /*basic unit layer rate control*/ + else + { + /*top field of I frame*/ + if (p_Vid->type == I_SLICE) + { + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if( p_Vid->type == B_SLICE ) + { + /*top field of B frame*/ + if((topfield)||(p_gen->FieldControl==0)) + { + if(p_Inp->NumberBFrames==1) + { + /*adaptive field/frame coding*/ + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + + if(p_quad->PrevLastQP==p_quad->CurrLastQP) + p_quad->m_Qc=p_quad->PrevLastQP+2; + else + p_quad->m_Qc = ((p_quad->PrevLastQP+p_quad->CurrLastQP) >> 1) + 1; + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + else + { + BFrameNumber=(p_quad->NumberofBFrames+1)%p_Inp->NumberBFrames; + if(BFrameNumber==0) + BFrameNumber=p_Inp->NumberBFrames; + + /*adaptive field/frame coding*/ + if(BFrameNumber==1) + { + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + } + + if((p_quad->CurrLastQP-p_quad->PrevLastQP)<=(-2*p_Inp->NumberBFrames-3)) + StepSize=-3; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames-2)) + StepSize=-2; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames-1)) + StepSize=-1; + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames)) + StepSize=0;//0 + else if((p_quad->CurrLastQP-p_quad->PrevLastQP)==(-2*p_Inp->NumberBFrames+1)) + StepSize=1;//1 + else + StepSize=2;//2 + p_quad->m_Qc=p_quad->PrevLastQP+StepSize; + p_quad->m_Qc += + iClip3( -2*(BFrameNumber-1), 2*(BFrameNumber-1), (BFrameNumber-1)*(p_quad->CurrLastQP-p_quad->PrevLastQP)/(p_Inp->NumberBFrames-1) ); + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + return p_quad->m_Qc; + } + /*bottom field of B frame*/ + else + { + return p_quad->m_Qc; + } + } + else if( p_Vid->type == P_SLICE ) + { + if( (p_gen->NumberofGOP == 1) && (p_quad->NumberofPPicture == 0) ) + { + if((p_gen->FieldControl==0)||((p_gen->FieldControl==1) && (p_gen->NoGranularFieldRC==0))) + return updateFirstP( p_Vid, p_Inp, p_quad, p_gen, topfield ); + } + else + { + p_quad->m_X1=p_quad->Pm_X1; + p_quad->m_X2=p_quad->Pm_X2; + p_quad->MADPictureC1=p_quad->PMADPictureC1; + p_quad->MADPictureC2=p_quad->PMADPictureC2; + + m_Qp=p_quad->Pm_Qp; + + if(p_gen->FieldControl==0) + SumofBasicUnit=p_quad->TotalNumberofBasicUnit; + else + SumofBasicUnit=p_quad->TotalNumberofBasicUnit>>1; + + /*the average QP of the previous frame is used to coded the first basic unit of the current frame or field*/ + if(p_quad->NumberofBasicUnit==SumofBasicUnit) + return updateFirstBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + else + { + /*compute the number of remaining bits*/ + p_quad->Target -= (p_gen->NumberofBasicUnitHeaderBits + p_gen->NumberofBasicUnitTextureBits); + p_gen->NumberofBasicUnitHeaderBits = 0; + p_gen->NumberofBasicUnitTextureBits = 0; + if(p_quad->Target<0) + return updateNegativeTarget( p_Vid, p_Inp, p_quad, p_gen, topfield, m_Qp ); + else + { + /*predict the MAD of current picture*/ + predictCurrPicMAD( p_Inp, p_quad, p_gen ); + + /*compute the total number of bits for the current basic unit*/ + updateModelQPBU( p_Vid, p_Inp, p_quad, m_Qp ); + + p_quad->TotalFrameQP +=p_quad->m_Qc; + p_quad->Pm_Qp=p_quad->m_Qc; + p_quad->NumberofBasicUnit--; + if( p_quad->NumberofBasicUnit == 0 && p_Vid->type == P_SLICE ) + updateLastBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + + return p_quad->m_Qc; + } + } + } + } + } + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * compute a quantization parameter for each frame + * + ************************************************************************************* +*/ +int updateQPRC1(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield) +{ + int m_Bits; + int SumofBasicUnit; + int MaxQpChange, m_Qp, m_Hp; + + /* frame layer rate control */ + if( p_Vid->BasicUnit == p_Vid->FrameSizeInMbs ) + { + /* fixed quantization parameter is used to coded I frame, the first P frame and the first B frame + the quantization parameter is adjusted according the available channel bandwidth and + the type of vide */ + /*top field*/ + if((topfield) || (p_gen->FieldControl==0)) + { + if (p_Vid->number == 0) + { + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if( p_quad->NumberofPPicture == 0 && (p_Vid->number != 0)) + { + p_quad->m_Qc=p_quad->MyInitialQp; + + if(p_gen->FieldControl==0) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + return p_quad->m_Qc; + } + else + { + /*adaptive field/frame coding*/ + if( ( p_Inp->PicInterlace == ADAPTIVE_CODING || p_Inp->MbInterlace ) && p_gen->FieldControl == 0 ) + updateQPInterlaceBU( p_quad, p_gen ); + + p_quad->m_X1 = p_quad->Pm_X1; + p_quad->m_X2 = p_quad->Pm_X2; + p_quad->MADPictureC1 = p_quad->PMADPictureC1; + p_quad->MADPictureC2 = p_quad->PMADPictureC2; + p_quad->PreviousPictureMAD = p_quad->PPictureMAD[0]; + + MaxQpChange = p_quad->PMaxQpChange; + m_Qp = p_quad->Pm_Qp; + m_Hp = p_quad->PPreHeader; + + /* predict the MAD of current picture*/ + p_quad->CurrentFrameMAD=p_quad->MADPictureC1*p_quad->PreviousPictureMAD + p_quad->MADPictureC2; + + /*compute the number of bits for the texture*/ + if(p_quad->Target < 0) + { + p_quad->m_Qc=m_Qp+MaxQpChange; + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + else + { + m_Bits = p_quad->Target-m_Hp; + m_Bits = imax(m_Bits, (int)(p_quad->bit_rate/(MINVALUE*p_quad->frame_rate))); + + updateModelQPFrame( p_quad, m_Bits ); + + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // clipping + p_quad->m_Qc = iClip3(m_Qp-MaxQpChange, m_Qp+MaxQpChange, p_quad->m_Qc); // control variation + } + + if( p_gen->FieldControl == 0 ) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + + return p_quad->m_Qc; + } + } + /*bottom field*/ + else + { + if( p_gen->NoGranularFieldRC == 0 ) + updateBottomField( p_Inp, p_quad ); + return p_quad->m_Qc; + } + } + /*basic unit layer rate control*/ + else + { + /*top field of I frame*/ + if (p_Vid->number == 0) + { + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else + { + if((p_gen->NumberofGOP==1)&&(p_quad->NumberofPPicture==0)) + { + if((p_gen->FieldControl==0)||((p_gen->FieldControl==1) && (p_gen->NoGranularFieldRC==0))) + return updateFirstP( p_Vid, p_Inp, p_quad, p_gen, topfield ); + } + else + { + p_quad->m_X1=p_quad->Pm_X1; + p_quad->m_X2=p_quad->Pm_X2; + p_quad->MADPictureC1=p_quad->PMADPictureC1; + p_quad->MADPictureC2=p_quad->PMADPictureC2; + + m_Qp=p_quad->Pm_Qp; + + if(p_gen->FieldControl==0) + SumofBasicUnit=p_quad->TotalNumberofBasicUnit; + else + SumofBasicUnit=p_quad->TotalNumberofBasicUnit>>1; + + /*the average QP of the previous frame is used to coded the first basic unit of the current frame or field*/ + if(p_quad->NumberofBasicUnit==SumofBasicUnit) + return updateFirstBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + else + { + /*compute the number of remaining bits*/ + p_quad->Target -= (p_gen->NumberofBasicUnitHeaderBits + p_gen->NumberofBasicUnitTextureBits); + p_gen->NumberofBasicUnitHeaderBits = 0; + p_gen->NumberofBasicUnitTextureBits = 0; + if(p_quad->Target<0) + return updateNegativeTarget( p_Vid, p_Inp, p_quad, p_gen, topfield, m_Qp ); + else + { + /*predict the MAD of current picture*/ + predictCurrPicMAD( p_Inp, p_quad, p_gen ); + + /*compute the total number of bits for the current basic unit*/ + updateModelQPBU( p_Vid, p_Inp, p_quad, m_Qp ); + + p_quad->TotalFrameQP +=p_quad->m_Qc; + p_quad->Pm_Qp=p_quad->m_Qc; + p_quad->NumberofBasicUnit--; + if((p_quad->NumberofBasicUnit==0) && (p_Vid->number != 0)) + updateLastBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + + return p_quad->m_Qc; + } + } + } + } + } + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * compute a quantization parameter for each frame + * + ************************************************************************************* +*/ +int updateQPRC2(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield) +{ + int m_Bits; + int SumofBasicUnit; + int MaxQpChange, m_Qp, m_Hp; + + /* frame layer rate control */ + if( p_Vid->BasicUnit == p_Vid->FrameSizeInMbs ) + { + /* fixed quantization parameter is used to coded I frame, the first P frame and the first B frame + the quantization parameter is adjusted according the available channel bandwidth and + the type of vide */ + /*top field*/ + if((topfield) || (p_gen->FieldControl==0)) + { + if (p_Vid->number == 0) + { + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if (p_Vid->type==I_SLICE) + { + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + + if ( p_Vid->p_curr_frm_struct->idr_flag ) + p_quad->m_Qc = p_quad->MyInitialQp; + else + p_quad->m_Qc = p_quad->CurrLastQP; // Set QP to average qp of last P frame + + return p_quad->m_Qc; + } + else if(p_Vid->type == B_SLICE) + { + int prevQP = imax(p_quad->PrevLastQP, p_quad->CurrLastQP); + // for more than one consecutive B frames the below call will overwrite the old anchor frame QP with the current value + // it should be called once in the B-frame sequence....this should be modified for the BU < frame as well + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + + if (p_Inp->HierarchicalCoding) + { + p_quad->m_Qc = prevQP + p_Vid->p_curr_frm_struct->layer; + } + else + p_quad->m_Qc = prevQP + 2 - p_Vid->nal_reference_idc; + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + + return p_quad->m_Qc; + } + else if( p_Vid->type == P_SLICE && p_quad->NumberofPPicture == 0 ) + { + p_quad->m_Qc=p_quad->MyInitialQp; + + if(p_gen->FieldControl==0) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + return p_quad->m_Qc; + } + else + { + /*adaptive field/frame coding*/ + if( ( p_Inp->PicInterlace == ADAPTIVE_CODING || p_Inp->MbInterlace ) && p_gen->FieldControl == 0 ) + updateQPInterlaceBU( p_quad, p_gen ); + + p_quad->m_X1 = p_quad->Pm_X1; + p_quad->m_X2 = p_quad->Pm_X2; + p_quad->MADPictureC1 = p_quad->PMADPictureC1; + p_quad->MADPictureC2 = p_quad->PMADPictureC2; + p_quad->PreviousPictureMAD = p_quad->PPictureMAD[0]; + + MaxQpChange = p_quad->PMaxQpChange; + m_Qp = p_quad->Pm_Qp; + m_Hp = p_quad->PPreHeader; + + /* predict the MAD of current picture*/ + p_quad->CurrentFrameMAD=p_quad->MADPictureC1*p_quad->PreviousPictureMAD + p_quad->MADPictureC2; + + /*compute the number of bits for the texture*/ + if(p_quad->Target < 0) + { + p_quad->m_Qc=m_Qp+MaxQpChange; + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + else + { + m_Bits = p_quad->Target-m_Hp; + m_Bits = imax(m_Bits, (int)(p_quad->bit_rate/(MINVALUE*p_quad->frame_rate))); + + updateModelQPFrame( p_quad, m_Bits ); + + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // clipping + p_quad->m_Qc = iClip3(m_Qp-MaxQpChange, m_Qp+MaxQpChange, p_quad->m_Qc); // control variation + } + + if( p_gen->FieldControl == 0 ) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + + return p_quad->m_Qc; + } + } + /*bottom field*/ + else + { + if( p_Vid->type==P_SLICE && p_gen->NoGranularFieldRC == 0 ) + updateBottomField( p_Inp, p_quad ); + return p_quad->m_Qc; + } + } + /*basic unit layer rate control*/ + else + { + /*top field of I frame*/ + if (p_Vid->number == 0) + { + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if (p_Vid->type==I_SLICE) + { + /*adaptive field/frame coding*/ + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + + p_quad->m_Qc = p_quad->PrevLastQP; // Set QP to average qp of last P frame + p_quad->PrevLastQP = p_quad->CurrLastQP; + p_quad->CurrLastQP = p_quad->PrevLastQP; + p_quad->PAveFrameQP = p_quad->CurrLastQP; + + return p_quad->m_Qc; + } + else if(p_Vid->type == B_SLICE) + { + int prevQP = imax(p_quad->PrevLastQP, p_quad->CurrLastQP); + if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + + if (p_Inp->HierarchicalCoding) + { + p_quad->m_Qc = prevQP + p_Vid->p_curr_frm_struct->layer; + } + else + p_quad->m_Qc = prevQP + 2 - p_Vid->nal_reference_idc; + + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + + return p_quad->m_Qc; + + } + else if( p_Vid->type == P_SLICE ) + { + if((p_gen->NumberofGOP==1)&&(p_quad->NumberofPPicture==0)) + { + if((p_gen->FieldControl==0)||((p_gen->FieldControl==1) && (p_gen->NoGranularFieldRC==0))) + return updateFirstP( p_Vid, p_Inp, p_quad, p_gen, topfield ); + } + else + { + p_quad->m_X1=p_quad->Pm_X1; + p_quad->m_X2=p_quad->Pm_X2; + p_quad->MADPictureC1=p_quad->PMADPictureC1; + p_quad->MADPictureC2=p_quad->PMADPictureC2; + + m_Qp=p_quad->Pm_Qp; + + if(p_gen->FieldControl==0) + SumofBasicUnit=p_quad->TotalNumberofBasicUnit; + else + SumofBasicUnit=p_quad->TotalNumberofBasicUnit>>1; + + /*the average QP of the previous frame is used to coded the first basic unit of the current frame or field*/ + if(p_quad->NumberofBasicUnit==SumofBasicUnit) + return updateFirstBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + else + { + /*compute the number of remaining bits*/ + p_quad->Target -= (p_gen->NumberofBasicUnitHeaderBits + p_gen->NumberofBasicUnitTextureBits); + p_gen->NumberofBasicUnitHeaderBits = 0; + p_gen->NumberofBasicUnitTextureBits = 0; + if(p_quad->Target<0) + return updateNegativeTarget( p_Vid, p_Inp, p_quad, p_gen, topfield, m_Qp ); + else + { + /*predict the MAD of current picture*/ + predictCurrPicMAD( p_Inp, p_quad, p_gen ); + + /*compute the total number of bits for the current basic unit*/ + updateModelQPBU( p_Vid, p_Inp, p_quad, m_Qp ); + + p_quad->TotalFrameQP +=p_quad->m_Qc; + p_quad->Pm_Qp=p_quad->m_Qc; + p_quad->NumberofBasicUnit--; + if((p_quad->NumberofBasicUnit==0) && p_Vid->type == P_SLICE ) + updateLastBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + + return p_quad->m_Qc; + } + } + } + } + } + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * compute a quantization parameter for each frame + * + ************************************************************************************* +*/ +int updateQPRC3(VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield) +{ + int m_Bits; + int SumofBasicUnit; + int MaxQpChange, m_Qp, m_Hp; + + /* frame layer rate control */ + if( p_Vid->BasicUnit == p_Vid->FrameSizeInMbs || p_Vid->type != P_SLICE ) + { + /* fixed quantization parameter is used to coded I frame, the first P frame and the first B frame + the quantization parameter is adjusted according the available channel bandwidth and + the type of video */ + /*top field*/ + if((topfield) || (p_gen->FieldControl==0)) + { + if (p_Vid->number == 0) + { + if((p_Inp->PicInterlace == ADAPTIVE_CODING) || (p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if( p_Vid->type == P_SLICE && p_quad->NumberofPPicture == 0 ) + { + p_quad->m_Qc=p_quad->MyInitialQp; + + if(p_gen->FieldControl==0) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + return p_quad->m_Qc; + } + else + { + if( ( (p_Vid->type == B_SLICE && (p_Vid->p_curr_frm_struct->layer && p_Vid->p_curr_frm_struct->atom_idx == 1)) || p_Vid->type == I_SLICE) && ((p_Inp->PicInterlace == ADAPTIVE_CODING) || (p_Inp->MbInterlace)) ) + updateQPInterlace( p_quad, p_gen ); + /*adaptive field/frame coding*/ + if( p_Vid->type == P_SLICE && ( p_Inp->PicInterlace == ADAPTIVE_CODING || p_Inp->MbInterlace ) && p_gen->FieldControl == 0 ) + updateQPInterlaceBU( p_quad, p_gen ); + + p_quad->m_X1 = p_quad->Pm_X1; + p_quad->m_X2 = p_quad->Pm_X2; + p_quad->MADPictureC1 = p_quad->PMADPictureC1; + p_quad->MADPictureC2 = p_quad->PMADPictureC2; + p_quad->PreviousPictureMAD = p_quad->PPictureMAD[0]; + + MaxQpChange = p_quad->PMaxQpChange; + m_Qp = p_quad->Pm_Qp; + m_Hp = p_quad->PPreHeader; + + if ( p_Vid->BasicUnit < p_Vid->FrameSizeInMbs && p_Vid->type != P_SLICE ) + { + // when RC_MODE_3 is set and basic unit is smaller than a frame, note that: + // the linear MAD model and the quadratic QP model operate on small units and not on a whole frame; + // we therefore have to account for this + p_quad->PreviousPictureMAD = p_quad->PreviousWholeFrameMAD; + } + if ( p_Vid->type == I_SLICE ) + m_Hp = 0; // it is usually a very small portion of the total I_SLICE bit budget + + /* predict the MAD of current picture*/ + p_quad->CurrentFrameMAD=p_quad->MADPictureC1*p_quad->PreviousPictureMAD + p_quad->MADPictureC2; + + /*compute the number of bits for the texture*/ + if(p_quad->Target < 0) + { + p_quad->m_Qc=m_Qp+MaxQpChange; + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // Clipping + } + else + { + if ( p_Vid->type != P_SLICE ) + { + if ( p_Vid->BasicUnit < p_Vid->FrameSizeInMbs ) + m_Bits =(p_quad->Target-m_Hp)/p_quad->TotalNumberofBasicUnit; + else + m_Bits =p_quad->Target-m_Hp; + } + else { + m_Bits = p_quad->Target-m_Hp; + m_Bits = imax(m_Bits, (int)(p_quad->bit_rate/(MINVALUE*p_quad->frame_rate))); + } + updateModelQPFrame( p_quad, m_Bits ); + + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // clipping + if ( p_Vid->type == P_SLICE ) + p_quad->m_Qc = iClip3(m_Qp-MaxQpChange, m_Qp+MaxQpChange, p_quad->m_Qc); // control variation + } + + if( p_Vid->type == P_SLICE && p_gen->FieldControl == 0 ) + updateQPNonPicAFF( p_Vid->active_sps, p_quad ); + + if ( p_Vid->type == B_SLICE ) + { + // hierarchical adjustment + int prevqp = ((p_quad->PrevLastQP+p_quad->CurrLastQP) >> 1) + 1; + if ( p_Inp->HierarchicalCoding && p_Vid->p_curr_frm_struct->layer) + p_quad->m_Qc -= (p_Vid->p_curr_frm_struct->p_atom->gop_levels - p_Vid->p_curr_frm_struct->layer); + // check bounds + p_quad->m_Qc = iClip3(prevqp - (p_Inp->HierarchicalCoding ? 0 : 5), prevqp + 5, p_quad->m_Qc); // control variation + p_quad->m_Qc = iClip3(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // clipping + } + return p_quad->m_Qc; + } + } + /*bottom field*/ + else + { + if( p_Vid->type==P_SLICE && p_gen->NoGranularFieldRC == 0 ) + updateBottomField( p_Inp, p_quad ); + return p_quad->m_Qc; + } + } + /*basic unit layer rate control*/ + else + { + /*top field of I frame*/ + if (p_Vid->number == 0) + { + if((p_Inp->PicInterlace == ADAPTIVE_CODING) || (p_Inp->MbInterlace)) + updateQPInterlace( p_quad, p_gen ); + p_quad->m_Qc = p_quad->MyInitialQp; + return p_quad->m_Qc; + } + else if( p_Vid->type == P_SLICE ) + { + if((p_gen->NumberofGOP==1)&&(p_quad->NumberofPPicture==0)) + { + if((p_gen->FieldControl==0)||((p_gen->FieldControl==1) && (p_gen->NoGranularFieldRC==0))) + return updateFirstP( p_Vid, p_Inp, p_quad, p_gen, topfield ); + } + else + { + if( ( (p_Vid->type == B_SLICE && (p_Vid->p_curr_frm_struct->layer && p_Vid->p_curr_frm_struct->atom_idx == 1)) || p_Vid->type == I_SLICE) && ((p_Inp->PicInterlace == ADAPTIVE_CODING) || (p_Inp->MbInterlace)) ) + updateQPInterlace( p_quad, p_gen ); + p_quad->m_X1=p_quad->Pm_X1; + p_quad->m_X2=p_quad->Pm_X2; + p_quad->MADPictureC1=p_quad->PMADPictureC1; + p_quad->MADPictureC2=p_quad->PMADPictureC2; + + m_Qp=p_quad->Pm_Qp; + + if(p_gen->FieldControl==0) + SumofBasicUnit=p_quad->TotalNumberofBasicUnit; + else + SumofBasicUnit=p_quad->TotalNumberofBasicUnit>>1; + + /*the average QP of the previous frame is used to coded the first basic unit of the current frame or field*/ + if(p_quad->NumberofBasicUnit==SumofBasicUnit) + return updateFirstBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + else + { + /*compute the number of remaining bits*/ + p_quad->Target -= (p_gen->NumberofBasicUnitHeaderBits + p_gen->NumberofBasicUnitTextureBits); + p_gen->NumberofBasicUnitHeaderBits = 0; + p_gen->NumberofBasicUnitTextureBits = 0; + if(p_quad->Target<0) + return updateNegativeTarget( p_Vid, p_Inp, p_quad, p_gen, topfield, m_Qp ); + else + { + /*predict the MAD of current picture*/ + predictCurrPicMAD( p_Inp, p_quad, p_gen ); + + /*compute the total number of bits for the current basic unit*/ + updateModelQPBU( p_Vid, p_Inp, p_quad, m_Qp ); + + p_quad->TotalFrameQP +=p_quad->m_Qc; + p_quad->Pm_Qp=p_quad->m_Qc; + p_quad->NumberofBasicUnit--; + if((p_quad->NumberofBasicUnit==0) && p_Vid->type == P_SLICE ) + updateLastBU( p_Vid, p_Inp, p_quad, p_gen, topfield ); + + return p_quad->m_Qc; + } + } + } + } + } + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * Save previous QP values for interlaced coding + * + ************************************************************************************* +*/ +void updateQPInterlace( RCQuadratic *p_quad, RCGeneric *p_gen ) +{ + if(p_gen->FieldControl==0) + { + /*previous choice is frame coding*/ + if(p_gen->FieldFrame==1) + { + p_quad->PrevLastQP=p_quad->CurrLastQP; + p_quad->CurrLastQP=p_quad->FrameQPBuffer; + } + /*previous choice is field coding*/ + else + { + p_quad->PrevLastQP=p_quad->CurrLastQP; + p_quad->CurrLastQP=p_quad->FieldQPBuffer; + } + } +} + +/*! + ************************************************************************************* + * \brief + * Save previous QP values for the case of non-PicAFF + * + ************************************************************************************* +*/ +void updateQPNonPicAFF( seq_parameter_set_rbsp_t *active_sps, RCQuadratic *p_quad ) +{ + if(active_sps->frame_mbs_only_flag) + { + p_quad->TotalQpforPPicture +=p_quad->m_Qc; + p_quad->PrevLastQP=p_quad->CurrLastQP; + p_quad->CurrLastQP=p_quad->m_Qc; + p_quad->Pm_Qp=p_quad->m_Qc; + } + /*adaptive field/frame coding*/ + else + p_quad->FrameQPBuffer=p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * Update QP values for bottom field in field coding + ************************************************************************************* +*/ +void updateBottomField( InputParameters *p_Inp, RCQuadratic *p_quad ) +{ + /*field coding*/ + if(p_Inp->PicInterlace==FIELD_CODING) + { + p_quad->TotalQpforPPicture +=p_quad->m_Qc; + p_quad->PrevLastQP=p_quad->CurrLastQP+1; + p_quad->CurrLastQP=p_quad->m_Qc;//+0 Recent change 13/1/2003 + p_quad->Pm_Qp=p_quad->m_Qc; + } + /*adaptive field/frame coding*/ + else + p_quad->FieldQPBuffer=p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * update QP variables for P frames + ************************************************************************************* +*/ +int updateFirstP( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield ) +{ + + /*top field of the first P frame*/ + p_quad->m_Qc=p_quad->MyInitialQp; + p_gen->NumberofBasicUnitHeaderBits=0; + p_gen->NumberofBasicUnitTextureBits=0; + p_quad->NumberofBasicUnit--; + /*bottom field of the first P frame*/ + if((!topfield)&&(p_quad->NumberofBasicUnit==0)) + { + /*frame coding or field coding*/ + if((p_Vid->active_sps->frame_mbs_only_flag)||(p_Inp->PicInterlace==FIELD_CODING)) + { + p_quad->TotalQpforPPicture +=p_quad->m_Qc; + p_quad->PrevLastQP=p_quad->CurrLastQP; + p_quad->CurrLastQP=p_quad->m_Qc; + p_quad->PAveFrameQP=p_quad->m_Qc; + p_quad->PAveHeaderBits3=p_quad->PAveHeaderBits2; + } + /*adaptive frame/field coding*/ + else if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + { + if(p_gen->FieldControl==0) + { + p_quad->FrameQPBuffer=p_quad->m_Qc; + p_quad->FrameAveHeaderBits=p_quad->PAveHeaderBits2; + } + else + { + p_quad->FieldQPBuffer=p_quad->m_Qc; + p_quad->FieldAveHeaderBits=p_quad->PAveHeaderBits2; + } + } + } + p_quad->Pm_Qp=p_quad->m_Qc; + p_quad->TotalFrameQP +=p_quad->m_Qc; + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * update QP when bit target is negative + ************************************************************************************* +*/ +int updateNegativeTarget( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield, int m_Qp ) +{ + int PAverageQP; + + if(p_quad->GOPOverdue==TRUE) + p_quad->m_Qc=m_Qp+2; + else + p_quad->m_Qc=m_Qp+p_quad->DDquant;//2 + + p_quad->m_Qc = imin(p_quad->m_Qc, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale); // clipping + if(p_Inp->basicunit>=p_quad->MBPerRow) + p_quad->m_Qc = imin(p_quad->m_Qc, p_quad->PAveFrameQP + 6); + else + p_quad->m_Qc = imin(p_quad->m_Qc, p_quad->PAveFrameQP + 3); + + p_quad->TotalFrameQP +=p_quad->m_Qc; + p_quad->NumberofBasicUnit--; + if(p_quad->NumberofBasicUnit==0) + { + if((!topfield)||(p_gen->FieldControl==0)) + { + /*frame coding or field coding*/ + if((p_Vid->active_sps->frame_mbs_only_flag)||(p_Inp->PicInterlace==FIELD_CODING)) + { + PAverageQP=(int)((double)p_quad->TotalFrameQP/(double)p_quad->TotalNumberofBasicUnit+0.5); + if (p_quad->NumberofPPicture == (p_Inp->intra_period - 2)) + p_quad->QPLastPFrame = PAverageQP; + + p_quad->TotalQpforPPicture +=PAverageQP; + if(p_quad->GOPOverdue==TRUE) + { + p_quad->PrevLastQP=p_quad->CurrLastQP+1; + p_quad->CurrLastQP=PAverageQP; + } + else + { + if((p_quad->NumberofPPicture==0)&&(p_gen->NumberofGOP>1)) + { + p_quad->PrevLastQP=p_quad->CurrLastQP; + p_quad->CurrLastQP=PAverageQP; + } + else if(p_quad->NumberofPPicture>0) + { + p_quad->PrevLastQP=p_quad->CurrLastQP+1; + p_quad->CurrLastQP=PAverageQP; + } + } + p_quad->PAveFrameQP=PAverageQP; + p_quad->PAveHeaderBits3=p_quad->PAveHeaderBits2; + } + /*adaptive field/frame coding*/ + else if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + { + if(p_gen->FieldControl==0) + { + PAverageQP=(int)((double)p_quad->TotalFrameQP/(double)p_quad->TotalNumberofBasicUnit+0.5); + p_quad->FrameQPBuffer=PAverageQP; + p_quad->FrameAveHeaderBits=p_quad->PAveHeaderBits2; + } + else + { + PAverageQP=(int)((double)p_quad->TotalFrameQP/(double)p_quad->TotalNumberofBasicUnit+0.5); + p_quad->FieldQPBuffer=PAverageQP; + p_quad->FieldAveHeaderBits=p_quad->PAveHeaderBits2; + } + } + } + } + if(p_quad->GOPOverdue==TRUE) + p_quad->Pm_Qp=p_quad->PAveFrameQP; + else + p_quad->Pm_Qp=p_quad->m_Qc; + + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * update QP for the first Basic Unit in the picture + ************************************************************************************* +*/ +int updateFirstBU( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield ) +{ + /*adaptive field/frame coding*/ + if(((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace))&&(p_gen->FieldControl==0)) + { + /*previous choice is frame coding*/ + if(p_gen->FieldFrame==1) + { + if(p_quad->NumberofPPicture>0) + p_quad->TotalQpforPPicture +=p_quad->FrameQPBuffer; + p_quad->PAveFrameQP=p_quad->FrameQPBuffer; + p_quad->PAveHeaderBits3=p_quad->FrameAveHeaderBits; + } + /*previous choice is field coding*/ + else + { + if(p_quad->NumberofPPicture>0) + p_quad->TotalQpforPPicture +=p_quad->FieldQPBuffer; + p_quad->PAveFrameQP=p_quad->FieldQPBuffer; + p_quad->PAveHeaderBits3=p_quad->FieldAveHeaderBits; + } + } + + if(p_quad->Target<=0) + { + p_quad->m_Qc = p_quad->PAveFrameQP + 2; + if(p_quad->m_Qc > (p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale)) + p_quad->m_Qc = p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale; + + if(topfield||(p_gen->FieldControl==0)) + p_quad->GOPOverdue=TRUE; + } + else + { + p_quad->m_Qc=p_quad->PAveFrameQP; + } + p_quad->TotalFrameQP +=p_quad->m_Qc; + p_quad->NumberofBasicUnit--; + p_quad->Pm_Qp = p_quad->PAveFrameQP; + + return p_quad->m_Qc; +} + +/*! + ************************************************************************************* + * \brief + * update QP for the last Basic Unit in the picture + ************************************************************************************* +*/ +void updateLastBU( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen, int topfield ) +{ + int PAverageQP; + + if((!topfield)||(p_gen->FieldControl==0)) + { + /*frame coding or field coding*/ + if((p_Vid->active_sps->frame_mbs_only_flag)||(p_Inp->PicInterlace==FIELD_CODING)) + { + PAverageQP=(int)((double)p_quad->TotalFrameQP/(double) p_quad->TotalNumberofBasicUnit+0.5); + if (p_quad->NumberofPPicture == (p_Inp->intra_period - 2)) + p_quad->QPLastPFrame = PAverageQP; + + p_quad->TotalQpforPPicture +=PAverageQP; + p_quad->PrevLastQP=p_quad->CurrLastQP; + p_quad->CurrLastQP=PAverageQP; + p_quad->PAveFrameQP=PAverageQP; + p_quad->PAveHeaderBits3=p_quad->PAveHeaderBits2; + } + else if((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace)) + { + if(p_gen->FieldControl==0) + { + PAverageQP=(int)((double) p_quad->TotalFrameQP/(double)p_quad->TotalNumberofBasicUnit+0.5); + p_quad->FrameQPBuffer=PAverageQP; + p_quad->FrameAveHeaderBits=p_quad->PAveHeaderBits2; + } + else + { + PAverageQP=(int)((double) p_quad->TotalFrameQP/(double) p_quad->TotalNumberofBasicUnit+0.5); + p_quad->FieldQPBuffer=PAverageQP; + p_quad->FieldAveHeaderBits=p_quad->PAveHeaderBits2; + } + } + } +} + +/*! + ************************************************************************************* + * \brief + * update current picture MAD + ************************************************************************************* +*/ +void predictCurrPicMAD( InputParameters *p_Inp, RCQuadratic *p_quad, RCGeneric *p_gen ) +{ + int i; + if(((p_Inp->PicInterlace==ADAPTIVE_CODING)||(p_Inp->MbInterlace))&&(p_gen->FieldControl==1)) + { + p_quad->CurrentFrameMAD=p_quad->MADPictureC1*p_quad->FCBUPFMAD[p_quad->TotalNumberofBasicUnit-p_quad->NumberofBasicUnit]+p_quad->MADPictureC2; + p_quad->TotalBUMAD=0; + for(i=p_quad->TotalNumberofBasicUnit-1; i>=(p_quad->TotalNumberofBasicUnit-p_quad->NumberofBasicUnit);i--) + { + p_quad->CurrentBUMAD=p_quad->MADPictureC1*p_quad->FCBUPFMAD[i]+p_quad->MADPictureC2; + p_quad->TotalBUMAD +=p_quad->CurrentBUMAD*p_quad->CurrentBUMAD; + } + } + else + { + p_quad->CurrentFrameMAD=p_quad->MADPictureC1*p_quad->BUPFMAD[p_quad->TotalNumberofBasicUnit-p_quad->NumberofBasicUnit]+p_quad->MADPictureC2; + p_quad->TotalBUMAD=0; + for(i=p_quad->TotalNumberofBasicUnit-1; i>=(p_quad->TotalNumberofBasicUnit-p_quad->NumberofBasicUnit);i--) + { + p_quad->CurrentBUMAD=p_quad->MADPictureC1*p_quad->BUPFMAD[i]+p_quad->MADPictureC2; + p_quad->TotalBUMAD +=p_quad->CurrentBUMAD*p_quad->CurrentBUMAD; + } + } +} + +/*! + ************************************************************************************* + * \brief + * update QP using the quadratic model for basic unit coding + ************************************************************************************* +*/ +void updateModelQPBU( VideoParameters *p_Vid, InputParameters *p_Inp, RCQuadratic *p_quad, int m_Qp ) +{ + double dtmp, m_Qstep; + int m_Bits; + /*compute the total number of bits for the current basic unit*/ + m_Bits =(int)(p_quad->Target * p_quad->CurrentFrameMAD * p_quad->CurrentFrameMAD / p_quad->TotalBUMAD); + /*compute the number of texture bits*/ + m_Bits -=p_quad->PAveHeaderBits2; + + m_Bits=imax(m_Bits,(int)(p_quad->bit_rate/(MINVALUE*p_quad->frame_rate*p_quad->TotalNumberofBasicUnit))); + + dtmp = p_quad->CurrentFrameMAD * p_quad->CurrentFrameMAD * p_quad->m_X1 * p_quad->m_X1 \ + + 4 * p_quad->m_X2 * p_quad->CurrentFrameMAD * m_Bits; + if ((p_quad->m_X2 == 0.0) || (dtmp < 0) || ((sqrt (dtmp) - p_quad->m_X1 * p_quad->CurrentFrameMAD) <= 0.0)) // fall back 1st order mode + m_Qstep = (float)(p_quad->m_X1 * p_quad->CurrentFrameMAD / (double) m_Bits); + else // 2nd order mode + m_Qstep = (float) ((2 * p_quad->m_X2 * p_quad->CurrentFrameMAD) / (sqrt (dtmp) - p_quad->m_X1 * p_quad->CurrentFrameMAD)); + + p_quad->m_Qc = Qstep2QP(m_Qstep, p_quad->bitdepth_qp_scale); + p_quad->m_Qc = imin(m_Qp+p_quad->DDquant, p_quad->m_Qc); // control variation + + if(p_Inp->basicunit>=p_quad->MBPerRow) + p_quad->m_Qc = imin(p_quad->PAveFrameQP+6, p_quad->m_Qc); + else + p_quad->m_Qc = imin(p_quad->PAveFrameQP+3, p_quad->m_Qc); + + p_quad->m_Qc = iClip3(m_Qp-p_quad->DDquant, p_Vid->RCMaxQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); // clipping + if(p_Inp->basicunit>=p_quad->MBPerRow) + p_quad->m_Qc = imax(p_quad->PAveFrameQP-6, p_quad->m_Qc); + else + p_quad->m_Qc = imax(p_quad->PAveFrameQP-3, p_quad->m_Qc); + + p_quad->m_Qc = imax(p_Vid->RCMinQP + p_quad->bitdepth_qp_scale, p_quad->m_Qc); +} + +/*! + ************************************************************************************* + * \brief + * update QP variables for interlaced pictures and basic unit coding + ************************************************************************************* +*/ +void updateQPInterlaceBU( RCQuadratic *p_quad, RCGeneric *p_gen ) +{ + /*previous choice is frame coding*/ + if(p_gen->FieldFrame==1) + { + p_quad->TotalQpforPPicture +=p_quad->FrameQPBuffer; + p_quad->Pm_Qp=p_quad->FrameQPBuffer; + } + /*previous choice is field coding*/ + else + { + p_quad->TotalQpforPPicture +=p_quad->FieldQPBuffer; + p_quad->Pm_Qp=p_quad->FieldQPBuffer; + } +} + +/*! + ************************************************************************************* + * \brief + * update QP with quadratic model + ************************************************************************************* +*/ +void updateModelQPFrame( RCQuadratic *p_quad, int m_Bits ) +{ + double dtmp, m_Qstep; + + dtmp = p_quad->CurrentFrameMAD * p_quad->m_X1 * p_quad->CurrentFrameMAD * p_quad->m_X1 + + 4 * p_quad->m_X2 * p_quad->CurrentFrameMAD * m_Bits; + if ((p_quad->m_X2 == 0.0) || (dtmp < 0) || ((sqrt (dtmp) - p_quad->m_X1 * p_quad->CurrentFrameMAD) <= 0.0)) // fall back 1st order mode + m_Qstep = (float) (p_quad->m_X1 * p_quad->CurrentFrameMAD / (double) m_Bits); + else // 2nd order mode + m_Qstep = (float) ((2 * p_quad->m_X2 * p_quad->CurrentFrameMAD) / (sqrt (dtmp) - p_quad->m_X1 * p_quad->CurrentFrameMAD)); + + p_quad->m_Qc = Qstep2QP(m_Qstep, p_quad->bitdepth_qp_scale); +} + +/*! + ************************************************************************************* + * \brief + * rate control at the MB level + ************************************************************************************* +*/ +int rc_handle_mb( Macroblock *currMB, int prev_mb ) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Macroblock *prevMB = currMB->PrevMB; + int mb_qp = p_Vid->qp; + RCGeneric *p_gen = p_Vid->p_rc_gen; + RCQuadratic *p_quad = p_Vid->p_rc_quad; + + if (prev_mb > -1) + { + if ( p_Inp->MbInterlace == ADAPTIVE_CODING && !p_Vid->bot_MB && currMB->mb_field ) + mb_qp = prevMB->qp; + } + + // frame layer rate control + if (p_Inp->basicunit != p_Vid->FrameSizeInMbs) + { + // each I or B frame has only one QP + if ( ((p_Vid->type == I_SLICE || p_Vid->type == B_SLICE) && p_Inp->RCUpdateMode != RC_MODE_1 ) || !(p_Vid->number) ) + { + return mb_qp; + } + else if ( p_Vid->type == P_SLICE || p_Inp->RCUpdateMode == RC_MODE_1 ) + { + if (!p_Vid->write_macroblock) //write macroblock + { + if (prev_mb > -1) + { + if (!((p_Inp->MbInterlace) && p_Vid->bot_MB)) //top macroblock + { + if (prevMB->prev_cbp != 1) + { + mb_qp = prevMB->prev_qp; + } + } + } + } + + // compute the quantization parameter for each basic unit of P frame + + if (!p_Vid->write_macroblock) + { + if(!((p_Inp->MbInterlace) && p_Vid->bot_MB)) + { + if(p_Inp->RCUpdateMode <= MAX_RC_MODE && (p_Vid->NumberofCodedMacroBlocks > 0) && (p_Vid->NumberofCodedMacroBlocks % p_Vid->BasicUnit == 0)) + { + updateRCModel(p_Vid, p_Inp, p_quad, p_gen); + // frame coding + if(p_Vid->active_sps->frame_mbs_only_flag) + { + p_Vid->BasicUnitQP = p_Vid->updateQP(p_Vid, p_Inp, p_quad, p_gen, p_gen->TopFieldFlag) - p_quad->bitdepth_qp_scale; + } + // picture adaptive field/frame coding + else if(p_Inp->MbInterlace || ((p_Inp->PicInterlace!=FRAME_CODING) && (p_gen->NoGranularFieldRC==0))) + { + p_Vid->BasicUnitQP = p_Vid->updateQP(p_Vid, p_Inp, p_quad, p_gen, p_gen->TopFieldFlag) - p_quad->bitdepth_qp_scale; + } + } + + if(p_Vid->current_mb_nr==0) + p_Vid->BasicUnitQP = mb_qp; + + + mb_qp = p_Vid->BasicUnitQP; + mb_qp = iClip3(MIN_QP - p_Vid->bitdepth_luma_qp_scale, MAX_QP, mb_qp); + } + } + } + } + return mb_qp; +} + +/*! + ************************************************************************************* + * \brief + * initialize rate control model for the top field + ************************************************************************************* +*/ +void rc_init_top_field ( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + RCGeneric *p_gen = p_Vid->p_rc_gen; + RCQuadratic *p_quad = p_Vid->p_rc_quad; + + p_Vid->BasicUnit = p_Inp->basicunit; + p_gen->TopFieldFlag = 1; + p_Vid->rc_init_pict_ptr(p_Vid, p_Inp, p_quad, p_gen, 0, 1, (p_Inp->PicInterlace == FIELD_CODING), 1.0F); + p_Vid->p_curr_frm_struct->qp = p_Vid->qp = p_Vid->updateQP(p_Vid, p_Inp, p_quad, p_gen, 1) - p_quad->bitdepth_qp_scale; +} + +/*! + ************************************************************************************* + * \brief + * initialize rate control model for the bottom field + ************************************************************************************* +*/ +void rc_init_bottom_field ( VideoParameters *p_Vid, InputParameters *p_Inp, int TopFieldBits ) +{ + RCGeneric *p_gen = p_Vid->p_rc_gen; + RCQuadratic *p_quad = p_Vid->p_rc_quad; + + p_quad->bits_topfield = TopFieldBits; + p_gen->TopFieldFlag = 0; + p_Vid->rc_init_pict_ptr(p_Vid, p_Inp, p_quad, p_gen, 0,0,0, 1.0F); + p_Vid->p_curr_frm_struct->qp = p_Vid->qp = p_Vid->updateQP(p_Vid, p_Inp, p_quad, p_gen, 0) - p_quad->bitdepth_qp_scale; +} + +/*! + ************************************************************************************* + * \brief + * initialize rate control for RDPictureDecision + ************************************************************************************* +*/ +void rc_init_frame_rdpic( VideoParameters *p_Vid, InputParameters *p_Inp, float rateRatio ) +{ + RCGeneric *p_gen = p_Vid->p_rc_gen; + RCGeneric *p_gen_init = p_Vid->p_rc_gen_init; + RCQuadratic *p_quad = p_Vid->p_rc_quad; + RCQuadratic *p_quad_init = p_Vid->p_rc_quad_init; + + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + // re-store the initial RC model + rc_copy_quadratic( p_Vid, p_Inp, p_quad, p_quad_init ); + rc_copy_generic( p_Vid, p_gen, p_gen_init ); + p_Vid->rc_init_pict_ptr(p_Vid, p_Inp, p_quad, p_gen, 1, 0, 1, rateRatio ); + p_Vid->p_curr_frm_struct->qp = p_Vid->qp = p_Vid->updateQP(p_Vid, p_Inp, p_quad, p_gen, 0) - p_quad->bitdepth_qp_scale; + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * allocate rate control memory + ************************************************************************************* +*/ +void rc_allocate_memory( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: + case RC_MODE_1: + case RC_MODE_2: + case RC_MODE_3: + rc_alloc_generic( p_Vid, &p_Vid->p_rc_gen ); + rc_alloc_quadratic( p_Vid, p_Inp, &p_Vid->p_rc_quad ); + + if ( p_Inp->RDPictureDecision || p_Inp->MbInterlace == ADAPTIVE_CODING || p_Inp->PicInterlace == ADAPTIVE_CODING ) + { + rc_alloc_generic( p_Vid, &p_Vid->p_rc_gen_init ); + rc_alloc_quadratic( p_Vid, p_Inp, &p_Vid->p_rc_quad_init ); + rc_alloc_generic( p_Vid, &p_Vid->p_rc_gen_best ); + rc_alloc_quadratic( p_Vid, p_Inp, &p_Vid->p_rc_quad_best ); + } + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * free rate control memory + ************************************************************************************* +*/ +void rc_free_memory( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: + case RC_MODE_1: + case RC_MODE_2: + case RC_MODE_3: + rc_free_generic( &p_Vid->p_rc_gen ); + rc_free_quadratic( &p_Vid->p_rc_quad ); + + if ( p_Inp->RDPictureDecision || p_Inp->MbInterlace == ADAPTIVE_CODING || p_Inp->PicInterlace == ADAPTIVE_CODING ) + { + rc_free_generic( &p_Vid->p_rc_gen_init ); + rc_free_quadratic( &p_Vid->p_rc_quad_init ); + rc_free_generic( &p_Vid->p_rc_gen_best ); + rc_free_quadratic( &p_Vid->p_rc_quad_best ); + } + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * update coding statistics after MB coding + ************************************************************************************* +*/ +void rc_update_mb_stats(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + BitCounter *mbBits = &currMB->bits; + RCGeneric *p_gen = p_Vid->p_rc_gen; + + // Rate control + p_Vid->NumberofMBHeaderBits = mbBits->mb_mode + mbBits->mb_inter + + mbBits->mb_cbp + mbBits->mb_delta_quant; + p_Vid->NumberofMBTextureBits = mbBits->mb_y_coeff + mbBits->mb_uv_coeff; + + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + p_gen->NumberofTextureBits += p_Vid->NumberofMBTextureBits; + p_gen->NumberofHeaderBits += p_Vid->NumberofMBHeaderBits; + // basic unit layer rate control + if(p_Vid->BasicUnit < p_Vid->FrameSizeInMbs) + { + p_gen->NumberofBasicUnitHeaderBits += p_Vid->NumberofMBHeaderBits; + p_gen->NumberofBasicUnitTextureBits += p_Vid->NumberofMBTextureBits; + } + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * save state of rate control model + ************************************************************************************* +*/ +void rc_save_state( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad_best, p_Vid->p_rc_quad ); + rc_copy_generic( p_Vid, p_Vid->p_rc_gen_best, p_Vid->p_rc_gen ); + break; + default: + break; + } +} + +/*! + ************************************************************************************* + * \brief + * restore state of rate control model + ************************************************************************************* +*/ +void rc_restore_state( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + switch (p_Inp->RCUpdateMode) + { + case RC_MODE_0: case RC_MODE_1: case RC_MODE_2: case RC_MODE_3: + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_quad_best ); + rc_copy_generic( p_Vid, p_Vid->p_rc_gen, p_Vid->p_rc_gen_best ); + break; + default: + break; + } +} diff --git a/lencod/src/rd_intra_jm.c b/lencod/src/rd_intra_jm.c new file mode 100644 index 0000000..24063c0 --- /dev/null +++ b/lencod/src/rd_intra_jm.c @@ -0,0 +1,563 @@ +/*! + *************************************************************************** + * \file rd_intra_jm.c + * + * \brief + * Rate-Distortion optimized mode decision + * + * \author + * - Heiko Schwarz + * - Valeri George + * - Lowell Winger + * - Alexis Michael Tourapis + * \date + * 12. April 2001 + ************************************************************************** + */ + +#include + +#include "global.h" + +#include "image.h" +#include "macroblock.h" +#include "mb_access.h" +#include "rdopt_coding_state.h" +#include "mode_decision.h" +#include "rdopt.h" +#include "rd_intra_jm.h" +#include "q_around.h" +#include "intra4x4.h" +#include "intra8x8.h" +#include "md_common.h" +#include "transform8x8.h" +#include "md_distortion.h" +#include "elements.h" +#include "symbol.h" +#include "intra16x16.h" +#include "intra4x4.h" +#include "intra8x8.h" + +extern int MBType2Value (Macroblock* currMB); + +/*! + ************************************************************************************* + * \brief + * Mode Decision for an 4x4 Intra block + ************************************************************************************* + */ +int mode_decision_for_I4x4_blocks_JM_High (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int ipmode, best_ipmode = 0, y; + int available_mode; + int c_nz, nonzero = 0; + int* ACLevel = currSlice->cofAC[b8][b4][0]; + int* ACRun = currSlice->cofAC[b8][b4][1]; + distblk rdcost = 0; + distblk min_rdcost = DISTBLK_MAX; + int block_x = ((b8 & 0x01) << 3) + ((b4 & 0x01) << 2); + int block_y = ((b8 >> 1) << 3) + ((b4 >> 1) << 2); + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_x = currMB->pix_x + block_x; + int pic_opix_y = currMB->opix_y + block_y; + int pic_block_x = pic_pix_x >> 2; + int pic_block_y = pic_pix_y >> 2; + + int left_available, up_available, all_available; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block, top_block; + + int lrec4x4[4][4]; + int best_nz_coeff = 0; + int block_x4 = block_x>>2; + int block_y4 = block_y>>2; + +#ifdef BEST_NZ_COEFF + int best_coded_block_flag = 0; + int bit_pos = 1 + ((((b8>>1)<<1)+(b4>>1))<<2) + (((b8&1)<<1)+(b4&1)); + int64 cbp_bits; + + if (b8==0 && b4==0) + cbp_bits = 0; +#endif + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + // constrained intra pred + if (p_Inp->UseConstrainedIntraPred) + { + left_block.available = left_block.available ? p_Vid->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? p_Vid->intra_block[top_block.mb_addr] : 0; + } + + upMode = top_block.available ? p_Vid->ipredmode[top_block.pos_y ][top_block.pos_x ] : (char) -1; + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : (char) -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + + currMB->ipmode_DPCM = NO_INTRA_PMODE; ////For residual DPCM + + //===== INTRA PREDICTION FOR 4x4 BLOCK ===== + // set intra prediction values for 4x4 intra prediction + currSlice->set_intrapred_4x4(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + //===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + available_mode = (all_available) || (ipmode==DC_PRED) || + (up_available && (ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED)) || + (left_available && (ipmode==HOR_PRED||ipmode==HOR_UP_PRED)); + + if (valid_intra_mode(currSlice, ipmode) == 0) + continue; + + if( available_mode) + { + // generate intra 4x4 prediction block given availability + get_intrapred_4x4(currMB, PLANE_Y, ipmode, block_x, block_y, left_available, up_available); + + // get prediction and prediction error + generate_pred_error_4x4(&p_Vid->pCurImg[pic_opix_y], currSlice->mpr_4x4[0][ipmode], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], pic_opix_x, block_x); + + // get and check rate-distortion cost +#ifdef BEST_NZ_COEFF + currMB->cbp_bits[0] = cbp_bits; +#endif + + rdcost = currSlice->rdcost_for_4x4_intra_blocks (currMB, &c_nz, b8, b4, ipmode, lambda, mostProbableMode, min_rdcost); + if ((rdcost < min_rdcost) || (rdcost == min_rdcost && ipmode == mostProbableMode)) + { + //--- set coefficients --- + memcpy(p_RDO->cofAC4x4[0], ACLevel, 18 * sizeof(int)); + memcpy(p_RDO->cofAC4x4[1], ACRun, 18 * sizeof(int)); + + //--- set reconstruction --- + copy_4x4block(p_RDO->rec4x4[PLANE_Y], &p_Vid->enc_picture->imgY[pic_pix_y], 0, pic_pix_x); + + // SP/SI reconstruction + if(currSlice->slice_type == SP_SLICE && !currSlice->sp2_frame_indicator) + { + for (y=0; y<4; y++) + { + memcpy(lrec4x4[y],&p_Vid->lrec[pic_pix_y+y][pic_pix_x], BLOCK_SIZE * sizeof(int));// stores the mode coefficients + } + } + + //--- flag if transform-coefficients must be coded --- + nonzero = c_nz; + + //--- set best mode update minimum cost --- + *min_cost = rdcost; + min_rdcost = rdcost; + best_ipmode = ipmode; + + best_nz_coeff = p_Vid->nz_coeff [currMB->mbAddrX][block_x4][block_y4]; +#ifdef BEST_NZ_COEFF + best_coded_block_flag = (int)((currMB->cbp_bits[0] >> bit_pos)&(int64)(1)); +#endif + if (p_Vid->AdaptiveRounding) + { + store_adaptive_rounding_4x4 (p_Vid, p_Vid->ARCofAdj4x4, I4MB, block_y, block_x); + } + } + } + } +#if INTRA_RDCOSTCALC_NNZ + p_Vid->nz_coeff [currMB->mbAddrX][block_x4][block_y4] = best_nz_coeff; +#endif +#ifdef BEST_NZ_COEFF + cbp_bits &= (~(int64)(1<ipredmode[pic_block_y][pic_block_x] = (char) best_ipmode; + currMB->intra_pred_modes[4*b8+b4] = + (char) (mostProbableMode == best_ipmode ? -1 : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1)); + + //===== restore coefficients ===== + memcpy (ACLevel, p_RDO->cofAC4x4[0], 18 * sizeof(int)); + memcpy (ACRun, p_RDO->cofAC4x4[1], 18 * sizeof(int)); + + //===== restore reconstruction and prediction (needed if single coeffs are removed) ===== + copy_4x4block(&p_Vid->enc_picture->imgY[pic_pix_y], p_RDO->rec4x4[PLANE_Y], pic_pix_x, 0); + copy_4x4block(&currSlice->mb_pred[0][block_y], currSlice->mpr_4x4[0][best_ipmode], block_x, 0); + + // SP/SI reconstuction + if(currSlice->slice_type == SP_SLICE && !currSlice->sp2_frame_indicator) + { + for (y=0; ylrec[pic_pix_y+y][pic_pix_x], lrec4x4[y], BLOCK_SIZE * sizeof(int));//restore coefficients when encoding primary SP frame + } + } + + if (p_Vid->AdaptiveRounding) + { + update_adaptive_rounding_4x4 (p_Vid,p_Vid->ARCofAdj4x4, I4MB, block_y, block_x); + } + + return nonzero; +} + +/*! +************************************************************************************* +* \brief +* 8x8 Intra mode decision for a macroblock - High complexity +************************************************************************************* +*/ +int mode_decision_for_I8x8_blocks_JM_High (Macroblock *currMB, int b8, int lambda, distblk *min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int ipmode, best_ipmode = 0, j; + int c_nz, nonzero = 0; + distblk rdcost = 0; + distblk min_rdcost = DISTBLK_MAX; + int block_x = (b8 & 0x01) << 3; + int block_y = (b8 >> 1) << 3; + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_x = currMB->pix_x + block_x; + int pic_opix_y = currMB->opix_y + block_y; + int pic_block_x = pic_pix_x >> 2; + int pic_block_y = pic_pix_y >> 2; + int mb_block_y = (currMB->block_y) + ((b8 >> 1) << 1); + int mb_block_x = (currMB->block_x) + ((b8 & 0x01) << 1); + int *p_AC8x8 = p_RDO->coefAC8x8intra[b8][0][0][0]; + int *cofAC = currSlice->cofAC[b8][0][0]; + + int left_available, up_available, all_available; + int **mb_ores = currSlice->mb_ores[0]; + imgpel **mb_pred = currSlice->mb_pred[0]; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block, top_block; + + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + // constrained intra pred + if (p_Inp->UseConstrainedIntraPred) + { + left_block.available = left_block.available ? p_Vid->intra_block [left_block.mb_addr] : 0; + top_block.available = top_block.available ? p_Vid->intra_block [top_block.mb_addr ] : 0; + } + + if(b8 >> 1) + upMode = top_block.available ? p_Vid->ipredmode8x8[top_block.pos_y ][top_block.pos_x ] : (char) -1; + else + upMode = top_block.available ? p_Vid->ipredmode [top_block.pos_y ][top_block.pos_x ] : (char) -1; + + if(b8 & 0x01) + leftMode = left_block.available ? p_Vid->ipredmode8x8[left_block.pos_y][left_block.pos_x] : (char) -1; + else + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : (char) -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + currMB->ipmode_DPCM = NO_INTRA_PMODE; //For residual DPCM + + //===== INTRA PREDICTION FOR 8x8 BLOCK ===== + currSlice->set_intrapred_8x8(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + //===== LOOP OVER ALL 8x8 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + if( (ipmode==DC_PRED) || + ((ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED) && up_available ) || + ((ipmode==HOR_PRED||ipmode==HOR_UP_PRED) && left_available ) || + (all_available) ) + { + get_intrapred_8x8(currMB, PLANE_Y, ipmode, left_available, up_available); + // get prediction and prediction error + generate_pred_error_8x8(&p_Vid->pCurImg[pic_opix_y], currSlice->mpr_8x8[0][ipmode], &mb_pred[block_y], &mb_ores[block_y], pic_opix_x, block_x); + + currMB->ipmode_DPCM = (short) ipmode; + + // get and check rate-distortion cost + + rdcost = currSlice->rdcost_for_8x8_intra_blocks (currMB, &c_nz, b8, ipmode, lambda, min_rdcost, mostProbableMode); + if ((rdcost < min_rdcost) || (rdcost == min_rdcost && ipmode == mostProbableMode)) + { + //--- set coefficients --- + memcpy(p_AC8x8, cofAC, 4 * 2 * 65 * sizeof(int)); + + //--- set reconstruction --- + copy_image_data_8x8(p_RDO->rec8x8[PLANE_Y], &p_Vid->enc_picture->imgY[pic_pix_y], 0, pic_pix_x); + + if (p_Vid->AdaptiveRounding) + { + for (j = block_y; j < block_y + 8; j++) + memcpy(&p_Vid->ARCofAdj8x8[0][DUMMY][j][block_x],&p_Vid->ARCofAdj8x8[0][I8MB][j][block_x], 8 * sizeof(int)); + } + + //--- flag if transform coefficients must be coded --- + nonzero = c_nz; + + //--- set best mode update minimum cost --- + *min_cost = rdcost; + min_rdcost = rdcost; + best_ipmode = ipmode; + } + } + } + + //===== set intra mode prediction ===== + p_Vid->ipredmode8x8[pic_block_y][pic_block_x] = (char) best_ipmode; + currMB->ipmode_DPCM = (short) best_ipmode; //For residual DPCM + + currMB->intra_pred_modes8x8[4*b8] = (char) ((mostProbableMode == best_ipmode) + ? -1 + : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode - 1)); + + memset(&p_Vid->ipredmode8x8[mb_block_y ][mb_block_x], best_ipmode, 2 * sizeof(char)); + memset(&p_Vid->ipredmode8x8[mb_block_y + 1][mb_block_x], best_ipmode, 2 * sizeof(char)); + + //===== restore coefficients ===== + memcpy(cofAC, p_AC8x8, 4 * 2 * 65 * sizeof(int)); + + if (p_Vid->AdaptiveRounding) + { + for (j=block_y; j< block_y + 8; j++) + memcpy(&p_Vid->ARCofAdj8x8[0][I8MB][j][block_x], &p_Vid->ARCofAdj8x8[0][DUMMY][j][block_x], 8 * sizeof(int)); + } + + //===== restore reconstruction and prediction (needed if single coeffs are removed) ===== + copy_image_data_8x8(&p_Vid->enc_picture->imgY[pic_pix_y], p_RDO->rec8x8[0], pic_pix_x, 0); + copy_image_data_8x8(&mb_pred[block_y], currSlice->mpr_8x8[0][best_ipmode], block_x, 0); + + return nonzero; +} + +/*! + ************************************************************************************* + * \brief + * Mode Decision for an 8x8 Intra block + ************************************************************************************* + */ +int Mode_Decision_for_IntraSubMBlocks(Macroblock *currMB, int b8, int lambda, distblk *cost, int non_zero[3]) +{ + Slice *currSlice = currMB->p_Slice; + int b4; + distblk cost4x4; + currMB->cr_cbp[0] = 0; + currMB->cr_cbp[1] = 0; + currMB->cr_cbp[2] = 0; + + memset(non_zero, 0, 3 * sizeof(int)); + *cost = weighted_cost(lambda, 6); //6 * lambda; + for (b4=0; b4<4; b4++) + { + non_zero[0] |= currSlice->mode_decision_for_I4x4_blocks (currMB, b8, b4, lambda, &cost4x4); + non_zero[1] |= currMB->cr_cbp[1]; + non_zero[2] |= currMB->cr_cbp[2]; + *cost += cost4x4; + } + + return non_zero[0]; +} + +/*! + ************************************************************************************* + * \brief + * 4x4 Intra mode decision for an macroblock + ************************************************************************************* + */ +int mode_decision_for_I4x4_MB (Macroblock *currMB, int lambda, distblk* cost) +{ + Slice *currSlice = currMB->p_Slice; + int cbp=0, b8; + distblk cost8x8; + int non_zero[3] = {0, 0, 0}; + + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + + for (*cost=0, b8=0; b8<4; b8++) + { + if (Mode_Decision_for_IntraSubMBlocks (currMB, b8, lambda, &cost8x8, non_zero)) + { + cbp |= (1<cmp_cbp[1] |= (1<cmp_cbp[1]; + currSlice->cmp_cbp[1] = cbp; + currSlice->cmp_cbp[2] = cbp; + } + if (non_zero[2]) + { + currSlice->cmp_cbp[2] |= (1<cmp_cbp[2]; + currSlice->cmp_cbp[1] = cbp; + currSlice->cmp_cbp[2] = cbp; + } + } + return cbp; +} + +int find_best_mode_I16x16_MB (Macroblock *currMB, int lambda, distblk min_cost) +{ + Slice *currSlice = currMB->p_Slice; + currMB->luma_transform_size_8x8_flag = FALSE; + return (int) currSlice->find_sad_16x16 (currMB); +} + +/*! +************************************************************************************* +* \brief +* Intra 16x16 mode decision +************************************************************************************* +*/ +int mode_decision_for_I16x16_MB (Macroblock* currMB, int lambda) +{ + find_best_mode_I16x16_MB (currMB, lambda, DISTBLK_MAX); + return currMB->residual_transform_quant_luma_16x16 (currMB, PLANE_Y); +} + + +/************************************************************************************ +* \brief +* Intra 16x16 mode decision using Rate-Distortion Optimization +************************************************************************************* +*/ +int mode_decision_for_I16x16_MB_RDO (Macroblock* currMB, int lambda) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + SyntaxElement se; + const int* partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition* dataPart = &(currSlice->partArr[partMap[SE_MBTYPE]]); + + distblk min_rdcost = DISTBLK_MAX, rdcost; + distblk distortionY; + int rate; + int i,k; + int b8, b4; + + + int up_avail, left_avail, left_up_avail; + + int best_mode = 0, best_cbp = 0; + int bestCofAC[4][4][2][65]; + int bestCofDC[2][18]; + imgpel bestRec[MB_BLOCK_SIZE][MB_BLOCK_SIZE]; + + currMB->mb_type = I16MB; + + currSlice->set_intrapred_16x16(currMB, PLANE_Y, &left_avail, &up_avail, &left_up_avail); + + for (k = 0;k < 4; k++) + { + if (p_Inp->IntraDisableInterOnly == 0 || (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE)) + { + if (p_Inp->Intra16x16ParDisable && (k==VERT_PRED_16||k==HOR_PRED_16)) + continue; + + if (p_Inp->Intra16x16PlaneDisable && k==PLANE_16) + continue; + } + + if ((k==0 && !up_avail) || (k==1 && !left_avail) || (k==3 && (!left_avail || !up_avail || !left_up_avail))) + continue; + + get_intrapred_16x16(currMB, PLANE_Y, k, left_avail, up_avail); + + currMB->i16mode = (char) k; + currMB->cbp = currMB->residual_transform_quant_luma_16x16(currMB, PLANE_Y); + distortionY = compute_SSE16x16_thres(&p_Vid->pCurImg[currMB->opix_y], &p_Vid->enc_picture->p_curr_img[currMB->pix_y], currMB->pix_x, currMB->pix_x, min_rdcost); + + if (distortionY < min_rdcost - weighted_cost(lambda, 4)) + { + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_tmp); + currMB->i16offset = I16Offset (currMB->cbp, currMB->i16mode); + se.value1 = MBType2Value (currMB); + se.value2 = 0; + se.type = SE_MBTYPE; + + currSlice->writeMB_typeInfo (currMB, &se, dataPart); + + rate = se.len; + if (distortionY + weighted_cost(lambda, rate) < min_rdcost) + { + rate += currSlice->writeCoeff16x16 (currMB, PLANE_Y); + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_tmp); + + rdcost = distortionY + weighted_cost(lambda, rate); + + if(rdcost < min_rdcost) + { + min_rdcost = rdcost; + best_mode = k; + best_cbp = currMB->cbp; + for(b8 = 0; b8 < 4; b8++) + { + for(b4 = 0; b4 < 4; b4++) + { + memcpy(bestCofAC[b8][b4][0], currSlice->cofAC[b8][b4][0], 2 * sizeof(int) * 65); + memcpy(bestCofAC[b8][b4][1], currSlice->cofAC[b8][b4][1], sizeof(int) * 65); + } + } + + memcpy(bestCofDC[0], currSlice->cofDC[0][0], sizeof(int)*18); + memcpy(bestCofDC[1], currSlice->cofDC[0][1], sizeof(int)*18); + + for(i = 0; i < MB_BLOCK_SIZE; i++) + memcpy(bestRec[i], &p_Vid->enc_picture->p_curr_img[currMB->pix_y + i][currMB->pix_x], sizeof(imgpel)*MB_BLOCK_SIZE); + } + } + else + { + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_tmp); + } + } + } + + currMB->i16mode = (char) best_mode; + currMB->cbp = best_cbp; + currMB->i16offset = I16Offset (currMB->cbp, currMB->i16mode); + + for(b8 = 0; b8 < 4; b8++) + { + for(b4 = 0; b4 < 4; b4++) + { + memcpy(currSlice->cofAC[b8][b4][0], bestCofAC[b8][b4][0], sizeof(int)*65); + memcpy(currSlice->cofAC[b8][b4][1], bestCofAC[b8][b4][1], sizeof(int)*65); + } + } + + memcpy(currSlice->cofDC[0][0], bestCofDC[0], sizeof(int)*18); + memcpy(currSlice->cofDC[0][1], bestCofDC[1], sizeof(int)*18); + + for(i = 0; i < MB_BLOCK_SIZE; i++) + { + memcpy(&p_Vid->enc_picture->p_curr_img[currMB->pix_y+i][currMB->pix_x], bestRec[i], MB_BLOCK_SIZE*sizeof(imgpel)); + } + + return currMB->cbp; +} + + diff --git a/lencod/src/rd_intra_jm444.c b/lencod/src/rd_intra_jm444.c new file mode 100644 index 0000000..c93dfa0 --- /dev/null +++ b/lencod/src/rd_intra_jm444.c @@ -0,0 +1,468 @@ +/*! + *************************************************************************** + * \file rd_intra_jm444.c + * + * \brief + * Rate-Distortion optimized mode decision + * + * \author + * - Heiko Schwarz + * - Valeri George + * - Lowell Winger + * - Alexis Michael Tourapis + * \date + * 12. April 2001 + ************************************************************************** + */ + +#include + +#include "global.h" + +#include "image.h" +#include "macroblock.h" +#include "mb_access.h" +#include "rdopt_coding_state.h" +#include "mode_decision.h" +#include "rdopt.h" +#include "rd_intra_jm.h" +#include "q_around.h" +#include "intra4x4.h" +#include "rd_intra_jm.h" +#include "blk_prediction.h" + +/*! + ************************************************************************************* + * \brief + * Mode Decision for an 4x4 Intra block + ************************************************************************************* + */ +int mode_decision_for_I4x4_blocks_JM_High444 (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int ipmode, best_ipmode = 0, y, dummy; + int c_nz, nonzero = 0; + int* ACLevel = currSlice->cofAC[b8][b4][0]; + int* ACRun = currSlice->cofAC[b8][b4][1]; + int uv; + distblk rdcost = 0; + distblk min_rdcost = DISTBLK_MAX; + int block_x = ((b8 & 0x01) << 3) + ((b4 & 0x01) << 2); + int block_y = ((b8 >> 1) << 3) + ((b4 >> 1) << 2); + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_x = currMB->pix_x + block_x; + int pic_opix_y = currMB->opix_y + block_y; + int pic_block_x = pic_pix_x >> 2; + int pic_block_y = pic_pix_y >> 2; + + int left_available, up_available, all_available; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block, top_block; + + int lrec4x4[4][4]; + int best_nz_coeff = 0; + int block_x4 = block_x>>2; + int block_y4 = block_y>>2; + +#ifdef BEST_NZ_COEFF + int best_coded_block_flag = 0; + int bit_pos = 1 + ((((b8>>1)<<1)+(b4>>1))<<2) + (((b8&1)<<1)+(b4&1)); + int64 cbp_bits; + + if (b8==0 && b4==0) + cbp_bits = 0; +#endif + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + // constrained intra pred + if (p_Inp->UseConstrainedIntraPred) + { + left_block.available = left_block.available ? p_Vid->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? p_Vid->intra_block[top_block.mb_addr] : 0; + } + + upMode = top_block.available ? p_Vid->ipredmode[top_block.pos_y ][top_block.pos_x ] : -1; + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + currMB->ipmode_DPCM = NO_INTRA_PMODE; ////For residual DPCM + + //===== INTRA PREDICTION FOR 4x4 BLOCK ===== + // set intra prediction values for 4x4 intra prediction + currSlice->set_intrapred_4x4(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + if (currSlice->P444_joined) + { + select_plane(p_Vid, PLANE_U); + currSlice->set_intrapred_4x4(currMB, PLANE_U, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_V); + currSlice->set_intrapred_4x4(currMB, PLANE_V, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_Y); + } + + //===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + int available_mode = (all_available) || (ipmode==DC_PRED) || + (up_available && (ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED)) || + (left_available && (ipmode==HOR_PRED||ipmode==HOR_UP_PRED)); + + if (valid_intra_mode(currSlice, ipmode) == 0) + continue; + + if( available_mode) + { + // generate intra 4x4 prediction block given availability + get_intrapred_4x4(currMB, PLANE_Y, ipmode, block_x, block_y, left_available, up_available); + + // get prediction and prediction error + generate_pred_error_4x4(&p_Vid->pCurImg[pic_opix_y], currSlice->mpr_4x4[0][ipmode], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], pic_opix_x, block_x); + + if (p_Vid->yuv_format == YUV444) + { + currMB->ipmode_DPCM = (short) ipmode; + if ((p_Inp->separate_colour_plane_flag == 0)) + { + // generate intra 4x4 prediction block given availability + get_intrapred_4x4(currMB, PLANE_U, ipmode, block_x, block_y, left_available, up_available); + generate_pred_error_4x4(&p_Vid->pImgOrg[1][pic_opix_y], currSlice->mpr_4x4[1][ipmode], &currSlice->mb_pred[1][block_y], &currSlice->mb_ores[1][block_y], pic_opix_x, block_x); + // generate intra 4x4 prediction block given availability + get_intrapred_4x4(currMB, PLANE_V, ipmode, block_x, block_y, left_available, up_available); + generate_pred_error_4x4(&p_Vid->pImgOrg[2][pic_opix_y], currSlice->mpr_4x4[2][ipmode], &currSlice->mb_pred[2][block_y], &currSlice->mb_ores[2][block_y], pic_opix_x, block_x); + } + } + + // get and check rate-distortion cost +#ifdef BEST_NZ_COEFF + currMB->cbp_bits[0] = cbp_bits; +#endif + + rdcost = currSlice->rdcost_for_4x4_intra_blocks (currMB, &c_nz, b8, b4, ipmode, lambda, mostProbableMode, min_rdcost); + if ((rdcost < min_rdcost) || (rdcost == min_rdcost && ipmode == mostProbableMode)) + { + //--- set coefficients --- + memcpy(p_RDO->cofAC4x4[0], ACLevel, 18 * sizeof(int)); + memcpy(p_RDO->cofAC4x4[1], ACRun, 18 * sizeof(int)); + + //--- set reconstruction --- + copy_4x4block(p_RDO->rec4x4[PLANE_Y], &p_Vid->enc_picture->imgY[pic_pix_y], 0, pic_pix_x); + + // SP/SI reconstruction + if(currSlice->slice_type == SP_SLICE && !currSlice->sp2_frame_indicator) + { + for (y=0; y<4; y++) + { + memcpy(lrec4x4[y],&p_Vid->lrec[pic_pix_y+y][pic_pix_x], BLOCK_SIZE * sizeof(int));// stores the mode coefficients + } + } + + if(currSlice->P444_joined) + { + //--- set coefficients --- + for (uv=0; uv < 2; uv++) + { + memcpy(p_RDO->cofAC4x4CbCr[uv][0],currSlice->cofAC[b8+4+uv*4][b4][0], 18 * sizeof(int)); + memcpy(p_RDO->cofAC4x4CbCr[uv][1],currSlice->cofAC[b8+4+uv*4][b4][1], 18 * sizeof(int)); + currMB->cr_cbp[uv + 1] = currMB->c_nzCbCr[uv + 1]; + + //--- set reconstruction --- + copy_4x4block(p_RDO->rec4x4[uv + 1], &p_Vid->enc_picture->imgUV[uv][pic_pix_y], 0, pic_pix_x); + } + } + //--- flag if transform coefficients must be coded --- + nonzero = c_nz; + + //--- set best mode update minimum cost --- + *min_cost = rdcost; + min_rdcost = rdcost; + best_ipmode = ipmode; + + best_nz_coeff = p_Vid->nz_coeff [currMB->mbAddrX][block_x4][block_y4]; +#ifdef BEST_NZ_COEFF + best_coded_block_flag = (int)((currMB->cbp_bits[0] >> bit_pos)&(int64)(1)); +#endif + if (p_Vid->AdaptiveRounding) + { + store_adaptive_rounding_4x4 (p_Vid, p_Vid->ARCofAdj4x4, I4MB, block_y, block_x); + } + } + } + } +#if INTRA_RDCOSTCALC_NNZ + p_Vid->nz_coeff [currMB->mbAddrX][block_x4][block_y4] = best_nz_coeff; +#endif +#ifdef BEST_NZ_COEFF + cbp_bits &= (~(int64)(1<ipredmode[pic_block_y][pic_block_x] = (char) best_ipmode; + currMB->intra_pred_modes[4*b8+b4] = + (char) (mostProbableMode == best_ipmode ? -1 : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1)); + + if(currSlice->P444_joined) + { + ColorPlane k; + for (k = PLANE_U; k <= PLANE_V; k++) + { + select_plane(p_Vid, k); + + copy_4x4block(&currSlice->mb_pred[k][block_y], currSlice->mpr_4x4[k][best_ipmode], block_x, 0); + /* + for (j=0; j<4; j++) + { + for (i=0; i<4; i++) + { + currSlice->mb_ores[k][block_y+j][block_x+i] = p_Vid->pImgOrg[k][currMB->pix_y+block_y+j][currMB->pix_x+block_x+i] - currSlice->mpr_4x4[k][best_ipmode][j][i]; + } + } + */ + compute_residue(&(p_Vid->pImgOrg[k][currMB->pix_y+block_y]), &currSlice->mb_pred[k][block_y], &currSlice->mb_ores[k][block_y], block_x, currMB->pix_x+block_x, 4, 4); + currMB->cr_cbp[k] = currMB->residual_transform_quant_luma_4x4(currMB, k, block_x,block_y,&dummy,1); + } + select_plane(p_Vid, PLANE_Y); + } + + //===== restore coefficients ===== + memcpy (ACLevel, p_RDO->cofAC4x4[0], 18 * sizeof(int)); + memcpy (ACRun, p_RDO->cofAC4x4[1], 18 * sizeof(int)); + + //===== restore reconstruction and prediction (needed if single coeffs are removed) ===== + copy_4x4block(&p_Vid->enc_picture->imgY[pic_pix_y], p_RDO->rec4x4[PLANE_Y], pic_pix_x, 0); + copy_4x4block(&currSlice->mb_pred[0][block_y], currSlice->mpr_4x4[0][best_ipmode], block_x, 0); + + // SP/SI reconstuction + if(currSlice->slice_type == SP_SLICE && !p_Vid->sp2_frame_indicator) + { + for (y=0; ylrec[pic_pix_y+y][pic_pix_x], lrec4x4[y], BLOCK_SIZE * sizeof(int));//restore coefficients when encoding primary SP frame + } + } + if (currSlice->P444_joined) + { + for (uv=0; uv < 2; uv++ ) + { + //===== restore coefficients ===== + memcpy(currSlice->cofAC[b8+4+uv*4][b4][0], p_RDO->cofAC4x4CbCr[uv][0], 18 * sizeof(int)); + memcpy(currSlice->cofAC[b8+4+uv*4][b4][1], p_RDO->cofAC4x4CbCr[uv][1], 18 * sizeof(int)); + //===== restore reconstruction and prediction (needed if single coeffs are removed) ===== + copy_4x4block(&p_Vid->enc_picture->imgUV[uv][pic_pix_y], p_RDO->rec4x4[uv + 1], pic_pix_x, 0); + copy_4x4block(&currSlice->mb_pred[uv + 1][block_y], currSlice->mpr_4x4[uv + 1][best_ipmode], block_x, 0); + } + } + + if (p_Vid->AdaptiveRounding) + { + update_adaptive_rounding_4x4 (p_Vid,p_Vid->ARCofAdj4x4, I4MB, block_y, block_x); + } + + return nonzero; +} + +/*! + ************************************************************************************* + * \brief + * Mode Decision for an 4x4 Intra block + ************************************************************************************* + */ +int mode_decision_for_I4x4_blocks_JM_Low444 (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int ipmode, best_ipmode = 0, dummy; + distblk cost; + int nonzero = 0; + + int block_x = ((b8 & 0x01) << 3) + ((b4 & 0x01) << 2); + int block_y = ((b8 >> 1) << 3) + ((b4 >> 1) << 2); + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_x = currMB->pix_x + block_x; + int pic_opix_y = currMB->opix_y + block_y; + int pic_block_x = pic_pix_x >> 2; + int pic_block_y = pic_pix_y >> 2; + + int left_available, up_available, all_available; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block; + PixelPos top_block; + + distblk fixedcost = weighted_cost(lambda, 4); //(int) floor(4 * lambda ); + int *mb_size = p_Vid->mb_size[IS_LUMA]; + int best_nz_coeff = 0; + int block_x4 = block_x>>2; + int block_y4 = block_y>>2; + +#ifdef BEST_NZ_COEFF + int best_coded_block_flag = 0; + int bit_pos = 1 + ((((b8>>1)<<1)+(b4>>1))<<2) + (((b8&1)<<1)+(b4&1)); + int64 cbp_bits; + + if (b8==0 && b4==0) + cbp_bits = 0; +#endif + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + // constrained intra pred + if (p_Inp->UseConstrainedIntraPred) + { + left_block.available = left_block.available ? p_Vid->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? p_Vid->intra_block[top_block.mb_addr] : 0; + } + + upMode = top_block.available ? p_Vid->ipredmode[top_block.pos_y ][top_block.pos_x ] : -1; + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + currMB->ipmode_DPCM = NO_INTRA_PMODE; ////For residual DPCM + + //===== INTRA PREDICTION FOR 4x4 BLOCK ===== + // set intra prediction values for 4x4 intra prediction + currSlice->set_intrapred_4x4(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + if (currSlice->P444_joined) + { + select_plane(p_Vid, PLANE_U); + currSlice->set_intrapred_4x4(currMB, PLANE_U, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_V); + currSlice->set_intrapred_4x4(currMB, PLANE_V, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_Y); + } + + //===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + int available_mode = (all_available) || (ipmode==DC_PRED) || + (up_available && (ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED)) || + (left_available && (ipmode==HOR_PRED||ipmode==HOR_UP_PRED)); + + if (valid_intra_mode(currSlice, ipmode) == 0) + continue; + + if( available_mode) + { + // generate intra 4x4 prediction block given availability + // Note that some checks may not be necessary internally since the "available_mode" test has already tested + // mode availability. + get_intrapred_4x4(currMB, PLANE_Y, ipmode, block_x, block_y, left_available, up_available); + cost = (ipmode == mostProbableMode) ? 0 : fixedcost; + cost += currSlice->compute_cost4x4(p_Vid, &p_Vid->pCurImg[pic_opix_y], currSlice->mpr_4x4[0][ipmode], pic_opix_x, *min_cost - cost); + if (currSlice->P444_joined) + { + get_intrapred_4x4(currMB, PLANE_U, ipmode, block_x, block_y, left_available, up_available); + cost += currSlice->compute_cost4x4(p_Vid, &p_Vid->pImgOrg[1][pic_opix_y], currSlice->mpr_4x4[1][ipmode], pic_opix_x, *min_cost - cost); + get_intrapred_4x4(currMB, PLANE_V, ipmode, block_x, block_y, left_available, up_available); + cost += currSlice->compute_cost4x4(p_Vid, &p_Vid->pImgOrg[2][pic_opix_y], currSlice->mpr_4x4[2][ipmode], pic_opix_x, *min_cost - cost); + } + + if (cost < *min_cost) + { + best_ipmode = ipmode; + *min_cost = cost; + } + } + } + +#if INTRA_RDCOSTCALC_NNZ + p_Vid->nz_coeff [currMB->mbAddrX][block_x4][block_y4] = best_nz_coeff; +#endif +#ifdef BEST_NZ_COEFF + cbp_bits &= (~(int64)(1<ipredmode[pic_block_y][pic_block_x] = (char) best_ipmode; + currMB->intra_pred_modes[4*b8+b4] = + (char) (mostProbableMode == best_ipmode ? -1 : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1)); + + // get prediction and prediction error + generate_pred_error_4x4(&p_Vid->pCurImg[pic_opix_y], currSlice->mpr_4x4[0][best_ipmode], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], pic_opix_x, block_x); + + currMB->ipmode_DPCM = (short) best_ipmode; + + select_transform(currMB); + nonzero = currMB->cr_cbp[0] = currMB->residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &dummy, 1); + + if (currSlice->P444_joined) + { + ColorPlane k; + for (k = PLANE_U; k <= PLANE_V; k++) + { + select_plane(p_Vid, k); + /* + for (j=0; j<4; j++) + { + for (i=0; i<4; i++) + { + currSlice->mb_pred[k][block_y + j][block_x+i] = currSlice->mpr_4x4[k][best_ipmode][j][i]; + currSlice->mb_ores[k][block_y + j][block_x+i] = p_Vid->pImgOrg[k][pic_opix_y+j][pic_opix_x+i] - currSlice->mpr_4x4[k][best_ipmode][j][i]; + } + } + */ + copy_4x4block(&currSlice->mb_pred[k][block_y], currSlice->mpr_4x4[k][best_ipmode], block_x, 0); + compute_residue(&(p_Vid->pImgOrg[k][pic_opix_y]), &currSlice->mb_pred[k][block_y], &currSlice->mb_ores[k][block_y], block_x, pic_opix_x, 4, 4); + currMB->cr_cbp[k] = currMB->residual_transform_quant_luma_4x4 (currMB, k, block_x, block_y, &dummy, 1); + } + select_plane(p_Vid, PLANE_Y); + } + + return nonzero; +} + +/*! +************************************************************************************* +* \brief +* Intra 16x16 mode decision +************************************************************************************* +*/ +int mode_decision_for_I16x16_MB_444 (Macroblock* currMB, int lambda) +{ + Slice *currSlice = currMB->p_Slice; + int cbp; + find_best_mode_I16x16_MB(currMB, lambda, DISTBLK_MAX); + + if (!currSlice->P444_joined) + { + cbp = currMB->residual_transform_quant_luma_16x16 (currMB, PLANE_Y); + } + else + { + VideoParameters *p_Vid = currSlice->p_Vid; + + cbp = currMB->residual_transform_quant_luma_16x16 (currMB, PLANE_Y); + select_plane(p_Vid, PLANE_U); + currSlice->cmp_cbp[1] = currMB->residual_transform_quant_luma_16x16 (currMB, PLANE_U); + select_plane(p_Vid, PLANE_V); + currSlice->cmp_cbp[2] = currMB->residual_transform_quant_luma_16x16 (currMB, PLANE_V); + select_plane(p_Vid, PLANE_Y); + + cbp |= (currSlice->cmp_cbp[1] | currSlice->cmp_cbp[2]); + currSlice->cmp_cbp[1] = cbp; + currSlice->cmp_cbp[2] = cbp; + } + + return cbp; +} + diff --git a/lencod/src/rd_intra_jm_low.c b/lencod/src/rd_intra_jm_low.c new file mode 100644 index 0000000..e3ad363 --- /dev/null +++ b/lencod/src/rd_intra_jm_low.c @@ -0,0 +1,278 @@ +/*! + *************************************************************************** + * \file rd_intra_jm_low.c + * + * \brief + * Rate-Distortion optimized mode decision + * + * \author + * - Heiko Schwarz + * - Valeri George + * - Lowell Winger + * - Alexis Michael Tourapis + * \date + * 12. April 2001 + ************************************************************************** + */ + +#include + +#include "global.h" + +#include "image.h" +#include "macroblock.h" +#include "mb_access.h" +#include "rdopt_coding_state.h" +#include "mode_decision.h" +#include "rdopt.h" +#include "rd_intra_jm.h" +#include "q_around.h" +#include "intra4x4.h" +#include "intra8x8.h" + +/*! + ************************************************************************************* + * \brief + * Mode Decision for an 4x4 Intra block + ************************************************************************************* + */ +int mode_decision_for_I4x4_blocks_JM_Low (Macroblock *currMB, int b8, int b4, int lambda, distblk* min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int ipmode, best_ipmode = 0, dummy; + int nonzero = 0; + distblk cost; + int block_x = ((b8 & 0x01) << 3) + ((b4 & 0x01) << 2); + int block_y = ((b8 >> 1) << 3) + ((b4 >> 1) << 2); + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_y = currMB->opix_y + block_y; + + int left_available, up_available, all_available; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block, top_block; + + distblk fixedcost = weighted_cost(lambda, 4); //(int) floor(4 * lambda ); + distblk onecost = weighted_cost(lambda, 1); //(int) floor( lambda ); + + int best_nz_coeff = 0; + int block_x4 = block_x>>2; + int block_y4 = block_y>>2; + imgpel ***mpr4x4 = currSlice->mpr_4x4[0]; + imgpel **cur_img = &p_Vid->pCurImg[pic_opix_y]; + +#ifdef BEST_NZ_COEFF + int best_coded_block_flag = 0; + int bit_pos = 1 + ((((b8>>1)<<1)+(b4>>1))<<2) + (((b8&1)<<1)+(b4&1)); + int64 cbp_bits; + + if (b8==0 && b4==0) + cbp_bits = 0; +#endif + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + // constrained intra pred + if (p_Inp->UseConstrainedIntraPred) + { + left_block.available = left_block.available ? p_Vid->intra_block[left_block.mb_addr] : 0; + top_block.available = top_block.available ? p_Vid->intra_block[top_block.mb_addr] : 0; + } + + upMode = top_block.available ? p_Vid->ipredmode[top_block.pos_y ][top_block.pos_x ] : (char) -1; + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : (char) -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + + currMB->ipmode_DPCM = NO_INTRA_PMODE; ////For residual DPCM + + //===== INTRA PREDICTION FOR 4x4 BLOCK ===== + // set intra prediction values for 4x4 intra prediction + currSlice->set_intrapred_4x4(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + //===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + int available_mode = (all_available) || (ipmode==DC_PRED) || + (up_available && (ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED)) || + (left_available && (ipmode==HOR_PRED||ipmode==HOR_UP_PRED)); + + if( valid_intra_mode(currSlice, ipmode) != 0 && available_mode) + { + // generate intra 4x4 prediction block given availability + get_intrapred_4x4(currMB, PLANE_Y, ipmode, block_x, block_y, left_available, up_available); + + cost = (ipmode == mostProbableMode) ? onecost : fixedcost; + if (cost < *min_cost) + { + cost += currSlice->compute_cost4x4(p_Vid, cur_img, mpr4x4[ipmode], pic_pix_x, *min_cost - cost); + + if (cost < *min_cost) + { + best_ipmode = ipmode; + *min_cost = cost; + } + } + } + } + +#if INTRA_RDCOSTCALC_NNZ + p_Vid->nz_coeff [currMB->mbAddrX][block_x4][block_y4] = best_nz_coeff; +#endif +#ifdef BEST_NZ_COEFF + cbp_bits &= (~(int64)(1<ipredmode[pic_pix_y >> 2][pic_pix_x >> 2] = (char) best_ipmode; + currMB->intra_pred_modes[4*b8+b4] = (char) (mostProbableMode == best_ipmode ? -1 : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode - 1)); + + // get prediction and prediction error + generate_pred_error_4x4(cur_img, mpr4x4[best_ipmode], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], pic_pix_x, block_x); + + currMB->ipmode_DPCM = (short) best_ipmode; + + select_transform(currMB); + + if (currMB->mb_type == I4MB) + nonzero = currMB->cr_cbp[0] = residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &dummy, 1); + else + nonzero = currMB->cr_cbp[0] = currMB->residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &dummy, 1); + + return nonzero; +} + + +/*! + ************************************************************************************* + * \brief + * 8x8 Intra mode decision for a macroblock - Low complexity + ************************************************************************************* + */ +int mode_decision_for_I8x8_blocks_JM_Low (Macroblock *currMB, int b8, int lambda, distblk *min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int ipmode, best_ipmode = 0, j, dummy; + distblk cost; + int nonzero = 0; + int block_x = (b8 & 0x01) << 3; + int block_y = (b8 >> 1) << 3; + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_y = currMB->opix_y + block_y; + int mb_block_y = (currMB->block_y) + (block_y >> 2); + int mb_block_x = (currMB->block_x) + (block_x >> 2); + + int left_available, up_available, all_available; + int **mb_ores = currSlice->mb_ores[0]; + imgpel **mb_pred = currSlice->mb_pred[0]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + char upMode; + char leftMode; + int mostProbableMode; + int fixedcost = (int) weighted_cost(lambda, 4); + int mprobcost = (int) weighted_cost(lambda, 1); + + PixelPos left_block, top_block; + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + if (p_Inp->UseConstrainedIntraPred) + { + top_block.available = top_block.available ? p_Vid->intra_block [top_block.mb_addr] : 0; + left_block.available = left_block.available ? p_Vid->intra_block [left_block.mb_addr] : 0; + } + + if(b8 >> 1) + upMode = top_block.available ? p_Vid->ipredmode8x8[top_block.pos_y ][top_block.pos_x ] : -1; + else + upMode = top_block.available ? p_Vid->ipredmode [top_block.pos_y ][top_block.pos_x ] : -1; + + if(b8 & 0x01) + leftMode = left_block.available ? p_Vid->ipredmode8x8[left_block.pos_y][left_block.pos_x] : -1; + else + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + currMB->ipmode_DPCM = NO_INTRA_PMODE; //For residual DPCM + + //===== INTRA PREDICTION FOR 8x8 BLOCK ===== + currSlice->set_intrapred_8x8(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + // first check most probable mode + ipmode = mostProbableMode; + { + if( (ipmode==DC_PRED) || + ((ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED) && up_available ) || + ((ipmode==HOR_PRED||ipmode==HOR_UP_PRED) && left_available ) || + (all_available) ) + { + get_intrapred_8x8(currMB, PLANE_Y, ipmode, left_available, up_available); + cost = mprobcost; + cost += currSlice->compute_cost8x8(p_Vid, &p_Vid->pImgOrg[0][pic_opix_y], currSlice->mpr_8x8[0][ipmode], pic_pix_x, *min_cost - cost); + best_ipmode = mostProbableMode; + *min_cost = cost; + } + } + + //===== LOOP OVER ALL 8x8 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + if (ipmode != mostProbableMode) + { + if( (ipmode==DC_PRED) || + ((ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED) && up_available ) || + ((ipmode==HOR_PRED||ipmode==HOR_UP_PRED) && left_available ) || + (all_available) ) + { + get_intrapred_8x8(currMB, PLANE_Y, ipmode, left_available, up_available); + cost = fixedcost; + + if (cost < *min_cost) + { + cost += currSlice->compute_cost8x8(p_Vid, &p_Vid->pImgOrg[0][pic_opix_y], currSlice->mpr_8x8[0][ipmode], pic_pix_x, *min_cost - cost); + if (cost < *min_cost) + { + best_ipmode = ipmode; + *min_cost = cost; + } + } + } + } + } + + //===== set intra mode prediction ===== + p_Vid->ipredmode8x8[pic_pix_y >> 2][pic_pix_x >> 2] = (char) best_ipmode; + currMB->ipmode_DPCM = (short) best_ipmode; //For residual DPCM + + currMB->intra_pred_modes8x8[4*b8] = (char)((mostProbableMode == best_ipmode) + ? -1 + : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1)); + + for(j = mb_block_y; j < mb_block_y + 2; j++) //loop 4x4s in the subblock for 8x8 prediction setting + memset(&p_Vid->ipredmode8x8[j][mb_block_x], best_ipmode, 2 * sizeof(char)); + + // get prediction and prediction error + generate_pred_error_8x8(&p_Vid->pCurImg[pic_opix_y], currSlice->mpr_8x8[0][best_ipmode], &mb_pred[block_y], &mb_ores[block_y], pic_pix_x, block_x); + currMB->ipmode_DPCM = (short) best_ipmode; + + nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, b8, &dummy, 1); + return nonzero; +} + diff --git a/lencod/src/rdopt.c b/lencod/src/rdopt.c new file mode 100644 index 0000000..6ba9ddd --- /dev/null +++ b/lencod/src/rdopt.c @@ -0,0 +1,4081 @@ +/*! + *************************************************************************** + * \file rdopt.c + * + * \brief + * Rate-Distortion optimized mode decision + * + * \author + * - Heiko Schwarz + * - Valeri George + * - Lowell Winger + * - Alexis Michael Tourapis + * \date + * 12. April 2001 + ************************************************************************** + */ + +#include +#include + +#include "global.h" + +#include "rdopt.h" +#include "q_around.h" +#include "rdopt_coding_state.h" +#include "memalloc.h" +#include "mb_access.h" +#include "elements.h" +#include "intrarefresh.h" +#include "image.h" +#include "transform8x8.h" +#include "cabac.h" +#include "biariencode.h" +#include "slice.h" +#include "vlc.h" +#include "ratectl.h" // head file for rate control +#include "mode_decision.h" +#include "rd_intra_jm.h" +#include "rd_intra_jm444.h" +#include "macroblock.h" +#include "q_offsets.h" +#include "conformance.h" +#include "errdo.h" +#include "mv_search.h" +#include "md_common.h" +#include "md_distortion.h" +#include "intra16x16.h" + +#define FASTMODE 1 + +static void set_stored_macroblock_parameters (Macroblock *currMB); +static void set_stored_macroblock_parameters_sp (Macroblock *currMB); +static void set_stored_macroblock_parameters_mpass(Macroblock *currMB); +static void set_ref_and_motion_vectors_P_slice (Macroblock *currMB, PicMotionParams **motion, Info8x8 *pred, int); +static void set_ref_and_motion_vectors_B_slice (Macroblock *currMB, PicMotionParams **motion, Info8x8 *pred, int); + +static distblk compute_sad4x4_cost (VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost); +static distblk compute_sse4x4_cost (VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost); +static distblk compute_satd4x4_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost); +static distblk compute_comp4x4_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost); + +static distblk rdcost_for_4x4_intra_blocks (Macroblock *currMB, int* nonzero, int b8, int b4, int ipmode, int lambda, int mostProbableMode, distblk min_rdcost); +static distblk rdcost_for_4x4_intra_blocks_444 (Macroblock *currMB, int* nonzero, int b8, int b4, int ipmode, int lambda, int mostProbableMode, distblk min_rdcost); + +static inline void copy_motion_vectors_MB (Slice *currSlice, RD_DATA *rdopt) +{ + memcpy(&currSlice->all_mv [LIST_0][0][0][0][0], &rdopt->all_mv [LIST_0][0][0][0][0], 288 * currSlice->max_num_references * sizeof(MotionVector)); +} + +Info8x8 init_info_8x8_struct(void) +{ + Info8x8 i8x8; + i8x8.mode = 0; + i8x8.pdir = 0; + i8x8.ref[LIST_0] = 0; + i8x8.ref[LIST_1] = -1; + i8x8.bipred = 0; + + return i8x8; +} + +void alloc_rd8x8data (RD_8x8DATA *rd_data) +{ + get_mem2Dint(&rd_data->lrec, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem2Dpel(&rd_data->mpr8x8, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem3Dpel(&rd_data->mpr8x8CbCr, 2, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem2Dpel(&rd_data->rec_mbY8x8, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem3Dpel(&rd_data->rec_mb8x8_cr, 2, MB_BLOCK_SIZE, MB_BLOCK_SIZE); +} + +void free_rd8x8data (RD_8x8DATA *rd_data) +{ + free_mem3Dpel(rd_data->rec_mb8x8_cr); + free_mem2Dpel(rd_data->rec_mbY8x8); + free_mem3Dpel(rd_data->mpr8x8CbCr); + free_mem2Dpel(rd_data->mpr8x8); + free_mem2Dint(rd_data->lrec); +} + +/*! + ************************************************************************ + * \brief + * delete structure for RD-optimized mode decision + ************************************************************************ + */ +void clear_rdopt (Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + free_mem_DCcoeff (p_RDO->cofDC); + free_mem_ACcoeff (p_RDO->cofAC); + free_mem_ACcoeff (p_RDO->cofAC4x4intern); + free_mem_ACcoeff_new(p_RDO->coefAC8x8); + free_mem_ACcoeff_new(p_RDO->coefAC8x8intra); + + if (p_Inp->Transform8x8Mode) + { + free_mem_ACcoeff_new(p_RDO->cofAC8x8ts); + } + + if (p_Vid->P444_joined) + { + free_mem_ACcoeff_new(p_RDO->cofAC4x4CbCrintern); + } + + // Should create new functions for free/alloc of RD_8x8DATA + free_rd8x8data(p_RDO->tr4x4); + free(p_RDO->tr4x4); + free_rd8x8data(p_RDO->tr8x8); + free(p_RDO->tr8x8); + + free_mem4Dmv(p_RDO->all_mv8x8); + + free_mem3Dpel(p_RDO->rec4x4); + free_mem3Dpel(p_RDO->rec8x8); + free_mem2Dpel(p_RDO->pred); + free_mem3Dpel(p_RDO->rec_mb); + + if (p_Inp->ProfileIDC == EXTENDED) + { + free_mem2Dint(p_RDO->lrec_rec); + free_mem3Dint(p_RDO->lrec_rec_uv); + } + + free_mem2D((byte **) p_RDO->l0_refframe); + free_mem2D((byte **) p_RDO->l1_refframe); + + // structure for saving the coding state + delete_coding_state (p_RDO->cs_mb); + delete_coding_state (p_RDO->cs_b8); + delete_coding_state (p_RDO->cs_cm); + delete_coding_state (p_RDO->cs_tmp); +} + +void setupDistCost(Slice *currSlice, InputParameters *p_Inp) +{ + switch(p_Inp->ModeDecisionMetric) + { + case ERROR_SAD: + currSlice->compute_cost4x4 = compute_sad4x4_cost; + currSlice->compute_cost8x8 = compute_sad8x8_cost; + currSlice->distI16x16 = distI16x16_sad; + break; + case ERROR_SSE: + currSlice->compute_cost4x4 = compute_sse4x4_cost; + currSlice->compute_cost8x8 = compute_sse8x8_cost; + currSlice->distI16x16 = distI16x16_sse; + break; + case ERROR_SATD: + currSlice->compute_cost4x4 = compute_satd4x4_cost; + currSlice->compute_cost8x8 = compute_satd8x8_cost; + currSlice->distI16x16 = distI16x16_satd; + break; + default: + currSlice->compute_cost4x4 = compute_comp4x4_cost; + currSlice->compute_cost8x8 = compute_comp8x8_cost; + currSlice->distI16x16 = distI16x16_satd; + break; + } +} + + +/*! + ************************************************************************ + * \brief + * create structure for RD-optimized mode decision + ************************************************************************ + */ +void init_rdopt (Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + get_mem_DCcoeff (&p_RDO->cofDC); + get_mem_ACcoeff (p_Vid, &p_RDO->cofAC); + get_mem_ACcoeff (p_Vid, &p_RDO->cofAC4x4intern); + p_RDO->cofAC4x4 = p_RDO->cofAC4x4intern[0][0]; + get_mem_ACcoeff_new(&p_RDO->coefAC8x8, 3); + get_mem_ACcoeff_new(&p_RDO->coefAC8x8intra, 3); + + if (p_Inp->Transform8x8Mode) + { + get_mem_ACcoeff_new(&p_RDO->cofAC8x8ts, 3); + } + + if (((p_RDO->tr4x4) = (RD_8x8DATA *) calloc(1, sizeof(RD_8x8DATA)))==NULL) + no_mem_exit("init_rdopt: p_RDO->tr4x4"); + alloc_rd8x8data(p_RDO->tr4x4); + if (((p_RDO->tr8x8) = (RD_8x8DATA *) calloc(1, sizeof(RD_8x8DATA)))==NULL) + no_mem_exit("init_rdopt: p_RDO->tr4x4"); + alloc_rd8x8data(p_RDO->tr8x8); + + get_mem2Dpel(&p_RDO->pred, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem3Dpel(&p_RDO->rec8x8, 3, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8); + get_mem3Dpel(&p_RDO->rec4x4, 3, BLOCK_SIZE, BLOCK_SIZE); + get_mem3Dpel(&p_RDO->rec_mb, 3, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + if (p_Inp->ProfileIDC == EXTENDED) + { + get_mem2Dint(&p_RDO->lrec_rec, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem3Dint(&p_RDO->lrec_rec_uv, 2, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + } + + get_mem2D((byte ***) &p_RDO->l0_refframe, 4, 4); + get_mem2D((byte ***) &p_RDO->l1_refframe, 4, 4); + + get_mem4Dmv(&p_RDO->all_mv8x8, 2, 2, 4, 4); + + if (p_Vid->P444_joined) + { + get_mem_ACcoeff_new(&p_RDO->cofAC4x4CbCrintern, 2); + + p_RDO->cofAC4x4CbCr[0] = p_RDO->cofAC4x4CbCrintern[0][0][0]; + p_RDO->cofAC4x4CbCr[1] = p_RDO->cofAC4x4CbCrintern[0][1][0]; + } + + currSlice->set_lagrangian_multipliers = p_Inp->rdopt == 0 ? SetLagrangianMultipliersOff : SetLagrangianMultipliersOn; + + switch (p_Inp->rdopt) + { + case 0: + currSlice->encode_one_macroblock = encode_one_macroblock_low; + break; + case 1: + default: + currSlice->encode_one_macroblock = encode_one_macroblock_high; + break; + case 2: + currSlice->encode_one_macroblock = encode_one_macroblock_highfast; + break; + case 3: + currSlice->encode_one_macroblock = encode_one_macroblock_highloss; + break; + } + + if (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1)) + currSlice->set_stored_mb_parameters = set_stored_macroblock_parameters_mpass; + else + { + if (currSlice->slice_type == SP_SLICE || currSlice->slice_type == SI_SLICE) + currSlice->set_stored_mb_parameters = set_stored_macroblock_parameters_sp; + else + currSlice->set_stored_mb_parameters = set_stored_macroblock_parameters; + } + + // structure for saving the coding state + p_RDO->cs_mb = create_coding_state (p_Inp); + p_RDO->cs_b8 = create_coding_state (p_Inp); + p_RDO->cs_cm = create_coding_state (p_Inp); + p_RDO->cs_tmp = create_coding_state (p_Inp); + if (p_Inp->CtxAdptLagrangeMult == 1) + { + p_Vid->mb16x16_cost = CALM_MF_FACTOR_THRESHOLD; + p_RDO->lambda_mf_factor = 1.0; + } + + currSlice->rdcost_for_4x4_intra_blocks = (p_Vid->yuv_format == YUV444) ? rdcost_for_4x4_intra_blocks_444 : rdcost_for_4x4_intra_blocks; + currSlice->rdcost_for_8x8_intra_blocks = (p_Vid->yuv_format == YUV444) ? rdcost_for_8x8_intra_blocks_444 : rdcost_for_8x8_intra_blocks; + + if (currSlice->mb_aff_frame_flag) + currSlice->intra_chroma_RD_decision = intra_chroma_RD_decision_mbaff; + else + currSlice->intra_chroma_RD_decision = intra_chroma_RD_decision; + if (p_Inp->rdopt == 0) + { + currSlice->mode_decision_for_I8x8_blocks = (p_Vid->yuv_format == YUV444) ? mode_decision_for_I8x8_blocks_JM_Low444 : mode_decision_for_I8x8_blocks_JM_Low; + currSlice->mode_decision_for_I4x4_blocks = (p_Vid->yuv_format == YUV444) ? mode_decision_for_I4x4_blocks_JM_Low444 : mode_decision_for_I4x4_blocks_JM_Low; + } + else + { + currSlice->mode_decision_for_I8x8_blocks = (p_Vid->yuv_format == YUV444) ? mode_decision_for_I8x8_blocks_JM_High444 : mode_decision_for_I8x8_blocks_JM_High; + currSlice->mode_decision_for_I4x4_blocks = (p_Vid->yuv_format == YUV444) ? mode_decision_for_I4x4_blocks_JM_High444 : mode_decision_for_I4x4_blocks_JM_High; + } + + currSlice->find_sad_16x16 = find_sad_16x16_JM; + + if (currSlice->slice_type == B_SLICE) + currSlice->set_ref_and_motion_vectors = set_ref_and_motion_vectors_B_slice; + else + currSlice->set_ref_and_motion_vectors = set_ref_and_motion_vectors_P_slice; + + setupDistortion(currSlice); + setupDistCost (currSlice, p_Inp); +} + +/*! + ************************************************************************************* + * \brief + * Updates the pixel map that shows, which reference frames are reliable for + * each MB-area of the picture. + * + * \note + * The new values of the p_Vid->pixel_map are taken from the temporary buffer p_Vid->refresh_map + * + ************************************************************************************* + */ +void UpdatePixelMap(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int mx,my,y,x,i,j; + if (p_Vid->type==I_SLICE) + { + memset(p_Vid->pixel_map, 1, p_Vid->height * p_Vid->width * sizeof(byte)); + } + else + { + for (my=0; myheight >> 3; my++) + { + for (mx=0; mxwidth >> 3; mx++) + { + j = my*8 + 8; + i = mx*8 + 8; + if (p_Vid->refresh_map[my][mx]) + { + for (y=my*8; ypixel_map[y][mx*8], 1, 8 * sizeof(byte)); + } + else + { + for (y=my*8; ypixel_map[y][x] = (byte) imin(p_Vid->pixel_map[y][x] + 1, p_Inp->num_ref_frames+1); + } + } + } + } + } + } +} + +/*! + ************************************************************************************* + * \brief + * Checks if a given reference frame is reliable for the current + * macroblock, given the motion vectors that the motion search has + * returned. + * + * \return + * If the return value is 1, the reference frame is reliable. If it + * is 0, then it is not reliable. + * + * \note + * A specific area in each reference frame is assumed to be unreliable + * if the same area has been intra-refreshed in a subsequent frame. + * The information about intra-refreshed areas is kept in the p_Vid->pixel_map. + * + ************************************************************************************* + */ +int CheckReliabilityOfRef (Macroblock *currMB, int block, int list_idx, int ref, int mode) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int y,x, block_y, block_x, dy, dx, y_pos, x_pos, yy, xx, pres_x, pres_y; + int maxold_x = p_Vid->width - 1; + int maxold_y = p_Vid->height - 1; + int ref_frame = ref + 1; + + int by0 = (mode>=4?2*(block >> 1):mode==2?2*block:0); + int by1 = by0 + (mode>=4||mode==2?2:4); + int bx0 = (mode>=4?2*(block & 0x01):mode==3?2*block:0); + int bx1 = bx0 + (mode>=4||mode==3?2:4); + + for (block_y=by0; block_yall_mv[list_idx][ref][mode][block_y][block_x].mv_y; + y_pos += (currMB->block_y + block_y) * BLOCK_SIZE * 4; + x_pos = currSlice->all_mv[list_idx][ref][mode][block_y][block_x].mv_x; + x_pos += (currMB->block_x + block_x) * BLOCK_SIZE * 4; + + /* Here we specify which pixels of the reference frame influence + the reference values and check their reliability. This is + based on the function Get_Reference_Pixel */ + + dy = y_pos & 3; + dx = x_pos & 3; + + y_pos = (y_pos - dy) >> 2; + x_pos = (x_pos - dx) >> 2; + + if (dy==0 && dx==0) //full-pel + { + for (y=y_pos ; y < y_pos + BLOCK_SIZE ; y++) + for (x=x_pos ; x < x_pos + BLOCK_SIZE ; x++) + if (p_Vid->pixel_map[iClip3(0,maxold_y,y)][iClip3(0,maxold_x,x)] < ref_frame) + return 0; + } + else /* other positions */ + { + if (dy == 0) + { + for (y = y_pos ; y < y_pos + BLOCK_SIZE ; y++) + { + pres_y = iClip3(0, maxold_y, y); + for (x = x_pos ; x < x_pos + BLOCK_SIZE ; x++) + { + for(xx = -2 ; xx < 4 ; xx++) + { + pres_x = iClip3(0, maxold_x, x + xx); + if (p_Vid->pixel_map[pres_y][pres_x] < ref_frame) + return 0; + } + } + } + } + else if (dx == 0) + { + for (y = y_pos ; y < y_pos + BLOCK_SIZE ; y++) + for (x = x_pos ; x < x_pos + BLOCK_SIZE ; x++) + { + pres_x = iClip3(0,maxold_x,x); + for(yy=-2;yy<4;yy++) + { + pres_y = iClip3(0,maxold_y, yy + y); + if (p_Vid->pixel_map[pres_y][pres_x] < ref_frame) + return 0; + } + } + } + else if (dx == 2) + { + for (y = y_pos ; y < y_pos + BLOCK_SIZE ; y++) + for (x = x_pos ; x < x_pos + BLOCK_SIZE ; x++) + { + for(yy=-2;yy<4;yy++) + { + pres_y = iClip3(0,maxold_y, yy + y); + for(xx=-2;xx<4;xx++) + { + pres_x = iClip3(0,maxold_x, xx + x); + if (p_Vid->pixel_map[pres_y][pres_x] < ref_frame) + return 0; + } + } + } + } + else if (dy == 2) + { + for (y = y_pos ; y < y_pos + BLOCK_SIZE ; y++) + for (x = x_pos ; x < x_pos + BLOCK_SIZE ; x++) + { + for(xx=-2;xx<4;xx++) + { + pres_x = iClip3(0,maxold_x, xx + x); + for(yy=-2;yy<4;yy++) + { + pres_y = iClip3(0,maxold_y, yy + y); + if (p_Vid->pixel_map[pres_y][pres_x] < ref_frame) + return 0; + } + } + } + } + else + { + for (y = y_pos ; y < y_pos + BLOCK_SIZE ; y++) + { + for (x = x_pos ; x < x_pos + BLOCK_SIZE ; x++) + { + pres_y = dy == 1 ? y : y + 1; + pres_y = iClip3(0,maxold_y,pres_y); + + for(xx = -2; xx < 4; xx++) + { + pres_x = iClip3(0,maxold_x,xx + x); + if (p_Vid->pixel_map[pres_y][pres_x] < ref_frame) + return 0; + } + + pres_x = dx == 1 ? x : x + 1; + pres_x = iClip3(0,maxold_x,pres_x); + + for(yy=-2;yy<4;yy++) + { + pres_y = iClip3(0,maxold_y, yy + y); + if (p_Vid->pixel_map[pres_y][pres_x] < ref_frame) + return 0; + } + } + } + } + } + } + } + return 1; +} + +/*! + ************************************************************************************* + * \brief + * R-D Cost for an 4x4 Intra block + ************************************************************************************* + */ +static distblk rdcost_for_4x4_intra_blocks (Macroblock *currMB, + int* nonzero, + int b8, + int b4, + int ipmode, + int lambda, + int mostProbableMode, + distblk min_rdcost) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + distblk rdcost; + int dummy = 0, rate; + distblk distortion = 0; + int block_x = ((b8 & 0x01) << 3) + ((b4 & 0x01) << 2); + int block_y = ((b8 >> 1) << 3) + ((b4 >> 1) << 2); + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_y = currMB->opix_y + block_y; + + SyntaxElement se; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + //--- choose data partition --- + DataPartition *dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + + //===== perform forward transform, Q, IQ, inverse transform, Reconstruction ===== + //select_transform(currMB); + + currMB->ipmode_DPCM = (short) ipmode; + *nonzero = currMB->residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &dummy, 1); + + //===== get distortion (SSD) of 4x4 block ===== + distortion += compute_SSE4x4(&p_Vid->pCurImg[pic_opix_y], &p_Vid->enc_picture->imgY[pic_pix_y], pic_pix_x, pic_pix_x); +#if INTRA_RDCOSTCALC_ET + // check if already distortion larger than min_rdcost + if (distortion >= min_rdcost) + { + return (distortion); + } +#endif + currMB->ipmode_DPCM = NO_INTRA_PMODE; + + //===== RATE for INTRA PREDICTION MODE (SYMBOL MODE MUST BE SET TO CAVLC) ===== + se.value1 = (mostProbableMode == ipmode) ? -1 : ipmode < mostProbableMode ? ipmode : ipmode - 1; + + //--- set position and type --- + se.context = (b8 << 2) + b4; + se.type = SE_INTRAPREDMODE; + + //--- encode and update rate --- + currSlice->writeIntraPredMode (&se, dataPart); + rate = se.len; + + //===== RATE for LUMINANCE COEFFICIENTS ===== + if (currSlice->symbol_mode == CAVLC) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, b4, 0); + } + else + { + rate += writeCoeff4x4_CABAC (currMB, PLANE_Y, b8, b4, 1); + } + + rdcost = distortion + weighted_cost(lambda, rate); //((distblk)lambda) * rate; + + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + + return rdcost; +} + + +/*! + ************************************************************************************* + * \brief + * R-D Cost for an 4x4 Intra block (for 4:4:4 formats) + ************************************************************************************* + */ +static distblk rdcost_for_4x4_intra_blocks_444 (Macroblock *currMB, + int* nonzero, + int b8, + int b4, + int ipmode, + int lambda, + int mostProbableMode, + distblk min_rdcost) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + distblk rdcost; + int dummy = 0, rate; + distblk distortion = 0; + int block_x = ((b8 & 0x01) << 3) + ((b4 & 0x01) << 2); + int block_y = ((b8 >> 1) << 3) + ((b4 >> 1) << 2); + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_y = currMB->opix_y + block_y; + + SyntaxElement se; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition *dataPart; + ColorPlane k; + + //===== perform forward transform, Q, IQ, inverse transform, Reconstruction ===== + //select_transform(currMB); + *nonzero = currMB->residual_transform_quant_luma_4x4 (currMB, PLANE_Y, block_x, block_y, &dummy, 1); + + //===== get distortion (SSD) of 4x4 block ===== + distortion += compute_SSE4x4(&p_Vid->pCurImg[pic_opix_y], &p_Vid->enc_picture->imgY[pic_pix_y], pic_pix_x, pic_pix_x); + + if(p_Vid->P444_joined) + { + for (k = PLANE_U; k <= PLANE_V; k++) + { + select_plane(p_Vid, k); + currMB->c_nzCbCr[k] = currMB->residual_transform_quant_luma_4x4(currMB, k, block_x, block_y, &dummy, 1); + distortion += compute_SSE4x4(&p_Vid->pCurImg[pic_opix_y], &p_Vid->enc_picture->p_curr_img[pic_pix_y], pic_pix_x, pic_pix_x); + } + select_plane(p_Vid, PLANE_Y); + } + currMB->ipmode_DPCM = NO_INTRA_PMODE; + + //===== RATE for INTRA PREDICTION MODE (SYMBOL MODE MUST BE SET TO CAVLC) ===== + se.value1 = (mostProbableMode == ipmode) ? -1 : ipmode < mostProbableMode ? ipmode : ipmode - 1; + + //--- set position and type --- + se.context = (b8 << 2) + b4; + se.type = SE_INTRAPREDMODE; + + //--- choose data partition --- + dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + //--- encode and update rate --- + currSlice->writeIntraPredMode (&se, dataPart); + rate = se.len; + + //===== RATE for LUMINANCE COEFFICIENTS ===== + if (currSlice->symbol_mode == CAVLC) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, b4, 0); + if(p_Vid->P444_joined) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CB, b8, b4, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CR, b8, b4, 0); + } + } + else + { + rate += writeCoeff4x4_CABAC (currMB, PLANE_Y, b8, b4, 1); + if(p_Vid->P444_joined) + { + rate += writeCoeff4x4_CABAC (currMB, PLANE_U, b8, b4, 1); + rate += writeCoeff4x4_CABAC (currMB, PLANE_V, b8, b4, 1); + } + } + rdcost = distortion + weight_cost(lambda,rate); + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + + return rdcost; +} + +/*! +************************************************************************************* +* \brief +* R-D Cost for an 8x8 Partition +************************************************************************************* +*/ +distblk rdcost_for_8x8blocks (Macroblock *currMB, // --> Current macroblock to code + RD_8x8DATA *dataTr, + int* cnt_nonz, // --> number of nonzero coefficients + int64* cbp_blk, // --> cbp blk + int lambda, // <-- lagrange multiplier + int block, // <-- 8x8 block number + short mode, // <-- partitioning mode + Info8x8 *part, // <-- partition information + distblk min_rdcost) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps; + int rate=0; + distblk distortion=0; + + int dummy = 0, mrate; + int list_mode[2]; + int cbp = 0; + int pax = 8*(block & 0x01); + int pay = 8*(block >> 1); + int i0 = pax >> 2; + int j0 = pay >> 2; + int direct = (currSlice->slice_type == B_SLICE && mode==0); + int b8value = B8Mode2Value (currSlice, (short) mode, part->pdir); + + SyntaxElement se; + DataPartition *dataPart; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + + EncodingEnvironmentPtr eep_dp; + + short pdir = part->pdir; + int l0_ref = part->ref[LIST_0]; + int l1_ref = part->ref[LIST_1]; + + //===== + //===== GET COEFFICIENTS, RECONSTRUCTIONS, CBP + //===== + currMB->b8x8[block].bipred = part->bipred; + currMB->ar_mode = (short) ((mode != 0)? mode: P8x8); + + + if (direct) + { + int p_dir = currSlice->direct_pdir[currMB->block_y + j0][currMB->block_x + i0]; + if (p_dir < 0) // mode not allowed + return (DISTBLK_MAX); + else + { + int list_mode[2] = {0, 0}; + *cnt_nonz = currSlice->luma_residual_coding_8x8 (currMB, &cbp, cbp_blk, block, (short) p_dir, list_mode, + currSlice->direct_ref_idx[currMB->block_y+j0][currMB->block_x+i0]); + } + } + else + { + if (pdir == 2 && active_pps->weighted_bipred_idc == 1) + { + + int weight_sum = (active_pps->weighted_bipred_idc == 1)? currSlice->wbp_weight[0][l0_ref][l1_ref][0] + currSlice->wbp_weight[1][l0_ref][l1_ref][0] : 0; + if (weight_sum < -128 || weight_sum > 127) + { + return (DISTBLK_MAX); + } + } + + list_mode[0] = (pdir==0||pdir==2 ? mode : 0); + list_mode[1] = (pdir==1||pdir==2 ? mode : 0); + *cnt_nonz = currSlice->luma_residual_coding_8x8 (currMB, &cbp, cbp_blk, block, pdir, list_mode, part->ref); + } + + if(p_Vid->P444_joined) + { + *cnt_nonz += ( currSlice->coeff_cost_cr[1] + currSlice->coeff_cost_cr[2] ); + } + + // RDOPT with losses + if (p_Inp->rdopt==3) + { + //Zhifeng 090611 + distortion = p_Vid->estimate_distortion(currMB, block, 8, mode, pdir, min_rdcost); //===== get residue ===== + } + else + { + distortion += compute_SSE8x8(&p_Vid->pCurImg[currMB->opix_y + pay], &p_Vid->enc_picture->imgY[currMB->pix_y + pay], currMB->pix_x + pax, currMB->pix_x + pax); + } + + if (p_Vid->P444_joined) + { + distortion += compute_SSE8x8(&p_Vid->pImgOrg[1][currMB->opix_y + pay], &p_Vid->enc_picture->imgUV[0][currMB->pix_y + pay], currMB->pix_x + pax, currMB->pix_x + pax); + distortion += compute_SSE8x8(&p_Vid->pImgOrg[2][currMB->opix_y + pay], &p_Vid->enc_picture->imgUV[1][currMB->pix_y + pay], currMB->pix_x + pax, currMB->pix_x + pax); + } + + // Early termination + if (distortion >= min_rdcost) + return (distortion); + //printf("distortion %.2f %.2f\n", (double) distortion, min_rdcost); + + if(p_Vid->P444_joined) + { + cbp |= currSlice->cmp_cbp[1]; + cbp |= currSlice->cmp_cbp[2]; + + currSlice->cmp_cbp[1] = cbp; + currSlice->cmp_cbp[2] = cbp; + } + + //===== + //===== GET RATE + //===== + //----- block 8x8 mode ----- + if (currSlice->symbol_mode == CAVLC) + { + ue_linfo (b8value, dummy, &mrate, &dummy); + rate += mrate; + } + else + { + se.value1 = b8value; + se.type = SE_MBTYPE; + dataPart = &(currSlice->partArr[partMap[se.type]]); + currSlice->writeB8_typeInfo(&se, dataPart); + rate += se.len; + } + + //----- motion information ----- + if (!direct) + { + if ((currSlice->num_ref_idx_active[LIST_0] > 1 ) && (pdir==0 || pdir==2)) + rate += writeReferenceFrame (currMB, i0, j0, LIST_0, l0_ref); + + if ((currSlice->num_ref_idx_active[LIST_1] > 1 && currSlice->slice_type == B_SLICE ) && (pdir==1 || pdir==2)) + { + rate += writeReferenceFrame (currMB, i0, j0, LIST_1, l1_ref); + } + + if (pdir==0 || pdir==2) + { + rate += writeMotionVector8x8 (currMB, i0, j0, i0 + 2, j0 + 2, l0_ref, LIST_0, mode, currMB->b8x8[block].bipred); + } + if (pdir==1 || pdir==2) + { + rate += writeMotionVector8x8 (currMB, i0, j0, i0 + 2, j0 + 2, l1_ref, LIST_1, mode, currMB->b8x8[block].bipred); + } + } + + //----- coded block pattern (for CABAC only) ----- + if (!currSlice->symbol_mode == CAVLC) + { + dataPart = &(currSlice->partArr[partMap[SE_CBP]]); + eep_dp = &(dataPart->ee_cabac); + mrate = arienco_bits_written (eep_dp); + writeCBP_BIT_CABAC (currMB, block, ((*cnt_nonz>0)?1:0), dataTr->cbp8x8, eep_dp, currSlice->tex_ctx); + mrate = arienco_bits_written (eep_dp) - mrate; + rate += mrate; + } + + //----- luminance coefficients ----- + if (*cnt_nonz) + { + rate += writeCoeff8x8 ( currMB, PLANE_Y, block, mode, currMB->luma_transform_size_8x8_flag); + } + + if(p_Vid->P444_joined) + { + rate += writeCoeff8x8( currMB, PLANE_U, block, mode, currMB->luma_transform_size_8x8_flag ); + rate += writeCoeff8x8( currMB, PLANE_V, block, mode, currMB->luma_transform_size_8x8_flag ); + } + return (distortion + weight_cost(lambda, rate)); +} + + +/* + ************************************************************************************* + * \brief + * Gets mode offset for intra16x16 mode + ************************************************************************************* + */ +short I16Offset (int cbp, short i16mode) +{ + return (short) ((cbp & 15 ? 13 : 1) + i16mode + ((cbp & 0x30) >> 2)); +} + + +/*! + ************************************************************************************* + * \brief + * Sets modes and reference frames for a macroblock + ************************************************************************************* + */ +void set_modes_and_refs_for_blocks_i_slice(Macroblock *currMB, short mode) +{ + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j; + Block8x8Info *b8x8info = p_Vid->b8x8info; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + //--- macroblock type --- + currMB->mb_type = mode; + currMB->ar_mode = mode; + + for( i = 0; i < 4; i++) + { + currMB->b8x8[i] = b8x8info->best[mode][i]; + } + + //--- block 8x8 mode and prediction direction --- + switch (mode) + { + case I4MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = IBLOCK; + currMB->b8x8[i].pdir = -1; + } + break; + case I16MB: + //memset(currMB->b8x8, 0, 4 * sizeof(short)); + currMB->b8x8[0].mode = 0; + currMB->b8x8[1].mode = 0; + currMB->b8x8[2].mode = 0; + currMB->b8x8[3].mode = 0; + for(i=0;i<4;i++) + { + currMB->b8x8[i].pdir = -1; + } + break; + case I8MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = I8MB; + currMB->b8x8[i].pdir = -1; + } + //switch to 8x8 transform + currMB->luma_transform_size_8x8_flag = TRUE; + break; + case IPCM: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = IPCM; + currMB->b8x8[i].pdir = -1; + } + currMB->luma_transform_size_8x8_flag = FALSE; + break; + default: + printf ("Unsupported mode in set_modes_and_refs_for_blocks!\n"); + exit (1); + } + + //--- reference frame arrays --- + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4;i++) + { + motion[j][i].ref_pic [LIST_0] = NULL; + motion[j][i].ref_idx [LIST_0] = -1; + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Sets modes and reference frames for a macroblock + ************************************************************************************* + */ +void set_modes_and_refs_for_blocks_p_slice(Macroblock *currMB, short mode) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j,k; + + Block8x8Info *b8x8info = p_Vid->b8x8info; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + //--- macroblock type --- + currMB->mb_type = mode; + + for( i = 0; i < 4; i++) + { + currMB->b8x8[i] = b8x8info->best[mode][i]; + } + + currMB->ar_mode = mode; + + //--- block 8x8 mode and prediction direction --- + switch (mode) + { + case 0: + currMB->b8x8[0].mode = 0; + currMB->b8x8[1].mode = 0; + currMB->b8x8[2].mode = 0; + currMB->b8x8[3].mode = 0; + currMB->b8x8[0].pdir = 0; + currMB->b8x8[1].pdir = 0; + currMB->b8x8[2].pdir = 0; + currMB->b8x8[3].pdir = 0; + break; + case 1: + case 2: + case 3: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = (char) mode; + } + break; + case P8x8: + break; + case I4MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = IBLOCK; + currMB->b8x8[i].pdir = -1; + } + break; + case I16MB: + //memset(currMB->b8x8, 0, 4 * sizeof(short)); + currMB->b8x8[0].mode = 0; + currMB->b8x8[1].mode = 0; + currMB->b8x8[2].mode = 0; + currMB->b8x8[3].mode = 0; + for(i=0;i<4;i++) + { + currMB->b8x8[i].pdir = -1; + } + break; + case I8MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = I8MB; + currMB->b8x8[i].pdir = -1; + } + //switch to 8x8 transform + currMB->luma_transform_size_8x8_flag = TRUE; + break; + case IPCM: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = IPCM; + currMB->b8x8[i].pdir = -1; + } + currMB->luma_transform_size_8x8_flag = FALSE; + break; + default: + printf ("Unsupported mode in set_modes_and_refs_for_blocks!\n"); + exit (1); + } + + //--- reference frame arrays --- + if (mode==0 || mode==I4MB || mode==I16MB || mode==I8MB || mode == IPCM || mode == SI4MB) + { + if (!mode) // Skip + { + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + for (i = currMB->block_x; i < currMB->block_x + 4; i++) + motion[j][i].ref_idx[LIST_0] = 0; + } + else // Intra + { + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + for (i = currMB->block_x; i < currMB->block_x + 4; i++) + motion[j][i].ref_idx[LIST_0] = -1; + } + } + else + { + if (mode == 1) + { + short curref = b8x8info->best[mode][0].pdir == 0 ? b8x8info->best[mode][0].ref[LIST_0] : -1; + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4;i++) + { + motion[j][i].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[j][i].ref_idx [LIST_0] = (char) curref; + } + } + } + else if (mode == 2) + { + short curref = b8x8info->best[mode][0].pdir == 0 ? b8x8info->best[mode][0].ref[LIST_0] : -1; + for (j = currMB->block_y; j < currMB->block_y + 2; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4;i++) + { + motion[j][i].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[j][i].ref_idx [LIST_0] = (char) curref; + } + } + curref = b8x8info->best[mode][2].pdir == 0 ? b8x8info->best[mode][2].ref[LIST_0] : -1; + for (j = currMB->block_y + 2; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4;i++) + { + motion[j][i].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[j][i].ref_idx [LIST_0] = (char) curref; + } + } + } + else if (mode == 3) + { + short curref = (b8x8info->best[mode][0].pdir == 0) ? b8x8info->best[mode][0].ref[LIST_0] : -1; + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 2;i++) + { + motion[j][i].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[j][i].ref_idx [LIST_0] = (char) curref; + } + } + curref = (b8x8info->best[mode][1].pdir == 0) ? b8x8info->best[mode][1].ref[LIST_0] : -1; + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x + 2; i < currMB->block_x + 4;i++) + { + motion[j][i].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[j][i].ref_idx [LIST_0] = (char) curref; + } + } + } + else + { + int block_x, block_y; + int curref; + for (j = 0; j < 4; j++) + { + block_x = currMB->block_x; + block_y = currMB->block_y + j; + k = 2*(j >> 1); + curref = b8x8info->best[mode][k++].ref[LIST_0]; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[block_y][block_x++].ref_idx[LIST_0] = (char) curref; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[block_y][block_x++].ref_idx[LIST_0] = (char) curref; + curref = b8x8info->best[mode][k].ref[LIST_0]; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[block_y][block_x++].ref_idx[LIST_0] = (char) curref; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][curref]; + motion[block_y][block_x].ref_idx[LIST_0] = (char) curref; + } + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Sets modes and reference frames for a macroblock + ************************************************************************************* + */ +void set_modes_and_refs_for_blocks_b_slice(Macroblock *currMB, short mode) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int i,j,k; + int block_x, block_y, block8x8, block4x4; + int cur_ref; + int clist; + char curref, bestref; + Block8x8Info *b8x8info = p_Vid->b8x8info; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + //--- macroblock type --- + currMB->mb_type = mode; + currMB->ar_mode = mode; + + for( i = 0; i < 4; i++) + { + currMB->b8x8[i] = b8x8info->best[mode][i]; + } + + //--- block 8x8 mode and prediction direction --- + switch (mode) + { + case 0: + currMB->b8x8[0].mode = 0; + currMB->b8x8[1].mode = 0; + currMB->b8x8[2].mode = 0; + currMB->b8x8[3].mode = 0; + + currMB->b8x8[0].pdir = currSlice->direct_pdir[currMB->block_y ][currMB->block_x ]; + currMB->b8x8[1].pdir = currSlice->direct_pdir[currMB->block_y ][currMB->block_x + 2]; + currMB->b8x8[2].pdir = currSlice->direct_pdir[currMB->block_y + 2][currMB->block_x ]; + currMB->b8x8[3].pdir = currSlice->direct_pdir[currMB->block_y + 2][currMB->block_x + 2]; + break; + case 1: + case 2: + case 3: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = (char) mode; + } + break; + case P8x8: + break; + case I4MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = IBLOCK; + currMB->b8x8[i].pdir = -1; + } + break; + case I16MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = 0; + currMB->b8x8[i].pdir = -1; + } + break; + case I8MB: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = I8MB; + currMB->b8x8[i].pdir = -1; + } + //switch to 8x8 transform + currMB->luma_transform_size_8x8_flag = TRUE; + break; + case IPCM: + for(i=0;i<4;i++) + { + currMB->b8x8[i].mode = IPCM; + currMB->b8x8[i].pdir = -1; + } + currMB->luma_transform_size_8x8_flag = FALSE; + break; + default: + printf ("Unsupported mode in set_modes_and_refs_for_blocks!\n"); + exit (1); + } + +#define IS_FW ((b8x8info->best[mode][k].pdir==0 || b8x8info->best[mode][k].pdir==2) && (mode!=P8x8 || b8x8info->best[mode][k].mode!=0)) +#define IS_BW ((b8x8info->best[mode][k].pdir==1 || b8x8info->best[mode][k].pdir==2) && (mode!=P8x8 || b8x8info->best[mode][k].mode!=0)) + + //--- reference frame arrays --- + if (mode == 0) // Direct + { + for (clist = LIST_0; clist <= LIST_1; clist++) + { + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4; i++) + motion[j][i].ref_idx[clist] = currSlice->direct_ref_idx[j][i][clist]; + } + } + } + else if (mode==I4MB || mode==I16MB || mode==I8MB || mode == IPCM) + { + for (clist = LIST_0; clist <= LIST_1; clist++) + { + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4; i++) + motion[j][i].ref_idx[clist] = -1; + } + } + } + else if (mode == 1 || mode == 2 || mode == 3) + { + for (block8x8 = 0; block8x8 < 4; block8x8++) + { + for (clist = LIST_0; clist <= LIST_1; clist++) + { + bestref = b8x8info->best[mode][block8x8].ref[clist]; + + if ( b8x8info->best[mode][block8x8].pdir == 2) + { + curref = (b8x8info->best[mode][block8x8].bipred) ? 0 : bestref; + } + else + { + curref = (clist == b8x8info->best[mode][block8x8].pdir) ? bestref : -1; + } + + for (block4x4 = 0; block4x4 < 4; block4x4++) + { + block_x = currMB->block_x + 2 * (block8x8 & 0x01) + (block4x4 & 0x01); + block_y = currMB->block_y + 2 * (block8x8 >> 1) + (block4x4 >> 1); + motion[block_y][block_x].ref_idx[clist] = curref; + } + } + } + } + else // mode == P8x8 + { + for (j = 0; j < 4; j++) + { + block_y = currMB->block_y + j; + for (i = 0; i < 4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1) + (i >> 1); + + if(b8x8info->best[mode][k].mode==0) + { + motion[block_y][block_x].ref_idx[LIST_0] = currSlice->direct_ref_idx[block_y][block_x][LIST_0]; + motion[block_y][block_x].ref_idx[LIST_1] = currSlice->direct_ref_idx[block_y][block_x][LIST_1]; + } + else + { + motion[block_y][block_x].ref_idx[LIST_0] = (IS_FW ? b8x8info->best[mode][k].ref[LIST_0] : -1); + motion[block_y][block_x].ref_idx[LIST_1] = (IS_BW ? b8x8info->best[mode][k].ref[LIST_1] : -1); + } + } + } + } + + for (clist = LIST_0; clist <= LIST_1; clist++) + { + StorablePicture **ref_pic = currSlice->listX[clist + currMB->list_offset]; + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4;i++) + { + cur_ref = (int) motion[j][i].ref_idx[clist]; + motion[j][i].ref_pic [clist] = (cur_ref < 0 ? NULL : ref_pic[cur_ref]); + } + } + } + +#undef IS_FW +#undef IS_BW +} + + +/*! + ************************************************************************************* + * \brief + * Sets Coefficients and reconstruction for an 8x8 block + ************************************************************************************* + */ +void set_coeff_and_recon_8x8_p_slice (Macroblock* currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int block, k, j, i, uv; + int cur_ref; + + //============= MIXED TRANSFORM SIZES FOR 8x8 PARTITION ============== + //-------------------------------------------------------------------- + if (currMB->luma_transform_size_8x8_flag && (currMB->valid_8x8)) + { + //============= set mode and ref. frames ============== + memcpy(currMB->b8x8, p_RDO->tr8x8->part, 4 * sizeof(Info8x8)); + + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + k = 2*(j >> 1)+(i >> 1); + motion[currMB->block_y+j][currMB->block_x+i].ref_idx[LIST_0] = p_RDO->tr8x8->part[k].ref[LIST_0]; + } + } + + for (j = currMB->block_y;jblock_y + BLOCK_MULTIPLE;j++) + { + for (i = currMB->block_x;iblock_x + BLOCK_MULTIPLE;i++) + { + cur_ref = (int) motion[j][i].ref_idx[LIST_0]; + motion[j][i].ref_pic[LIST_0] =(cur_ref >= 0 ? currSlice->listX[LIST_0 + currMB->list_offset][cur_ref] : NULL); + } + } + + + //====== set the mv's for 8x8 partition with transform size 8x8 ====== + //save the mv data for 4x4 transform + StoreMV8x8(currSlice, 1); + //set new mv data for 8x8 transform + RestoreMV8x8(currSlice, 0); + + //============= get pre-calculated data ============== + //restore coefficients from 8x8 transform + + for (block = 0; block<4; block++) + { + memcpy (currSlice->cofAC[block][0][0],p_RDO->cofAC8x8ts[block][0][0][0], 4 * 2 * 65 * sizeof(int)); + } + + if (p_Vid->P444_joined) + { + for (uv=0; uv<2; uv++) + { + for (block = 0; block<4; block++) + { + memcpy (currSlice->cofAC[4+block+uv*4][0][0],p_RDO->cofAC8x8ts[block][uv + 1][0][0], 4 * 2 * 65 * sizeof(int)); + } + } + } + + //restore reconstruction + if (p_RDO->tr8x8->cnt_nonz_8x8 <= _LUMA_8x8_COEFF_COST_ && + ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0) && + (currSlice->slice_type != SP_SLICE))// modif ES added last condition (we probably never go there so is the next modification useful ? check) + { + currMB->cbp = 0; + currMB->cbp_blk = 0; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr8x8->mpr8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 0; + } + + if(currSlice->slice_type == SP_SLICE && !p_Vid->sp2_frame_indicator) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy(&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x],p_RDO->tr8x8->lrec[j], MB_BLOCK_SIZE * sizeof(int)); + } + } + + //memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + if(p_Vid->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr8x8->mpr8x8CbCr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr8x8->mpr8x8CbCr[1], currMB->pix_x, 0); + + for (uv=0; uv<2; uv++) + { + for (block = 0; block<4; block++) + { + memset( currSlice->cofAC[4+block+uv*4][0][0], 0, 4 * 2 * 65 * sizeof(int)); + } + } + } + } + else + { + currMB->cbp = p_RDO->tr8x8->cbp8x8; + currMB->cbp_blk = p_RDO->tr8x8->cbp_blk8x8; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr8x8->rec_mbY8x8, currMB->pix_x, 0); + + if (p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 1; + } + + if(currSlice->slice_type == SP_SLICE && !p_Vid->sp2_frame_indicator) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy (&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x],p_RDO->tr8x8->lrec[j], MB_BLOCK_SIZE * sizeof(int)); + } + } + + if (p_Vid->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = p_RDO->tr8x8->cbp8x8; + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr8x8->rec_mb8x8_cr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr8x8->rec_mb8x8_cr[1], currMB->pix_x, 0); + } + } + if (p_Inp->rdopt == 3) + { + errdo_get_best_P8x8(currMB, 1); + } + } + else + { + //============= get pre-calculated data ============== + //--------------------------------------------------- + //--- restore coefficients --- + for (block = 0; block < 4; block ++) + { + memcpy (currSlice->cofAC[block][0][0],p_RDO->coefAC8x8[block][0][0][0], 4 * 2 * 65 * sizeof(int)); + } + + if (currSlice->P444_joined) + { + for (block = 0; block<4; block++) + { + memcpy (currSlice->cofAC[block+4][0][0],p_RDO->coefAC8x8[block][1][0][0], 4 * 2 * 65 * sizeof(int)); + memcpy (currSlice->cofAC[block+8][0][0],p_RDO->coefAC8x8[block][2][0][0], 4 * 2 * 65 * sizeof(int)); + } + } + + if (((p_Inp->disthres && p_RDO->tr4x4->cnt_nonz_8x8 <= 0) || (p_RDO->tr4x4->cnt_nonz_8x8 <= 5)) && currSlice->slice_type != SP_SLICE && + ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0)) + { + currMB->cbp = 0; + currMB->cbp_blk = 0; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr4x4->mpr8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 0; + } + + if(currSlice->slice_type == SP_SLICE && !p_Vid->sp2_frame_indicator) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy (&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x],p_RDO->tr4x4->lrec[j], MB_BLOCK_SIZE * sizeof(int)); // restore coeff. SP frame + } + } + + //memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + if (currSlice->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr4x4->mpr8x8CbCr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr4x4->mpr8x8CbCr[1], currMB->pix_x, 0); + + for (uv=0; uv<2; uv++) + { + for (block = 0; block<4; block++) + { + memset( currSlice->cofAC[4+block+uv*4][0][0], 0, 4 * 2 * 65 * sizeof(int)); + } + } + } + } + else + { + currMB->cbp = p_RDO->tr4x4->cbp8x8; + currMB->cbp_blk = p_RDO->tr4x4->cbp_blk8x8; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr4x4->rec_mbY8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 1; + } + + if(currSlice->slice_type == SP_SLICE && !p_Vid->sp2_frame_indicator) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy (&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x],p_RDO->tr4x4->lrec[j], MB_BLOCK_SIZE * sizeof(int)); + } + } + if (currSlice->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = p_RDO->tr4x4->cbp8x8; + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr4x4->rec_mb8x8_cr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr4x4->rec_mb8x8_cr[1], currMB->pix_x, 0); + } + } + if (p_Inp->rdopt == 3) + { + errdo_get_best_P8x8(currMB, 0); + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Sets Coefficients and reconstruction for an 8x8 block + ************************************************************************************* + */ +void set_coeff_and_recon_8x8_b_slice (Macroblock* currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int block, k, j, i, uv; + int cur_ref; + + //============= MIXED TRANSFORM SIZES FOR 8x8 PARTITION ============== + //-------------------------------------------------------------------- + if (currMB->luma_transform_size_8x8_flag && (currMB->valid_8x8)) + { + //============= set mode and ref. frames ============== + memcpy(currMB->b8x8, p_RDO->tr8x8->part, 4 * sizeof(Info8x8)); + + for (j = 0;j<4;j++) + { + for (i = 0;i<4;i++) + { + k = 2*(j >> 1)+(i >> 1); + motion[currMB->block_y+j][currMB->block_x+i].ref_idx[LIST_0] = ((currMB->b8x8[k].pdir & 0x01) == 0) ? p_RDO->tr8x8->part[k].ref[LIST_0] : - 1; + motion[currMB->block_y+j][currMB->block_x+i].ref_idx[LIST_1] = (currMB->b8x8[k].pdir > 0) ? p_RDO->tr8x8->part[k].ref[LIST_1] : - 1; + } + } + + for (j = currMB->block_y;jblock_y + BLOCK_MULTIPLE;j++) + { + for (i = currMB->block_x;iblock_x + BLOCK_MULTIPLE;i++) + { + cur_ref = (int) motion[j][i].ref_idx[LIST_0]; + motion[j][i].ref_pic[LIST_0] =(cur_ref >= 0 ? currSlice->listX[LIST_0 + currMB->list_offset][cur_ref] : NULL); + } + } + + for (j = currMB->block_y;jblock_y + BLOCK_MULTIPLE;j++) + { + for (i = currMB->block_x;iblock_x + BLOCK_MULTIPLE;i++) + { + cur_ref = (int) motion[j][i].ref_idx[LIST_1]; + motion[j][i].ref_pic[LIST_1] =(cur_ref >= 0 ? currSlice->listX[LIST_1 + currMB->list_offset][cur_ref] : NULL); + } + } + + //====== set the mv's for 8x8 partition with transform size 8x8 ====== + //save the mv data for 4x4 transform + StoreMV8x8(currSlice, 1); + //set new mv data for 8x8 transform + RestoreMV8x8(currSlice, 0); + + //============= get pre-calculated data ============== + //restore coefficients from 8x8 transform + + for (block = 0; block<4; block++) + { + memcpy (currSlice->cofAC[block][0][0],p_RDO->cofAC8x8ts[block][0][0][0], 4 * 2 * 65 * sizeof(int)); + } + + if (p_Vid->P444_joined) + { + for (uv=0; uv<2; uv++) + { + for (block = 0; block<4; block++) + { + memcpy (currSlice->cofAC[4+block+uv*4][0][0],p_RDO->cofAC8x8ts[block][uv + 1][0][0], 4 * 2 * 65 * sizeof(int)); + } + } + } + + //restore reconstruction + if (p_RDO->tr8x8->cnt_nonz_8x8 <= _LUMA_8x8_COEFF_COST_ && + ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0))// modif ES added last condition (we probably never go there so is the next modification useful ? check) + { + currMB->cbp = 0; + currMB->cbp_blk = 0; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr8x8->mpr8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 0; + } + + + //memset( currSlice->cofAC[0][0][0], 0, 2080 * sizeof(int)); // 4 * 4 * 2 * 65 + + if(p_Vid->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr8x8->mpr8x8CbCr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr8x8->mpr8x8CbCr[1], currMB->pix_x, 0); + + for (uv=0; uv<2; uv++) + { + for (block = 0; block<4; block++) + { + memset( currSlice->cofAC[4+block+uv*4][0][0], 0, 4 * 2 * 65 * sizeof(int)); + } + } + } + } + else + { + currMB->cbp = p_RDO->tr8x8->cbp8x8; + currMB->cbp_blk = p_RDO->tr8x8->cbp_blk8x8; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr8x8->rec_mbY8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 1; + } + + + if (p_Vid->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = p_RDO->tr8x8->cbp8x8; + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr8x8->rec_mb8x8_cr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr8x8->rec_mb8x8_cr[1], currMB->pix_x, 0); + } + } + if (p_Inp->rdopt == 3) + { + errdo_get_best_P8x8(currMB, 1); + } + } + else + { + if (currMB->valid_8x8) + { + StoreMV8x8(currSlice, 1); + } + + //============= get pre-calculated data ============== + //--------------------------------------------------- + //--- restore coefficients --- + for (block = 0; block < 4; block ++) + { + memcpy (currSlice->cofAC[block][0][0],p_RDO->coefAC8x8[block][0][0][0], 4 * 2 * 65 * sizeof(int)); + } + + if (currSlice->P444_joined) + { + for (block = 0; block<4; block++) + { + memcpy (currSlice->cofAC[block+4][0][0],p_RDO->coefAC8x8[block][1][0][0], 4 * 2 * 65 * sizeof(int)); + memcpy (currSlice->cofAC[block+8][0][0],p_RDO->coefAC8x8[block][2][0][0], 4 * 2 * 65 * sizeof(int)); + } + } + + if (((p_Inp->disthres && p_RDO->tr4x4->cnt_nonz_8x8 <= 0) || (p_RDO->tr4x4->cnt_nonz_8x8 <= 5)) && + ((currMB->qp_scaled[0])!=0 || p_Vid->active_sps->lossless_qpprime_flag==0)) + { + currMB->cbp = 0; + currMB->cbp_blk = 0; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr4x4->mpr8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 0; + } + + if (currSlice->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr4x4->mpr8x8CbCr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr4x4->mpr8x8CbCr[1], currMB->pix_x, 0); + + for (uv=0; uv<2; uv++) + { + for (block = 0; block<4; block++) + { + memset( currSlice->cofAC[4+block+uv*4][0][0], 0, 4 * 2 * 65 * sizeof(int)); + } + } + } + } + else + { + currMB->cbp = p_RDO->tr4x4->cbp8x8; + currMB->cbp_blk = p_RDO->tr4x4->cbp_blk8x8; + + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], p_RDO->tr4x4->rec_mbY8x8, currMB->pix_x, 0); + + if(p_Inp->rdopt == 3) + { + p_Vid->p_decs->rec_type = 1; + } + + if (currSlice->P444_joined) + { + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = p_RDO->tr4x4->cbp8x8; + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[0][currMB->pix_y], p_RDO->tr4x4->rec_mb8x8_cr[0], currMB->pix_x, 0); + copy_image_data_16x16(&p_Vid->enc_picture->imgUV[1][currMB->pix_y], p_RDO->tr4x4->rec_mb8x8_cr[1], currMB->pix_x, 0); + } + } + if (p_Inp->rdopt == 3) + { + errdo_get_best_P8x8(currMB, 0); + } + } +} + +/*! + ************************************************************************************* + * \brief + * Restore Non zero coefficients + ************************************************************************************* + */ +void restore_nz_coeff(Macroblock *currMB) +{ +#ifdef BEST_NZ_COEFF + VideoParameters *p_Vid = currMB->p_Vid; + int i, j; + int **nz_coeff = p_Vid->nz_coeff[currMB->mbAddrX]; + for (j=0;j<4;j++) + for (i=0; i<(4+p_Vid->num_blk8x8_uv); i++) + nz_coeff[j][i] = p_Vid->gaaiMBAFF_NZCoeff[j][i]; +#endif +} + + +void prepare_ipcm_mode(Macroblock *currMB) +{ + int i, j; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + // LUMA + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], &p_Vid->pCurImg[currMB->opix_y], currMB->pix_x, currMB->pix_x); + + // CHROMA + if ((p_Vid->yuv_format != YUV400) && (p_Inp->separate_colour_plane_flag == 0)) + { + copy_image_data(&p_Vid->enc_picture->imgUV[0][currMB->pix_c_y], &p_Vid->pImgOrg[1][currMB->opix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + copy_image_data(&p_Vid->enc_picture->imgUV[1][currMB->pix_c_y], &p_Vid->pImgOrg[2][currMB->opix_c_y], currMB->pix_c_x, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + for (j=0;j<4;j++) + for (i=0; i<(4+p_Vid->num_blk8x8_uv); i++) + p_Vid->nz_coeff[currMB->mbAddrX][j][i] = 16; +} + +/*! + ************************************************************************************* + * \brief + * R-D Cost for a macroblock + ************************************************************************************* + */ +int RDCost_for_macroblocks (Macroblock *currMB, // <-- Current Macroblock to code + int lambda, // <-- lagrange multiplier + short mode) // <-- mode (0-COPY/DIRECT, 1-16x16, 2-16x8, 3-8x16, 4-8x8(+), 5-Intra4x4, 6-Intra16x16) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + int rate = 0, coeff_rate = 0; + distblk distortion = 0; + Macroblock *prevMB = currMB->PrevMB; + int tmp_cc; + + int use_of_cc = (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE && currSlice->symbol_mode == CAVLC); + int cc_rate, dummy; + + distblk rdcost; + distblk dummy_d; + imgpel **mb_pred = currSlice->mb_pred[0]; + imgpel ***curr_mpr_16x16 = currSlice->mpr_16x16[0]; + + // Test MV limits for Skip Mode. This could be necessary for MBAFF case Frame MBs. + if ((currSlice->mb_aff_frame_flag) && (!currMB->mb_field) && (currSlice->slice_type == P_SLICE) && (mode==0) ) + { + if (out_of_bounds_mvs(p_Vid, &currSlice->all_mv[LIST_0][0][0][0][0])) + return 0; + } + + if(/*(p_Inp->rdopt==9) &&*/ (mode==P8x8)) + { + if((currMB->luma_transform_size_8x8_flag && !currMB->valid_8x8) || (!currMB->luma_transform_size_8x8_flag && !currMB->valid_4x4)) + return 0; + } + + //===== + //===== Set Reference Pictures and Block modes + //===== + currSlice->set_modes_and_refs_for_blocks (currMB, mode); + //===== + //===== Set Motion Vectors + //===== + currSlice->set_motion_vectors_mb (currMB); + + //===== + //===== Get coefficients, reconstruction values, CBP etc + //===== + if (mode < P8x8) + { + currSlice->luma_residual_coding(currMB); + } + else if (mode == P8x8) + { + currSlice->set_coeff_and_recon_8x8 (currMB); + } + else if (mode==I4MB) + { + currMB->cbp = mode_decision_for_I4x4_MB (currMB, lambda, &dummy_d); + } + else if (mode==I16MB) + { + currMB->cbp = currSlice->mode_decision_for_I16x16_MB (currMB, lambda); + } + else if(mode==I8MB) + { + currMB->cbp = mode_decision_for_I8x8_MB(currMB, lambda, &dummy_d); + } + else if(mode==IPCM) + { + prepare_ipcm_mode(currMB); + } + + //if (p_Inp->rdopt == 3) + //{ + // // We need the reconstructed prediction residue for the simulated decoders. + // compute_residue_block (currMB, &p_Vid->enc_picture->p_curr_img[currMB->pix_y], p_Vid->p_decs->res_img[0], mode == I16MB ? currSlice->mpr_16x16[0][ (short) currMB->i16mode] : currSlice->mb_pred[0], 0, 16); + //} + + //Rate control + if (p_Inp->RCEnable) + { + if (mode == I16MB) + memcpy(p_RDO->pred[0], curr_mpr_16x16[ (short) currMB->i16mode][0], MB_PIXELS * sizeof(imgpel)); + else + memcpy(p_RDO->pred[0], mb_pred[0], MB_PIXELS * sizeof(imgpel)); + } + + currMB->i16offset = 0; + dummy = 0; + + if (((p_Vid->yuv_format != YUV400) && (active_sps->chroma_format_idc != YUV444)) && (mode != IPCM)) + currSlice->chroma_residual_coding (currMB); + + if (mode==I16MB) + currMB->i16offset = I16Offset (currMB->cbp, currMB->i16mode); + + //===== + //===== GET DISTORTION + //===== + // LUMA + if (p_Inp->rdopt == 3) + { + distortion = p_Vid->estimate_distortion(currMB, 0, 16, mode, 0, currMB->min_rdcost); + //if (errdo_distortion (currMB, mode, &distortion) == 0) + // return 0; + } + else + { + + distortion = currSlice->getDistortion(currMB); + } + if (distortion > currMB->min_rdcost) + return 0; + //printf("passed distortion %.2f %.2f\n", (double)distortion, currMB->min_rdcost); + + if (currMB->qp_scaled[0] == 0 && p_Vid->active_sps->lossless_qpprime_flag == 1 && distortion != 0) + return 0; + + //===== S T O R E C O D I N G S T A T E ===== + //--------------------------------------------------- + currSlice->store_coding_state (currMB, currSlice->p_RDO->cs_cm); + + //===== + //===== GET RATE + //===== + //----- macroblock header ----- + if (use_of_cc) + { + if (currMB->mb_type!=0 || (currSlice->slice_type == B_SLICE && currMB->cbp!=0)) + { + // cod counter and macroblock mode are written ==> do not consider code counter + tmp_cc = p_Vid->cod_counter; + + rate = currSlice->write_MB_layer (currMB, 1, &coeff_rate); + + ue_linfo (tmp_cc, dummy, &cc_rate, &dummy); + rate -= cc_rate; + p_Vid->cod_counter = tmp_cc; + } + else + { + // cod counter is just increased ==> get additional rate + ue_linfo (p_Vid->cod_counter + 1, dummy, &rate, &dummy); + ue_linfo (p_Vid->cod_counter , dummy, &cc_rate, &dummy); + rate -= cc_rate; + } + } + else + { + rate = currSlice->write_MB_layer (currMB, 1, &coeff_rate); + } + + //===== R E S T O R E C O D I N G S T A T E ===== + //------------------------------------------------------- + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + + if (p_Inp->ForceTrueRateRDO == 1) + rdcost = distortion + weight_cost(lambda, rate); + else if (p_Inp->ForceTrueRateRDO == 2) + rdcost = distortion + weight_cost(lambda, (rate + IS_INTRA(currMB))); + else + rdcost = distortion + (rate>0? (weight_cost(lambda, rate)): (weight_cost(lambda, 1)/2)); + +#if JCOST_OVERFLOWCHECK //overflow checking; + if(rdcost < distortion) + { + printf("lambda: %d, rate: %d, error: %s: %d\n", lambda, rate, __FILE__, __LINE__); + exit(-1); + } +#endif //end; + + // + if ((currSlice->slice_type != I_SLICE) && (p_Inp->BiasSkipRDO == 1) && (mode == 1) && (currMB->best_mode == 0) && (currMB->min_dcost > 4 * distortion) && (currMB->min_dcost > ((64 * (256 + 2 * p_Vid->mb_cr_size_y * p_Vid->mb_cr_size_x)) << LAMBDA_ACCURACY_BITS))) + { + currMB->min_rdcost = rdcost + 1; + } + + if ((rdcost >= currMB->min_rdcost) || + ((currMB->qp_scaled[0]) == 0 && p_Vid->active_sps->lossless_qpprime_flag == 1 && distortion != 0)) + { +#if FASTMODE + // Reordering RDCost comparison order of mode 0 and mode 1 in P_SLICE + // if RDcost of mode 0 and mode 1 is same, we choose best_mode is 0 + // This might not always be good since mode 0 is more biased towards rate than quality. + if((currSlice->slice_type != P_SLICE || mode != 0 || rdcost != currMB->min_rdcost) || is_FREXT_profile(p_Inp->ProfileIDC)) +#endif + return 0; + } + + + if ((currSlice->mb_aff_frame_flag) && (mode ? 0: ((currSlice->slice_type == B_SLICE) ? !currMB->cbp:1))) // AFF and current is skip + { + if (currMB->mbAddrX & 0x01) //bottom + { + if (prevMB->mb_type ? 0:((currSlice->slice_type == B_SLICE) ? !prevMB->cbp:1)) //top is skip + { + if (!(field_flag_inference(currMB) == currMB->mb_field)) //skip only allowed when correct inference + return 0; + } + } + } + + //===== U P D A T E M I N I M U M C O S T ===== + //----------------------------------------------------- + currMB->min_rdcost = rdcost; + currMB->min_dcost = distortion; + currMB->min_rate = weight_cost(lambda, coeff_rate); + currMB->min_bits = rate; + +#ifdef BEST_NZ_COEFF + for (j=0;j<4;j++) + memcpy(&p_Vid->gaaiMBAFF_NZCoeff[j][0], &p_Vid->nz_coeff[currMB->mbAddrX][j][0], (4 + p_Vid->num_blk8x8_uv) * sizeof(int)); +#endif + + return 1; +} + +/*! + ************************************************************************************* + * \brief + * Initialize best mode information + ************************************************************************************* + */ +void init_md_best(BestMode *best) +{ + best->cbp = 0; + best->cost = DISTBLK_MAX; //(1i64<<(20+LAMBDA_ACCURACY_BITS)); + best->rdcost = 1e20; + best->dcost = 1e20; + best->rate = 1e20; + best->c_imode = 0; + best->i16offset = 0; + best->mode = 10; +} + +/*! + ************************************************************************************* + * \brief + * Store macroblock parameters + ************************************************************************************* + */ +void store_macroblock_parameters (Macroblock *currMB, int mode) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + int i, j, ****i4p, ***i3p; + + //--- store best mode --- + currMB->best_mode = (short) mode; + currMB->best_c_imode = currMB->c_ipred_mode; + currMB->best_i16offset = currMB->i16offset; + currMB->best_i16mode = currMB->i16mode; + currMB->best_cbp = currMB->cbp; + + memcpy(currSlice->p_RDO->best8x8, currMB->b8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + memcpy(currSlice->b4_intra_pred_modes, currMB->intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(currSlice->b8_intra_pred_modes8x8,currMB->intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + + for (j = 0 ; j < BLOCK_MULTIPLE; j++) + { + memcpy(&currSlice->b4_ipredmode[j * BLOCK_MULTIPLE],&p_Vid->ipredmode [currMB->block_y + j][currMB->block_x],BLOCK_MULTIPLE * sizeof(char)); + memcpy(&currSlice->b8_ipredmode8x8[j][0], &p_Vid->ipredmode8x8[currMB->block_y + j][currMB->block_x],BLOCK_MULTIPLE * sizeof(char)); + } + //--- reconstructed blocks ---- + copy_image_data_16x16(p_RDO->rec_mb[0], &p_Vid->enc_picture->imgY[currMB->pix_y], 0, currMB->pix_x); + + if((currSlice->slice_type == SP_SLICE) && p_Vid->sp2_frame_indicator==0) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + { + memcpy(p_RDO->lrec_rec[j], &p_Vid->lrec[currMB->pix_y+j][currMB->pix_x], MB_BLOCK_SIZE * sizeof(int));//store coefficients SP frame + } + } + + //modes 0, and 1 of a B frame + if (p_Vid->AdaptiveRounding && (currSlice->slice_type == B_SLICE) && mode <= 1) + { + if (currMB->luma_transform_size_8x8_flag) + store_adaptive_rounding_16x16( p_Vid, p_Vid->ARCofAdj8x8, mode); + else + store_adaptive_rounding_16x16( p_Vid, p_Vid->ARCofAdj4x4, mode); + } + + if (p_Vid->yuv_format != YUV400) + { + int k; + for (k = 0; k < 2; k++) + { + copy_image_data(p_RDO->rec_mb[k + 1], &p_Vid->enc_picture->imgUV[k][currMB->pix_c_y], 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + if((currSlice->slice_type == SP_SLICE) && p_Vid->sp2_frame_indicator==0) + { + //store uv coefficients SP frame + for (k = 0; k < 2; k++) + { + for (j = 0; jmb_cr_size_y; j++) + { + memcpy(p_RDO->lrec_rec_uv[k][j],&p_Vid->lrec_uv[k][currMB->pix_c_y + j][currMB->pix_c_x], p_Vid->mb_cr_size_x * sizeof(int)); + } + } + } + } + + //--- store results of decoders --- + if (p_Inp->rdopt == 3) + { + errdo_store_best_MB(currMB); + } + + //--- coeff, cbp, kac --- + if (mode || currSlice->slice_type == B_SLICE) + { + i4p = p_RDO->cofAC; + p_RDO->cofAC = currSlice->cofAC; + currSlice->cofAC = i4p; + i3p = p_RDO->cofDC; + p_RDO->cofDC = currSlice->cofDC; + currSlice->cofDC = i3p; + p_RDO->cbp = currMB->cbp; + currSlice->curr_cbp[0] = currSlice->cmp_cbp[1]; + currSlice->curr_cbp[1] = currSlice->cmp_cbp[2]; + + currSlice->cur_cbp_blk[0] = currMB->cbp_blk; + } + else + { + currSlice->cur_cbp_blk[0] = p_RDO->cbp = 0; + currSlice->cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + } + + //--- store transform size --- + currMB->temp_transform_size_8x8_flag = currMB->luma_transform_size_8x8_flag; + + if (currSlice->slice_type != B_SLICE) + { + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + p_RDO->l0_refframe[j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + } + } + } + else + { + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + p_RDO->l0_refframe[j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + p_RDO->l1_refframe[j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + } + } + } +} + +/*! +************************************************************************************* +* \brief +* Set stored macroblock parameters +************************************************************************************* +*/ +static void set_stored_macroblock_parameters_mpass (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + imgpel **imgY = p_Vid->enc_picture->imgY; + imgpel ***imgUV = p_Vid->enc_picture->imgUV; + + int mode = currMB->best_mode; + int i, j, k, ****i4p, ***i3p; + int block_x, block_y; + char **ipredmodes = p_Vid->ipredmode; + + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + //===== reconstruction values ===== + + // Luma + copy_image_data_16x16(&imgY[currMB->pix_y], p_RDO->rec_mb[0], currMB->pix_x, 0); + + // Copy coding info into rddata structure for MBAFF or RDOQ + copy_image_data_16x16(currSlice->rddata->rec_mb[0], p_RDO->rec_mb[0], 0, 0); + + if((currSlice->slice_type == SP_SLICE) && p_Vid->sp2_frame_indicator==0) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + memcpy(&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x], p_RDO->lrec_rec[j], MB_BLOCK_SIZE * sizeof(int)); //restore coeff SP frame + } + + if (p_Vid->AdaptiveRounding) + { + update_offset_params(currMB, mode, currMB->temp_transform_size_8x8_flag); + } + + if (p_Vid->yuv_format != YUV400) + { + for (k = 0; k < 2; k++) + { + copy_image_data(&imgUV[k][currMB->pix_c_y], p_RDO->rec_mb[k + 1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + // Copy coding info into rddata structure for MBAFF or RDOQ + copy_image_data(currSlice->rddata->rec_mb[1], p_RDO->rec_mb[1], 0, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + copy_image_data(currSlice->rddata->rec_mb[2], p_RDO->rec_mb[2], 0, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + + if((currSlice->slice_type == SP_SLICE) && !p_Vid->sp2_frame_indicator) + { + for (k = 0; k < 2; k++) + { + for (j = 0; jmb_cr_size_y; j++) + { + memcpy(&p_Vid->lrec_uv[k][currMB->pix_c_y + j][currMB->pix_c_x], p_RDO->lrec_rec_uv[k][j], p_Vid->mb_cr_size_x * sizeof(int)); + } + } + } + } + + //===== coefficients and cbp ===== + i4p = p_RDO->cofAC; + p_RDO->cofAC = currSlice->cofAC; + currSlice->cofAC = i4p; + + i3p = p_RDO->cofDC; + p_RDO->cofDC = currSlice->cofDC; + currSlice->cofDC = i3p; + currMB->cbp = p_RDO->cbp; + currMB->cbp_blk = currSlice->cur_cbp_blk[0]; + currMB->cbp |= currSlice->curr_cbp[0]; + currMB->cbp |= currSlice->curr_cbp[1]; + currSlice->cmp_cbp[1] = currMB->cbp; + currSlice->cmp_cbp[2] = currMB->cbp; + + //==== macroblock type ==== + currMB->mb_type = (short) mode; + + memcpy(currMB->b8x8, currSlice->p_RDO->best8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + // Copy coding info into rddata structure for MBAFF or RDOQ + currSlice->rddata->mode = mode; + currSlice->rddata->i16offset = currMB->i16offset; + currSlice->rddata->i16mode = currMB->i16mode; + currSlice->rddata->cbp = p_RDO->cbp; + currSlice->rddata->cbp_blk = currSlice->cur_cbp_blk[0]; + currSlice->rddata->mb_type = (short) mode; + + currSlice->rddata->prev_qp = currMB->prev_qp; + currSlice->rddata->prev_dqp = currMB->prev_dqp; + currSlice->rddata->qp = currMB->qp; + currSlice->rddata->prev_cbp = currMB->prev_cbp; + + memcpy(currSlice->rddata->cofAC[0][0][0], currSlice->cofAC[0][0][0], (4+p_Vid->num_blk8x8_uv) * 4 * 2 * 65 * sizeof(int)); + memcpy(currSlice->rddata->cofDC[0][0], currSlice->cofDC[0][0], 3 * 2 * 18 * sizeof(int)); + + memcpy(currSlice->rddata->b8x8, currSlice->p_RDO->best8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + //if P8x8 mode and transform size 4x4 choosen, restore motion vector data for this transform size + if (mode == P8x8 && !currMB->temp_transform_size_8x8_flag && p_Inp->Transform8x8Mode && (currMB->valid_8x8 == TRUE)) + { + RestoreMV8x8(currSlice, 1); + } + + //==== transform size flag ==== + if (p_Vid->P444_joined) + { + if (((currMB->cbp == 0) && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0) && (currMB->mb_type != I4MB && currMB->mb_type != I8MB)) + currMB->luma_transform_size_8x8_flag = FALSE; + else + currMB->luma_transform_size_8x8_flag = currMB->temp_transform_size_8x8_flag; + } + else + { + + if (((currMB->cbp & 15) == 0) && (currMB->mb_type != I4MB && currMB->mb_type != I8MB)) + currMB->luma_transform_size_8x8_flag = FALSE; + else + currMB->luma_transform_size_8x8_flag = currMB->temp_transform_size_8x8_flag; + } + + currSlice->rddata->luma_transform_size_8x8_flag = currMB->luma_transform_size_8x8_flag; + + if (p_Inp->rdopt == 3) + { + errdo_get_best_MB(currMB); + } + + //==== reference frames ===== + for (j = 0; j < 4; j++) + { + block_y = currMB->block_y + j; + for (i = 0; i < 4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1)+(i >> 1); + + // backward prediction or intra + if ((currMB->b8x8[k].pdir == 1) || IS_INTRA(currMB)) + { + motion[block_y][block_x].ref_idx [LIST_0] = -1; + motion[block_y][block_x].mv [LIST_0] = zero_mv; + motion[block_y][block_x].ref_pic [LIST_0] = NULL; + + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_0][j][i] = -1; + } + else + { + if (currMB->b8x8[k].bipred && (currMB->b8x8[k].pdir == 2) && is_bipred_enabled(p_Vid, currMB->mb_type)) + { + motion[block_y][block_x].ref_idx [LIST_0] = 0; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][0]; + motion[block_y][block_x].mv [LIST_0] = currSlice->bipred_mv[currMB->b8x8[k].bipred - 1][LIST_0][0][(short) currMB->b8x8[k].mode][j][i]; + + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_0][j][i] = 0; + } + else + { + char cur_ref = p_RDO->l0_refframe[j][i]; + motion[block_y][block_x].ref_idx [LIST_0] = cur_ref; + if(cur_ref >=0) + { + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][(short)cur_ref]; + motion[block_y][block_x].mv [LIST_0] = currSlice->all_mv[LIST_0][(short)cur_ref][(short) currMB->b8x8[k].mode][j][i]; + } + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_0][j][i] = cur_ref; + } + } + + // forward prediction or intra + if ((currMB->b8x8[k].pdir == 0) || IS_INTRA(currMB)) + { + motion[block_y][block_x].ref_idx [LIST_1] = -1; + motion[block_y][block_x].ref_pic [LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_1][j][i] = -1; + } + } + } + + if (currSlice->slice_type == B_SLICE) + { + for (j=0; j<4; j++) + { + block_y = currMB->block_y + j; + for (i=0; i<4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1)+(i >> 1); + + // forward + if (IS_INTRA(currMB)||(currMB->b8x8[k].pdir == 0)) + { + motion[block_y][block_x].ref_idx [LIST_1] = -1; + motion[block_y][block_x].ref_pic [LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_1][j][i] = -1; + } + else + { + if (currMB->b8x8[k].bipred && (currMB->b8x8[k].pdir == 2) && is_bipred_enabled(p_Vid, currMB->mb_type)) + { + motion[block_y][block_x].ref_idx [LIST_1] = 0; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1 + currMB->list_offset][0]; + motion[block_y][block_x].mv [LIST_1] = currSlice->bipred_mv[currMB->b8x8[k].bipred - 1][LIST_1][0][(short) currMB->b8x8[k].mode][j][i]; + + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_1][j][i] = 0; + } + else + { + motion[block_y][block_x].ref_idx [LIST_1] = p_RDO->l1_refframe[j][i]; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1 + currMB->list_offset][(short)p_RDO->l1_refframe[j][i]]; + motion[block_y][block_x].mv [LIST_1] = currSlice->all_mv[LIST_1][(short)p_RDO->l1_refframe[j][i]][(short) currMB->b8x8[k].mode][j][i]; + + // MBAFF or RDOQ + currSlice->rddata->refar[LIST_1][j][i] = p_RDO->l1_refframe[j][i]; + } + } + } + } + } + + //==== intra prediction modes ==== + currMB->c_ipred_mode = currMB->best_c_imode; + currMB->i16offset = currMB->best_i16offset; + currMB->i16mode = currMB->best_i16mode; + currMB->cbp = currMB->best_cbp; + + if(currMB->mb_type == I8MB) + { + memcpy(currMB->intra_pred_modes8x8,currSlice->b8_intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(currMB->intra_pred_modes ,currSlice->b8_intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = 0; j < BLOCK_MULTIPLE; j++) + { + memcpy(&p_Vid->ipredmode [currMB->block_y+j][currMB->block_x], currSlice->b8_ipredmode8x8[j], BLOCK_MULTIPLE * sizeof(char)); + memcpy(&p_Vid->ipredmode8x8[currMB->block_y+j][currMB->block_x], currSlice->b8_ipredmode8x8[j], BLOCK_MULTIPLE * sizeof(char)); + } + } + else if (mode!=I4MB && mode!=I8MB) + { + memset(currMB->intra_pred_modes,DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memset(&p_Vid->ipredmode[j][currMB->block_x], DC_PRED, BLOCK_MULTIPLE * sizeof(char)); + } + // Residue Color Transform + else if (mode == I4MB) + { + memcpy(currMB->intra_pred_modes,currSlice->b4_intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = 0; j < BLOCK_MULTIPLE; j++) + memcpy(&p_Vid->ipredmode[currMB->block_y + j][currMB->block_x],&currSlice->b4_ipredmode[BLOCK_MULTIPLE * j], BLOCK_MULTIPLE * sizeof(char)); + } + + // Copy coding info into rddata structure for MBAFF or RDOQ + currSlice->rddata->c_ipred_mode = currMB->c_ipred_mode; + currSlice->rddata->i16offset = currMB->i16offset; + currSlice->rddata->i16mode = currMB->i16mode; + currSlice->rddata->cbp = currMB->cbp; + currSlice->rddata->cbp_blk = currMB->cbp_blk; + memcpy(currSlice->rddata->intra_pred_modes,currMB->intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(currSlice->rddata->intra_pred_modes8x8,currMB->intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memcpy(&currSlice->rddata->ipredmode[j][currMB->block_x],&ipredmodes[j][currMB->block_x], BLOCK_MULTIPLE * sizeof(char)); + + //==== motion vectors ===== + currSlice->set_motion_vectors_mb (currMB); +} + +/*! +************************************************************************************* +* \brief +* Set stored macroblock parameters (non RDOQ or MBAFF) +************************************************************************************* +*/ +static void set_stored_macroblock_parameters (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + imgpel **imgY = p_Vid->enc_picture->imgY; + imgpel ***imgUV = p_Vid->enc_picture->imgUV; + + int mode = currMB->best_mode; + int i, j, k, ****i4p, ***i3p; + int block_x, block_y; + + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + //===== reconstruction values ===== + + // Luma + copy_image_data_16x16(&imgY[currMB->pix_y], p_RDO->rec_mb[0], currMB->pix_x, 0); + + if (p_Vid->AdaptiveRounding) + { + update_offset_params(currMB, mode, currMB->temp_transform_size_8x8_flag); + } + + if (p_Vid->yuv_format != YUV400) + { + for (k = 0; k < 2; k++) + { + copy_image_data(&imgUV[k][currMB->pix_c_y], p_RDO->rec_mb[k + 1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + } + + //===== coefficients and cbp ===== + i4p = p_RDO->cofAC; + p_RDO->cofAC = currSlice->cofAC; + currSlice->cofAC = i4p; + + i3p = p_RDO->cofDC; + p_RDO->cofDC = currSlice->cofDC; + currSlice->cofDC = i3p; + currMB->cbp = p_RDO->cbp; + currMB->cbp_blk = currSlice->cur_cbp_blk[0]; + currMB->cbp |= currSlice->curr_cbp[0]; + currMB->cbp |= currSlice->curr_cbp[1]; + currSlice->cmp_cbp[1] = currMB->cbp; + currSlice->cmp_cbp[2] = currMB->cbp; + + //==== macroblock type ==== + currMB->mb_type = (short) mode; + + memcpy(currMB->b8x8, currSlice->p_RDO->best8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + + //if P8x8 mode and transform size 4x4 choosen, restore motion vector data for this transform size + if (mode == P8x8 && !currMB->temp_transform_size_8x8_flag && p_Inp->Transform8x8Mode && (currMB->valid_8x8 == TRUE)) + { + RestoreMV8x8(currSlice, 1); + } + + //==== transform size flag ==== + if (p_Vid->P444_joined) + { + if (((currMB->cbp == 0) && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0) && (currMB->mb_type != I4MB && currMB->mb_type != I8MB)) + currMB->luma_transform_size_8x8_flag = FALSE; + else + currMB->luma_transform_size_8x8_flag = currMB->temp_transform_size_8x8_flag; + } + else + { + + if (((currMB->cbp & 15) == 0) && (currMB->mb_type != I4MB && currMB->mb_type != I8MB)) + currMB->luma_transform_size_8x8_flag = FALSE; + else + currMB->luma_transform_size_8x8_flag = currMB->temp_transform_size_8x8_flag; + } + + currSlice->rddata->luma_transform_size_8x8_flag = currMB->luma_transform_size_8x8_flag; + + if (p_Inp->rdopt == 3) + { + errdo_get_best_MB(currMB); + } + + //==== reference frames ===== + for (j = 0; j < 4; j++) + { + block_y = currMB->block_y + j; + for (i = 0; i < 4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1)+(i >> 1); + + // backward prediction or intra + if ((currMB->b8x8[k].pdir == 1) || IS_INTRA(currMB)) + { + motion[block_y][block_x].ref_idx [LIST_0] = -1; + motion[block_y][block_x].ref_pic [LIST_0] = NULL; + motion[block_y][block_x].mv [LIST_0] = zero_mv; + } + else + { + if (currMB->b8x8[k].bipred && (currMB->b8x8[k].pdir == 2) && is_bipred_enabled(p_Vid, currMB->mb_type)) + { + motion[block_y][block_x].ref_idx [LIST_0] = 0; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][0]; + motion[block_y][block_x].mv [LIST_0] = currSlice->bipred_mv[currMB->b8x8[k].bipred - 1][LIST_0][0][(short) currMB->b8x8[k].mode][j][i]; + } + else + { + char cur_ref = p_RDO->l0_refframe[j][i]; + motion[block_y][block_x].ref_idx [LIST_0] = cur_ref; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][(short)cur_ref]; + motion[block_y][block_x].mv [LIST_0] = currSlice->all_mv[LIST_0][(short)cur_ref][(short) currMB->b8x8[k].mode][j][i]; + } + } + + // forward prediction or intra + if ((currMB->b8x8[k].pdir == 0) || IS_INTRA(currMB)) + { + motion[block_y][block_x].ref_idx [LIST_1] = -1; + motion[block_y][block_x].ref_pic [LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + } + } + } + + if (currSlice->slice_type == B_SLICE) + { + for (j=0; j<4; j++) + { + block_y = currMB->block_y + j; + for (i=0; i<4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1)+(i >> 1); + + // forward + if (IS_INTRA(currMB)||(currMB->b8x8[k].pdir == 0)) + { + motion[block_y][block_x].ref_idx [LIST_1] = -1; + motion[block_y][block_x].ref_pic [LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + } + else + { + if (currMB->b8x8[k].bipred && (currMB->b8x8[k].pdir == 2) && is_bipred_enabled(p_Vid, currMB->mb_type)) + { + motion[block_y][block_x].ref_idx [LIST_1] = 0; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1 + currMB->list_offset][0]; + motion[block_y][block_x].mv [LIST_1] = currSlice->bipred_mv[currMB->b8x8[k].bipred - 1][LIST_1][0][(short) currMB->b8x8[k].mode][j][i]; + } + else + { + motion[block_y][block_x].ref_idx [LIST_1] = p_RDO->l1_refframe[j][i]; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1 + currMB->list_offset][(short)p_RDO->l1_refframe[j][i]]; + motion[block_y][block_x].mv [LIST_1] = currSlice->all_mv[LIST_1][(short)p_RDO->l1_refframe[j][i]][(short) currMB->b8x8[k].mode][j][i]; + } + } + } + } + } + + //==== intra prediction modes ==== + currMB->c_ipred_mode = currMB->best_c_imode; + currMB->i16offset = currMB->best_i16offset; + currMB->i16mode = currMB->best_i16mode; + currMB->cbp = currMB->best_cbp; + + if(currMB->mb_type == I8MB) + { + memcpy(currMB->intra_pred_modes8x8,currSlice->b8_intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(currMB->intra_pred_modes ,currSlice->b8_intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = 0; j < BLOCK_MULTIPLE; j++) + { + memcpy(&p_Vid->ipredmode [currMB->block_y+j][currMB->block_x], currSlice->b8_ipredmode8x8[j], BLOCK_MULTIPLE * sizeof(char)); + memcpy(&p_Vid->ipredmode8x8[currMB->block_y+j][currMB->block_x], currSlice->b8_ipredmode8x8[j], BLOCK_MULTIPLE * sizeof(char)); + } + } + else if (mode!=I4MB && mode!=I8MB) + { + memset(currMB->intra_pred_modes,DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memset(&p_Vid->ipredmode[j][currMB->block_x], DC_PRED, BLOCK_MULTIPLE * sizeof(char)); + } + // Residue Color Transform + else if (mode == I4MB) + { + memcpy(currMB->intra_pred_modes,currSlice->b4_intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = 0; j < BLOCK_MULTIPLE; j++) + memcpy(&p_Vid->ipredmode[currMB->block_y + j][currMB->block_x],&currSlice->b4_ipredmode[BLOCK_MULTIPLE * j], BLOCK_MULTIPLE * sizeof(char)); + } + + //==== motion vectors ===== + currSlice->set_motion_vectors_mb (currMB); +} + + +/*! +************************************************************************************* +* \brief +* Set stored macroblock parameters (non RDOQ or MBAFF) +************************************************************************************* +*/ +static void set_stored_macroblock_parameters_sp (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + imgpel **imgY = p_Vid->enc_picture->imgY; + imgpel ***imgUV = p_Vid->enc_picture->imgUV; + + int mode = currMB->best_mode; + int i, j, k, ****i4p, ***i3p; + int block_x, block_y; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + + //===== reconstruction values ===== + + // Luma + copy_image_data_16x16(&imgY[currMB->pix_y], p_RDO->rec_mb[0], currMB->pix_x, 0); + + if((currSlice->slice_type == SP_SLICE) && p_Vid->sp2_frame_indicator==0) + { + for (j = 0; j < MB_BLOCK_SIZE; j++) + memcpy(&p_Vid->lrec[currMB->pix_y+j][currMB->pix_x], p_RDO->lrec_rec[j], MB_BLOCK_SIZE * sizeof(int)); //restore coeff SP frame + } + + if (p_Vid->AdaptiveRounding) + { + update_offset_params(currMB, mode, currMB->temp_transform_size_8x8_flag); + } + + if (p_Vid->yuv_format != YUV400) + { + for (k = 0; k < 2; k++) + { + copy_image_data(&imgUV[k][currMB->pix_c_y], p_RDO->rec_mb[k + 1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + if((currSlice->slice_type == SP_SLICE) && !p_Vid->sp2_frame_indicator) + { + for (k = 0; k < 2; k++) + { + for (j = 0; jmb_cr_size_y; j++) + { + memcpy(&p_Vid->lrec_uv[k][currMB->pix_c_y + j][currMB->pix_c_x], p_RDO->lrec_rec_uv[k][j], p_Vid->mb_cr_size_x * sizeof(int)); + } + } + } + } + + //===== coefficients and cbp ===== + i4p = p_RDO->cofAC; + p_RDO->cofAC = currSlice->cofAC; + currSlice->cofAC = i4p; + + i3p = p_RDO->cofDC; + p_RDO->cofDC = currSlice->cofDC; + currSlice->cofDC = i3p; + currMB->cbp = p_RDO->cbp; + currMB->cbp_blk = currSlice->cur_cbp_blk[0]; + currMB->cbp |= currSlice->curr_cbp[0]; + currMB->cbp |= currSlice->curr_cbp[1]; + currSlice->cmp_cbp[1] = currMB->cbp; + currSlice->cmp_cbp[2] = currMB->cbp; + + //==== macroblock type ==== + currMB->mb_type = (short) mode; + + memcpy(currMB->b8x8, currSlice->p_RDO->best8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + //if P8x8 mode and transform size 4x4 choosen, restore motion vector data for this transform size + if (mode == P8x8 && !currMB->temp_transform_size_8x8_flag && p_Inp->Transform8x8Mode && (currMB->valid_8x8 == TRUE)) + { + RestoreMV8x8(currSlice, 1); + } + + //==== transform size flag ==== + if (p_Vid->P444_joined) + { + if (((currMB->cbp == 0) && currSlice->cmp_cbp[1] == 0 && currSlice->cmp_cbp[2] == 0) && (currMB->mb_type != I4MB && currMB->mb_type != I8MB)) + currMB->luma_transform_size_8x8_flag = FALSE; + else + currMB->luma_transform_size_8x8_flag = currMB->temp_transform_size_8x8_flag; + } + else + { + + if (((currMB->cbp & 15) == 0) && (currMB->mb_type != I4MB && currMB->mb_type != I8MB)) + currMB->luma_transform_size_8x8_flag = FALSE; + else + currMB->luma_transform_size_8x8_flag = currMB->temp_transform_size_8x8_flag; + } + + currSlice->rddata->luma_transform_size_8x8_flag = currMB->luma_transform_size_8x8_flag; + + if (p_Inp->rdopt == 3) + { + errdo_get_best_MB(currMB); + } + + //==== reference frames ===== + for (j = 0; j < 4; j++) + { + block_y = currMB->block_y + j; + for (i = 0; i < 4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1)+(i >> 1); + + // backward prediction or intra + if ((currMB->b8x8[k].pdir == 1) || IS_INTRA(currMB)) + { + motion[block_y][block_x].ref_idx [LIST_0] = -1; + motion[block_y][block_x].ref_pic [LIST_0] = NULL; + motion[block_y][block_x].mv [LIST_0] = zero_mv; + } + else + { + if (currMB->b8x8[k].bipred && (currMB->b8x8[k].pdir == 2) && is_bipred_enabled(p_Vid, currMB->mb_type)) + { + motion[block_y][block_x].ref_idx [LIST_0] = 0; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][0]; + motion[block_y][block_x].mv [LIST_0] = currSlice->bipred_mv[currMB->b8x8[k].bipred - 1][LIST_0][0][(short) currMB->b8x8[k].mode][j][i]; + } + else + { + char cur_ref = p_RDO->l0_refframe[j][i]; + motion[block_y][block_x].ref_idx [LIST_0] = cur_ref; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][(short)cur_ref]; + motion[block_y][block_x].mv [LIST_0] = currSlice->all_mv[LIST_0][(short)cur_ref][(short) currMB->b8x8[k].mode][j][i]; + } + } + + // forward prediction or intra + if ((currMB->b8x8[k].pdir == 0) || IS_INTRA(currMB)) + { + motion[block_y][block_x].ref_idx [LIST_1] = -1; + motion[block_y][block_x].ref_pic [LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + } + } + } + + if (currSlice->slice_type == B_SLICE) + { + for (j=0; j<4; j++) + { + block_y = currMB->block_y + j; + for (i=0; i<4; i++) + { + block_x = currMB->block_x + i; + k = 2*(j >> 1)+(i >> 1); + + // forward + if (IS_INTRA(currMB)||(currMB->b8x8[k].pdir == 0)) + { + motion[block_y][block_x].ref_idx [LIST_1] = -1; + motion[block_y][block_x].ref_pic [LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + } + else + { + if (currMB->b8x8[k].bipred && (currMB->b8x8[k].pdir == 2) && is_bipred_enabled(p_Vid, currMB->mb_type)) + { + motion[block_y][block_x].ref_idx [LIST_1] = 0; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1 + currMB->list_offset][0]; + motion[block_y][block_x].mv [LIST_1] = currSlice->bipred_mv[currMB->b8x8[k].bipred - 1][LIST_1][0][(short) currMB->b8x8[k].mode][j][i]; + } + else + { + motion[block_y][block_x].ref_idx [LIST_1] = p_RDO->l1_refframe[j][i]; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1 + currMB->list_offset][(short)p_RDO->l1_refframe[j][i]]; + motion[block_y][block_x].mv [LIST_1] = currSlice->all_mv[LIST_1][(short)p_RDO->l1_refframe[j][i]][(short) currMB->b8x8[k].mode][j][i]; + } + } + } + } + } + + //==== intra prediction modes ==== + currMB->c_ipred_mode = currMB->best_c_imode; + currMB->i16offset = currMB->best_i16offset; + currMB->i16mode = currMB->best_i16mode; + currMB->cbp = currMB->best_cbp; + + if(currMB->mb_type == I8MB) + { + memcpy(currMB->intra_pred_modes8x8,currSlice->b8_intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(currMB->intra_pred_modes ,currSlice->b8_intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = 0; j < BLOCK_MULTIPLE; j++) + { + memcpy(&p_Vid->ipredmode [currMB->block_y+j][currMB->block_x], currSlice->b8_ipredmode8x8[j], BLOCK_MULTIPLE * sizeof(char)); + memcpy(&p_Vid->ipredmode8x8[currMB->block_y+j][currMB->block_x], currSlice->b8_ipredmode8x8[j], BLOCK_MULTIPLE * sizeof(char)); + } + } + else if (mode!=I4MB && mode!=I8MB) + { + memset(currMB->intra_pred_modes,DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memset(&p_Vid->ipredmode[j][currMB->block_x], DC_PRED, BLOCK_MULTIPLE * sizeof(char)); + } + // Residue Color Transform + else if (mode == I4MB) + { + memcpy(currMB->intra_pred_modes,currSlice->b4_intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = 0; j < BLOCK_MULTIPLE; j++) + memcpy(&p_Vid->ipredmode[currMB->block_y + j][currMB->block_x],&currSlice->b4_ipredmode[BLOCK_MULTIPLE * j], BLOCK_MULTIPLE * sizeof(char)); + } + + //==== motion vectors ===== + currSlice->set_motion_vectors_mb (currMB); +} + + +/*! + ************************************************************************************* + * \brief + * Set reference frames and motion vectors + ************************************************************************************* + */ +void set_ref_and_motion_vectors_P_slice (Macroblock *currMB, PicMotionParams **motion, Info8x8 *part, int block) +{ + int mode = part->mode; + int j = 0, i; + int pmode = (mode==1||mode==2||mode==3 ? mode : 4); + int j0 = ((block >> 1)<<1); + int i0 = ((block & 0x01)<<1); + int i1 = i0 + part_size[pmode][0]; + int j1 = j0 + part_size[pmode][1]; + PicMotionParams *mv = NULL; + + if (part->pdir < 0) + { + for (j = currMB->block_y + j0; j < currMB->block_y + j1; j++) + { + for (i = currMB->block_x + i0; i < currMB->block_x + i1; i++) + { + mv = &motion[j][i]; + mv->ref_pic[LIST_0] = NULL; + mv->ref_pic[LIST_1] = NULL; + mv->mv [LIST_0] = zero_mv; + mv->mv [LIST_1] = zero_mv; + mv->ref_idx[LIST_0] = -1; + mv->ref_idx[LIST_1] = -1; + } + } + return; + } + else + { + Slice *currSlice = currMB->p_Slice; + int block_y; + int fwref = part->ref[LIST_0]; + for (j = j0; j < j1; j++) + { + block_y = currMB->block_y + j; + for (i = i0; i < i1; i++) + { + mv = &motion[block_y][currMB->block_x + i]; + mv->ref_pic[LIST_0] = currSlice->listX[LIST_0+currMB->list_offset][fwref];; + mv->mv [LIST_0] = currSlice->all_mv[LIST_0][fwref][mode][j][i]; + mv->ref_idx[LIST_0] = (char) fwref; + } + } + return; + } +} + + +/*! + ************************************************************************************* + * \brief + * Set reference frames and motion vectors + ************************************************************************************* + */ +static void set_ref_and_motion_vectors_B_slice (Macroblock *currMB, PicMotionParams **motion, Info8x8 *part, int block) +{ + int mode = part->mode; + int i, j=0; + int pmode = (mode==1||mode==2||mode==3 ? mode : 4); + int j0 = ((block >> 1)<<1); + int i0 = ((block & 0x01)<<1); + int i1 = i0 + part_size[pmode][0]; + int j1 = j0 + part_size[pmode][1]; + PicMotionParams *mv = NULL; + + if (part->pdir < 0) + { + for (j = currMB->block_y + j0; j < currMB->block_y + j1; j++) + { + for (i = currMB->block_x + i0; i < currMB->block_x + i1; i++) + { + mv = &motion[j][i]; + mv->ref_pic[LIST_0] = NULL; + mv->ref_pic[LIST_1] = NULL; + mv->mv [LIST_0] = zero_mv; + mv->mv [LIST_1] = zero_mv; + mv->ref_idx[LIST_0] = -1; + mv->ref_idx[LIST_1] = -1; + } + } + return; + } + else + { + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + int block_x, block_y; + + if ((part->pdir == 0 || part->pdir == 2)) + { + if (part->bipred && (part->pdir == 2) && is_bipred_enabled(p_Vid, mode)) + { + for (j=j0; jblock_y + j; + for (i=i0; iblock_x + i; + + motion[block_y][block_x].mv [LIST_0] = currSlice->bipred_mv[part->bipred - 1][LIST_0][0][mode][j][i]; + motion[block_y][block_x].ref_idx [LIST_0] = 0; + motion[block_y][block_x].ref_pic [LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][0]; + } + } + } + else + { + if (mode==0) + { + int fwref; + for (j=j0; jblock_y + j; + for (i=i0; iblock_x + i; + fwref = currSlice->direct_ref_idx[block_y][block_x][LIST_0]; + motion[block_y][block_x].ref_pic[LIST_0] = currSlice->listX[LIST_0 + currMB->list_offset][fwref]; + motion[block_y][block_x].mv [LIST_0] = currSlice->all_mv[LIST_0][fwref][mode][j][i]; + motion[block_y][block_x].ref_idx[LIST_0] = (char) fwref; + } + } + } + else + { + int fwref = part->ref[LIST_0]; + for (j=j0; jblock_y + j; + for (i = i0; i < i1; i++) + { + block_x = currMB->block_x + i; + motion[block_y][block_x].ref_pic[LIST_0] = currSlice->listX[LIST_0+currMB->list_offset][fwref]; + motion[block_y][block_x].mv [LIST_0] = currSlice->all_mv[LIST_0][fwref][mode][j][i]; + motion[block_y][block_x].ref_idx[LIST_0] = (char) fwref; + } + } + } + } + } + else + { + for (j=currMB->block_y + j0; j < currMB->block_y + j1; j++) + { + for (i = currMB->block_x + i0; i < currMB->block_x + i1; i++) + { + motion[j][i].ref_pic [LIST_0] = NULL; + motion[j][i].mv [LIST_0] = zero_mv; + motion[j][i].ref_idx [LIST_0] = -1; + } + } + } + + + if ((part->pdir==1 || part->pdir==2)) + { + if (part->bipred && (part->pdir == 2) && is_bipred_enabled(p_Vid, mode)) + { + for (j=j0; jblock_y + j; + + for (i=i0; iblock_x + i; + + motion[block_y][block_x].mv [LIST_1] = currSlice->bipred_mv[part->bipred - 1][LIST_1][0][mode][j][i]; + motion[block_y][block_x].ref_idx [LIST_1] = 0; + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1+currMB->list_offset][0]; + } + } + } + else + { + if (mode==0) + { + int bwref = part->ref[LIST_1]; + for (j=j0; jblock_y + j; + + for (i = i0; i < i1; i++) + { + block_x = currMB->block_x + i; + if (bwref != currSlice->direct_ref_idx[block_y][block_x][LIST_1]) + printf("error\n"); + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1+currMB->list_offset][bwref]; + motion[block_y][block_x].mv [LIST_1] = currSlice->all_mv[LIST_1][bwref][mode][j][i]; + motion[block_y][block_x].ref_idx [LIST_1] = (char) bwref; // currSlice->direct_ref_idx[block_y][block_x][LIST_1]; + //motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1+currMB->list_offset][(short)motion[block_y][block_x].ref_idx [LIST_1]]; + } + } + } + else + { + int bwref = part->ref[LIST_1]; + for (j=j0; jblock_y + j; + for (i = i0; i < i1; i++) + { + block_x = currMB->block_x + i; + + motion[block_y][block_x].ref_pic [LIST_1] = currSlice->listX[LIST_1+currMB->list_offset][bwref]; + motion[block_y][block_x].mv [LIST_1] = currSlice->all_mv[LIST_1][bwref][mode][j][i]; + motion[block_y][block_x].ref_idx [LIST_1] = (char) bwref; + } + } + } + } + } + else + { + for (block_y = currMB->block_y + j0; block_y < currMB->block_y + j1; block_y++) + { + for (block_x = currMB->block_x + i0; block_x < currMB->block_x + i1; block_x++) + { + motion[block_y][block_x].ref_pic[LIST_1] = NULL; + motion[block_y][block_x].mv [LIST_1] = zero_mv; + motion[block_y][block_x].ref_idx[LIST_1] = -1; + } + } + } + } +} + +/*! + ************************************************************************************* + * \brief + * skip macroblock field inference + * \return + * inferred field flag + ************************************************************************************* + */ +byte field_flag_inference(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + byte mb_field; + + if (currMB->mbAvailA) + { + mb_field = p_Vid->mb_data[currMB->mbAddrA].mb_field; + } + else + { + // check top macroblock pair + if (currMB->mbAvailB) + mb_field = p_Vid->mb_data[currMB->mbAddrB].mb_field; + else + mb_field = 0; + } + + return mb_field; +} + +/*! + ************************************************************************************* + * \brief + * Store motion vectors for 8x8 partition + ************************************************************************************* + */ + +void StoreMVBlock8x8(Slice *currSlice, int dir, int block8x8, int mode, Info8x8 *B8x8Info) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + int i0 = (block8x8 & 0x01) << 1; + int j0 = (block8x8 >> 1) << 1; + int j1 = j0 + 1; + + MotionVector *****all_mv = currSlice->all_mv; + MotionVector **lc_l0_mv8x8 = p_RDO->all_mv8x8[dir][LIST_0]; + MotionVector **lc_l1_mv8x8 = p_RDO->all_mv8x8[dir][LIST_1]; + + if (currSlice->slice_type != B_SLICE ) + { + if (B8x8Info->pdir >= 0) //(mode8!=IBLOCK)&&(mode8!=I16MB)) // && ref != -1) + { + int l0_ref = B8x8Info->ref[LIST_0]; + memcpy(&lc_l0_mv8x8[j0][i0], &all_mv[LIST_0][l0_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[j1][i0], &all_mv[LIST_0][l0_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + } + else + { + int bipred_me = B8x8Info->bipred; + int pdir8 = B8x8Info->pdir; + + if (pdir8 == 0) // list0 + { + int l0_ref = B8x8Info->ref[LIST_0]; + memcpy(&lc_l0_mv8x8[j0][i0], &all_mv[LIST_0][l0_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[j1][i0], &all_mv[LIST_0][l0_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else if (pdir8 == 1) // list1 + { + int l1_ref = B8x8Info->ref[LIST_1]; + memcpy(&lc_l1_mv8x8[j0][i0], &all_mv[LIST_1][l1_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l1_mv8x8[j1][i0], &all_mv[LIST_1][l1_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else if (pdir8==2) // bipred + { + int l0_ref = B8x8Info->ref[LIST_0]; + int l1_ref = B8x8Info->ref[LIST_1]; + if (bipred_me) + { + all_mv = currSlice->bipred_mv[bipred_me - 1]; + } + + memcpy(&lc_l0_mv8x8[j0][i0], &all_mv[LIST_0][l0_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[j1][i0], &all_mv[LIST_0][l0_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l1_mv8x8[j0][i0], &all_mv[LIST_1][l1_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l1_mv8x8[j1][i0], &all_mv[LIST_1][l1_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else + { + error("invalid direction mode", 255); + } + } +} + +/*! + ************************************************************************************* + * \brief + * Store motion vectors of 8x8 partitions of one macroblock + ************************************************************************************* + */ +void StoreMV8x8(Slice *currSlice, int dir) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + int block8x8; + + for (block8x8=0; block8x8<4; block8x8++) + StoreMVBlock8x8(currSlice, dir, block8x8, p_RDO->tr8x8->part[block8x8].mode, &p_RDO->tr8x8->part[block8x8]); +} + +/*! +************************************************************************************* +* \brief +* Restore motion vectors for 8x8 partition +************************************************************************************* +*/ +void RestoreMVBlock8x8(Slice *currSlice, int dir, int block8x8, RD_8x8DATA *tr) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + MotionVector *****all_mv = currSlice->all_mv; + MotionVector **lc_l0_mv8x8 = p_RDO->all_mv8x8[dir][LIST_0]; + MotionVector **lc_l1_mv8x8 = p_RDO->all_mv8x8[dir][LIST_1]; + + short pdir8 = tr->part[block8x8].pdir; + short mode = tr->part[block8x8].mode; + short l0_ref = tr->part[block8x8].ref[LIST_0]; + short l1_ref = tr->part[block8x8].ref[LIST_1]; + short bipred_me = tr->part[block8x8].bipred; + + int i0 = (block8x8 & 0x01) << 1; + int j0 = (block8x8 >> 1) << 1; + int j1 = j0 + 1; + + if (currSlice->slice_type != B_SLICE) + { + if (pdir8>=0) //(mode8!=IBLOCK)&&(mode8!=I16MB)) // && ref != -1) + { + memcpy(&all_mv[LIST_0][l0_ref][4][j0][i0], &lc_l0_mv8x8[j0][i0], 2 * sizeof(MotionVector)); + memcpy(&all_mv[LIST_0][l0_ref][4][j1][i0], &lc_l0_mv8x8[j1][i0], 2 * sizeof(MotionVector)); + } + } + else + { + if (pdir8==0) // list0 + { + memcpy(&all_mv[LIST_0][l0_ref][mode][j0][i0], &lc_l0_mv8x8[j0][i0], 2 * sizeof(MotionVector)); + memcpy(&all_mv[LIST_0][l0_ref][mode][j1][i0], &lc_l0_mv8x8[j1][i0], 2 * sizeof(MotionVector)); + } + else if (pdir8==1) // list1 + { + memcpy(&all_mv[LIST_1][l1_ref][mode][j0][i0], &lc_l1_mv8x8[j0][i0], 2 * sizeof(MotionVector)); + memcpy(&all_mv[LIST_1][l1_ref][mode][j1][i0], &lc_l1_mv8x8[j1][i0], 2 * sizeof(MotionVector)); + } + else if (pdir8==2) // bipred + { + if(bipred_me) + { + all_mv = currSlice->bipred_mv[bipred_me - 1]; + } + + memcpy(&all_mv[LIST_0][l0_ref][mode][j0][i0], &lc_l0_mv8x8[j0][i0], 2 * sizeof(MotionVector)); + memcpy(&all_mv[LIST_0][l0_ref][mode][j1][i0], &lc_l0_mv8x8[j1][i0], 2 * sizeof(MotionVector)); + memcpy(&all_mv[LIST_1][l1_ref][mode][j0][i0], &lc_l1_mv8x8[j0][i0], 2 * sizeof(MotionVector)); + memcpy(&all_mv[LIST_1][l1_ref][mode][j1][i0], &lc_l1_mv8x8[j1][i0], 2 * sizeof(MotionVector)); + } + else + { + error("invalid direction mode", 255); + } + } +} + +/*! + ************************************************************************************* + * \brief + * Restore motion vectors of 8x8 partitions of one macroblock + ************************************************************************************* + */ +void RestoreMV8x8(Slice *currSlice, int dir) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + int block8x8; + + for (block8x8=0; block8x8<4; block8x8++) + RestoreMVBlock8x8(currSlice, dir, block8x8, p_RDO->tr8x8); +} + + +/*! + ************************************************************************************* + * \brief + * Store predictors for 8x8 partition + ************************************************************************************* + */ +void StoreNewMotionVectorsBlock8x8(Slice *currSlice, int dir, int block8x8, Info8x8 *B8x8Info) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + int mode = B8x8Info->mode; + int i0 = (block8x8 & 0x01) << 1; + int j0 = (block8x8 >> 1) << 1; + int j1 = j0 + 1; + + MotionVector ****all_mv_l0 = currSlice->all_mv[LIST_0]; + MotionVector ****all_mv_l1 = currSlice->all_mv[LIST_1]; + MotionVector **lc_l0_mv8x8 = &p_RDO->all_mv8x8[dir][LIST_0][j0]; + MotionVector **lc_l1_mv8x8 = &p_RDO->all_mv8x8[dir][LIST_1][j0]; + + + if (B8x8Info->pdir < 0) + { + memset(&lc_l0_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l0_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + return; + } + + if (currSlice->slice_type != B_SLICE) + { + int l0_ref = B8x8Info->ref[LIST_0]; + memcpy(&lc_l0_mv8x8[0][i0], &all_mv_l0[l0_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[1][i0], &all_mv_l0[l0_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + return; + } + else + { + int bipred_me = B8x8Info->bipred; + int pdir8 = B8x8Info->pdir; + if (bipred_me) + { + all_mv_l0 = currSlice->bipred_mv[bipred_me - 1][LIST_0]; + all_mv_l1 = currSlice->bipred_mv[bipred_me - 1][LIST_1]; + } + + if ((pdir8==0 || pdir8==2)) + { + int l0_ref = B8x8Info->ref[LIST_0]; + memcpy(&lc_l0_mv8x8[0][i0], &all_mv_l0[l0_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[1][i0], &all_mv_l0[l0_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else + { + memset(&lc_l0_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l0_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } + + if ((pdir8==1 || pdir8==2)) + { + int l1_ref = B8x8Info->ref[LIST_1]; + memcpy(&lc_l1_mv8x8[0][i0], &all_mv_l1[l1_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l1_mv8x8[1][i0], &all_mv_l1[l1_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else + { + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } + } +} + + +/*! + ************************************************************************************* + * \brief + * Store predictors for 8x8 partition + ************************************************************************************* + */ +void store_8x8_motion_vectors_p_slice(Slice *currSlice, int dir, int block8x8, Info8x8 *B8x8Info) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int i0 = (block8x8 & 0x01) << 1; + int j0 = (block8x8 >> 1) << 1; + + MotionVector **lc_l0_mv8x8 = &p_RDO->all_mv8x8[dir][LIST_0][j0]; + MotionVector **lc_l1_mv8x8 = &p_RDO->all_mv8x8[dir][LIST_1][j0]; + + if (B8x8Info->pdir < 0) + { + memset(&lc_l0_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l0_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } + else + { + int j1 = j0 + 1; + MotionVector **all_mv_l0 = currSlice->all_mv[LIST_0][(short) B8x8Info->ref[LIST_0]][(short)B8x8Info->mode]; + memcpy(&lc_l0_mv8x8[0][i0], &all_mv_l0[j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[1][i0], &all_mv_l0[j1][i0], 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } +} + + +/*! + ************************************************************************************* + * \brief + * Store predictors for 8x8 partition + ************************************************************************************* + */ +void store_8x8_motion_vectors_b_slice(Slice *currSlice, int dir, int block8x8, Info8x8 *B8x8Info) +{ + RDOPTStructure *p_RDO = currSlice->p_RDO; + int i0 = (block8x8 & 0x01) << 1; + int j0 = (block8x8 >> 1) << 1; + + MotionVector **lc_l0_mv8x8 = &p_RDO->all_mv8x8[dir][LIST_0][j0]; + MotionVector **lc_l1_mv8x8 = &p_RDO->all_mv8x8[dir][LIST_1][j0]; + + if (B8x8Info->pdir < 0) + { + memset(&lc_l0_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l0_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } + else + { + int mode = B8x8Info->mode; + int j1 = j0 + 1; + MotionVector ****all_mv_l0 = currSlice->all_mv[LIST_0]; + MotionVector ****all_mv_l1 = currSlice->all_mv[LIST_1]; + + int bipred_me = B8x8Info->bipred; + int pdir8 = B8x8Info->pdir; + if (bipred_me) + { + all_mv_l0 = currSlice->bipred_mv[bipred_me - 1][LIST_0]; + all_mv_l1 = currSlice->bipred_mv[bipred_me - 1][LIST_1]; + } + + if ((pdir8==0 || pdir8==2)) + { + int l0_ref = B8x8Info->ref[LIST_0]; + memcpy(&lc_l0_mv8x8[0][i0], &all_mv_l0[l0_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l0_mv8x8[1][i0], &all_mv_l0[l0_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else + { + memset(&lc_l0_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l0_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } + + if ((pdir8==1 || pdir8==2)) + { + int l1_ref = B8x8Info->ref[LIST_1]; + memcpy(&lc_l1_mv8x8[0][i0], &all_mv_l1[l1_ref][mode][j0][i0], 2 * sizeof(MotionVector)); + memcpy(&lc_l1_mv8x8[1][i0], &all_mv_l1[l1_ref][mode][j1][i0], 2 * sizeof(MotionVector)); + } + else + { + memset(&lc_l1_mv8x8[0][i0], 0, 2 * sizeof(MotionVector)); + memset(&lc_l1_mv8x8[1][i0], 0, 2 * sizeof(MotionVector)); + } + } +} + + +/*! +************************************************************************ +* \brief +* Sets MBAFF RD parameters +************************************************************************ +*/ +void set_mbaff_parameters(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int j, i; + int mode = currMB->best_mode; + char **ipredmodes = p_Vid->ipredmode; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + RD_DATA *rdopt = currSlice->rddata; + + + //===== reconstruction values ===== + copy_image_data_16x16(rdopt->rec_mb[0], &p_Vid->enc_picture->imgY[currMB->pix_y], 0, currMB->pix_x); + + if (p_Vid->yuv_format != YUV400) + { + copy_image_data(rdopt->rec_mb[1], &p_Vid->enc_picture->imgUV[0][currMB->pix_c_y], 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + copy_image_data(rdopt->rec_mb[2], &p_Vid->enc_picture->imgUV[1][currMB->pix_c_y], 0, currMB->pix_c_x, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + //===== coefficients and cbp ===== + rdopt->mode = mode; + rdopt->i16offset = currMB->i16offset; + rdopt->i16mode = currMB->i16mode; + rdopt->cbp = currMB->cbp; + rdopt->cbp_blk = currMB->cbp_blk; + rdopt->mb_type = currMB->mb_type; + + rdopt->luma_transform_size_8x8_flag = currMB->luma_transform_size_8x8_flag; + + if(rdopt->mb_type == 0 && mode != 0) + { + mode=0; + rdopt->mode=0; + } + + memcpy(rdopt->cofAC[0][0][0], currSlice->cofAC[0][0][0], (4+p_Vid->num_blk8x8_uv) * 4 * 2 * 65 * sizeof(int)); + memcpy(rdopt->cofDC[0][0], currSlice->cofDC[0][0], 3 * 2 * 18 * sizeof(int)); + + memcpy(rdopt->b8x8, currMB->b8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + //==== reference frames ===== + if (currSlice->slice_type == B_SLICE) + { + if (p_Inp->BiPredMERefinements == 1) + { + int k; + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + for (i = 0; i < BLOCK_MULTIPLE; i++) + { + k = 2*(j >> 1)+(i >> 1); + if (currMB->b8x8[k].bipred == 0) + { + rdopt->refar[LIST_0][j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + rdopt->refar[LIST_1][j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + } + else + { + rdopt->refar[LIST_0][j][i] = 0; + rdopt->refar[LIST_1][j][i] = 0; + } + } + } + } + else + { + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + for (i = 0; i < BLOCK_MULTIPLE; i++) + { + rdopt->refar[LIST_0][j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + rdopt->refar[LIST_1][j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + } + } + } + } + else + { + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + for (i = 0; i < BLOCK_MULTIPLE; i++) + { + rdopt->refar[LIST_0][j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_0]; + //rdopt->refar[LIST_1][j][i] = motion[currMB->block_y + j][currMB->block_x + i].ref_idx[LIST_1]; + } + } + } + + memcpy(rdopt->intra_pred_modes, currMB->intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(rdopt->intra_pred_modes8x8,currMB->intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + memcpy(&rdopt->ipredmode[j][currMB->block_x],&ipredmodes[j][currMB->block_x], BLOCK_MULTIPLE * sizeof(char)); + } +} + + +void assign_enc_picture_params (Macroblock *currMB, int mode, Info8x8 *best, int block) +{ + int i,j; + int block_y, block_x; + int list; + MotionVector **curr_mv = NULL; + int list_offset = currMB->list_offset; + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int maxlist = (currSlice->slice_type == B_SLICE) ? 1: 0; + StorablePicture *listX = NULL; + + int start_x = 0, start_y = 0, end_x = BLOCK_MULTIPLE, end_y = BLOCK_MULTIPLE; + + switch (mode) + { + case 1: + start_x = 0; + start_y = 0; + end_x = BLOCK_MULTIPLE; + end_y = BLOCK_MULTIPLE; + break; + case 2: + start_x = 0; + start_y = block; + end_x = BLOCK_MULTIPLE; + end_y = block + 2; + break; + case 3: + start_x = block; + start_y = 0; + end_x = block + 2; + end_y = BLOCK_MULTIPLE; + break; + case 4: //P8x8 + default: + start_x = ((block>>1) & 0x01)* 2; + start_y = ((block>>1) & 0x02); + end_x = start_x + 2; + end_y = start_y + 2; + break; + } + + for (list = 0; list <= maxlist; list++) + { + if ((best->pdir != 2) && (best->pdir != list)) + { + for (j = currMB->block_y + start_y; j < currMB->block_y + end_y; j++) + { + for (i = currMB->block_x + start_x; i < currMB->block_x + end_x; i++) + { + motion[j][i].ref_pic[list] = NULL; + motion[j][i].mv[list] = zero_mv; + motion[j][i].ref_idx[list] = - 1; + } + } + } + else + { + switch (best->bipred) + { + case 0: + { + int bestref = best->ref[list]; + curr_mv = currSlice->all_mv[list][bestref][mode]; + listX = currSlice->listX[list + list_offset][bestref]; + if(listX->view_id == 1) + { + int a = 0; + } + } + break; + case 1: + curr_mv = currSlice->bipred_mv[0][list][0][mode] ; //best->ref[LIST_0] has to be zero in this case + listX = currSlice->listX[list + list_offset][0]; + break; + case 2: + curr_mv = currSlice->bipred_mv[1][list][0][mode] ; //best->ref[LIST_0] has to be zero in this case + listX = currSlice->listX[list + list_offset][0]; + break; + default: + break; + } + + for (j = start_y; j < end_y; j++) + { + block_y = currMB->block_y + j; + for (i = start_x; i < end_x; i++) + { + block_x = currMB->block_x + i; + motion[block_y][block_x].ref_pic [list] = listX; + motion[block_y][block_x].mv [list] = curr_mv[j][i]; + } + } + } + } +} + +/*! + ************************************************************************************* + * \brief + * Set block 8x8 mode information + ************************************************************************************* + */ +void set_block8x8_info(Block8x8Info *b8x8info, int mode, int block, Info8x8 *best) +{ + //----- set reference frame and direction parameters ----- + if (mode==3) + { + b8x8info->best[3][block ] = *best; + b8x8info->best[3][block+2] = *best; + } + else if (mode==2) + { + b8x8info->best[2][2*block ] = *best; + b8x8info->best[2][2*block + 1] = *best; + } + else if (mode==1) + { + b8x8info->best[1][0] = *best; + b8x8info->best[1][1] = *best; + b8x8info->best[1][2] = *best; + b8x8info->best[1][3] = *best; + + } + else //P8x8 + { + b8x8info->best[mode][block] = *best; + } +} + +/*! + ************************************************************************************* + * \brief + * Set block 8x8 mode information for P8x8 mode + ************************************************************************************* + */ +void set_subblock8x8_info(Block8x8Info *b8x8info,int mode, int block, RD_8x8DATA *tr) +{ + b8x8info->best [mode][block] = tr->part[block]; +} + + + +void update_refresh_map(Macroblock *currMB, int intra, int intra1) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + if (p_Inp->RestrictRef==1) + { + // Modified for Fast Mode Decision. Inchoon Choi, SungKyunKwan Univ. + if (p_Inp->rdopt<2) + { + p_Vid->refresh_map[2*currMB->mb_y ][2*currMB->mb_x ] = (byte) (intra ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y ][2*currMB->mb_x+1] = (byte) (intra ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y + 1][2*currMB->mb_x ] = (byte) (intra ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y + 1][2*currMB->mb_x+1] = (byte) (intra ? 1 : 0); + } + else if (p_Inp->rdopt == 3) + { + p_Vid->refresh_map[2*currMB->mb_y ][2*currMB->mb_x ] = (byte) (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y ][2*currMB->mb_x+1] = (byte) (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y + 1][2*currMB->mb_x ] = (byte) (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y + 1][2*currMB->mb_x+1] = (byte) (intra1==0 && (currMB->mb_type==I16MB || currMB->mb_type==I4MB) ? 1 : 0); + } + } + else if (p_Inp->RestrictRef==2) + { + p_Vid->refresh_map[2*currMB->mb_y ][2*currMB->mb_x ] = (byte) (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y ][2*currMB->mb_x+1] = (byte) (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y + 1][2*currMB->mb_x ] = (byte) (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0); + p_Vid->refresh_map[2*currMB->mb_y + 1][2*currMB->mb_x+1] = (byte) (currMB->mb_type==I16MB || currMB->mb_type==I4MB ? 1 : 0); + } +} + +int valid_intra_mode(Slice *currSlice, int ipmode) +{ + InputParameters *p_Inp = currSlice->p_Inp; + + if (p_Inp->IntraDisableInterOnly==0 || (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE)) + { + if (p_Inp->Intra4x4ParDisable && (ipmode==VERT_PRED||ipmode==HOR_PRED)) + return 0; + + if (p_Inp->Intra4x4DiagDisable && (ipmode==DIAG_DOWN_LEFT_PRED||ipmode==DIAG_DOWN_RIGHT_PRED)) + return 0; + + if (p_Inp->Intra4x4DirDisable && ipmode>=VERT_RIGHT_PRED) + return 0; + } + return 1; +} + +distblk compute_sad4x4_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost) +{ + imgpel *cur_line, *prd_line; + int i32Cost = 0; + int imin_cost = dist_down(min_cost); + + int j; + for (j = 0; j < BLOCK_SIZE; j++) + { + cur_line = &cur_img[j][pic_opix_x]; + prd_line = prd_img[j]; + + i32Cost += iabs(cur_line[0] - prd_line[0]); + i32Cost += iabs(cur_line[1] - prd_line[1]); + i32Cost += iabs(cur_line[2] - prd_line[2]); + i32Cost += iabs(cur_line[3] - prd_line[3]); + + if (i32Cost > imin_cost) + { + return(min_cost); + } + } + return dist_scale(i32Cost); +} + +distblk compute_sse4x4_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost) +{ + int j, i; + imgpel *cur_line, *prd_line; + int i32Cost = 0; + int imin_cost = dist_down(min_cost); + for (j = 0; j < BLOCK_SIZE; j++) + { + cur_line = &cur_img[j][pic_opix_x]; + prd_line = prd_img[j]; + for (i = 0; i < BLOCK_SIZE; i++) + { + i32Cost += iabs2(*cur_line++ - *prd_line++); + } + + if (i32Cost > imin_cost) + { + return(min_cost); + } + } + return dist_scale(i32Cost); +} + +distblk compute_satd4x4_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost) +{ + int j, i; + imgpel *cur_line, *prd_line; + short diff[16]; + + short *d = &diff[0]; + + for (j = 0; j < BLOCK_SIZE; j++) + { + cur_line = &cur_img[j][pic_opix_x]; + prd_line = prd_img[j]; + + for (i = 0; i < BLOCK_SIZE; i++) + { + *d++ = *cur_line++ - *prd_line++; + } + } + + return dist_scale(HadamardSAD4x4 (diff)); +} + +static distblk compute_comp4x4_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **prd_img, int pic_opix_x, distblk min_cost) +{ + int j, i; + imgpel *cur_line, *prd_line; + short diff[16]; + + short *d = &diff[0]; + + for (j = 0; j < BLOCK_SIZE; j++) + { + cur_line = &cur_img[j][pic_opix_x]; + prd_line = prd_img[j]; + + for (i = 0; i < BLOCK_SIZE; i++) + { + *d++ = *cur_line++ - *prd_line++; + } + } + return(p_Vid->distortion4x4 (diff, min_cost)); +} + + + +void update_qp_cbp_tmp(Macroblock *currMB, int cbp) +{ + if (((cbp!=0 || currMB->best_mode==I16MB) && (currMB->best_mode!=IPCM) )) + currMB->prev_cbp = 1; + else if ((cbp==0) || (currMB->best_mode==IPCM)) + { + currMB->prev_cbp = 0; + currMB->qp = currMB->prev_qp; + currMB->p_Vid->qp = currMB->qp; + update_qp(currMB); + } +} + +/*! + ************************************************************************************* + * \brief + * Update QP Parameters (in case of SKIP MBs or MBAFF) + ************************************************************************************* + */ + +void update_qp_cbp(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + // delta_qp is present only for non-skipped macroblocks + if ((currMB->cbp!=0 || currMB->best_mode == I16MB) && (currMB->best_mode != IPCM)) + currMB->prev_cbp = 1; + else + { + currMB->prev_cbp = 0; + currMB->qp = currMB->prev_qp; + p_Vid->qp = currMB->qp; + update_qp(currMB); + } + + if (p_Inp->MbInterlace) + { + Slice *currSlice = currMB->p_Slice; + // update rdopt buffered qps... + currSlice->rddata->qp = currMB->qp; + currSlice->rddata->prev_cbp = currMB->prev_cbp; + } +} + +/*! +*************************************************************************** +// For MB level field/frame coding +*************************************************************************** +*/ +void copy_rdopt_data (Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + int i, j; + RD_DATA *rdopt = currSlice->rddata; + + int mode; + short b8mode, b8pdir; + int block_y; + + int list_offset = currMB->list_offset; + + mode = rdopt->mode; + currMB->mb_type = rdopt->mb_type; // copy mb_type + currMB->cbp = rdopt->cbp; // copy cbp + currMB->cbp_blk = rdopt->cbp_blk; // copy cbp_blk + currMB->i16offset = rdopt->i16offset; + currMB->i16mode = rdopt->i16mode; + + currMB->prev_qp = rdopt->prev_qp; + currMB->prev_dqp = rdopt->prev_dqp; + currMB->prev_cbp = rdopt->prev_cbp; + currMB->qp = rdopt->qp; + update_qp (currMB); + + currMB->c_ipred_mode = rdopt->c_ipred_mode; + + memcpy(currSlice->cofAC[0][0][0],rdopt->cofAC[0][0][0], (4 + p_Vid->num_blk8x8_uv) * 4 * 2 * 65 * sizeof(int)); + memcpy(currSlice->cofDC[0][0],rdopt->cofDC[0][0], 3 * 2 * 18 * sizeof(int)); + + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + block_y = currMB->block_y + j; + for (i = 0; i < BLOCK_MULTIPLE; i++) + { + motion[block_y][currMB->block_x + i].ref_idx [LIST_0] = rdopt->refar[LIST_0][j][i]; + motion[block_y][currMB->block_x + i].ref_pic [LIST_0] = rdopt->refar[LIST_0][j][i] < 0 ? NULL : + currSlice->listX[LIST_0 + list_offset][(short)rdopt->refar[LIST_0][j][i]]; + } + } + + if (currSlice->slice_type == B_SLICE) + { + for (j = 0; j < BLOCK_MULTIPLE; j++) + { + block_y = currMB->block_y + j; + for (i = 0; i < BLOCK_MULTIPLE; i++) + { + motion[block_y][currMB->block_x + i].ref_idx [LIST_1] = rdopt->refar[LIST_1][j][i]; + motion[block_y][currMB->block_x + i].ref_pic [LIST_1] = rdopt->refar[LIST_1][j][i] < 0 ? NULL : + currSlice->listX[LIST_1 + list_offset][(short) rdopt->refar[LIST_1][j][i]]; + } + } + } + + + //===== reconstruction values ===== + copy_image_data_16x16(&p_Vid->enc_picture->imgY[currMB->pix_y], rdopt->rec_mb[0], currMB->pix_x, 0); + + if (p_Vid->yuv_format != YUV400) + { + copy_image_data(&p_Vid->enc_picture->imgUV[0][currMB->pix_c_y], rdopt->rec_mb[1], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + copy_image_data(&p_Vid->enc_picture->imgUV[1][currMB->pix_c_y], rdopt->rec_mb[2], currMB->pix_c_x, 0, p_Vid->mb_cr_size_x, p_Vid->mb_cr_size_y); + } + + + memcpy(currMB->b8x8, rdopt->b8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + currMB->luma_transform_size_8x8_flag = rdopt->luma_transform_size_8x8_flag; + + //==== intra prediction modes ==== + if (mode == P8x8) + { + memcpy(currMB->intra_pred_modes,rdopt->intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + for (j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memcpy(&p_Vid->ipredmode[j][currMB->block_x],&rdopt->ipredmode[j][currMB->block_x], BLOCK_MULTIPLE * sizeof(char)); + } + else if (mode != I4MB && mode != I8MB) + { + memset(currMB->intra_pred_modes,DC_PRED, MB_BLOCK_PARTITIONS * sizeof(char)); + for (j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memset(&p_Vid->ipredmode[j][currMB->block_x],DC_PRED, BLOCK_MULTIPLE * sizeof(char)); + } + else if (mode == I4MB || mode == I8MB) + { + memcpy(currMB->intra_pred_modes,rdopt->intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(currMB->intra_pred_modes8x8,rdopt->intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for (j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + { + memcpy(&p_Vid->ipredmode[j][currMB->block_x],&rdopt->ipredmode[j][currMB->block_x], BLOCK_MULTIPLE * sizeof(char)); + } + } + + if (currSlice->mb_aff_frame_flag || (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1)) + { + // motion vectors + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + copy_motion_vectors_MB (currSlice, rdopt); + + if (!IS_INTRA(currMB)) + { + currMB->b8x8[0].bipred = 0; + currMB->b8x8[1].bipred = 0; + currMB->b8x8[2].bipred = 0; + currMB->b8x8[3].bipred = 0; + + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4; i++) + { + b8mode = currMB->b8x8[(i >> 1) + 2 * (j >> 1)].mode; + b8pdir = currMB->b8x8[(i >> 1) + 2 * (j >> 1)].pdir; + + if (b8pdir!=1) + { + motion[j+currMB->block_y][i+currMB->block_x].mv[LIST_0] = rdopt->all_mv[LIST_0][(short)rdopt->refar[LIST_0][j][i]][b8mode][j][i]; + } + else + { + motion[j+currMB->block_y][i+currMB->block_x].mv[LIST_0] = zero_mv; + } + if (currSlice->slice_type == B_SLICE) + { + if (b8pdir!=0) + { + motion[j+currMB->block_y][i+currMB->block_x].mv[LIST_1] = rdopt->all_mv[LIST_1][(short)rdopt->refar[LIST_1][j][i]][b8mode][j][i]; + } + else + { + motion[j+currMB->block_y][i+currMB->block_x].mv[LIST_1] = zero_mv; + } + } + } + } + } + else + { + + if (currSlice->slice_type == B_SLICE) + { + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4; i++) + { + motion[j][i].mv[LIST_0] = zero_mv; + motion[j][i].mv[LIST_1] = zero_mv; + } + } + } + else + { + for (j = currMB->block_y; j < currMB->block_y + 4; j++) + { + for (i = currMB->block_x; i < currMB->block_x + 4; i++) + { + motion[j][i].mv[LIST_0] = zero_mv; + } + } + } + } + } +} // end of copy_rdopt_data + + + diff --git a/lencod/src/rdopt_coding_state.c b/lencod/src/rdopt_coding_state.c new file mode 100644 index 0000000..aa9555b --- /dev/null +++ b/lencod/src/rdopt_coding_state.c @@ -0,0 +1,299 @@ + +/*! + *************************************************************************** + * \file rdopt_coding_state.c + * + * \brief + * Storing/restoring coding state for + * Rate-Distortion optimized mode decision + * + * \author + * Heiko Schwarz + * + * \date + * 17. April 2001 + **************************************************************************/ + +#include "global.h" + +#include "rdopt_coding_state.h" +#include "cabac.h" +#include "memalloc.h" + +/*! + ************************************************************************ + * \brief + * delete structure for storing coding state + ************************************************************************ + */ +void delete_coding_state (CSobj *cs) +{ + if (cs != NULL) + { + //=== structures of data partition array === + if (cs->encenv != NULL) + { + free (cs->encenv); + cs->encenv = NULL; + } + if (cs->bitstream != NULL) + { + free (cs->bitstream); + cs->bitstream = NULL; + } + + //=== contexts for binary arithmetic coding === + delete_contexts_MotionInfo (cs->mot_ctx); + delete_contexts_TextureInfo (cs->tex_ctx); + + if (cs->cbp_bits_8x8 != NULL) + { + free (cs->cbp_bits_8x8); + cs->cbp_bits_8x8 = NULL; + } + + //=== coding state structure === + free (cs); + cs=NULL; + } +} + + +/*! + ************************************************************************ + * \brief + * create structure for storing coding state + ************************************************************************ + */ +CSobj *create_coding_state (InputParameters *p_Inp) +{ + CSobj *cs; + + //=== coding state structure === + if ((cs = (CSobj *) calloc (1, sizeof(CSobj))) == NULL) + no_mem_exit("init_coding_state: cs"); + + //=== important variables of data partition array === + cs->no_part = p_Inp->partition_mode == 0 ? 1 : 3; + if (p_Inp->symbol_mode == CABAC) + { + if ((cs->encenv = (EncodingEnvironment*) calloc (cs->no_part, sizeof(EncodingEnvironment))) == NULL) + no_mem_exit("init_coding_state: cs->encenv"); + + if ((cs->bitstream = (Bitstream*) calloc (cs->no_part, sizeof(Bitstream))) == NULL) + no_mem_exit("init_coding_state: cs->bitstream"); + //=== context for binary arithmetic coding === + cs->mot_ctx = create_contexts_MotionInfo (); + cs->tex_ctx = create_contexts_TextureInfo(); + + } + else + { + cs->encenv = NULL; + if ((cs->bitstream = (Bitstream*) calloc (cs->no_part, sizeof(Bitstream))) == NULL) + no_mem_exit("init_coding_state: cs->bitstream"); + + cs->mot_ctx = NULL; + cs->tex_ctx = NULL; + } + + if (p_Inp->ProfileIDC == 244) + { + if ((cs->cbp_bits_8x8 = (int64 *) calloc (3, sizeof(int64))) == NULL) + no_mem_exit("init_coding_state: cs->cbp_bits_8x8"); + } + else + cs->cbp_bits_8x8 = NULL; + + return cs; +} + +/*! + ************************************************************************ + * \brief + * store coding state (for non rdo case. basically a dummy function) + ************************************************************************ + */ +static void store_coding_state_nordo (Macroblock *currMB, CSobj *cs) +{ +} + + +/*! + ************************************************************************ + * \brief + * store cavlc coding state (for rd-optimized mode decision) + ************************************************************************ + */ +void store_coding_state_cavlc (Macroblock *currMB, CSobj *cs) +{ + int i; + Slice *currSlice = currMB->p_Slice; + int i_last = currSlice->idr_flag? 1 : cs->no_part; + + //=== important variables of data partition array === + for (i = 0; i < i_last; i++) + { + cs->bitstream[i] = *currSlice->partArr[i].bitstream; + } + + //=== syntax element number and bitcounters === + cs->bits = currMB->bits; + + //=== elements of current macroblock === + if (currMB->mb_type <= P8x8) + memcpy (cs->mvd, currMB->mvd, BLOCK_CONTEXT * sizeof(short)); + memcpy (cs->cbp_bits, currMB->cbp_bits, 3 * sizeof(int64)); + + if (currSlice->P444_joined) + memcpy (cs->cbp_bits_8x8, currMB->cbp_bits_8x8, 3 * sizeof(int64)); +} + +/*! + ************************************************************************ + * \brief + * store cabac coding state (for rd-optimized mode decision) + ************************************************************************ + */ +static void store_coding_state_cabac (Macroblock *currMB, CSobj *cs) +{ + int i; + Slice *currSlice = currMB->p_Slice; + int i_last = currSlice->idr_flag? 1:cs->no_part; + DataPartition *partArr = &currSlice->partArr[0]; + + //=== important variables of data partition array === + //only one partition for an IDR picture + for (i = 0; i < i_last; i++) + { + cs->bitstream[i] = *partArr->bitstream; + cs->encenv[i] = (partArr++)->ee_cabac; + } + + //=== contexts for binary arithmetic coding === + *cs->mot_ctx = *currSlice->mot_ctx; + *cs->tex_ctx = *currSlice->tex_ctx; + + //=== syntax element number and bitcounters === + cs->bits = currMB->bits; + + //=== elements of current macroblock === + if (currMB->mb_type <= P8x8) + memcpy (cs->mvd, currMB->mvd, BLOCK_CONTEXT * sizeof(short)); + memcpy (cs->cbp_bits, currMB->cbp_bits, 3 * sizeof(int64)); + + if (currSlice->P444_joined) + memcpy (cs->cbp_bits_8x8, currMB->cbp_bits_8x8, 3 * sizeof(int64)); +} + +/*! + ************************************************************************ + * \brief + * restore coding state (for non rdo case. basically a dummy function) + ************************************************************************ + */ +static void reset_coding_state_nordo (Macroblock *currMB, CSobj *cs) +{ +} + +/*! + ************************************************************************ + * \brief + * restore coding state (for rd-optimized mode decision) + ************************************************************************ + */ +void reset_coding_state_cavlc (Macroblock *currMB, CSobj *cs) +{ + int i; + Slice *currSlice = currMB->p_Slice; + int i_last = currSlice->idr_flag? 1:cs->no_part; + + //=== important variables of data partition array === + //only one partition for an IDR picture + for (i = 0; i < i_last; i++) + { + //--- parameters of encoding environments --- + *currSlice->partArr[i].bitstream = cs->bitstream[i]; + } + + //=== syntax element number and bit counters === + currMB->bits = cs->bits; + + //=== elements of current macroblock === + if (currMB->mb_type <= P8x8) + memcpy (currMB->mvd, cs->mvd, BLOCK_CONTEXT * sizeof(short)); + memcpy (currMB->cbp_bits, cs->cbp_bits, 3 * sizeof(int64)); + if(currSlice->P444_joined) + memcpy (currMB->cbp_bits_8x8, cs->cbp_bits_8x8, 3 * sizeof(int64)); +} + + +/*! + ************************************************************************ + * \brief + * restore coding state (for rd-optimized mode decision) + ************************************************************************ + */ +static void reset_coding_state_cabac (Macroblock *currMB, CSobj *cs) +{ + int i; + Slice *currSlice = currMB->p_Slice; + int i_last = currSlice->idr_flag? 1:cs->no_part; + DataPartition *partArr = &currSlice->partArr[0]; + + //=== important variables of data partition array === + //only one partition for an IDR picture + for (i = 0; i < i_last; i++) + { + //--- parameters of encoding environments --- + *partArr->bitstream = cs->bitstream[i]; + (partArr++)->ee_cabac = cs->encenv[i]; + } + + //=== contexts for binary arithmetic coding === + *currSlice->mot_ctx = *cs->mot_ctx; + *currSlice->tex_ctx = *cs->tex_ctx; + + //=== syntax element number and bit counters === + currMB->bits = cs->bits; + + //=== elements of current macroblock === + if (currMB->mb_type <= P8x8) + memcpy (currMB->mvd, cs->mvd, BLOCK_CONTEXT * sizeof(short)); + + memcpy (currMB->cbp_bits, cs->cbp_bits, 3 * sizeof(int64)); + + if(currSlice->P444_joined) + memcpy (currMB->cbp_bits_8x8, cs->cbp_bits_8x8, 3 * sizeof(int64)); +} + + + + +/*! + ************************************************************************ + * \brief + * Select methods given entropy coding type + ************************************************************************ + */ +void init_coding_state_methods(Slice *currSlice) +{ + if (currSlice->p_Inp->rdopt == 0) + { + currSlice->reset_coding_state = reset_coding_state_nordo; + currSlice->store_coding_state = store_coding_state_nordo; + } + else + { + if (currSlice->symbol_mode == CABAC) + { + currSlice->reset_coding_state = reset_coding_state_cabac; + currSlice->store_coding_state = store_coding_state_cabac; + } + else + { + currSlice->reset_coding_state = reset_coding_state_cavlc; + currSlice->store_coding_state = store_coding_state_cavlc; + } + } +} diff --git a/lencod/src/rdoq.c b/lencod/src/rdoq.c new file mode 100644 index 0000000..e25a602 --- /dev/null +++ b/lencod/src/rdoq.c @@ -0,0 +1,496 @@ +/*! + ************************************************************************************* + * \file rdoq.c + * + * \brief + * Rate Distortion Optimized Quantization based on VCEG-AH21 + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "image.h" +#include "fmo.h" +#include "macroblock.h" +#include "mb_access.h" +#include "rdopt.h" +#include "rdoq.h" +#include "mv_search.h" + +#define RDOQ_BASE 0 + + +/*! +**************************************************************************** +* \brief +* Initialize the parameters related to RDO_Q in slice level +**************************************************************************** +*/ +void init_rdoq_slice(Slice *currSlice) +{ + //currSlice->norm_factor_4x4 = (double) ((int64) 1 << (2 * DQ_BITS + 19)); // norm factor 4x4 is basically (1<<31) + //currSlice->norm_factor_8x8 = (double) ((int64) 1 << (2 * Q_BITS_8 + 9)); // norm factor 8x8 is basically (1<<41) + currSlice->norm_factor_4x4 = pow(2, (2 * DQ_BITS + 19)); + currSlice->norm_factor_8x8 = pow(2, (2 * Q_BITS_8 + 9)); +} +/*! +**************************************************************************** +* \brief +* Initialize levelData for Chroma DC +**************************************************************************** +*/ +int init_trellis_data_DC_cr_CAVLC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params, const byte *p_scan, + levelDataStruct *dataLevel) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int i, j, coeff_ctr, end_coeff_ctr = p_Vid->num_cdc_coeff; + int *m7; + int q_bits = Q_BITS + qp_per + 1; + int q_offset = ( 1 << (q_bits - 1) ); + double err; + int scaled_coeff, level, lowerInt, k; + double estErr = (double) estErr4x4[qp_rem][0][0] / currSlice->norm_factor_4x4; // note that we could also use int64 + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + j = *p_scan++; // horizontal position + i = *p_scan++; // vertical position + + m7 = &tblock[j][i]; + if (*m7 == 0) + { + dataLevel->level[0] = 0; + dataLevel->levelDouble = 0; + dataLevel->errLevel[0] = 0.0; + dataLevel->noLevels = 1; + err = 0.0; + dataLevel->pre_level = 0; + dataLevel->sign = 0; + } + else + { + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt = ((scaled_coeff - (level << q_bits)) < q_offset )? 1 : 0; + dataLevel->level[0] = 0; + if (level == 0 && lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else if (level == 0 && lowerInt == 0) + { + dataLevel->level[1] = level + 1; + dataLevel->noLevels = 2; + } + else if (level > 0 && lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + + if(dataLevel->noLevels == 1) + dataLevel->pre_level = 0; + else + dataLevel->pre_level = (iabs (*m7) * q_params->ScaleComp + q_params->OffsetComp) >> q_bits; + dataLevel->sign = isign(*m7); + } + dataLevel++; + } + return 0; +} + + +/*! +**************************************************************************** +* \brief +* Initialize levelData for Chroma DC +**************************************************************************** +*/ +int init_trellis_data_DC_cr_CABAC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + int noCoeff = 0; + int i, j, coeff_ctr, end_coeff_ctr = p_Vid->num_cdc_coeff; + int *m7; + int q_bits = Q_BITS + qp_per + 1; + int q_offset = ( 1 << (q_bits - 1) ); + double err; + int scaled_coeff, level, lowerInt, k; + double estErr = (double) estErr4x4[qp_rem][0][0] / currSlice->norm_factor_4x4; // note that we could also use int64 + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + j = *p_scan++; // horizontal position + i = *p_scan++; // vertical position + + m7 = &tblock[j][i]; + if (*m7 == 0) + { + dataLevel->level[0] = 0; + dataLevel->levelDouble = 0; + dataLevel->errLevel[0] = 0.0; + dataLevel->noLevels = 1; + err = 0.0; + } + else + { + scaled_coeff = iabs (*m7) * q_params->ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt=( (scaled_coeff - (level << q_bits)) < q_offset )? 1 : 0; + dataLevel->level[0] = 0; + if (level == 0) + { + if (lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else + { + dataLevel->level[1] = level + 1; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + } + else if (lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + *kStop = coeff_ctr; + *kStart = coeff_ctr; + noCoeff++; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + } + dataLevel++; + } + return (noCoeff); +} + +void get_dQP_table(Slice *currSlice) +{ + int qp_offset = (currSlice->slice_type == B_SLICE) ? (currSlice->RDOQ_QP_Num / 3): (currSlice->RDOQ_QP_Num >> 1); + int deltaQPCnt, deltaQP; + + memset(currSlice->deltaQPTable, 0, sizeof(int)*9); + + for(deltaQPCnt = 0; deltaQPCnt < currSlice->RDOQ_QP_Num; deltaQPCnt++) + { + if (deltaQPCnt == 0) + deltaQP = 0; + else + { + if (deltaQPCnt <= qp_offset) + deltaQP = deltaQPCnt - 1 - qp_offset; + else + deltaQP = deltaQPCnt - qp_offset; + } + currSlice->deltaQPTable[deltaQPCnt] = deltaQP; + } +} + +void trellis_mp(Macroblock *currMB) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + + int masterQP = 0, deltaQP; +#if RDOQ_BASE + int qp_left, qp_up; + const int deltaQPTabB[] = {0, 1, -1, 2, 3, -2, 4, 5, -3}; + const int deltaQPTabP[] = {0, -1, 1, -2, 2, -3, 3, -4, 4}; + int qp_anchor; +#endif + int deltaQPCnt; + + masterQP = p_Vid->masterQP = p_Vid->qp; + + currSlice->rdoq_motion_copy = 0; + + currSlice->rddata_trellis_best.min_rdcost = 1e30; + + if (p_Inp->symbol_mode == CABAC) + { + estRunLevel_CABAC(currMB, LUMA_4x4); + estRunLevel_CABAC(currMB, LUMA_16AC); + estRunLevel_CABAC(currMB, LUMA_16DC); + if (p_Inp->Transform8x8Mode) + estRunLevel_CABAC(currMB, LUMA_8x8); + + if (p_Vid->yuv_format != YUV400) + { + estRunLevel_CABAC(currMB, CHROMA_AC); + if (p_Vid->yuv_format == YUV420) + estRunLevel_CABAC(currMB, CHROMA_DC); + else + estRunLevel_CABAC(currMB, CHROMA_DC_2x4); + } + } + +#if RDOQ_BASE + qp_left = (currMB->mb_left) ? currMB->mb_left->qp : p_Vid->masterQP; + qp_up = (currMB->mb_up) ? currMB->mb_up->qp : p_Vid->masterQP; + qp_anchor = (qp_left + qp_up + 1)>>1; +#endif + + for (deltaQPCnt=0; deltaQPCnt < currSlice->RDOQ_QP_Num; deltaQPCnt++) + { + currSlice->rddata = &currSlice->rddata_trellis_curr; + currSlice->rddata->min_dcost = 1e30; +#if RDOQ_BASE + if (currSlice->slice_type == B_SLICE) + deltaQP = deltaQPTabB[deltaQPCnt]; + else + deltaQP = deltaQPTabP[deltaQPCnt]; +#else + + // It seems that pushing the masterQP as first helps things when fast me is enabled. + // Could there be an issue with motion estimation? + deltaQP = currSlice->deltaQPTable[deltaQPCnt]; +#endif + + p_Vid->qp = iClip3(-p_Vid->bitdepth_luma_qp_scale, 51, masterQP + deltaQP); + deltaQP = p_Vid->qp - masterQP; + + +#if RDOQ_BASE + if(deltaQP != 0 && !(p_Vid->qp - qp_anchor >= -2 && p_Vid->qp - qp_anchor <= 1) && currMB->mb_left && currMB->mb_up && currSlice->slice_type == P_SLICE) + continue; + if(deltaQP != 0 && !(p_Vid->qp - qp_anchor >= -1 && p_Vid->qp - qp_anchor <= 2) && currMB->mb_left && currMB->mb_up && currSlice->slice_type == B_SLICE) + continue; +#endif + + reset_macroblock(currMB); + currMB->qp = (short) p_Vid->qp; + update_qp (currMB); + + currSlice->encode_one_macroblock (currMB); + end_encode_one_macroblock(currMB); + + + if ( currSlice->rddata_trellis_curr.min_rdcost < currSlice->rddata_trellis_best.min_rdcost) + copy_rddata_trellis(currMB, &currSlice->rddata_trellis_best, currSlice->rddata); + + if (p_Inp->RDOQ_CP_MV) + currSlice->rdoq_motion_copy = 1; + +#if (!RDOQ_BASE) + if (p_Inp->RDOQ_Fast == 1) + { + if ((p_Vid->qp - currSlice->rddata_trellis_best.qp > 1)) + break; + if ((currSlice->rddata_trellis_curr.cbp == 0) && (currSlice->rddata_trellis_curr.mb_type != 0)) + break; + if ((currSlice->rddata_trellis_best.mb_type == 0) && (currSlice->rddata_trellis_best.cbp == 0)) + break; + } +#endif + } + + reset_macroblock(currMB); + currSlice->rddata = &currSlice->rddata_trellis_best; + + copy_rdopt_data (currMB); // copy the MB data for Top MB from the temp buffers + write_macroblock (currMB, 1); + p_Vid->qp = masterQP; +} + +void trellis_sp(Macroblock *currMB) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + p_Vid->masterQP = p_Vid->qp; + + if (currSlice->symbol_mode == CABAC) + { + estRunLevel_CABAC(currMB, LUMA_4x4); + estRunLevel_CABAC(currMB, LUMA_16AC); + + estRunLevel_CABAC(currMB, LUMA_16DC); + if (p_Inp->Transform8x8Mode) + estRunLevel_CABAC(currMB, LUMA_8x8); + + if (p_Vid->yuv_format != YUV400) + { + estRunLevel_CABAC(currMB, CHROMA_AC); + + if (p_Vid->yuv_format == YUV420) + estRunLevel_CABAC(currMB, CHROMA_DC); + else + estRunLevel_CABAC(currMB, CHROMA_DC_2x4); + } + } + + currSlice->encode_one_macroblock (currMB); + end_encode_one_macroblock(currMB); + + write_macroblock (currMB, 1); +} + +void trellis_coding(Macroblock *currMB) +{ + if (currMB->p_Slice->RDOQ_QP_Num > 1) + { + trellis_mp(currMB); + } + else + { + trellis_sp(currMB); + } +} + +void RDOQ_update_mode(Slice *currSlice, RD_PARAMS *enc_mb) +{ + InputParameters *p_Inp = currSlice->p_Inp; +#if (MVC_EXTENSION_ENABLE) + int *InterSearch = p_Inp->InterSearch[(currSlice->p_Vid->num_of_layers > 1) ? currSlice->view_id : 0][(currSlice->slice_type == B_SLICE)]; +#else + int *InterSearch = p_Inp->InterSearch[0][(currSlice->slice_type == B_SLICE)]; +#endif + + int mb_type = currSlice->rddata_trellis_best.mb_type; + int i; + for(i=0; ivalid[i] = 0; + + enc_mb->valid[mb_type] = 1; + + if(mb_type == P8x8) + { + enc_mb->valid[4] = (short) (InterSearch[4]); + enc_mb->valid[5] = (short) (InterSearch[5] && !(p_Inp->Transform8x8Mode==2)); + enc_mb->valid[6] = (short) (InterSearch[6] && !(p_Inp->Transform8x8Mode==2)); + enc_mb->valid[7] = (short) (InterSearch[7] && !(p_Inp->Transform8x8Mode==2)); + } +} + +void copy_rddata_trellis (Macroblock *currMB, RD_DATA *dest, RD_DATA *src) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int j; + + dest->min_rdcost = src->min_rdcost; + dest->min_dcost = src->min_dcost; + dest->min_rate = src->min_rate; + + memcpy(&dest->rec_mb[0][0][0],&src->rec_mb[0][0][0], MB_PIXELS * sizeof(imgpel)); + + if (p_Vid->yuv_format != YUV400) + { + memcpy(&dest->rec_mb[1][0][0],&src->rec_mb[1][0][0], 2 * MB_PIXELS * sizeof(imgpel)); + } + + memcpy(&dest->cofAC[0][0][0][0], &src->cofAC[0][0][0][0], (4 + p_Vid->num_blk8x8_uv) * 4 * 2 * 65 * sizeof(int)); + memcpy(&dest->cofDC[0][0][0], &src->cofDC[0][0][0], 3 * 2 * 18 * sizeof(int)); + + dest->mb_type = src->mb_type; + + memcpy(dest->b8x8, src->b8x8, BLOCK_MULTIPLE * sizeof(Info8x8)); + + dest->cbp = src->cbp; + dest->mode = src->mode; + dest->i16offset = src->i16offset; + dest->i16mode = src->i16mode; + dest->c_ipred_mode = src->c_ipred_mode; + dest->luma_transform_size_8x8_flag = src->luma_transform_size_8x8_flag; + dest->NoMbPartLessThan8x8Flag = src->NoMbPartLessThan8x8Flag; + dest->qp = src->qp; + + dest->prev_qp = src->prev_qp; + dest->prev_dqp = src->prev_dqp; + dest->prev_cbp = src->prev_cbp; + dest->cbp_blk = src->cbp_blk; + + + if (p_Vid->type != I_SLICE && p_Vid->type != SI_SLICE) + { + // note that this is not copying the bipred mvs!!! + memcpy(&dest->all_mv [0][0][0][0][0], &src->all_mv [0][0][0][0][0], p_Vid->max_num_references * 288 * sizeof(MotionVector)); // 2 * ref * 9 * 4 * 4 + } + + memcpy(dest->intra_pred_modes,src->intra_pred_modes, MB_BLOCK_PARTITIONS * sizeof(char)); + memcpy(dest->intra_pred_modes8x8,src->intra_pred_modes8x8, MB_BLOCK_PARTITIONS * sizeof(char)); + for(j = currMB->block_y; j < currMB->block_y + BLOCK_MULTIPLE; j++) + memcpy(&dest->ipredmode[j][currMB->block_x],&src->ipredmode[j][currMB->block_x], BLOCK_MULTIPLE * sizeof(char)); + + memcpy(&dest->refar[LIST_0][0][0], &src->refar[LIST_0][0][0], 2 * BLOCK_MULTIPLE * BLOCK_MULTIPLE * sizeof(char)); + +} + +void updateMV_mp(Macroblock *currMB, distblk *m_cost, short ref, int list, int h, int v, int blocktype, int block8x8) +{ + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int i, j; + int bsx = block_size[blocktype][0] >> 2; + int bsy = block_size[blocktype][1] >> 2; + MotionVector all_mv; + + if ( (p_Inp->Transform8x8Mode == 1) && (blocktype == 4) && currMB->luma_transform_size_8x8_flag) + { + all_mv = currSlice->tmp_mv8[list][ref][v][h]; + *m_cost = currSlice->motion_cost8[list][ref][block8x8]; + } + else if ( (p_Inp->Transform8x8Mode == 1) && (blocktype == 4) && currMB->luma_transform_size_8x8_flag == 0) + { + all_mv = currSlice->tmp_mv4[list][ref][v][h]; + *m_cost = currSlice->motion_cost4[list][ref][block8x8]; + } + else + { + all_mv = currSlice->rddata_trellis_best.all_mv[list][ref][blocktype][v][h]; + } + + for (j = 0; j < bsy; j++) + { + for (i = 0; i < bsx; i++) + { + currSlice->all_mv[list][ref][blocktype][v+j][h+i] = all_mv; + } + } +} + + + diff --git a/lencod/src/rdoq_cabac.c b/lencod/src/rdoq_cabac.c new file mode 100644 index 0000000..9939e2f --- /dev/null +++ b/lencod/src/rdoq_cabac.c @@ -0,0 +1,888 @@ +/*! + ************************************************************************************* + * \file rdoq_cabac.c + * + * \brief + * Rate Distortion Optimized Quantization based on VCEG-AH21 related to CABAC + ************************************************************************************* + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "cabac.h" +#include "image.h" +#include "fmo.h" +#include "macroblock.h" +#include "mb_access.h" +#include "rdoq.h" + +#define RDOQ_SQ 0 + +static const int entropyBits[128]= +{ + 895, 943, 994, 1048, 1105, 1165, 1228, 1294, + 1364, 1439, 1517, 1599, 1686, 1778, 1875, 1978, + 2086, 2200, 2321, 2448, 2583, 2725, 2876, 3034, + 3202, 3380, 3568, 3767, 3977, 4199, 4435, 4684, + 4948, 5228, 5525, 5840, 6173, 6527, 6903, 7303, + 7727, 8178, 8658, 9169, 9714, 10294, 10914, 11575, + 12282, 13038, 13849, 14717, 15650, 16653, 17734, 18899, + 20159, 21523, 23005, 24617, 26378, 28306, 30426, 32768, + 32768, 35232, 37696, 40159, 42623, 45087, 47551, 50015, + 52479, 54942, 57406, 59870, 62334, 64798, 67262, 69725, + 72189, 74653, 77117, 79581, 82044, 84508, 86972, 89436, + 91900, 94363, 96827, 99291, 101755, 104219, 106683, 109146, + 111610, 114074, 116538, 119002, 121465, 123929, 126393, 128857, + 131321, 133785, 136248, 138712, 141176, 143640, 146104, 148568, + 151031, 153495, 155959, 158423, 160887, 163351, 165814, 168278, + 170742, 173207, 175669, 178134, 180598, 183061, 185525, 187989 +}; + + +static int biari_no_bits(signed short symbol, BiContextTypePtr bi_ct ) +{ + int ctx_state, estBits; + + symbol = (short) (symbol != 0); + + ctx_state = (symbol == bi_ct->MPS) ? 64 + bi_ct->state : 63 - bi_ct->state; + estBits = entropyBits[127 - ctx_state]; + + return(estBits); +} + +static int biari_state(signed short symbol, BiContextTypePtr bi_ct ) +{ + int ctx_state; + + symbol = (short) (symbol != 0); + ctx_state = (symbol == bi_ct->MPS) ? 64 + bi_ct->state : 63 - bi_ct->state; + + return(ctx_state); +} + +/*! +**************************************************************************** +* \brief +* estimate bit cost for each CBP bit +**************************************************************************** +*/ +static void est_CBP_block_bit (Macroblock* currMB, int type) +{ + Slice *currSlice = currMB->p_Slice; + estBitsCabacStruct *cabacEstBits = &currSlice->estBitsCabac[type]; + int ctx; + + for (ctx=0; ctx<=3; ctx++) + { + cabacEstBits->blockCbpBits[ctx][0]=biari_no_bits(0, currSlice->tex_ctx->bcbp_contexts[type2ctx_bcbp[type]]+ctx); + + cabacEstBits->blockCbpBits[ctx][1]=biari_no_bits(1, currSlice->tex_ctx->bcbp_contexts[type2ctx_bcbp[type]]+ctx); + } +} + +/*! +**************************************************************************** +* \brief +* estimate CABAC bit cost for significant coefficient map +**************************************************************************** +*/ +static void est_significance_map(Macroblock* currMB, int type) +{ + Slice *currSlice = currMB->p_Slice; + int k; + int k1 = maxpos[type]-1; +#if ENABLE_FIELD_CTX + int fld = ( currSlice->structure!=FRAME || currMB->mb_field ); +#else + int fld = 0; +#endif + BiContextTypePtr map_ctx = currSlice->tex_ctx->map_contexts [fld][type2ctx_map [type]]; + BiContextTypePtr last_ctx = currSlice->tex_ctx->last_contexts[fld][type2ctx_last[type]]; + const byte *pos2ctxmap = fld ? pos2ctx_map_int [type] : pos2ctx_map[type]; + const byte *pos2ctxlast = pos2ctx_last[type]; + + estBitsCabacStruct *cabacEstBits = &currSlice->estBitsCabac[type]; + + for (k = 0; k < k1; k++) // if last coeff is reached, it has to be significant + { + cabacEstBits->significantBits[pos2ctxmap[k]][0] = biari_no_bits (0, map_ctx + pos2ctxmap[k]); + + cabacEstBits->significantBits[pos2ctxmap[k]][1] = biari_no_bits (1, map_ctx + pos2ctxmap[k]); + + cabacEstBits->lastBits[pos2ctxlast[k]][0] = biari_no_bits(0, last_ctx+pos2ctxlast[k]); + + cabacEstBits->lastBits[pos2ctxlast[k]][1] = biari_no_bits(1, last_ctx+pos2ctxlast[k]); + } + // if last coeff is reached, it has to be significant + cabacEstBits->significantBits[pos2ctxmap[k1]][0]=0; + cabacEstBits->significantBits[pos2ctxmap[k1]][1]=0; + cabacEstBits->lastBits[pos2ctxlast[k1]][0]=0; + cabacEstBits->lastBits[pos2ctxlast[k1]][1]=0; +} + +/*! +**************************************************************************** +* \brief +* estimate bit cost of significant coefficient +**************************************************************************** +*/ +static void est_significant_coefficients (Macroblock* currMB, int type) +{ + Slice *currSlice = currMB->p_Slice; + int ctx; + int maxCtx = imin(4, max_c2[type]); + estBitsCabacStruct *cabacEstBits = &currSlice->estBitsCabac[type]; + + for (ctx=0; ctx<=4; ctx++){ + cabacEstBits->greaterOneBits[0][ctx][0]= + biari_no_bits (0, currSlice->tex_ctx->one_contexts[type2ctx_one[type]] + ctx); + + cabacEstBits->greaterOneBits[0][ctx][1]= + biari_no_bits (1, currSlice->tex_ctx->one_contexts[type2ctx_one[type]] + ctx); + } + + for (ctx=0; ctx<=maxCtx; ctx++){ + cabacEstBits->greaterOneBits[1][ctx][0]= + biari_no_bits(0, currSlice->tex_ctx->abs_contexts[type2ctx_abs[type]] + ctx); + + cabacEstBits->greaterOneState[ctx]=biari_state(0, currSlice->tex_ctx->abs_contexts[type2ctx_abs[type]] + ctx); + + cabacEstBits->greaterOneBits[1][ctx][1]= + biari_no_bits(1, currSlice->tex_ctx->abs_contexts[type2ctx_abs[type]] + ctx); + } +} + +/*! +**************************************************************************** +* \brief +* estimate unary exp golomb bit cost +**************************************************************************** +*/ +static int est_unary_exp_golomb_level_encode(Macroblock *currMB, unsigned int symbol, int ctx, int type) +{ + Slice *currSlice = currMB->p_Slice; + estBitsCabacStruct *cabacEstBits = &currSlice->estBitsCabac[type]; + unsigned int l = symbol, k = 1; + unsigned int exp_start = 13; // 15-2 : 0,1 level decision always sent + int estBits; + + if (symbol==0) + { + estBits = cabacEstBits->greaterOneBits[1][ctx][0]; + return (estBits); + } + else + { + estBits = cabacEstBits->greaterOneBits[1][ctx][1]; + // this could be done using min of the two conditionals * value + while (((--l)>0) && (++k <= exp_start)) + { + estBits += cabacEstBits->greaterOneBits[1][ctx][1]; + } + + if (symbol < exp_start) + { + estBits += cabacEstBits->greaterOneBits[1][ctx][0]; + } + else + { + estBits += est_exp_golomb_encode_eq_prob(symbol - exp_start); + } + } + return(estBits); +} + +void precalculate_unary_exp_golomb_level(VideoParameters *p_Vid) +{ + int state, ctx_state0, ctx_state1, estBits0, estBits1, symbol; + + for (state=0; state<=63; state++) + { + // symbol 0 is MPS + ctx_state0 = 64 + state; + estBits0 = entropyBits[127-ctx_state0]; + ctx_state1 = 63 - state; + estBits1 = entropyBits[127-ctx_state1]; + + for (symbol = 0; symbol < MAX_PREC_COEFF; symbol++) + { + p_Vid->precalcUnaryLevelTab[ctx_state0][symbol] = est_unary_exp_golomb_level_bits(symbol, estBits0, estBits1); + + // symbol 0 is LPS + p_Vid->precalcUnaryLevelTab[ctx_state1][symbol] =est_unary_exp_golomb_level_bits(symbol, estBits1, estBits0); + } + } +} + +int est_unary_exp_golomb_level_bits(unsigned int symbol, int bits0, int bits1) +{ + unsigned int l,k; + unsigned int exp_start = 13; // 15-2 : 0,1 level decision always sent + int estBits; + + if (symbol == 0) + { + return (bits0); + } + else + { + estBits = bits1; + l = symbol; + k = 1; + while (((--l)>0) && (++k <= exp_start)) + { + estBits += bits1; + } + if (symbol < exp_start) + { + estBits += bits0; + } + else + { + estBits += est_exp_golomb_encode_eq_prob(symbol - exp_start); + } + } + return(estBits); +} + +/*! +**************************************************************************** +* \brief +* estimate exp golomb bit cost +**************************************************************************** +*/ +int est_exp_golomb_encode_eq_prob(unsigned int symbol) +{ + int k = 0, estBits = 0; + + for(;;) + { + if (symbol >= (unsigned int)(1<p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + estBitsCabacStruct *cabacEstBits = &currSlice->estBitsCabac[type]; + + int y_ac = (type==LUMA_16AC || type==LUMA_8x8 || type==LUMA_8x4 || type==LUMA_4x8 || type==LUMA_4x4 + || type==CB_16AC || type==CB_8x8 || type==CB_8x4 || type==CB_4x8 || type==CB_4x4 + || type==CR_16AC || type==CR_8x8 || type==CR_8x4 || type==CR_4x8 || type==CR_4x4); + int y_dc = (type==LUMA_16DC || type==CB_16DC || type==CR_16DC); + int u_ac = (type==CHROMA_AC && !p_Vid->is_v_block); + int v_ac = (type==CHROMA_AC && p_Vid->is_v_block); + int chroma_dc = (type==CHROMA_DC || type==CHROMA_DC_2x4 || type==CHROMA_DC_4x4); + int u_dc = (chroma_dc && !p_Vid->is_v_block); + int v_dc = (chroma_dc && p_Vid->is_v_block); + int j = (y_ac || u_ac || v_ac ? currMB->subblock_y : 0); + int i = (y_ac || u_ac || v_ac ? currMB->subblock_x : 0); + int bit; + int default_bit = (IS_INTRA(currMB) ? 1 : 0); + int upper_bit = default_bit; + int left_bit = default_bit; + int ctx, estBits = 0; + + int bit_pos_a = 0; + int bit_pos_b = 0; + + PixelPos block_a, block_b; + + if (y_ac || y_dc) + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_LUMA], &block_a); + get4x4Neighbour(currMB, i, j -1, p_Vid->mb_size[IS_LUMA], &block_b); + if (y_ac) + { + if (block_a.available) + bit_pos_a = 4*block_a.y + block_a.x; + if (block_b.available) + bit_pos_b = 4*block_b.y + block_b.x; + } + } + else + { + get4x4Neighbour(currMB, i - 1, j , p_Vid->mb_size[IS_CHROMA], &block_a); + get4x4Neighbour(currMB, i, j - 1, p_Vid->mb_size[IS_CHROMA], &block_b); + if (u_ac||v_ac) + { + if (block_a.available) + bit_pos_a = (block_a.y << 2) + block_a.x; + if (block_b.available) + bit_pos_b = (block_b.y << 2) + block_b.x; + } + } + + bit = (y_dc ? 0 : y_ac ? 1 : u_dc ? 17 : v_dc ? 18 : u_ac ? 19 : 35); + + if (p_Vid->enc_picture->chroma_format_idc!=YUV444 || (currMB->p_Inp->separate_colour_plane_flag != 0)) + { + if (type!=LUMA_8x8) + { + if (block_b.available) + { + if(p_Vid->mb_data[block_b.mb_addr].mb_type==IPCM) + upper_bit = 1; + else + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits[0], bit + bit_pos_b); + } + + if (block_a.available) + { + if(p_Vid->mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit = 1; + else + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits[0], bit + bit_pos_a); + } + + ctx = 2*upper_bit+left_bit; + //===== encode symbol ===== + estBits = cabacEstBits->blockCbpBits[ctx][0] - cabacEstBits->blockCbpBits[ctx][1]; + } + } + else + { + if (block_b.available) + { + if(p_Vid->mb_data[block_b.mb_addr].mb_type == IPCM) + upper_bit=1; + else + { + if(type==LUMA_8x8) + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits_8x8[0], bit + bit_pos_b); + else if (type==CB_8x8) + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits_8x8[1], bit + bit_pos_b); + else if (type==CR_8x8) + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits_8x8[2], bit + bit_pos_b); + else if ((type==CB_4x4)||(type==CB_4x8)||(type==CB_8x4)||(type==CB_16AC)||(type==CB_16DC)) + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits[1], bit + bit_pos_b); + else if ((type==CR_4x4)||(type==CR_4x8)||(type==CR_8x4)||(type==CR_16AC)||(type==CR_16DC)) + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits[2], bit + bit_pos_b); + else + upper_bit = get_bit(p_Vid->mb_data[block_b.mb_addr].cbp_bits[0], bit + bit_pos_b); + } + } + + if (block_a.available) + { + if(p_Vid->mb_data[block_a.mb_addr].mb_type==IPCM) + left_bit = 1; + else + { + if(type==LUMA_8x8) + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits_8x8[0],bit + bit_pos_a); + else if (type==CB_8x8) + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits_8x8[1],bit + bit_pos_a); + else if (type==CR_8x8) + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits_8x8[2],bit + bit_pos_a); + else if ((type==CB_4x4)||(type==CB_4x8)||(type==CB_8x4)||(type==CB_16AC)||(type==CB_16DC)) + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits[1], bit + bit_pos_a); + else if ((type==CR_4x4)||(type==CR_4x8)||(type==CR_8x4)||(type==CR_16AC)||(type==CR_16DC)) + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits[2], bit + bit_pos_a); + else + left_bit = get_bit(p_Vid->mb_data[block_a.mb_addr].cbp_bits[0], bit + bit_pos_a); + } + } + + ctx = 2*upper_bit+left_bit; + + //===== encode symbol ===== + estBits = cabacEstBits->blockCbpBits[ctx][0] - cabacEstBits->blockCbpBits[ctx][1]; + } + + return(estBits); +} +/*! +**************************************************************************** +* \brief +* Rate distortion optimized trellis quantization +**************************************************************************** +*/ +void est_writeRunLevel_CABAC(Macroblock *currMB, levelDataStruct levelData[], int levelTabMin[], int type, double lambda, int kInit, int kStop, + int noCoeff, int estCBP) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + estBitsCabacStruct *cabacEstBits = &currSlice->estBitsCabac[type]; + int k, i; + int estBits; + double lagr, lagrMin=0, lagrTabMin, lagrTab; + int c1 = 1, c2 = 0, c1Tab[3], c2Tab[3]; + int iBest, levelTab[64]; + int ctx, greater_one, last, maxK = maxpos[type]; + double lagrAcc, lagrLastMin=0, lagrLast; + int kBest=0, kStart, first; + levelDataStruct *dataLevel; + int *last_bits, *significant_bits; + + memset(levelTabMin, 0, (maxK + 1) * sizeof(int)); + + if (noCoeff > 0) + { + if (noCoeff > 1) + { + kStart = kInit; kBest = 0; first = 1; + lagrAcc = 0.0; + + for (k = kStart; k <= kStop; k++) + { + lagrAcc += levelData[k].errLevel[0]; + } + + if (levelData[kStart].noLevels > 2) + { + last_bits = cabacEstBits->lastBits[pos2ctx_last[type][kStart]]; + lagrAcc -= levelData[kStart].errLevel[0]; + lagrLastMin = lambda * (last_bits[1] - last_bits[0]) + lagrAcc; + + kBest = kStart; + kStart++; + first = 0; + } + + for (k = kStart; k <= kStop; k++) + { + dataLevel = &levelData[k]; + significant_bits = cabacEstBits->significantBits[pos2ctx_map[type][k]]; + lagrMin = dataLevel->errLevel[0] + lambda * significant_bits[0]; + lagrAcc -= dataLevel->errLevel[0]; + + if (dataLevel->noLevels > 1) + { + last_bits = cabacEstBits->lastBits[pos2ctx_last[type][k]]; + estBits = SIGN_BITS + significant_bits[1] + cabacEstBits->greaterOneBits[0][4][0]; + + lagr = dataLevel->errLevel[1] + lambda * (estBits); + + lagrLast = lagr + lambda * last_bits[1] + lagrAcc; + lagr = lagr + lambda * last_bits[0]; + + lagrMin = (lagr < lagrMin) ? lagr : lagrMin; + + if ((lagrLast < lagrLastMin) || (first == 1)) + { + kBest = k; + first = 0; + lagrLastMin = lagrLast; + } + } + lagrAcc += lagrMin; + } + kStart = kBest; + } + else + { + kStart = kStop; + } + + lagrTabMin = 0.0; + for (k = 0; k <= kStart; k++) + { + lagrTabMin += levelData[k].errLevel[0]; + } + // Initial Lagrangian calculation + lagrTab = 0.0; + + ////////////////////////// + + lagrTabMin += (lambda*estCBP); + iBest = 0; first = 1; + for (k = kStart; k >= 0; k--) + { + significant_bits = cabacEstBits->significantBits[pos2ctx_map[type][k]]; + last_bits = cabacEstBits->lastBits[pos2ctx_last[type][k]]; + dataLevel = &levelData[k]; + last = (k == kStart); + + if (!last) + { + lagrMin = dataLevel->errLevel[0] + lambda * significant_bits[0]; + iBest = 0; + first = 0; + } + + for (i = 1; i < dataLevel->noLevels; i++) + { + estBits = SIGN_BITS + significant_bits[1]; + estBits += last_bits[last]; + + // greater than 1 + greater_one = (dataLevel->level[i] > 1); + + c1Tab[i] = c1; + c2Tab[i] = c2; + + ctx = imin(c1Tab[i], 4); + estBits += cabacEstBits->greaterOneBits[0][ctx][greater_one]; + + // magnitude if greater than 1 + if (greater_one) + { + ctx = imin(c2Tab[i], max_c2[type]); + if ( (dataLevel->level[i] - 2) < MAX_PREC_COEFF) + { + estBits += p_Vid->precalcUnaryLevelTab[cabacEstBits->greaterOneState[ctx]][dataLevel->level[i] - 2]; + } + else + { + estBits += est_unary_exp_golomb_level_encode(currMB, dataLevel->level[i] - 2, ctx, type); + } + + c1Tab[i] = 0; + c2Tab[i]++; + } + else if (c1Tab[i]) + { + c1Tab[i]++; + } + + lagr = dataLevel->errLevel[i] + lambda * estBits; + if ((lagr < lagrMin) || (first == 1)) + { + iBest = i; + lagrMin=lagr; + first = 0; + } + } + + if (iBest > 0) + { + c1 = c1Tab[iBest]; + c2 = c2Tab[iBest]; + } + + levelTab[k] = dataLevel->level[iBest]; + lagrTab += lagrMin; + } + /////////////////////////////////// + + if (lagrTab < lagrTabMin) + { + memcpy(levelTabMin, levelTab, (kStart + 1) * sizeof(int)); + } + } +} + + +/*! +**************************************************************************** +* \brief +* Initialize levelData +**************************************************************************** +*/ +int init_trellis_data_4x4_CABAC(Macroblock *currMB, int **tblock, + struct quant_methods *q_method, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop, int type) +{ + VideoParameters *p_Vid = currMB->p_Vid; + LevelQuantParams **q_params_4x4 = q_method->q_params; + QuantParameters *p_Quant = p_Vid->p_Quant; + int qp = q_method->qp; + int qp_per = p_Quant->qp_per_matrix[qp]; + int qp_rem = p_Quant->qp_rem_matrix[qp]; + int block_x = q_method->block_x; + + Slice *currSlice = currMB->p_Slice; + int noCoeff = 0; + int i, j, coeff_ctr; + int *m7; + int end_coeff_ctr = ( ( type == LUMA_4x4 ) ? 16 : 15 ); + int q_bits = Q_BITS + qp_per; + int q_offset = ( 1 << (q_bits - 1) ); + int scaled_coeff, level, lowerInt, k; + double err, estErr; + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (*m7 == 0) + { + dataLevel->level[0] = 0; + dataLevel->levelDouble = 0; + dataLevel->errLevel[0] = 0.0; + dataLevel->noLevels = 1; + //err = 0.0; + } + else + { + estErr = ((double) estErr4x4[qp_rem][j][i]) / currSlice->norm_factor_4x4; + + scaled_coeff = iabs(*m7) * q_params_4x4[j][i].ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt = ((scaled_coeff - (level << q_bits)) < q_offset )? 1 : 0; + +#if RDOQ_SQ + dataLevel->level[0] = max(0, level - 1); +#else + dataLevel->level[0] = 0; +#endif + if (level == 0) + { + if (lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else + { + dataLevel->level[1] = 1; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + } + else if (lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + *kStop = coeff_ctr; + *kStart = coeff_ctr; + noCoeff++; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + } + + dataLevel++; + } + return (noCoeff); +} + +/* +**************************************************************************** +* \brief +* Initialize levelData +**************************************************************************** +*/ +int init_trellis_data_8x8_CABAC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, LevelQuantParams **q_params, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop) +{ + Slice *currSlice = currMB->p_Slice; + int noCoeff = 0; + int *m7; + int i, j, coeff_ctr, end_coeff_ctr = 64; + int q_bits = Q_BITS_8 + qp_per; + int q_offset = ( 1 << (q_bits - 1) ); + double err, estErr; + int level, lowerInt, k; + int scaled_coeff; + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (*m7 == 0) + { + dataLevel->level[0] = 0; + dataLevel->levelDouble = 0; + dataLevel->errLevel[0] = 0.0; + dataLevel->noLevels = 1; + //err = 0.0; + } + else + { + estErr = (double) estErr8x8[qp_rem][j][i] / currSlice->norm_factor_8x8; + + scaled_coeff = iabs(*m7) * q_params[j][i].ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt = ((scaled_coeff - (level << q_bits)) < q_offset )? 1 : 0; + +#if RDOQ_SQ + dataLevel->level[0] = max(0, level - 1); +#else + dataLevel->level[0] = 0; +#endif + if (level == 0) + { + if (lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else + { + dataLevel->level[1] = 1; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + } + else if (lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + *kStop = coeff_ctr; + *kStart = coeff_ctr; + noCoeff++; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + } + + dataLevel++; + } + return (noCoeff); +} + +/*! +**************************************************************************** +* \brief +* Initialize levelData for Luma DC +**************************************************************************** +*/ +int init_trellis_data_DC_CABAC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params, const byte *p_scan, + levelDataStruct *dataLevel, int* kStart, int* kStop) +{ + Slice *currSlice = currMB->p_Slice; + int noCoeff = 0; + int i, j, coeff_ctr, end_coeff_ctr = 16; + int q_bits = Q_BITS + qp_per + 1; + int q_offset = ( 1 << (q_bits - 1) ); + int scaled_coeff, level, lowerInt, k; + int *m7; + double err, estErr = (double) estErr4x4[qp_rem][0][0] / currSlice->norm_factor_4x4; // note that we could also use int64 + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + m7 = &tblock[j][i]; + + if (*m7 == 0) + { + dataLevel->level[0] = 0; + dataLevel->levelDouble = 0; + dataLevel->errLevel[0] = 0.0; + dataLevel->noLevels = 1; + //err = 0.0; + } + else + { + scaled_coeff = iabs(*m7) * q_params->ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt=( (scaled_coeff - (level<level[0] = max(0, level - 1); +#else + dataLevel->level[0] = 0; +#endif + if (level == 0) + { + if (lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else + { + dataLevel->level[1] = 1; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + } + else if (lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + *kStop = coeff_ctr; + noCoeff++; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + *kStop = coeff_ctr; + *kStart = coeff_ctr; + noCoeff++; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + } + dataLevel++; + } + return (noCoeff); +} + + + diff --git a/lencod/src/rdoq_cavlc.c b/lencod/src/rdoq_cavlc.c new file mode 100644 index 0000000..56732bb --- /dev/null +++ b/lencod/src/rdoq_cavlc.c @@ -0,0 +1,721 @@ +/*! +************************************************************************************* +* \file rdoq_cavlc.c +* +* \brief +* Rate Distortion Optimized Quantization based on VCEG-AH21 related to CAVLC +************************************************************************************* +*/ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "image.h" +#include "fmo.h" +#include "macroblock.h" +#include "mb_access.h" +#include "rdoq.h" +#include "block.h" + +/*! +************************************************************************ +* \brief +* estimate VLC for Coeff Level +************************************************************************ +*/ +int estSyntaxElement_Level_VLC1(SyntaxElement *se) +{ + int level = se->value1; + int sign = (level < 0 ? 1 : 0); + int levabs = iabs(level); + + if (levabs < 8) + { + se->len = levabs * 2 + sign - 1; + } + else if (levabs < 16) + { + // escape code1 + se->len = 19; + } + else + { + // escape code2 + se->len = 28; + } + + return (se->len); +} + + + +/*! +************************************************************************ +* \brief +* estimate VLC for Coeff Level +************************************************************************ +*/ +int estSyntaxElement_Level_VLCN(SyntaxElement *se, int vlc)//, DataPartition *this_dataPart) +{ + int level = se->value1; + int levabs = iabs(level) - 1; + + int shift = vlc - 1; + int escape = (15 << shift); + + if (levabs < escape) + { + se->len = ((levabs) >> shift) + 1 + vlc; + } + else + { + se->len = 28; + } + + return (se->len); +} + +int cmp(const void *arg1, const void *arg2) +{ + if(((levelDataStruct *)arg2)->levelDouble != ((levelDataStruct *)arg1)->levelDouble) + return (((levelDataStruct *)arg2)->levelDouble - ((levelDataStruct *)arg1)->levelDouble); + else + return (((levelDataStruct *)arg1)->coeff_ctr - ((levelDataStruct *)arg2)->coeff_ctr); +} + +/*! +************************************************************************ +* \brief +* estimate CAVLC bits +************************************************************************ +*/ +int est_CAVLC_bits (VideoParameters *p_Vid, int level_to_enc[16], int sign_to_enc[16], int nnz, int block_type) +{ + int no_bits = 0; + SyntaxElement se; + + int coeff_ctr, scan_pos = 0; + int k, level = 1, run = -1, vlcnum; + int numcoeff = 0, lastcoeff = 0, numtrailingones = 0; + int numones = 0, totzeros = 0, zerosleft, numcoef; + int numcoeff_vlc; + int level_two_or_higher; + int max_coeff_num = 0, cdc = (block_type == CHROMA_DC ? 1 : 0); + int yuv = p_Vid->yuv_format - 1; + static const int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6 + + int pLevel[16] = {0}; + int pRun[16] = {0}; + + static const int Token_lentab[3][4][17] = + { + { + { 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16}, + { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16}, + { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16}, + { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16} + }, + { + { 2, 6, 6, 7, 8, 8, 9,11,11,12,12,12,13,13,13,14,14}, + { 0, 2, 5, 6, 6, 7, 8, 9,11,11,12,12,13,13,14,14,14}, + { 0, 0, 3, 6, 6, 7, 8, 9,11,11,12,12,13,13,13,14,14}, + { 0, 0, 0, 4, 4, 5, 6, 6, 7, 9,11,11,12,13,13,13,14} + }, + { + { 4, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,10}, + { 0, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,10}, + { 0, 0, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10}, + { 0, 0, 0, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9,10,10,10} + } + }; + + static const int Totalzeros_lentab[TOTRUN_NUM][16] = + { + { 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9}, + { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6}, + { 4,3,3,3,4,4,3,3,4,5,5,6,5,6}, + { 5,3,4,4,3,3,3,4,3,4,5,5,5}, + { 4,4,4,3,3,3,3,3,4,5,4,5}, + { 6,5,3,3,3,3,3,3,4,3,6}, + { 6,5,3,3,3,2,3,4,3,6}, + { 6,4,5,3,2,2,3,3,6}, + { 6,6,4,2,2,3,2,5}, + { 5,5,3,2,2,2,4}, + { 4,4,3,3,1,3}, + { 4,4,2,1,3}, + { 3,3,1,2}, + { 2,2,1}, + { 1,1}, + }; + static const int Run_lentab[TOTRUN_NUM][16] = + { + {1,1}, + {1,2,2}, + {2,2,2,2}, + {2,2,2,3,3}, + {2,2,3,3,3,3}, + {2,3,3,3,3,3,3}, + {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11}, + }; + static const int Token_lentab_cdc[3][4][17] = + { + //YUV420 + {{ 2, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 3, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV422 + {{ 1, 7, 7, 9, 9,10,11,12,13, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 2, 7, 7, 9,10,11,12,12, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 3, 7, 7, 9,10,11,12, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 5, 6, 7, 7,10,11, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV444 + {{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16}, + { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16}, + { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16}, + { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}} + }; + static const int Totalzeros_lentab_cdc[3][TOTRUN_NUM][16] = + { + //YUV420 + {{ 1,2,3,3}, + { 1,2,2}, + { 1,1}}, + //YUV422 + {{ 1,3,3,4,4,4,5,5}, + { 3,2,3,3,3,3,3}, + { 3,3,2,2,3,3}, + { 3,2,2,2,3}, + { 2,2,2,2}, + { 2,2,1}, + { 1,1}}, + //YUV444 + {{ 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9}, + { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6}, + { 4,3,3,3,4,4,3,3,4,5,5,6,5,6}, + { 5,3,4,4,3,3,3,4,3,4,5,5,5}, + { 4,4,4,3,3,3,3,3,4,5,4,5}, + { 6,5,3,3,3,3,3,3,4,3,6}, + { 6,5,3,3,3,2,3,4,3,6}, + { 6,4,5,3,2,2,3,3,6}, + { 6,6,4,2,2,3,2,5}, + { 5,5,3,2,2,2,4}, + { 4,4,3,3,1,3}, + { 4,4,2,1,3}, + { 3,3,1,2}, + { 2,2,1}, + { 1,1}} + }; + + max_coeff_num = ( (block_type == CHROMA_DC) ? p_Vid->num_cdc_coeff : + ( (block_type == LUMA_INTRA16x16AC || block_type == CB_INTRA16x16AC || block_type == CR_INTRA16x16AC || block_type == CHROMA_AC) ? 15 : 16) ); + + //convert zigzag scan to (run, level) pairs + for (coeff_ctr = 0; coeff_ctr < max_coeff_num; coeff_ctr++) + { + run++; + level = level_to_enc[coeff_ctr]; + if (level != 0) + { + pLevel[scan_pos] = isignab(level, sign_to_enc[coeff_ctr]); + pRun [scan_pos] = run; + ++scan_pos; + run = -1; // reset zero level counter + } + } + + level = 1; + for(k = 0; (k < max_coeff_num) && level != 0; k++) + { + level = pLevel[k]; // level + run = pRun[k]; // run + + if (level) + { + totzeros += run; // lets add run always (even if zero) to avoid conditional + if (iabs(level) == 1) + { + numones ++; + numtrailingones ++; + numtrailingones = imin(numtrailingones, 3); // clip to 3 + } + else + { + numtrailingones = 0; + } + numcoeff ++; + lastcoeff = k; + } + } + + if (!cdc) + { + numcoeff_vlc = (nnz < 2) ? 0 : ((nnz < 4) ? 1 : ((nnz < 8) ? 2 : 3)); + } + else + { + // chroma DC (has its own VLC) + // numcoeff_vlc not relevant + numcoeff_vlc = 0; + } + + se.value1 = numcoeff; + se.value2 = numtrailingones; + se.len = numcoeff_vlc; /* use len to pass vlcnum */ + + if (!cdc) + { + if (se.len == 3) + no_bits += 6; // 4 + 2 bit FLC + else + no_bits += Token_lentab[se.len][se.value2][se.value1]; + } + else + no_bits += Token_lentab_cdc[yuv][se.value2][se.value1]; + + if (!numcoeff) + return no_bits; + else + { + if (numtrailingones) + no_bits += numtrailingones; + + // encode levels + level_two_or_higher = (numcoeff > 3 && numtrailingones == 3) ? 0 : 1; + + vlcnum = (numcoeff > 10 && numtrailingones < 3) ? 1 : 0; + + for (k = lastcoeff - numtrailingones; k >= 0; k--) + { + level = pLevel[k]; // level + + se.value1 = level; + + if (level_two_or_higher) + { + level_two_or_higher = 0; + if (se.value1 > 0) + se.value1 --; + else + se.value1 ++; + } + + // encode level + if (vlcnum == 0) + estSyntaxElement_Level_VLC1(&se); + else + estSyntaxElement_Level_VLCN(&se, vlcnum); + + // update VLC table + if (iabs(level) > incVlc[vlcnum]) + vlcnum++; + + if ((k == lastcoeff - numtrailingones) && iabs(level) > 3) + vlcnum = 2; + + no_bits += se.len; + } + + // encode total zeroes + if (numcoeff < max_coeff_num) + { + se.value1 = totzeros; + + vlcnum = numcoeff-1; + + se.len = vlcnum; + + if (!cdc) + no_bits += Totalzeros_lentab[se.len][se.value1]; + else + no_bits += Totalzeros_lentab_cdc[yuv][se.len][se.value1]; + } + + // encode run before each coefficient + zerosleft = totzeros; + numcoef = numcoeff; + for (k = lastcoeff; k >= 0; k--) + { + run = pRun[k]; // run + + se.value1 = run; + + // for last coeff, run is remaining totzeros + // when zerosleft is zero, remaining coeffs have 0 run + if ((!zerosleft) || (numcoeff <= 1 )) + break; + + if (numcoef > 1 && zerosleft) + { + vlcnum = imin(zerosleft - 1, RUNBEFORE_NUM_M1); + se.len = vlcnum; + no_bits += Run_lentab[se.len][se.value1]; + zerosleft -= run; + numcoef --; + } + } + } + + return no_bits; +} + + +/*! +**************************************************************************** +* \brief +* estimate run and level for CAVLC +**************************************************************************** +*/ +void est_RunLevel_CAVLC(Macroblock *currMB, levelDataStruct *levelData, int *levelTrellis, int block_type, + int b8, int b4, int coeff_num, double lambda) +{ + int k, lastnonzero = -1, coeff_ctr; + int level_to_enc[16] = {0}, sign_to_enc[16] = {0}; + int cstat, bestcstat = 0; + int nz_coeff=0; + double lagr, lagrAcc = 0, minlagr = 0; + VideoParameters *p_Vid = currMB->p_Vid; + + int subblock_x = ((b8 & 0x1) == 0) ? (((b4 & 0x1) == 0) ? 0 : 1) : (((b4 & 0x1) == 0) ? 2 : 3); + // horiz. position for coeff_count context + int subblock_y = (b8 < 2) ? ((b4 < 2) ? 0 : 1) :((b4 < 2) ? 2 : 3); + // vert. position for coeff_count context + int nnz; + levelDataStruct *dataLevel = &levelData[0]; + + if (block_type != CHROMA_AC) + nnz = predict_nnz(currMB, LUMA, subblock_x, subblock_y); + else + nnz = predict_nnz_chroma(currMB, currMB->subblock_x >> 2, (currMB->subblock_y >> 2) + 4); + + for (coeff_ctr=0;coeff_ctr < coeff_num;coeff_ctr++) + { + levelTrellis[coeff_ctr] = 0; + + for(k=0; k < dataLevel->noLevels; k++) + { + dataLevel->errLevel[k] /= 32768; + } + + lagrAcc += dataLevel->errLevel[dataLevel->noLevels - 1]; + + level_to_enc[coeff_ctr] = dataLevel->pre_level; + sign_to_enc[coeff_ctr] = dataLevel->sign; + + if(dataLevel->noLevels > 1) + { + dataLevel->coeff_ctr = coeff_ctr; + lastnonzero = coeff_ctr; + } + else + dataLevel->coeff_ctr = -1; + dataLevel++; + } + + if(lastnonzero != -1) + { + //sort the coefficients based on their absolute value + qsort(levelData, lastnonzero + 1, sizeof(levelDataStruct), cmp); + dataLevel = &levelData[lastnonzero]; + + for(coeff_ctr = lastnonzero; coeff_ctr >= 0; coeff_ctr--) // go over all coeff + { + if(dataLevel->noLevels == 1) + { + dataLevel--; + continue; + } + + lagrAcc -= dataLevel->errLevel[dataLevel->noLevels-1]; + for(cstat=0; cstatnoLevels; cstat++) // go over all states of cur coeff k + { + level_to_enc[dataLevel->coeff_ctr] = dataLevel->level[cstat]; + lagr = lagrAcc + dataLevel->errLevel[cstat]; + lagr += lambda * est_CAVLC_bits( p_Vid, level_to_enc, sign_to_enc, nnz, block_type); + if(cstat==0 || lagrerrLevel[bestcstat]; + level_to_enc[dataLevel->coeff_ctr] = dataLevel->level[bestcstat]; + dataLevel--; + } + + for(coeff_ctr = 0; coeff_ctr <= lastnonzero; coeff_ctr++) + { + levelTrellis[coeff_ctr] = level_to_enc[coeff_ctr]; + if (level_to_enc[coeff_ctr] != 0) + nz_coeff++; + } + } + + p_Vid->nz_coeff [p_Vid->current_mb_nr ][subblock_x][subblock_y] = nz_coeff; +} + +/*! +**************************************************************************** +* \brief +* Initialize levelData +**************************************************************************** +*/ +void init_trellis_data_4x4_CAVLC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, LevelQuantParams **q_params, + const byte *p_scan, levelDataStruct *dataLevel, int type) +{ + Slice *currSlice = currMB->p_Slice; + int i, j, coeff_ctr; + int *m7; + int end_coeff_ctr = ( ( type == LUMA_4x4 ) ? 16 : 15 ); + int q_bits = Q_BITS + qp_per; + int q_offset = ( 1 << (q_bits - 1) ); + int scaled_coeff, level, lowerInt, k; + double err, estErr; + + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + if (*m7 == 0) + { + dataLevel->levelDouble = 0; + dataLevel->level[0] = 0; + dataLevel->noLevels = 1; + err = 0.0; + dataLevel->errLevel[0] = 0.0; + dataLevel->pre_level = 0; + dataLevel->sign = 0; + } + else + { + estErr = ((double) estErr4x4[qp_rem][j][i]) / currSlice->norm_factor_4x4; + + scaled_coeff = iabs(*m7) * q_params[j][i].ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt = ((scaled_coeff - (level << q_bits)) < q_offset )? 1 : 0; + + dataLevel->level[0] = 0; + if (level == 0 && lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else if (level == 0 && lowerInt == 0) + { + dataLevel->level[1] = 1; + dataLevel->noLevels = 2; + } + else if (level > 0 && lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + + if(dataLevel->noLevels == 1) + dataLevel->pre_level = 0; + else + dataLevel->pre_level = (iabs (*m7) * q_params[j][i].ScaleComp + q_params[j][i].OffsetComp) >> q_bits; + dataLevel->sign = isign(*m7); + } + dataLevel++; + } +} + +/*! +**************************************************************************** +* \brief +* Initialize levelData for Luma DC +**************************************************************************** +*/ +void init_trellis_data_DC_CAVLC(Macroblock *currMB, int **tblock, int qp_per, int qp_rem, + LevelQuantParams *q_params, const byte *p_scan, + levelDataStruct *dataLevel) +{ + Slice *currSlice = currMB->p_Slice; + int i, j, coeff_ctr, end_coeff_ctr = 16; + int q_bits = Q_BITS + qp_per + 1; + int q_offset = ( 1 << (q_bits - 1) ); + int scaled_coeff, level, lowerInt, k; + int *m7; + double err, estErr = (double) estErr4x4[qp_rem][0][0] / currSlice->norm_factor_4x4; // note that we could also use int64 + + for (coeff_ctr = 0; coeff_ctr < end_coeff_ctr; coeff_ctr++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + m7 = &tblock[j][i]; + + if (*m7 == 0) + { + dataLevel->levelDouble = 0; + dataLevel->level[0] = 0; + dataLevel->noLevels = 1; + err = 0.0; + dataLevel->errLevel[0] = 0.0; + dataLevel->pre_level = 0; + dataLevel->sign = 0; + } + else + { + scaled_coeff = iabs(*m7) * q_params->ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt=( (scaled_coeff - (level<level[0] = 0; + if (level == 0 && lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else if (level == 0 && lowerInt == 0) + { + dataLevel->level[1] = 1; + dataLevel->noLevels = 2; + } + else if (level > 0 && lowerInt == 1) + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = (err * err * estErr); + } + + if(dataLevel->noLevels == 1) + dataLevel->pre_level = 0; + else + dataLevel->pre_level = (iabs (*m7) * q_params->ScaleComp + q_params->OffsetComp) >> q_bits; + dataLevel->sign = isign(*m7); + } + dataLevel++; + } +} + +/*! +**************************************************************************** +* \brief +* Initialize levelData +**************************************************************************** +*/ +void init_trellis_data_8x8_CAVLC(Macroblock *currMB, int **tblock, int block_x, int qp_per, int qp_rem, LevelQuantParams **q_params, + const byte *p_scan, levelDataStruct levelData[4][16]) +{ + Slice *currSlice = currMB->p_Slice; + int i, j, block, coeff_ctr; + int *m7; + int q_bits = Q_BITS_8 + qp_per; + int q_offset = ( 1 << (q_bits - 1) ); + double err, estErr; + int scaled_coeff, level, lowerInt, k; + + levelDataStruct *dataLevel = &levelData[0][0]; + + for (coeff_ctr = 0; coeff_ctr < 16; coeff_ctr++) + { + for (block = 0; block < 4; block++) + { + i = *p_scan++; // horizontal position + j = *p_scan++; // vertical position + + m7 = &tblock[j][block_x + i]; + + dataLevel = &levelData[block][coeff_ctr]; + if (*m7 == 0) + { + dataLevel->levelDouble = 0; + dataLevel->level[0] = 0; + dataLevel->noLevels = 1; + err = 0.0; + dataLevel->errLevel[0] = 0.0; + dataLevel->pre_level = 0; + dataLevel->sign = 0; + } + else + { + estErr = (double) estErr8x8[qp_rem][j][i] / currSlice->norm_factor_8x8; + + scaled_coeff = iabs(*m7) * q_params[j][i].ScaleComp; + dataLevel->levelDouble = scaled_coeff; + level = (scaled_coeff >> q_bits); + + lowerInt = ((scaled_coeff - (level << q_bits)) < q_offset ) ? 1 : 0; + + dataLevel->level[0] = 0; + if (level == 0 && lowerInt == 1) + { + dataLevel->noLevels = 1; + } + else if (level == 0 && lowerInt == 0) + { + dataLevel->level[1] = 1; + dataLevel->noLevels = 2; + } + else if (level > 0 && lowerInt == 1) + { + if (level > 1) + { + dataLevel->level[1] = level - 1; + dataLevel->level[2] = level; + dataLevel->noLevels = 3; + } + else + { + dataLevel->level[1] = level; + dataLevel->noLevels = 2; + } + } + else + { + dataLevel->level[1] = level; + dataLevel->level[2] = level + 1; + dataLevel->noLevels = 3; + } + + for (k = 0; k < dataLevel->noLevels; k++) + { + err = (double)(dataLevel->level[k] << q_bits) - (double)scaled_coeff; + dataLevel->errLevel[k] = err * err * estErr; + } + + if(dataLevel->noLevels == 1) + dataLevel->pre_level = 0; + else + dataLevel->pre_level = (iabs (*m7) * q_params[j][i].ScaleComp + q_params[j][i].OffsetComp) >> q_bits; + dataLevel->sign = isign(*m7); + } + } + } +} + + diff --git a/lencod/src/rdpicdecision.c b/lencod/src/rdpicdecision.c new file mode 100644 index 0000000..f93e6fc --- /dev/null +++ b/lencod/src/rdpicdecision.c @@ -0,0 +1,64 @@ + +/*! +************************************************************************************* +* \file rdpicdecision.c +* +* \brief +* Perform RD optimal decisions between multiple coded versions of the same picture +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +************************************************************************************* +*/ + +#include "global.h" +#include + + +/*! + ************************************************************************ + * \brief + * RD decision between possible encoding cases + ************************************************************************ + */ +int rd_pic_decision(double snrY_version1, double snrY_version2, int bits_version1, int bits_version2, double lambda_picture) +{ + double cost_version1, cost_version2; + + cost_version1 = (double) bits_version1 * lambda_picture + snrY_version1; + cost_version2 = (double) bits_version2 * lambda_picture + snrY_version2; + //printf("%d %d %.2f %.2f %.2f %.2f \n",bits_version1,bits_version2,snrY_version1,snrY_version2,cost_version1,cost_version2); + if (cost_version2 > cost_version1 || (cost_version2 == cost_version1 && snrY_version2 >= snrY_version1) ) + return (0); + else + return (1); +} + +/*! + ************************************************************************ + * \brief + * Picture Coding Decision + ************************************************************************ + */ +int picture_coding_decision (VideoParameters *p_Vid, Picture *picture1, Picture *picture2, int qp) +{ + double lambda_picture; + double sse_picture1, sse_picture2; + + if (p_Vid->p_Inp->NumberBFrames) + lambda_picture = (qp < 20 ? 0.55 : 0.68) * pow (2, (qp - SHIFT_QP) / 3.0) * ((p_Vid->type == B_SLICE) || (p_Vid->type == SP_SLICE || p_Vid->type == SI_SLICE) ? 2 : 1); + else + lambda_picture = (qp < 20 ? 0.55 : 0.68) * pow (2, (qp - SHIFT_QP) / 3.0); + + if(picture1->distortion.value[0] == 0) + return 0; + else if(picture2->distortion.value[0] == 0) + return 1; + + sse_picture1 = picture1->distortion.value[0] + picture1->distortion.value[1] + picture1->distortion.value[2]; + sse_picture2 = picture2->distortion.value[0] + picture2->distortion.value[1] + picture2->distortion.value[2]; + + return rd_pic_decision(sse_picture1, sse_picture2, picture1->bits_per_picture, picture2->bits_per_picture, lambda_picture); +} + diff --git a/lencod/src/report.c b/lencod/src/report.c new file mode 100644 index 0000000..414d98f --- /dev/null +++ b/lencod/src/report.c @@ -0,0 +1,1514 @@ +/*! + * \file + * report.c + * \brief + * Report related files() + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Karsten Suehring + * - Alexis Michael Tourapis + *********************************************************************** + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "context_ini.h" +#include "explicit_gop.h" +#include "filehandle.h" +#include "fmo.h" +#include "image.h" +#include "intrarefresh.h" +#include "leaky_bucket.h" +#include "me_epzs.h" +#include "me_epzs_int.h" +#include "output.h" +#include "parset.h" +#include "report.h" +#include "img_process_types.h" + + +static const char DistortionType[3][20] = {"SAD", "SSE", "Hadamard SAD"}; + +void report_log_mode (VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats); +/*! + ************************************************************************ + * \brief + * Reports frame statistical data to a stats file + ************************************************************************ + */ +void report_frame_statistic(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + FILE *p_stat_frm = NULL; + + int i; + char name[30]; + int bitcounter; + StatParameters *cur_stats = &p_Vid->enc_picture->stats; + +#ifndef WIN32 + time_t now; + struct tm *l_time; + char string[1000]; +#else + char timebuf[128]; +#endif + + // write to log file + if ((p_stat_frm = fopen("stat_frame.dat", "r")) == 0) // check if file exists + { + if ((p_stat_frm = fopen("stat_frame.dat", "a")) == NULL) // append new statistic at the end + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "stat_frame.dat.dat"); + error(errortext, 500); + } + else // Create header for new log file + { + fprintf(p_stat_frm, " --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \n"); + fprintf(p_stat_frm, "| Encoder statistics. This file is generated during first encoding session, new sessions will be appended |\n"); + fprintf(p_stat_frm, " --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \n"); + } + } + else + { + fclose (p_stat_frm); + if ((p_stat_frm = fopen("stat_frame.dat", "a")) == NULL) // File exists, just open for appending + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "stat_frame.dat.dat"); + error(errortext, 500); + } + } + + if (p_Vid->frame_statistic_start) + { + fprintf(p_stat_frm, "| ver | Date | Time | Sequence |Frm | QP |P/MbInt| Bits | SNRY | SNRU | SNRV | I4 | I8 | I16 | IC0 | IC1 | IC2 | IC3 | PI4 | PI8 | PI16 | P0 | P1 | P2 | P3 | P1*4*| P1*8*| P2*4*| P2*8*| P3*4*| P3*8*| P8 | P8:4 | P4*4*| P4*8*| P8:5 | P8:6 | P8:7 | BI4 | BI8 | BI16 | B0 | B1 | B2 | B3 | B0*4*| B0*8*| B1*4*| B1*8*| B2*4*| B2*8*| B3*4*| B3*8*| B8 | B8:0 |B80*4*|B80*8*| B8:4 | B4*4*| B4*8*| B8:5 | B8:6 | B8:7 |\n"); + fprintf(p_stat_frm, " ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ \n"); + } + + //report + fprintf(p_stat_frm, "|%4s/%s", VERSION, EXT_VERSION); + +#ifdef WIN32 + _strdate( timebuf ); + fprintf(p_stat_frm, "| %1.5s |", timebuf); + + _strtime( timebuf); + fprintf(p_stat_frm, " % 1.5s |", timebuf); +#else + now = time ((time_t *) NULL); // Get the system time and put it into 'now' as 'calender time' + time (&now); + l_time = localtime (&now); + strftime (string, sizeof string, "%d-%b-%Y", l_time); + fprintf(p_stat_frm, "| %1.5s |", string ); + + strftime (string, sizeof string, "%H:%M:%S", l_time); + fprintf(p_stat_frm, " %1.5s |", string); +#endif + + for (i=0;i<30;i++) + name[i] = p_Inp->input_file1.fname[i + imax(0,(int) (strlen(p_Inp->input_file1.fname)- 30))]; // write last part of path, max 30 chars + + fprintf(p_stat_frm, "%30.30s|", name); + fprintf(p_stat_frm, "%3d |", p_Vid->frame_no); + fprintf(p_stat_frm, "%3d |", p_Vid->qp); + fprintf(p_stat_frm, " %d/%d |", p_Inp->PicInterlace, p_Inp->MbInterlace); + +#if (MVC_EXTENSION_ENABLE) + if (p_Vid->curr_frm_idx == 0 && p_Vid->frame_num == 0 && !p_Vid->view_id) +#else + if (p_Vid->curr_frm_idx == 0 && p_Vid->frame_num == 0) +#endif + { + bitcounter = (int) p_Vid->p_Stats->bit_counter[I_SLICE]; + } + else + { + bitcounter = (int) (p_Vid->p_Stats->bit_ctr_n - p_Vid->last_bit_ctr_n); + p_Vid->last_bit_ctr_n = p_Vid->p_Stats->bit_ctr_n; + } + + //report bitrate + fprintf(p_stat_frm, " %9d|", bitcounter); + + //report snr's + fprintf(p_stat_frm, " %2.4f| %2.4f| %2.4f|", p_Dist->metric[PSNR].value[0], p_Dist->metric[PSNR].value[1], p_Dist->metric[PSNR].value[2]); + + //report modes + //I-Modes + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[I_SLICE][I4MB ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[I_SLICE][I8MB ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[I_SLICE][I16MB]); + + //chroma intra mode + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->intra_chroma_mode[0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->intra_chroma_mode[1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->intra_chroma_mode[2]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->intra_chroma_mode[3]); + + //P-Modes + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][I4MB ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][I8MB ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][I16MB]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][0 ]); + + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][1 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][2 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][3 ]); + + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][1][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][1][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][2][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][2][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][3][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][3][1]); + + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][P8x8 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][4 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][4][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[P_SLICE][4][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][5 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][6 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[P_SLICE][7 ]); + + //B-Modes + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][I4MB ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][I8MB ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][I16MB]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][0 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][1 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][2 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][3 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][0][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][0][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][1][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][1][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][2][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][2][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][3][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][3][1]); + + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][P8x8]); + fprintf(p_stat_frm, " %d|", (cur_stats->b8_mode_0_use [B_SLICE][0] + cur_stats->b8_mode_0_use [B_SLICE][1])); + fprintf(p_stat_frm, " %5d|", cur_stats->b8_mode_0_use [B_SLICE][0]); + fprintf(p_stat_frm, " %5d|", cur_stats->b8_mode_0_use [B_SLICE][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][4 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][4][0]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use_transform[B_SLICE][4][1]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][5 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][6 ]); + fprintf(p_stat_frm, " %5" FORMAT_OFF_T "|", cur_stats->mode_use[B_SLICE][7 ]); + + fprintf(p_stat_frm, "\n"); + + //save the last results + p_Vid->frame_statistic_start = 0; + fclose(p_stat_frm); +} + + +double report_slice_pred_stats(FILE *p_stat, StatParameters *p_Stats, int slice_type, double bit_use, char *slice_name) +{ + fprintf(p_stat,"\n ---------------------|----------------|-----------------|"); + fprintf(p_stat,"\n %8s | Mode used | MotionInfo bits |", slice_name); + fprintf(p_stat,"\n ---------------------|----------------|-----------------|"); + fprintf(p_stat,"\n Mode 0 (copy) | %5" FORMAT_OFF_T " | %8.2f |", p_Stats->mode_use[slice_type][0 ], (double)p_Stats->bit_use_mode[slice_type][0 ] / bit_use); + fprintf(p_stat,"\n Mode 1 (16x16) | %5" FORMAT_OFF_T " | %8.2f |", p_Stats->mode_use[slice_type][1 ], (double)p_Stats->bit_use_mode[slice_type][1 ] / bit_use); + fprintf(p_stat,"\n Mode 2 (16x8) | %5" FORMAT_OFF_T " | %8.2f |", p_Stats->mode_use[slice_type][2 ], (double)p_Stats->bit_use_mode[slice_type][2 ] / bit_use); + fprintf(p_stat,"\n Mode 3 (8x16) | %5" FORMAT_OFF_T " | %8.2f |", p_Stats->mode_use[slice_type][3 ], (double)p_Stats->bit_use_mode[slice_type][3 ] / bit_use); + fprintf(p_stat,"\n Mode 4 (8x8) | %5" FORMAT_OFF_T " | %8.2f |", p_Stats->mode_use[slice_type][P8x8], (double)p_Stats->bit_use_mode[slice_type][P8x8] / bit_use); + fprintf(p_stat,"\n Mode 5 intra 4x4 | %5" FORMAT_OFF_T " |-----------------|", p_Stats->mode_use[slice_type][I4MB]); + fprintf(p_stat,"\n Mode 6 intra 8x8 | %5" FORMAT_OFF_T " |", p_Stats->mode_use[slice_type][I8MB]); + fprintf(p_stat,"\n Mode 7+ intra 16x16 | %5" FORMAT_OFF_T " |", p_Stats->mode_use[slice_type][I16MB]); + fprintf(p_stat,"\n Mode intra IPCM | %5" FORMAT_OFF_T " |", p_Stats->mode_use[slice_type][IPCM ]); + + return (double)(p_Stats->bit_use_mode[slice_type][0] + p_Stats->bit_use_mode[slice_type][1] + p_Stats->bit_use_mode[slice_type][2] + + p_Stats->bit_use_mode[slice_type][3] + p_Stats->bit_use_mode[slice_type][P8x8]) / bit_use; +} + +/*! + *********************************************************************** + * \brief + * Terminates and reports statistics on error. + * + *********************************************************************** + */ +void report_stats_on_error(void) +{ + free_encoder_memory(p_Enc->p_Vid, p_Enc->p_Inp); + exit (-1); +} + + +void report_stats(VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats, int64 bit_use[NUM_SLICE_TYPES][2]) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + FILE *p_stat; //!< status file for the last encoding session + double mean_motion_info_bit_use[NUM_SLICE_TYPES] = {0.0}; + int i; + + if (strlen(p_Inp->StatsFile) == 0) + strcpy (p_Inp->StatsFile,"stats.dat"); + + if ((p_stat = fopen(p_Inp->StatsFile, "wt")) == 0) + { + snprintf(errortext, ET_SIZE, "Error open file %s", p_Inp->StatsFile); + error(errortext, 500); + } + + fprintf(p_stat," -------------------------------------------------------------- \n"); + fprintf(p_stat," This file contains statistics for the last encoded sequence \n"); + fprintf(p_stat," -------------------------------------------------------------- \n"); + fprintf(p_stat, " Sequence : %s\n", p_Inp->input_file1.fname); + + + fprintf(p_stat, " No.of coded pictures : %4d\n", p_Stats->frame_counter); + fprintf(p_stat, " Freq. for encoded bitstream : %4.0f\n", p_Inp->output.frame_rate); + + fprintf(p_stat, " I Slice Bitrate(kb/s) : %6.2f\n", p_Stats->bitrate_st[I_SLICE] / 1000.0); + fprintf(p_stat, " P Slice Bitrate(kb/s) : %6.2f\n", p_Stats->bitrate_st[P_SLICE] / 1000.0); + fprintf(p_stat, " B Slice Bitrate(kb/s) : %6.2f\n", p_Stats->bitrate_st[B_SLICE] / 1000.0); + fprintf(p_stat, " Total Bitrate(kb/s) : %6.2f\n", p_Stats->bitrate / 1000.0); + + for (i = 0; i < 3; i++) + { + fprintf(p_stat," ME Level %1d Metric : %s\n", i, DistortionType[p_Inp->MEErrorMetric[i]]); + } + fprintf(p_stat," Mode Decision Metric : %s\n", DistortionType[p_Inp->ModeDecisionMetric]); + + switch ( p_Inp->ChromaMEEnable ) + { + case 1: + fprintf(p_stat," ME for components : YCbCr\n"); + break; + default: + fprintf(p_stat," ME for components : Y\n"); + break; + } + + fprintf(p_stat, " Image format : %dx%d\n", p_Inp->output.width[0], p_Inp->output.height[0]); + + if (p_Inp->intra_upd) + fprintf(p_stat," Error robustness : On\n"); + else + fprintf(p_stat," Error robustness : Off\n"); + + fprintf(p_stat, " Search range : %d\n", p_Inp->search_range[0]); +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->SepViewInterSearch ) + { + fprintf(p_stat, " Search range (view 1) : %d\n", p_Inp->search_range[1]); + } +#endif + + fprintf(p_stat, " Total number of references : %d\n", p_Inp->num_ref_frames_org); + fprintf(p_stat, " References for P slices : %d\n", p_Inp->P_List0_refs_org[0] ? p_Inp->P_List0_refs_org[0] : p_Inp->num_ref_frames_org); + + if (p_Stats->frame_ctr[B_SLICE]!=0) + { + fprintf(p_stat, " List0 refs for B slices : %d\n", p_Inp->B_List0_refs_org[0] ? p_Inp->B_List0_refs_org[0] : p_Inp->num_ref_frames_org); + fprintf(p_stat, " List1 refs for B slices : %d\n", p_Inp->B_List1_refs_org[0] ? p_Inp->B_List1_refs_org[0] : p_Inp->num_ref_frames_org); + } + +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->num_of_layers > 1 ) + { + fprintf(p_stat, " View 1 refs for P slices : %d\n", p_Inp->P_List0_refs_org[1] ? p_Inp->P_List0_refs_org[1] : p_Inp->num_ref_frames_org); + fprintf(p_stat, " View 1 L0 refs for B slices : %d\n", p_Inp->B_List0_refs_org[1] ? p_Inp->B_List0_refs_org[1] : p_Inp->num_ref_frames_org); + fprintf(p_stat, " View 1 L1 refs for B slices : %d\n", p_Inp->B_List1_refs_org[1] ? p_Inp->B_List1_refs_org[1] : p_Inp->num_ref_frames_org); + } +#endif + + fprintf(p_stat, " Profile/Level IDC : (%d,%d)\n", p_Inp->ProfileIDC, p_Inp->LevelIDC); + if (p_Inp->symbol_mode == CAVLC) + fprintf(p_stat, " Entropy coding method : CAVLC\n"); + else + fprintf(p_stat, " Entropy coding method : CABAC\n"); + + if (p_Inp->MbInterlace) + fprintf(p_stat, " MB Field Coding : On \n"); + + if (p_Inp->SearchMode[0] == EPZS || p_Inp->SearchMode[1] == EPZS) + { + EPZSOutputStats(p_Inp, p_stat, 1); + } + + if (p_Inp->full_search == 2) + fprintf(p_stat," Search range restrictions : none\n"); + else if (p_Inp->full_search == 1) + fprintf(p_stat," Search range restrictions : older reference frames\n"); + else + fprintf(p_stat," Search range restrictions : smaller blocks and older reference frames\n"); + + if (p_Inp->rdopt) + fprintf(p_stat," RD-optimized mode decision : used\n"); + else + fprintf(p_stat," RD-optimized mode decision : not used\n"); + + fprintf(p_stat,"\n ---------------------|----------------|---------------|"); + fprintf(p_stat,"\n Item | Intra | All frames |"); + fprintf(p_stat,"\n ---------------------|----------------|---------------|"); + fprintf(p_stat,"\n SNR Y(dB) |"); + fprintf(p_stat," %5.2f |", p_Dist->metric[PSNR].avslice[I_SLICE][0]); + fprintf(p_stat," %5.2f |", p_Dist->metric[PSNR].average[0]); + fprintf(p_stat,"\n SNR U/V (dB) |"); + fprintf(p_stat," %5.2f/%5.2f |", p_Dist->metric[PSNR].avslice[I_SLICE][1], p_Dist->metric[PSNR].avslice[I_SLICE][2]); + fprintf(p_stat," %5.2f/%5.2f |", p_Dist->metric[PSNR].average[1], p_Dist->metric[PSNR].average[2]); + fprintf(p_stat,"\n ---------------------|----------------|---------------|"); + fprintf(p_stat,"\n"); + + fprintf(p_stat,"\n ---------------------|----------------|---------------|---------------|"); + fprintf(p_stat,"\n SNR | I | P | B |"); + fprintf(p_stat,"\n ---------------------|----------------|---------------|---------------|"); + fprintf(p_stat,"\n SNR Y(dB) | %5.3f | %5.3f | %5.3f |", + p_Dist->metric[PSNR].avslice[I_SLICE][0], p_Dist->metric[PSNR].avslice[P_SLICE][0], p_Dist->metric[PSNR].avslice[B_SLICE][0]); + fprintf(p_stat,"\n SNR U(dB) | %5.3f | %5.3f | %5.3f |", + p_Dist->metric[PSNR].avslice[I_SLICE][1], p_Dist->metric[PSNR].avslice[P_SLICE][1], p_Dist->metric[PSNR].avslice[B_SLICE][1]); + fprintf(p_stat,"\n SNR V(dB) | %5.3f | %5.3f | %5.3f |", + p_Dist->metric[PSNR].avslice[I_SLICE][2], p_Dist->metric[PSNR].avslice[P_SLICE][2], p_Dist->metric[PSNR].avslice[B_SLICE][2]); + fprintf(p_stat,"\n ---------------------|----------------|---------------|---------------|"); + fprintf(p_stat,"\n"); + + // QUANT. + fprintf(p_stat,"\n ---------------------|----------------|---------------|---------------|"); + fprintf(p_stat,"\n Ave Quant | I | P | B |"); + fprintf(p_stat,"\n ---------------------|----------------|---------------|---------------|"); + fprintf(p_stat,"\n QP | %5.3f | %5.3f | %5.3f |", + (float)p_Stats->quant[I_SLICE]/dmax(1.0,(float)p_Stats->num_macroblocks[I_SLICE]), + (float)p_Stats->quant[P_SLICE]/dmax(1.0,(float)p_Stats->num_macroblocks[P_SLICE]), + (float)p_Stats->quant[B_SLICE]/dmax(1.0,(float)p_Stats->num_macroblocks[B_SLICE])); + fprintf(p_stat,"\n ---------------------|----------------|---------------|---------------|"); + fprintf(p_stat,"\n"); + + // MODE + fprintf(p_stat,"\n ---------------------|----------------|"); + fprintf(p_stat,"\n Intra | Mode used |"); + fprintf(p_stat,"\n ---------------------|----------------|"); + fprintf(p_stat,"\n Mode 0 intra 4x4 | %5" FORMAT_OFF_T " |", p_Stats->mode_use[I_SLICE][I4MB ]); + fprintf(p_stat,"\n Mode 1 intra 8x8 | %5" FORMAT_OFF_T " |", p_Stats->mode_use[I_SLICE][I8MB ]); + fprintf(p_stat,"\n Mode 2+ intra 16x16 | %5" FORMAT_OFF_T " |", p_Stats->mode_use[I_SLICE][I16MB]); + fprintf(p_stat,"\n Mode intra IPCM | %5" FORMAT_OFF_T " |", p_Stats->mode_use[I_SLICE][IPCM ]); + + // P slices + if (p_Stats->frame_ctr[P_SLICE]!=0) + { + mean_motion_info_bit_use[P_SLICE] = report_slice_pred_stats(p_stat, p_Stats, P_SLICE,(double) bit_use[P_SLICE][0], "P Slice "); + } + // B slices + if (p_Stats->frame_ctr[B_SLICE]!=0) + { + mean_motion_info_bit_use[B_SLICE] = report_slice_pred_stats(p_stat, p_Stats, B_SLICE,(double) bit_use[B_SLICE][0], "B Slice "); + } + // SP slices + if (p_Stats->frame_ctr[SP_SLICE]!=0) + { + mean_motion_info_bit_use[SP_SLICE] = report_slice_pred_stats(p_stat, p_Stats, SP_SLICE,(double) bit_use[SP_SLICE][0], "SP Slice"); + } + + + fprintf(p_stat,"\n ---------------------|----------------|"); + fprintf(p_stat,"\n"); + + fprintf(p_stat,"\n ---------------------|----------------|----------------|----------------|----------------|"); + fprintf(p_stat,"\n Bit usage: | Intra | Inter | B frame | SP frame |"); + fprintf(p_stat,"\n ---------------------|----------------|----------------|----------------|----------------|"); + + fprintf(p_stat,"\n Header |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_header[I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_header[P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_header[B_SLICE] / bit_use[B_SLICE][0]); + + fprintf(p_stat,"\n Mode |"); + fprintf(p_stat," %10.2f |", (float)p_Stats->bit_use_mb_type[I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float)p_Stats->bit_use_mb_type[P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float)p_Stats->bit_use_mb_type[B_SLICE] / bit_use[B_SLICE][0]); + + fprintf(p_stat,"\n Motion Info |"); + fprintf(p_stat," ./. |"); + fprintf(p_stat," %10.2f |", mean_motion_info_bit_use[P_SLICE]); + fprintf(p_stat," %10.2f |", mean_motion_info_bit_use[B_SLICE]); + + fprintf(p_stat,"\n CBP Y/C |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->tmp_bit_use_cbp[I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->tmp_bit_use_cbp[P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->tmp_bit_use_cbp[B_SLICE] / bit_use[B_SLICE][0]); + + // Print SP_SLICE + fprintf(p_stat,"\n Coeffs. Y |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[0][I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[0][P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[0][B_SLICE] / bit_use[B_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[0][SP_SLICE] / bit_use[SP_SLICE][0]); + + fprintf(p_stat,"\n Coeffs. C |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeffC[I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeffC[P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeffC[B_SLICE] / bit_use[B_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeffC[SP_SLICE] / bit_use[SP_SLICE][0]); + + fprintf(p_stat,"\n Coeffs. CB |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[1][I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[1][P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[1][B_SLICE] / bit_use[B_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[1][SP_SLICE] / bit_use[SP_SLICE][0]); + + fprintf(p_stat,"\n Coeffs. CR |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[2][I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[2][P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[2][B_SLICE] / bit_use[B_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_coeff[2][SP_SLICE] / bit_use[SP_SLICE][0]); + + fprintf(p_stat,"\n Delta quant |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_delta_quant[I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_delta_quant[P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_delta_quant[B_SLICE] / bit_use[B_SLICE][0]); + + fprintf(p_stat,"\n Stuffing Bits |"); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_stuffing_bits[I_SLICE] / bit_use[I_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_stuffing_bits[P_SLICE] / bit_use[P_SLICE][0]); + fprintf(p_stat," %10.2f |", (float) p_Stats->bit_use_stuffing_bits[B_SLICE] / bit_use[B_SLICE][0]); + + fprintf(p_stat,"\n ---------------------|----------------|----------------|----------------|"); + fprintf(p_stat,"\n average bits/frame |"); + fprintf(p_stat," %10.2f |", (float) bit_use[I_SLICE][1] / (float) bit_use[I_SLICE][0] ); + fprintf(p_stat," %10.2f |", (float) bit_use[P_SLICE][1] / (float) bit_use[P_SLICE][0] ); + fprintf(p_stat," %10.2f |", (float) bit_use[B_SLICE][1] / (float) bit_use[B_SLICE][0] ); + fprintf(p_stat,"\n ---------------------|----------------|----------------|----------------|"); + fprintf(p_stat,"\n"); + + fclose(p_stat); +} + + +void report_log(VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + FILE *p_log = p_Vid->p_log; + char name[40]; + int i; +#ifndef WIN32 + time_t now; + struct tm *l_time; + char string[1000]; +#else + char timebuf[128]; +#endif + + if ((p_log = fopen("log.dat", "r")) == 0) // check if file exists + { + if ((p_log = fopen("log.dat", "a")) == NULL) // append new statistic at the end + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "log.dat"); + error(errortext, 500); + } + else // Create header for new log file + { + fprintf(p_log," ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ \n"); + fprintf(p_log,"| Encoder statistics. This file is generated during first encoding session, new sessions will be appended |\n"); + fprintf(p_log," ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ \n"); + fprintf(p_log,"| ver | Date | Time | Sequence | #Img |P/MbInt| QPI| QPP| QPB| Format |Iperiod| #B | FMES | Hdmd | S.R |#Ref | Freq |Coding|RD-opt|Intra upd|8x8Tr| SNRY 1| SNRU 1| SNRV 1| SNRY N| SNRU N| SNRV N|#Bitr I|#Bitr P|#Bitr B|#Bitr IPB| Total Time | Me Time |\n"); + fprintf(p_log," ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ \n"); + + } + } + else + { + fclose (p_log); + if ((p_log = fopen("log.dat", "a")) == NULL) // File exists, just open for appending + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "log.dat"); + error(errortext, 500); + } + } + fprintf(p_log,"|%5s/%-5s", VERSION, EXT_VERSION); + +#ifdef WIN32 + _strdate( timebuf ); + fprintf(p_log,"| %1.5s |", timebuf ); + + _strtime( timebuf); + fprintf(p_log," % 1.5s |", timebuf); +#else + now = time ((time_t *) NULL); // Get the system time and put it into 'now' as 'calender time' + time (&now); + l_time = localtime (&now); + strftime (string, sizeof string, "%d-%b-%Y", l_time); + fprintf(p_log,"| %1.5s |", string ); + + strftime (string, sizeof string, "%H:%M:%S", l_time); + fprintf(p_log," %1.5s |", string ); +#endif + + for (i=0; i < 40; i++) + name[i] = p_Inp->input_file1.fname[i + imax(0, ((int) strlen(p_Inp->input_file1.fname)) - 40)]; // write last part of path, max 40 chars + fprintf(p_log,"%40.40s|",name); + + fprintf(p_log,"%5d | %d/%d |", p_Inp->no_frames, p_Inp->PicInterlace, p_Inp->MbInterlace); + fprintf(p_log," %-3d| %-3d| %-3d|", p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], p_Inp->qp[B_SLICE]); + + fprintf(p_log,"%4dx%-4d|", p_Inp->output.width[0], p_Inp->output.height[0]); + fprintf(p_log," %3d |%3d |", p_Inp->intra_period, p_Stats->NumberBFrames); + + + switch( p_Inp->SearchMode[0] ) + { + case UM_HEX: + fprintf(p_log," HEX |"); + break; + case UM_HEX_SIMPLE: + fprintf(p_log," SHEX |"); + break; + case EPZS: + fprintf(p_log," EPZS |"); + break; + case FAST_FULL_SEARCH: + fprintf(p_log," FFS |"); + break; + default: + fprintf(p_log," FS |"); + break; + } +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->SepViewInterSearch ) + { + switch( p_Inp->SearchMode[1] ) + { + case UM_HEX: + fprintf(p_log," HEX |"); + break; + case UM_HEX_SIMPLE: + fprintf(p_log," SHEX |"); + break; + case EPZS: + fprintf(p_log," EPZS |"); + break; + case FAST_FULL_SEARCH: + fprintf(p_log," FFS |"); + break; + default: + fprintf(p_log," FS |"); + break; + } + } +#endif + + fprintf(p_log," %1d%1d%1d |", p_Inp->MEErrorMetric[F_PEL], p_Inp->MEErrorMetric[H_PEL], p_Inp->MEErrorMetric[Q_PEL]); + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->SepViewInterSearch ) + { + fprintf(p_log," %3d (%3d) | %2d |", p_Inp->search_range[0], p_Inp->search_range[1], p_Inp->num_ref_frames ); + } + else +#endif + fprintf(p_log," %3d | %2d |", p_Inp->search_range[0], p_Inp->num_ref_frames ); + + fprintf(p_log," %5.2f|", p_Vid->framerate); + + if (p_Inp->symbol_mode == CAVLC) + fprintf(p_log," CAVLC|"); + else + fprintf(p_log," CABAC|"); + + fprintf(p_log," %d |", p_Inp->rdopt); + + if (p_Inp->intra_upd == 1) + fprintf(p_log," ON |"); + else + fprintf(p_log," OFF |"); + + fprintf(p_log," %d |", p_Inp->Transform8x8Mode); + + fprintf(p_log,"%7.3f|%7.3f|%7.3f|", + p_Dist->metric[PSNR].avslice[I_SLICE][0], + p_Dist->metric[PSNR].avslice[I_SLICE][1], + p_Dist->metric[PSNR].avslice[I_SLICE][2]); + fprintf(p_log,"%7.3f|%7.3f|%7.3f|", p_Dist->metric[PSNR].average[0],p_Dist->metric[PSNR].average[1],p_Dist->metric[PSNR].average[2]); + /* + fprintf(p_log,"%-5.3f|%-5.3f|%-5.3f|", p_Dist->metric[PSNR].avslice[I_SLICE][0], p_Dist->metric[PSNR].avslice[I_SLICE][1], p_Dist->metric[PSNR].avslice[I_SLICE][2]); + fprintf(p_log,"%-5.3f|%-5.3f|%-5.3f|", p_Dist->metric[PSNR].avslice[P_SLICE][0], p_Dist->metric[PSNR].avslice[P_SLICE][1], p_Dist->metric[PSNR].avslice[P_SLICE][2]); + fprintf(p_log,"%-5.3f|%-5.3f|%-5.3f|", p_Dist->metric[PSNR].avslice[B_SLICE][0], p_Dist->metric[PSNR].avslice[B_SLICE][1], p_Dist->metric[PSNR].avslice[B_SLICE][2]); + */ + fprintf(p_log,"%7.0f|%7.0f|%7.0f|%9.0f|", p_Stats->bitrate_st[I_SLICE],p_Stats->bitrate_st[P_SLICE],p_Stats->bitrate_st[B_SLICE], p_Stats->bitrate); + fprintf(p_log," %12d | %12d |", (int)p_Vid->tot_time,(int)p_Vid->me_tot_time); + + + fprintf(p_log,"\n"); + + fclose(p_log); + + p_log = fopen("data.txt", "a"); + + if ((p_Stats->NumberBFrames != 0) && (p_Stats->frame_ctr[B_SLICE] != 0)) // B picture used + { + fprintf(p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5" FORMAT_OFF_T " " + "%2.2f %2.2f %2.2f %5d " + "%2.2f %2.2f %2.2f %5" FORMAT_OFF_T " %5" FORMAT_OFF_T " %.3f\n", + p_Stats->frame_counter, p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], + p_Dist->metric[PSNR].avslice[I_SLICE][0], + p_Dist->metric[PSNR].avslice[I_SLICE][1], + p_Dist->metric[PSNR].avslice[I_SLICE][2], + p_Stats->bit_counter[I_SLICE], + 0.0, + 0.0, + 0.0, + 0, + p_Dist->metric[PSNR].average[0], + p_Dist->metric[PSNR].average[1], + p_Dist->metric[PSNR].average[2], + (p_Stats->bit_counter[I_SLICE] + p_Stats->bit_ctr) / p_Stats->frame_counter, + p_Stats->bit_counter[B_SLICE] / p_Stats->frame_ctr[B_SLICE], + (double) 0.001 * p_Vid->tot_time / (p_Stats->frame_counter)); + } + else + { + if (p_Inp->no_frames != 0) + fprintf(p_log, "%3d %2d %2d %2.2f %2.2f %2.2f %5" FORMAT_OFF_T " " + "%2.2f %2.2f %2.2f %5d " + "%2.2f %2.2f %2.2f %5" FORMAT_OFF_T " %5d %.3f\n", + p_Stats->frame_counter, p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], + p_Dist->metric[PSNR].avslice[I_SLICE][0], + p_Dist->metric[PSNR].avslice[I_SLICE][1], + p_Dist->metric[PSNR].avslice[I_SLICE][2], + p_Stats->bit_counter[I_SLICE], + 0.0, + 0.0, + 0.0, + 0, + p_Dist->metric[PSNR].average[0], + p_Dist->metric[PSNR].average[1], + p_Dist->metric[PSNR].average[2], + (p_Stats->bit_counter[I_SLICE] + p_Stats->bit_ctr)/ p_Stats->frame_counter, + 0, + (double)0.001 * p_Vid->tot_time / p_Stats->frame_counter); + } + + fclose(p_log); +} + +/*! + ************************************************************************ + * \brief + * Reports the gathered information to appropriate outputs + * \par Input: + * InputParameters *inp, \n + * VideoParameters *p_Vid, \n + * struct stat_par *p_Stats, \n + * + * \par Output: + * None + ************************************************************************ + */ +void report( VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats) +{ + DistortionParams *p_Dist = p_Vid->p_Dist; + int64 bit_use[NUM_SLICE_TYPES][2]; + int i,j; + int64 total_bits; +#if (MVC_EXTENSION_ENABLE) + int64 total_bits_v[NUM_VIEWS]; +#endif + + bit_use[ I_SLICE][0] = p_Stats->frame_ctr[I_SLICE]; + bit_use[ P_SLICE][0] = imax(p_Stats->frame_ctr[P_SLICE ] + p_Stats->frame_ctr[SP_SLICE], 1); + bit_use[ B_SLICE][0] = imax(p_Stats->frame_ctr[B_SLICE ], 1); + bit_use[SP_SLICE][0] = imax(p_Stats->frame_ctr[SP_SLICE], 1); + + // normalize time p_Stats + p_Vid->tot_time = timenorm(p_Vid->tot_time); + p_Vid->me_tot_time = timenorm(p_Vid->me_tot_time); + // Accumulate bit usage for inter and intra frames + for (j=0; j < NUM_SLICE_TYPES; j++) + { + bit_use[j][1] = 0; + } + + for (j=0; j < NUM_SLICE_TYPES; j++) + { + for(i=0; i < MAXMODE; i++) + bit_use[j][1] += p_Stats->bit_use_mode[j][i]; + + bit_use[j][1] += p_Stats->bit_use_mb_type[j]; + bit_use[j][1] += p_Stats->bit_use_header[j]; + bit_use[j][1] += p_Stats->tmp_bit_use_cbp[j]; + bit_use[j][1] += p_Stats->bit_use_coeffC[j]; + bit_use[j][1] += p_Stats->bit_use_coeff[0][j]; + bit_use[j][1] += p_Stats->bit_use_coeff[1][j]; + bit_use[j][1] += p_Stats->bit_use_coeff[2][j]; + bit_use[j][1] += p_Stats->bit_use_delta_quant[j]; + bit_use[j][1] += p_Stats->bit_use_stuffing_bits[j]; + } + + //! Currently adding NVB bits on P rate. Maybe additional p_Stats info should be created instead and added in log file + p_Stats->bitrate_st[ I_SLICE] = (p_Stats->bit_counter[ I_SLICE]) * (float) (p_Inp->output.frame_rate) / (float) (p_Stats->frame_counter); + p_Stats->bitrate_st[ P_SLICE] = (p_Stats->bit_counter[ P_SLICE]) * (float) (p_Inp->output.frame_rate) / (float) (p_Stats->frame_counter); + p_Stats->bitrate_st[ B_SLICE] = (p_Stats->bit_counter[ B_SLICE]) * (float) (p_Inp->output.frame_rate) / (float) (p_Stats->frame_counter); + p_Stats->bitrate_st[SP_SLICE] = (p_Stats->bit_counter[SP_SLICE]) * (float) (p_Inp->output.frame_rate) / (float) (p_Stats->frame_counter); + + switch (p_Inp->Verbose) + { + case 0: + case 1: + default: + fprintf(stdout,"------------------ Average data all frames -----------------------------------\n\n"); + break; + case 2: + fprintf(stdout,"------------------------------------ Average data all frames ---------------------------------\n\n"); + break; + case 3: + fprintf(stdout,"--------------------------------------- Average data all frames -------------------------------------\n\n"); + break; + } + + if (p_Inp->Verbose != 0) + { + DistMetric *snr = &p_Dist->metric[PSNR ]; + DistMetric *sse = &p_Dist->metric[SSE ]; + DistMetric *snr_rgb = &p_Dist->metric[PSNR_RGB]; + DistMetric *sse_rgb = &p_Dist->metric[SSE_RGB ]; + + int impix = p_Inp->output.size_cmp[0]; + int impix_cr = p_Inp->output.size_cmp[1]; + + float csnr_y = psnr(p_Vid->max_imgpel_value_comp_sq[0], impix , sse->average[0]); + float csnr_u = psnr(p_Vid->max_imgpel_value_comp_sq[1], impix_cr, sse->average[1]); + float csnr_v = psnr(p_Vid->max_imgpel_value_comp_sq[2], impix_cr, sse->average[2]); + +#if (MVC_EXTENSION_ENABLE) + DistMetric *snr_v[2] = {NULL, NULL}; + DistMetric *sse_v[2] = {NULL, NULL}; + float csnr_y_v[2] = {0.0, 0.0}; + float csnr_u_v[2] = {0.0, 0.0}; + float csnr_v_v[2] = {0.0, 0.0}; + + if (p_Inp->num_of_views == 2) + { + snr_v[0] = &p_Dist->metric_v[0][PSNR]; + snr_v[1] = &p_Dist->metric_v[1][PSNR]; + sse_v[0] = &p_Dist->metric_v[0][SSE]; + sse_v[1] = &p_Dist->metric_v[1][SSE]; + csnr_y_v[0] = psnr(p_Vid->max_imgpel_value_comp_sq[0], impix , sse_v[0]->average[0]); + csnr_u_v[0] = psnr(p_Vid->max_imgpel_value_comp_sq[1], impix_cr, sse_v[0]->average[1]); + csnr_v_v[0] = psnr(p_Vid->max_imgpel_value_comp_sq[2], impix_cr, sse_v[0]->average[2]); + csnr_y_v[1] = psnr(p_Vid->max_imgpel_value_comp_sq[0], impix , sse_v[1]->average[0]); + csnr_u_v[1] = psnr(p_Vid->max_imgpel_value_comp_sq[1], impix_cr, sse_v[1]->average[1]); + csnr_v_v[1] = psnr(p_Vid->max_imgpel_value_comp_sq[2], impix_cr, sse_v[1]->average[2]); + } +#endif + + fprintf(stdout, " Total encoding time for the seq. : %7.3f sec (%3.2f fps)\n", (float) p_Vid->tot_time * 0.001, 1000.0 * (float) (p_Stats->frame_counter) / (float)p_Vid->tot_time); + fprintf(stdout, " Total ME time for sequence : %7.3f sec \n\n", (float)p_Vid->me_tot_time * 0.001); + + fprintf(stdout," Y { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr->average[0], csnr_y, sse->average[0]/(float)impix); + fprintf(stdout," U { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr->average[1], csnr_u, sse->average[1]/(float)impix_cr); + fprintf(stdout," V { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr->average[2], csnr_v, sse->average[2]/(float)impix_cr); +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + fprintf( stdout, "\n" ); + fprintf(stdout," View0_Y { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_v[0]->average[0], csnr_y_v[0], sse_v[0]->average[0]/(float)impix); + fprintf(stdout," View0_U { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_v[0]->average[1], csnr_u_v[0], sse_v[0]->average[1]/(float)impix_cr); + fprintf(stdout," View0_V { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_v[0]->average[2], csnr_v_v[0], sse_v[0]->average[2]/(float)impix_cr); + fprintf( stdout, "\n" ); + fprintf(stdout," View1_Y { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_v[1]->average[0], csnr_y_v[1], sse_v[1]->average[0]/(float)impix); + fprintf(stdout," View1_U { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_v[1]->average[1], csnr_u_v[1], sse_v[1]->average[1]/(float)impix_cr); + fprintf(stdout," View1_V { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_v[1]->average[2], csnr_v_v[1], sse_v[1]->average[2]/(float)impix_cr); + } +#endif + + if(p_Inp->DistortionYUVtoRGB == 1) + { + float csnr_r = psnr(p_Vid->max_imgpel_value_comp_sq[0], impix, sse_rgb->average[0]); + float csnr_g = psnr(p_Vid->max_imgpel_value_comp_sq[1], impix, sse_rgb->average[1]); + float csnr_b = psnr(p_Vid->max_imgpel_value_comp_sq[2], impix, sse_rgb->average[2]); + + fprintf(stdout," R { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_rgb->average[0], csnr_r, sse_rgb->average[0] / (float) impix); + fprintf(stdout," G { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_rgb->average[1], csnr_g, sse_rgb->average[1] / (float) impix); + fprintf(stdout," B { PSNR (dB), cSNR (dB), MSE } : { %7.3f, %7.3f, %9.5f }\n", + snr_rgb->average[2], csnr_b, sse_rgb->average[2] / (float) impix); + } + + if (p_Inp->Distortion[SSIM] == 1) + { + if(p_Inp->DistortionYUVtoRGB == 1) + { + fprintf(stdout," SSIM {Y, R} : { %5.4f, %5.4f }\n", p_Dist->metric[SSIM].average[0], p_Dist->metric[SSIM_RGB].average[0]); + fprintf(stdout," SSIM {U, G} : { %5.4f, %5.4f }\n", p_Dist->metric[SSIM].average[1], p_Dist->metric[SSIM_RGB].average[1]); + fprintf(stdout," SSIM {V, B} : { %5.4f, %5.4f }\n", p_Dist->metric[SSIM].average[2], p_Dist->metric[SSIM_RGB].average[2]); + } + else + { + fprintf(stdout," Y SSIM : %5.4f\n", p_Dist->metric[SSIM].average[0]); + fprintf(stdout," U SSIM : %5.4f\n", p_Dist->metric[SSIM].average[1]); + fprintf(stdout," V SSIM : %5.4f\n", p_Dist->metric[SSIM].average[2]); + } + } + if (p_Inp->Distortion[MS_SSIM] == 1) + { + if(p_Inp->DistortionYUVtoRGB == 1) + { + fprintf(stdout," MS-SSIM {Y, R} : { %5.4f, %5.4f }\n", p_Dist->metric[MS_SSIM].average[0], p_Dist->metric[MS_SSIM_RGB].average[0]); + fprintf(stdout," MS-SSIM {U, G} : { %5.4f, %5.4f }\n", p_Dist->metric[MS_SSIM].average[1], p_Dist->metric[MS_SSIM_RGB].average[1]); + fprintf(stdout," MS-SSIM {V, B} : { %5.4f, %5.4f }\n", p_Dist->metric[MS_SSIM].average[2], p_Dist->metric[MS_SSIM_RGB].average[2]); + } + else + { + fprintf(stdout," Y MS-SSIM : %5.4f\n", p_Dist->metric[MS_SSIM].average[0]); + fprintf(stdout," U MS-SSIM : %5.4f\n", p_Dist->metric[MS_SSIM].average[1]); + fprintf(stdout," V MS-SSIM : %5.4f\n", p_Dist->metric[MS_SSIM].average[2]); + } + } + fprintf(stdout,"\n"); + } + else + fprintf(stdout, " Total encoding time for the seq. : %5.3f sec (%5.2f fps)\n\n", p_Vid->tot_time * 0.001, 1000.0 * (p_Stats->frame_counter) / p_Vid->tot_time); + + total_bits = p_Stats->bit_ctr_parametersets; + total_bits += p_Stats->bit_ctr_filler_data; + for (i = 0; i < NUM_SLICE_TYPES; i++) + total_bits += p_Stats->bit_counter[i]; +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + for ( j = 0; j < NUM_VIEWS; j++ ) + { + total_bits_v[j] = p_Stats->bit_ctr_parametersets_v[j]; + total_bits_v[j] += p_Stats->bit_ctr_filler_data_v[j]; + for (i = 0; i < NUM_SLICE_TYPES; i++) + total_bits_v[j] += p_Stats->bit_counter_v[j][i]; + } + } + + if (p_Inp->num_of_views == 2 && p_Vid->fld_flag) + { + if (p_Stats->frame_ctr[B_SLICE] != 0) + { + fprintf(stdout, " Total bits : %" FORMAT_OFF_T " (I %" FORMAT_OFF_T ", P %" FORMAT_OFF_T ", B %" FORMAT_OFF_T " NVB %d) \n", + total_bits_v[0] + total_bits_v[1], + p_Stats->bit_counter_v[0][I_SLICE] + p_Stats->bit_counter_v[1][I_SLICE], + p_Stats->bit_counter_v[0][P_SLICE] + p_Stats->bit_counter_v[1][P_SLICE], + p_Stats->bit_counter_v[0][B_SLICE] + p_Stats->bit_counter_v[1][B_SLICE], + p_Stats->bit_ctr_parametersets_v[0] + p_Stats->bit_ctr_parametersets_v[1]); + } + else + { + fprintf(stdout, " Total bits : %" FORMAT_OFF_T " (I %" FORMAT_OFF_T ", P %" FORMAT_OFF_T ", NVB %d) \n", + total_bits_v[0] + total_bits_v[1], + p_Stats->bit_counter_v[0][I_SLICE] + p_Stats->bit_counter_v[1][I_SLICE], + p_Stats->bit_counter_v[0][P_SLICE] + p_Stats->bit_counter_v[1][P_SLICE], + p_Stats->bit_ctr_parametersets_v[0] + p_Stats->bit_ctr_parametersets_v[1]); + } + } + else +#endif + { + if (p_Stats->frame_ctr[B_SLICE] != 0) + { + fprintf(stdout, " Total bits : %" FORMAT_OFF_T " (I %" FORMAT_OFF_T ", P %" FORMAT_OFF_T ", B %" FORMAT_OFF_T " NVB %d) \n", + total_bits, p_Stats->bit_counter[I_SLICE], p_Stats->bit_counter[P_SLICE], p_Stats->bit_counter[B_SLICE], p_Stats->bit_ctr_parametersets); + } + else + { + fprintf(stdout, " Total bits : %" FORMAT_OFF_T " (I %" FORMAT_OFF_T ", P %" FORMAT_OFF_T ", NVB %d) \n", + total_bits, p_Stats->bit_counter[I_SLICE], p_Stats->bit_counter[P_SLICE], p_Stats->bit_ctr_parametersets); + } + } +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + int view_id; + + for ( view_id = 0; view_id < NUM_VIEWS; view_id++ ) + { + if (p_Stats->frame_ctr[B_SLICE] != 0) + { + fprintf(stdout, " View %1d Total-bits : %" FORMAT_OFF_T " (I %" FORMAT_OFF_T ", P %" FORMAT_OFF_T ", B %" FORMAT_OFF_T " NVB %d) \n", + view_id, total_bits_v[view_id], p_Stats->bit_counter_v[view_id][I_SLICE], p_Stats->bit_counter_v[view_id][P_SLICE], p_Stats->bit_counter_v[view_id][B_SLICE], p_Stats->bit_ctr_parametersets_v[view_id]); + } + else + { + fprintf(stdout, " View %1d Total-bits : %" FORMAT_OFF_T " (I %" FORMAT_OFF_T ", P %" FORMAT_OFF_T ", NVB %d) \n", + view_id, total_bits_v[view_id], p_Stats->bit_counter_v[view_id][I_SLICE], p_Stats->bit_counter_v[view_id][P_SLICE], p_Stats->bit_ctr_parametersets_v[view_id]); + } + } + } + + if (p_Inp->num_of_views == 2) + { + p_Stats->bitrate= ((float) total_bits * (float) p_Inp->output.frame_rate) / ((float) (p_Stats->frame_counter>>1)); + } + else +#endif + p_Stats->bitrate= ((float) total_bits * (float) p_Inp->output.frame_rate) / ((float) (p_Stats->frame_counter)); + fprintf(stdout, " Bit rate (kbit/s) @ %2.2f Hz : %5.2f\n", p_Inp->output.frame_rate, p_Stats->bitrate / 1000.0); +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + p_Stats->bitrate_v[0] = ((float) total_bits_v[0] * (float) p_Inp->output.frame_rate) / ((float) (p_Stats->frame_counter >> 1)); + p_Stats->bitrate_v[1] = ((float) total_bits_v[1] * (float) p_Inp->output.frame_rate) / ((float) (p_Stats->frame_counter >> 1)); + fprintf(stdout, " View 0 BR (kbit/s) @ %2.2f Hz : %5.2f\n", p_Inp->output.frame_rate, p_Stats->bitrate_v[0] / 1000.0); + fprintf(stdout, " View 1 BR (kbit/s) @ %2.2f Hz : %5.2f\n", p_Inp->output.frame_rate, p_Stats->bitrate_v[1] / 1000.0); + } +#endif + + for (i = 0; i < 5; i++) + { + p_Stats->bit_ctr_emulation_prevention += p_Stats->bit_use_stuffing_bits[i]; + } +#if (MVC_EXTENSION_ENABLE) + if ( p_Vid->num_of_layers == 2 ) + { + for (i = 0; i < 5; i++) + { + p_Stats->bit_ctr_emulationprevention_v[p_Vid->dpb_layer_id] += p_Stats->bit_use_stuffing_bits[i]; + } + } +#endif + + fprintf(stdout, " Bits to avoid Startcode Emulation : %" FORMAT_OFF_T " \n", p_Stats->bit_ctr_emulation_prevention); + fprintf(stdout, " Bits for parameter sets : %d \n", p_Stats->bit_ctr_parametersets); + fprintf(stdout, " Bits for filler data : %" FORMAT_OFF_T " \n\n", p_Stats->bit_ctr_filler_data); + + switch (p_Inp->Verbose) + { + case 0: + case 1: + default: + fprintf(stdout,"-------------------------------------------------------------------------------\n"); + break; + case 2: + fprintf(stdout,"------------------------------------------------------------------------------------------------\n"); + break; + case 3: + fprintf(stdout,"-------------------------------------------------------------------------------------------------------\n"); + break; + } + fprintf(stdout,"Exit JM %s encoder ver %s ", JM, VERSION); + fprintf(stdout,"\n"); + + // status file + report_stats(p_Vid, p_Inp, p_Stats, bit_use); + + // write to log file + report_log(p_Vid, p_Inp, p_Stats); + + if (p_Inp->ReportFrameStats) + { + if ((p_Vid->p_log = fopen("stat_frame.dat", "a")) == NULL) // append new statistic at the end + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "stat_frame.dat.dat"); + // error(errortext, 500); + } + else + { + fprintf(p_Vid->p_log," --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \n"); + fclose(p_Vid->p_log); + } + report_log_mode(p_Vid, p_Inp, p_Stats); + } +} + + +/*! + ************************************************************************ + * \brief + * Prints the header of the protocol. + * \par Input: + * InputParameters *inp + * \par Output: + * none + ************************************************************************ + */ +void information_init ( VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats) +{ + int i; + static const char yuv_types[4][10] = {"YUV 4:0:0", "YUV 4:2:0", "YUV 4:2:2", "YUV 4:4:4"}; + switch (p_Inp->Verbose) + { + case 0: + case 1: + default: + printf("------------------------------- JM %4.4s %7.7s -------------------------------\n", VERSION, EXT_VERSION); + break; + case 2: + printf("--------------------------------------- JM %4.4s %7.7s ----------------------------------------\n", VERSION, EXT_VERSION); + break; + case 3: + printf("------------------------------------------ JM %4.4s %7.7s ------------------------------------------\n", VERSION, EXT_VERSION); + break; + } + + fprintf(stdout, " Input YUV file : %s \n", p_Inp->input_file1.fname); +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + fprintf(stdout, " Input YUV file 2 : %s \n", p_Inp->input_file2.fname); +#endif + + fprintf(stdout, " Output H.264 bitstream : %s \n", p_Inp->outfile); + if (p_Vid->p_dec != -1) + fprintf(stdout, " Output YUV file : %s \n", p_Inp->ReconFile); +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views==2) + { + if (p_Vid->p_dec2 != -1) + fprintf(stdout, " Output YUV file 2 : %s \n", p_Inp->ReconFile2); + } +#endif + fprintf(stdout, " YUV Format : %s \n", &yuv_types[p_Vid->yuv_format][0]);//p_Vid->yuv_format==YUV422?"YUV 4:2:2":(p_Vid->yuv_format==YUV444)?"YUV 4:4:4":"YUV 4:2:0"); + fprintf(stdout, " Frames to be encoded : %d\n", p_Inp->no_frames); + if (p_Inp->Verbose != 0) + { + fprintf(stdout, " Freq. for encoded bitstream : %3.2f\n", p_Inp->output.frame_rate); + fprintf(stdout, " PicInterlace / MbInterlace : %d/%d\n", p_Inp->PicInterlace, p_Inp->MbInterlace); + fprintf(stdout, " Transform8x8Mode : %d\n", p_Inp->Transform8x8Mode); + + for (i=0; i<3; i++) + { + fprintf(stdout," ME Metric for Refinement Level %1d : %s\n", i, DistortionType[p_Inp->MEErrorMetric[i]]); + } + fprintf(stdout, " Mode Decision Metric : %s\n", DistortionType[p_Inp->ModeDecisionMetric]); + + if( p_Inp->OnTheFlyFractMCP ) + { + fprintf(stdout," On-the-fly interpolation mode : OTF_L%d\n", p_Inp->OnTheFlyFractMCP ); + } + + switch ( p_Inp->ChromaMEEnable ) + { + case 1: + fprintf(stdout," Motion Estimation for components : YCbCr\n"); + break; + default: + fprintf(stdout," Motion Estimation for components : Y\n"); + break; + } + + fprintf(stdout, " Image format : %dx%d (%dx%d)\n", p_Inp->output.width[0], p_Inp->output.height[0], p_Vid->width,p_Vid->height); + + if (p_Inp->intra_upd) + fprintf(stdout," Error robustness : On\n"); + else + fprintf(stdout," Error robustness : Off\n"); + fprintf(stdout, " Search range : %d\n", p_Inp->search_range[0]); +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->SepViewInterSearch ) + { + fprintf(stdout, " Search range (view 1) : %d\n", p_Inp->search_range[1]); + } +#endif + + fprintf(stdout, " Total number of references : %d\n", p_Inp->num_ref_frames_org); + fprintf(stdout, " References for P slices : %d\n", p_Inp->P_List0_refs_org[0] ? p_Inp->P_List0_refs_org[0] : p_Inp->num_ref_frames_org); + fprintf(stdout, " References for B slices (L0, L1) : %d, %d\n", + p_Inp->B_List0_refs_org[0] ? p_Inp->B_List0_refs_org[0] : p_Inp->num_ref_frames_org, + p_Inp->B_List1_refs_org[0] ? p_Inp->B_List1_refs_org[0] : p_Inp->num_ref_frames_org); + + if ( p_Vid->num_of_layers > 1 ) + { + fprintf(stdout, " View 1 refs for P slices : %d\n", p_Inp->P_List0_refs_org[1] ? p_Inp->P_List0_refs_org[1] : p_Inp->num_ref_frames_org); + fprintf(stdout, " View 1 refs for B slices (L0, L1) : %d, %d\n", + p_Inp->B_List0_refs_org[1] ? p_Inp->B_List0_refs_org[1] : p_Inp->num_ref_frames_org, + p_Inp->B_List1_refs_org[1] ? p_Inp->B_List1_refs_org[1] : p_Inp->num_ref_frames_org); + } + + // Sequence Type + fprintf(stdout, " Sequence type :"); + if (p_Stats->NumberBFrames > 0 && p_Inp->HierarchicalCoding) + { + fprintf(stdout, " Hierarchy (QP: I %d, P %d, B %d) \n", + p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], p_Inp->qp[B_SLICE]); + } + else if (p_Stats->NumberBFrames > 0) + { + char seqtype[80]; + int i,j; + + strcpy (seqtype,"I"); + + for (j=0; j < 2; j++) + { + for (i=0; i < p_Stats->NumberBFrames; i++) + { + if (p_Inp->BRefPictures) + strncat(seqtype,"-RB", imax(0, (int) (79 - strlen(seqtype)))); + else + strncat(seqtype,"-B", imax(0, (int) (79 - strlen(seqtype)))); + } + strncat(seqtype,"-P", imax(0, (int) (79 - strlen(seqtype)))); + } + if (p_Inp->BRefPictures) + fprintf(stdout, " %s (QP: I %d, P %d, RB %d) \n", seqtype, p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], iClip3(0, 51, p_Inp->qp[B_SLICE] + p_Inp->qpBRSOffset)); + else + fprintf(stdout, " %s (QP: I %d, P %d, B %d) \n", seqtype, p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], p_Inp->qp[B_SLICE]); + } + else if (p_Stats->NumberBFrames == 0 && (p_Inp->intra_period == 1 || p_Inp->idr_period == 1)) + fprintf(stdout, " IIII (QP: I %d) \n", p_Inp->qp[I_SLICE]); + else if (p_Stats->NumberBFrames == 0 && p_Inp->sp_periodicity == 0) + fprintf(stdout, " IPPP (QP: I %d, P %d) \n", p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE]); + else + fprintf(stdout, " I-P-P-SP-P (QP: I %d, P %d, SP (%d, %d)) \n", p_Inp->qp[I_SLICE], p_Inp->qp[P_SLICE], p_Inp->qp[SP_SLICE], p_Inp->qpsp); + + // report on entropy coding method + if (p_Inp->symbol_mode == CAVLC) + fprintf(stdout," Entropy coding method : CAVLC\n"); + else + fprintf(stdout," Entropy coding method : CABAC\n"); + + fprintf(stdout, " Profile/Level IDC : (%d,%d)\n", p_Inp->ProfileIDC, p_Inp->LevelIDC); + + if (p_Inp->SearchMode[0] == UM_HEX) + fprintf(stdout, " Motion Estimation Scheme : HEX\n"); + else if (p_Inp->SearchMode[0] == UM_HEX_SIMPLE) + fprintf(stdout, " Motion Estimation Scheme : SHEX\n"); + else if (p_Inp->SearchMode[0] == EPZS) + { + fprintf(stdout, " Motion Estimation Scheme : EPZS\n"); + EPZSOutputStats(p_Inp, stdout, 0); + } + else if (p_Inp->SearchMode[0] == FAST_FULL_SEARCH) + fprintf(stdout, " Motion Estimation Scheme : Fast Full Search\n"); + else + fprintf(stdout, " Motion Estimation Scheme : Full Search\n"); + +#if (MVC_EXTENSION_ENABLE) + if ( p_Inp->SepViewInterSearch ) + { + if (p_Inp->SearchMode[1] == UM_HEX) + fprintf(stdout, " Motion Estimation Scheme : HEX\n"); + else if (p_Inp->SearchMode[1] == UM_HEX_SIMPLE) + fprintf(stdout, " Motion Estimation Scheme : SHEX\n"); + else if (p_Inp->SearchMode[1] == EPZS) + { + fprintf(stdout, " Motion Estimation Scheme : EPZS\n"); + EPZSOutputStats(p_Inp, stdout, 0); + } + else if (p_Inp->SearchMode[1] == FAST_FULL_SEARCH) + fprintf(stdout, " Motion Estimation Scheme : Fast Full Search\n"); + else + fprintf(stdout, " Motion Estimation Scheme : Full Search\n"); + } +#endif + + if (p_Inp->full_search == 2) + fprintf(stdout," Search range restrictions : none\n"); + else if (p_Inp->full_search == 1) + fprintf(stdout," Search range restrictions : older reference frames\n"); + else + fprintf(stdout," Search range restrictions : smaller blocks and older reference frames\n"); + + if (p_Inp->rdopt) + fprintf(stdout," RD-optimized mode decision : used\n"); + else + fprintf(stdout," RD-optimized mode decision : not used\n"); + + switch(p_Inp->partition_mode) + { + case PAR_DP_1: + fprintf(stdout," Data Partitioning Mode : 1 partition \n"); + break; + case PAR_DP_3: + fprintf(stdout," Data Partitioning Mode : 3 partitions \n"); + break; + default: + fprintf(stdout," Data Partitioning Mode : not supported\n"); + break; + } + + switch(p_Inp->of_mode) + { + case PAR_OF_ANNEXB: + fprintf(stdout," Output File Format : H.264/AVC Annex B Byte Stream Format \n"); + break; + case PAR_OF_RTP: + fprintf(stdout," Output File Format : RTP Packet File Format \n"); + break; + default: + fprintf(stdout," Output File Format : not supported\n"); + break; + } + } + + + switch (p_Inp->Verbose) + { + case 0: + default: + printf("-------------------------------------------------------------------------------\n"); + printf("\nEncoding. Please Wait.\n\n"); + break; + case 1: +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + printf("------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic QP SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld Ref \n"); + printf("------------------------------------------------------------------------------------\n"); + } + else +#endif + { + printf("-------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic QP SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld Ref \n"); + printf("-------------------------------------------------------------------------------\n"); + } + break; + case 2: +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + if (p_Inp->Distortion[SSIM] == 1) + { + printf("----------------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic WP QP QL SnrY SnrU SnrV SsimY SsimU SsimV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("----------------------------------------------------------------------------------------------------------------------------------\n"); + } + else + { + printf("---------------------------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic WP QP QL SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("---------------------------------------------------------------------------------------------------------\n"); + } + } + else +#endif + { + if (p_Inp->Distortion[SSIM] == 1) + { + printf("---------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic WP QP QL SnrY SnrU SnrV SsimY SsimU SsimV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("---------------------------------------------------------------------------------------------------------------------------\n"); + } + else + { + printf("---------------------------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic WP QP QL SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("---------------------------------------------------------------------------------------------------\n"); + } + } + break; + case 3: +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + if (p_Inp->Distortion[SSIM] == 1) + { + printf("---------------------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic NVB WP QP QL SnrY SnrU SnrV SsimY SsimU SsimV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("---------------------------------------------------------------------------------------------------------------------------------------\n"); + } + else + { + printf("---------------------------------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic NVB WP QP QL SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("---------------------------------------------------------------------------------------------------------------\n"); + } + } + else +#endif + { + if (p_Inp->Distortion[SSIM] == 1) + { + printf("--------------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic NVB WP QP QL SnrY SnrU SnrV SsimY SsimU SsimV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("--------------------------------------------------------------------------------------------------------------------------------\n"); + } + else + { + printf("--------------------------------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic NVB WP QP QL SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("--------------------------------------------------------------------------------------------------------\n"); + } + } + break; + case 4: +#if (MVC_EXTENSION_ENABLE) + if (p_Inp->num_of_views == 2) + { + if (p_Inp->Distortion[SSIM] == 1) + { + printf("-------------------------------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic Filler NVB WP QP QL SnrY SnrU SnrV SsimY SsimU SsimV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("-------------------------------------------------------------------------------------------------------------------------------------------------\n"); + } + else + { + printf("-------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame View Bit/pic Filler NVB WP QP QL SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("-------------------------------------------------------------------------------------------------------------------------\n"); + } + } + else +#endif + { + if (p_Inp->Distortion[SSIM] == 1) + { + printf("------------------------------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic Filler NVB WP QP QL SnrY SnrU SnrV SsimY SsimU SsimV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("------------------------------------------------------------------------------------------------------------------------------------------\n"); + } + else + { + printf("------------------------------------------------------------------------------------------------------------------\n"); + printf("Frame Bit/pic Filler NVB WP QP QL SnrY SnrU SnrV Time(ms) MET(ms) Frm/Fld I D L0 L1 RDP Ref\n"); + printf("------------------------------------------------------------------------------------------------------------------\n"); + } + } + break; + } +} + +/*! + ************************************************************************ + * \brief + * Report mode distribution of the sequence to log_mode.dat + ************************************************************************ + */ +void report_log_mode(VideoParameters *p_Vid, InputParameters *p_Inp, StatParameters *p_Stats) +{ + FILE *p_stat; //!< status file for the last encoding session + int i; + char name[40]; +#ifndef WIN32 + time_t now; + struct tm *l_time; + char string[1000]; +#else + char timebuf[128]; +#endif + + if ((p_stat = fopen("log_mode.dat", "r")) == 0) // check if file exists + { + if ((p_stat = fopen("log_mode.dat", "a")) == NULL) // append new statistic at the end + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "log_mode.dat"); + error(errortext, 500); + } + else // Create header for new log file + { + fprintf(p_stat, " ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \n"); + fprintf(p_stat,"| Encoder statistics. This file is generated during first encoding session, new sessions will be appended |\n"); + fprintf(p_stat, " ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \n"); + fprintf(p_stat, "| ver | Date | Time | Sequence | QP | I4 | I8 | I16 | IC0 | IC1 | IC2 | IC3 | PI4 | PI8 | PI16 | P0 | P1 | P2 | P3 | P1*4*| P1*8*| P2*4*| P2*8*| P3*4*| P3*8*| P8 | P8:4 | P4*4*| P4*8*| P8:5 | P8:6 | P8:7 | BI4 | BI8 | BI16 | B0 | B1 | B2 | B3 | B0*4*| B0*8*| B1*4*| B1*8*| B2*4*| B2*8*| B3*4*| B3*8*| B8 | B8:0 |B80*4*|B80*8*| B8:4 | B4*4*| B4*8*| B8:5 | B8:6 | B8:7 |\n"); + fprintf(p_stat, " ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \n"); + } + } + else + { + fclose (p_stat); + if ((p_stat = fopen("log_mode.dat", "a")) == NULL) // File exists, just open for appending + { + snprintf(errortext, ET_SIZE, "Error open file %s \n", "log_mode.dat"); + error(errortext, 500); + } + } + + //report + fprintf(p_stat, "|%4s/%s", VERSION, EXT_VERSION); + +#ifdef WIN32 + _strdate( timebuf ); + fprintf(p_stat, "| %1.5s |", timebuf); + + _strtime( timebuf); + fprintf(p_stat, " % 1.5s |", timebuf); +#else + now = time ((time_t *) NULL); // Get the system time and put it into 'now' as 'calender time' + time (&now); + l_time = localtime (&now); + strftime (string, sizeof string, "%d-%b-%Y", l_time); + fprintf(p_stat, "| %1.5s |", string ); + + strftime (string, sizeof string, "%H:%M:%S", l_time); + fprintf(p_stat, " %1.5s |", string); +#endif + + for (i=0;i<30;i++) + name[i]=p_Inp->input_file1.fname[i + imax(0,(int) (strlen(p_Inp->input_file1.fname)- 30))]; // write last part of path, max 30 chars + + fprintf(p_stat, "%30.30s|", name); + fprintf(p_stat, "%3d |", p_Vid->qp); + + //report modes + //I-Modes + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[I_SLICE][I4MB ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[I_SLICE][I8MB ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[I_SLICE][I16MB]); + + //chroma intra mode + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->intra_chroma_mode[0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->intra_chroma_mode[1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->intra_chroma_mode[2]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->intra_chroma_mode[3]); + + //P-Modes + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][I4MB ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][I8MB ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][I16MB]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][0 ]); + + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][1 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][2 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][3 ]); + + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][1][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][1][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][2][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][2][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][3][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][3][1]); + + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][P8x8 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][4 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][4][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[P_SLICE][4][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][5 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][6 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[P_SLICE][7 ]); + + //B-Modes + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][I4MB ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][I8MB ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][I16MB]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][0 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][1 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][2 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][3 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][0][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][0][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][1][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][1][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][2][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][2][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][3][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][3][1]); + + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][P8x8]); + fprintf(p_stat, " %d|", (p_Stats->b8_mode_0_use [B_SLICE][0]+p_Stats->b8_mode_0_use [B_SLICE][1])); + fprintf(p_stat, " %5d|", p_Stats->b8_mode_0_use [B_SLICE][0]); + fprintf(p_stat, " %5d|", p_Stats->b8_mode_0_use [B_SLICE][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][4 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][4][0]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use_transform[B_SLICE][4][1]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][5 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][6 ]); + fprintf(p_stat, " %5" FORMAT_OFF_T "|", p_Stats->mode_use[B_SLICE][7 ]); + + fprintf(p_stat, "\n"); + fclose(p_stat); +} + + diff --git a/lencod/src/rtp.c b/lencod/src/rtp.c new file mode 100644 index 0000000..4f9402f --- /dev/null +++ b/lencod/src/rtp.c @@ -0,0 +1,324 @@ + +/*! + ***************************************************************************** + * \file rtp.c + * + * \brief + * Functions to handle RTP headers and packets per RFC 3984 + * with restricted functionality. + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + +#ifdef WIN32 +#include +#else +#include +#endif + +#include "global.h" +#include "rtp.h" +#include "sei.h" + +// A little trick to avoid those horrible #if TRACE all over the source code +#if TRACE +#define SYMTRACESTRING(s) strncpy(sym.tracestring,s,TRACESTRING_SIZE) +#else +#define SYMTRACESTRING(s) // to nothing +#endif + +/*! + ***************************************************************************** + * + * \brief + * ComposeRTPpacket composes the complete RTP packet using the various + * structure members of the RTPpacket_t structure + * + * \return + * 0 in case of success + * negative error code in case of failure + * + * \par Parameters + * Caller is responsible to allocate enough memory for the generated packet + * in parameter->packet. Typically a malloc of 12+paylen bytes is sufficient + * + * \par Side effects + * none + * + * \note + * Function contains assert() tests for debug purposes (consistency checks + * for RTP header fields + * + * \date + * 30 September 2001 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + +int ComposeRTPPacket (RTPpacket_t *p) + +{ + unsigned int temp32; + uint16 temp16; + + // Consistency checks through assert, only used for debug purposes + assert (p->v == 2); + assert (p->p == 0); + assert (p->x == 0); + assert (p->cc == 0); // mixer designers need to change this one + assert (p->m == 0 || p->m == 1); + assert (p->pt < 128); + assert (p->payload != NULL); + assert (p->paylen < 65536 - 40); // 2**16 -40 for IP/UDP/RTP header + assert (p->packet != NULL); + + // Compose RTP header, little endian + + p->packet[0] = (byte) + ( ((p->v & 0x03) << 6) + | ((p->p & 0x01) << 5) + | ((p->x & 0x01) << 4) + | ((p->cc & 0x0F) << 0) ); + + p->packet[1] = (byte) + ( ((p->m & 0x01) << 7) + | ((p->pt & 0x7F) << 0) ); + + // sequence number, msb first + temp16 = htons((uint16)p->seq); + memcpy (&p->packet[2], &temp16, 2); // change to shifts for unified byte sex + + //declare a temporary variable to perform network byte order conversion + temp32 = htonl(p->timestamp); + memcpy (&p->packet[4], &temp32, 4); // change to shifts for unified byte sex + + temp32 = htonl(p->ssrc); + memcpy (&p->packet[8], &temp32, 4);// change to shifts for unified byte sex + + // Copy payload + + memcpy (&p->packet[12], p->payload, p->paylen); + p->packlen = p->paylen+12; + return 0; +} + + + +/*! + ***************************************************************************** + * + * \brief + * WriteRTPPacket writes the supplied RTP packet to the output file + * + * \return + * 0 in case of access + * <0 in case of write failure (typically fatal) + * + * \param p + * the RTP packet to be written (after ComposeRTPPacket() ) + * \param f + * output file + * + * \date + * October 23, 2001 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + +int WriteRTPPacket (RTPpacket_t *p, FILE *f) + +{ + int intime = -1; + + assert (f != NULL); + assert (p != NULL); + + + if (1 != fwrite (&p->packlen, 4, 1, f)) + return -1; + if (1 != fwrite (&intime, 4, 1, f)) + return -1; + if (1 != fwrite (p->packet, p->packlen, 1, f)) + return -1; + return 0; +} + + + + + +/*! + ***************************************************************************** + * + * \brief + * int RTPWriteNALU write a NALU to the RTP file + * + * \return + * Number of bytes written to output file + * + * \par Side effects + * Packet written, RTPSequenceNumber and RTPTimestamp updated + * + * \date + * December 13, 2002 + * + * \author + * Stephan Wenger stewe@cs.tu-berlin.de + *****************************************************************************/ + + +int WriteRTPNALU (VideoParameters *p_Vid, NALU_t *n, FILE **f_rtp) +{ + RTPpacket_t *p; + + byte first_byte; + + assert ((*f_rtp) != NULL); + assert (n != NULL); + assert (n->len < 65000); + + first_byte = (byte) + (n->forbidden_bit << 7 | + n->nal_reference_idc << 5 | + n->nal_unit_type ); + + // Set RTP structure elements and alloca() memory foor the buffers + if ((p = (RTPpacket_t *) malloc (sizeof (RTPpacket_t))) == NULL) + no_mem_exit ("RTPWriteNALU-1"); + if ((p->packet = (byte *) malloc (MAXRTPPACKETSIZE * sizeof(byte) )) == NULL) + no_mem_exit ("RTPWriteNALU-2"); + if ((p->payload = (byte *) malloc (MAXRTPPACKETSIZE * sizeof(byte) )) == NULL) + no_mem_exit ("RTPWriteNALU-3"); + + p->v=2; + p->p=0; + p->x=0; + p->cc=0; + p->m=(n->startcodeprefix_len==4)&1; // a long startcode of Annex B sets marker bit of RTP + // Not exactly according to the RTP paylaod spec, but + // good enough for now (hopefully). + //! For error resilience work, we need the correct + //! marker bit. Introduce a nalu->marker and set it in + //! terminate_slice()? + p->pt=H264PAYLOADTYPE; + p->seq = p_Vid->CurrentRTPSequenceNumber++; + p->timestamp = p_Vid->CurrentRTPTimestamp; + p->ssrc=H264SSRC; + p->paylen = 1 + n->len; + + p->payload[0] = first_byte; + memcpy (p->payload+1, n->buf, n->len); + + // Generate complete RTP packet + if (ComposeRTPPacket (p) < 0) + { + printf ("Cannot compose RTP packet, exit\n"); + exit (-1); + } + if (WriteRTPPacket (p, *f_rtp) < 0) + { + printf ("Cannot write %d bytes of RTP packet to outfile, exit\n", p->packlen); + exit (-1); + } + free (p->packet); + free (p->payload); + free (p); + return (n->len * 8); +} + + +/*! + ******************************************************************************************** + * \brief + * RTPUpdateTimestamp: patches the RTP timestamp depending on the TR + * + * \param p_Vid + * Image parameters for current picture encoding + * \param tr + * tr: TRof the following NALUs + * + * \return + * none. + * + ******************************************************************************************** +*/ + + +void RTPUpdateTimestamp (VideoParameters *p_Vid, int tr) +{ + int delta; + static int oldtr = -1; + + if (oldtr == -1) // First invocation + { + p_Vid->CurrentRTPTimestamp = 0; //! This is a violation of the security req. of + //! RTP (random timestamp), but easier to debug + oldtr = 0; + return; + } + + /*! The following code assumes a wrap around of TR at 256, and + needs to be changed as soon as this is no more true. + + The support for B frames is a bit tricky, because it is not easy to distinguish + between a natural wrap-around of the tr, and the intentional going back of the + tr because of a B frame. It is solved here by a heuristic means: It is assumed that + B frames are never "older" than 10 tr ticks. Everything higher than 10 is considered + a wrap around. + */ + + delta = tr - oldtr; + + if (delta < -10) // wrap-around + delta+=256; + + p_Vid->CurrentRTPTimestamp += delta * RTP_TR_TIMESTAMP_MULT; + oldtr = tr; +} + + +/*! + ******************************************************************************************** + * \brief + * Opens the output file for the RTP packet stream + * + * \param p_Vid + * Image parameters for current picture encoding + * \param Filename + * The filename of the file to be opened + * + * \return + * none. Function terminates the program in case of an error + * + ******************************************************************************************** +*/ + +void OpenRTPFile (char *Filename, FILE **f_rtp) +{ + if (((*f_rtp) = fopen (Filename, "wb")) == NULL) + { + printf ("Fatal: cannot open bitstream file '%s', exit (-1)\n", Filename); + exit (-1); + } +} + + +/*! + ******************************************************************************************** + * \brief + * Closes the output file for the RTP packet stream + * + * \return + * none. Function terminates the program in case of an error + * + ******************************************************************************************** +*/ + +void CloseRTPFile (FILE *f_rtp) +{ + fclose(f_rtp); +} + diff --git a/lencod/src/sei.c b/lencod/src/sei.c new file mode 100644 index 0000000..e1a2fff --- /dev/null +++ b/lencod/src/sei.c @@ -0,0 +1,3065 @@ + +/*! + ************************************************************************ + * \file + * sei.c + * \brief + * implementation of SEI related functions + * \author(s) + * - Dong Tian + * - Athanasios Leontaris + * + ************************************************************************ + */ + +#include "global.h" +#include "memalloc.h" +#include "rtp.h" +#include "mbuffer.h" +#include "sei.h" +#include "vlc.h" +#include "header.h" + +static void InitRandomAccess (SEIParameters *p_SEI); +static void CloseRandomAccess (SEIParameters *p_SEI); +static void InitToneMapping (SEIParameters *p_SEI, InputParameters *p_Inp); +static void CloseToneMapping (SEIParameters *p_SEI); +static void CloseBufferingPeriod (SEIParameters *p_SEI); +static void InitPicTiming (SEIParameters *p_SEI); +static void ClosePicTiming (SEIParameters *p_SEI); +static void InitDRPMRepetition (SEIParameters *p_SEI); +static void CloseDRPMRepetition (SEIParameters *p_SEI); +static void FinalizeDRPMRepetition (VideoParameters *p_Vid); +static void InitSparePicture (SEIParameters *p_SEI); +static void CloseSparePicture (SEIParameters *p_SEI); +static void FinalizeSpareMBMap (VideoParameters *p_Vid); +static void InitSubseqChar (VideoParameters *p_Vid); +static void ClearSubseqCharPayload (SEIParameters *p_SEI); +static void CloseSubseqChar (SEIParameters *p_SEI); +static void InitSubseqLayerInfo (SEIParameters *p_SEI); +static void InitPanScanRectInfo (SEIParameters *p_SEI); +static void ClosePanScanRectInfo (SEIParameters *p_SEI); +static void InitUser_data_unregistered (SEIParameters *p_SEI); +static void InitUser_data_registered_itu_t_t35(SEIParameters *p_SEI); +static void ClearUser_data_unregistered(SEIParameters *p_SEI); +static void CloseUser_data_unregistered(SEIParameters *p_SEI); +static void ClearUser_data_registered_itu_t_t35(SEIParameters *p_SEI); +static void CloseUser_data_registered_itu_t_t35(SEIParameters *p_SEI); +static void InitPostFilterHints (SEIParameters *p_SEI); +static void ClearPostFilterHints (SEIParameters *p_SEI); +static void ClosePostFilterHints (SEIParameters *p_SEI); +static void InitFramePackingArrangement(VideoParameters *p_Vid); +static void CloseFramePackingArrangement(SEIParameters *p_SEI); + +void init_sei(SEIParameters *p_SEI) +{ + p_SEI->seiHasTemporal_reference=FALSE; + p_SEI->seiHasClock_timestamp=FALSE; + p_SEI->seiHasPanscan_rect=FALSE; + p_SEI->seiHasHrd_picture=FALSE; + p_SEI->seiHasFiller_payload=FALSE; + p_SEI->seiHasUser_data_registered_itu_t_t35=FALSE; + p_SEI->seiHasUser_data_unregistered=FALSE; + p_SEI->seiHasRecoveryPoint_info=FALSE; + p_SEI->seiHasRef_pic_buffer_management_repetition=FALSE; + p_SEI->seiHasSpare_picture=FALSE; + p_SEI->seiHasBufferingPeriod_info=FALSE; + p_SEI->seiHasPicTiming_info=FALSE; + p_SEI->seiHasSceneInformation=FALSE; + p_SEI->seiHasSubseq_information=FALSE; + p_SEI->seiHasSubseq_layer_characteristics=FALSE; + p_SEI->seiHasSubseq_characteristics=FALSE; + p_SEI->seiHasTone_mapping=FALSE; + p_SEI->seiHasPostFilterHints_info=FALSE; + p_SEI->seiHasDRPMRepetition_info=FALSE; + p_SEI->seiHasSparePicture = FALSE; + p_SEI->seiHasSubseqChar = FALSE; + p_SEI->seiHasSubseqInfo = FALSE; + p_SEI->seiHasSubseqLayerInfo = FALSE; + p_SEI->seiHasPanScanRectInfo = FALSE; +} + +/* + ************************************************************************ + * \basic functions on supplemental enhancement information + * \brief + * The implementations are based on FCD + ************************************************************************ + */ +void InitSEIMessages(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + int i; + for (i=0; i<2; i++) + { + p_SEI->sei_message[i].data = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->sei_message[i].data == NULL ) no_mem_exit("InitSEIMessages: sei_message[i].data"); + p_SEI->sei_message[i].subPacketType = SEI_PACKET_TYPE; + clear_sei_message(p_SEI, i); + } + + // init sei messages + p_SEI->seiSparePicturePayload.data = NULL; + InitSparePicture(p_SEI); + if (p_Inp->NumFramesInELSubSeq != 0) + { + InitSubseqLayerInfo(p_SEI); + InitSubseqChar(p_Vid); + } + InitSceneInformation(p_SEI); + // init panscanrect sei message + InitPanScanRectInfo(p_SEI); + // init user_data_unregistered + InitUser_data_unregistered(p_SEI); + // init user_data_unregistered + InitUser_data_registered_itu_t_t35(p_SEI); + // init user_RandomAccess + InitRandomAccess(p_SEI); + // Init tone_mapping + InitToneMapping(p_SEI, p_Inp); + // init post_filter_hints + InitPostFilterHints(p_SEI); + // init BufferingPeriod + InitBufferingPeriod(p_Vid); + // init PicTiming + InitPicTiming(p_SEI); + // init DRPM Repetition + InitDRPMRepetition(p_SEI); + // init Frame Packing Arrangement + InitFramePackingArrangement(p_Vid); +} + +void CloseSEIMessages(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + int i; + + if (p_Inp->NumFramesInELSubSeq != 0) + CloseSubseqLayerInfo(); + + CloseSubseqChar(p_SEI); + CloseSparePicture(p_SEI); + CloseSceneInformation(p_SEI); + ClosePanScanRectInfo(p_SEI); + CloseUser_data_unregistered(p_SEI); + CloseUser_data_registered_itu_t_t35(p_SEI); + CloseRandomAccess(p_SEI); + CloseToneMapping(p_SEI); + ClosePostFilterHints(p_SEI); + CloseBufferingPeriod(p_SEI); + ClosePicTiming(p_SEI); + CloseDRPMRepetition(p_SEI); + CloseFramePackingArrangement(p_SEI); + + for (i=0; isei_message[i].data ) + free( p_SEI->sei_message[i].data ); + p_SEI->sei_message[i].data = NULL; + } +} + +Boolean HaveAggregationSEI(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + if (p_SEI->sei_message[AGGREGATION_SEI].available && p_Vid->type != B_SLICE) + return TRUE; + if (p_SEI->seiHasSubseqInfo) + return TRUE; + if (p_SEI->seiHasSubseqLayerInfo && p_Vid->number == 0) + return TRUE; + if (p_SEI->seiHasSubseqChar) + return TRUE; + if (p_SEI->seiHasSceneInformation) + return TRUE; + if (p_SEI->seiHasPanScanRectInfo) + return TRUE; + if (p_SEI->seiHasUser_data_unregistered_info) + return TRUE; + if (p_SEI->seiHasUser_data_registered_itu_t_t35_info) + return TRUE; + if (p_SEI->seiHasRecoveryPoint_info) + return TRUE; + if (p_SEI->seiHasTone_mapping) + return TRUE; + if (p_SEI->seiHasPostFilterHints_info) + return TRUE; + if (p_SEI->seiHasBufferingPeriod_info) + return TRUE; + if (p_SEI->seiHasPicTiming_info) + return TRUE; + if (p_SEI->seiHasDRPMRepetition_info) + return TRUE; + + return FALSE; +// return p_Inp->SparePictureOption && ( seiHasSpare_picture || seiHasSubseq_information || +// seiHasSubseq_layer_characteristics || seiHasSubseq_characteristics ); +} + +/*! + ************************************************************************ + * \brief + * write one sei payload to the sei message + * \param p_SEI + * SEI message + * \param id + * 0, if this is the normal packet\n + * 1, if this is a aggregation packet + * \param payload + * a pointer that point to the sei payload. Note that the bitstream + * should have be byte aligned already. + * \param payload_size + * the size of the sei payload + * \param payload_type + * the type of the sei payload + * \par Output + * the content of the sei message (sei_message[id]) is updated. + ************************************************************************ + */ +static void write_sei_message(SEIParameters *p_SEI, int id, byte* payload, int payload_size, int payload_type) +{ + int offset, type, size; + assert(payload_type >= 0 && payload_type < SEI_MAX_ELEMENTS); + + type = payload_type; + size = payload_size; + offset = p_SEI->sei_message[id].payloadSize; + + while ( type > 254 ) + { + p_SEI->sei_message[id].data[offset++] = 0xFF; + type = type - 255; + } + p_SEI->sei_message[id].data[offset++] = (byte) type; + + while ( size > 254 ) + { + p_SEI->sei_message[id].data[offset++] = 0xFF; + size = size - 255; + } + p_SEI->sei_message[id].data[offset++] = (byte) size; + + memcpy(p_SEI->sei_message[id].data + offset, payload, payload_size); + offset += payload_size; + + p_SEI->sei_message[id].payloadSize = offset; +} + +/*! + ************************************************************************ + * \brief + * write rbsp_trailing_bits to the sei message + * \param p_SEI + * SEI message + * \param id + * 0, if this is the normal packet \n + * 1, if this is a aggregation packet + * \par Output + * the content of the sei message is updated and ready for packetisation + ************************************************************************ + */ +static void finalize_sei_message(SEIParameters *p_SEI, int id) +{ + int offset = p_SEI->sei_message[id].payloadSize; + + p_SEI->sei_message[id].data[offset] = 0x80; + p_SEI->sei_message[id].payloadSize++; + + p_SEI->sei_message[id].available = TRUE; +} + +/*! + ************************************************************************ + * \brief + * empty the sei message buffer + * \param p_SEI + * the SEI message to be cleared + * \param id + * 0, if this is the normal packet \n + * 1, if this is a aggregation packet + * \par Output + * the content of the sei message is cleared and ready for storing new + * messages + ************************************************************************ + */ +void clear_sei_message(SEIParameters *p_SEI, int id) +{ + memset( p_SEI->sei_message[id].data, 0, MAXRTPPAYLOADLEN); + p_SEI->sei_message[id].payloadSize = 0; + p_SEI->sei_message[id].available = FALSE; +} + +/*! + ************************************************************************ + * \brief + * copy the bits from one bitstream buffer to another one + * \param dest + * pointer to the dest bitstream buffer + * \param source + * pointer to the source bitstream buffer + * \par Output + * the content of the dest bitstream is changed. + ************************************************************************ + */ +void AppendTmpbits2Buf( Bitstream* dest, Bitstream* source ) +{ + int i, j; + byte mask; + int bits_in_last_byte; + + // copy the first bytes in source buffer + for (i=0; ibyte_pos; i++) + { + mask = 0x80; + for (j=0; j<8; j++) + { + dest->byte_buf <<= 1; + if (source->streamBuffer[i] & mask) + dest->byte_buf |= 1; + dest->bits_to_go--; + mask >>= 1; + if (dest->bits_to_go==0) + { + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + } + } + // copy the last byte, there are still (8-source->bits_to_go) bits in the source buffer + bits_in_last_byte = 8-source->bits_to_go; + if ( bits_in_last_byte > 0 ) + { + mask = (byte) (1 << (bits_in_last_byte-1)); + for (j=0; jbyte_buf <<= 1; + if (source->byte_buf & mask) + dest->byte_buf |= 1; + dest->bits_to_go--; + mask >>= 1; + if (dest->bits_to_go==0) + { + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + } + } +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on spare pictures + * \brief + * implementation of Spare Pictures related functions based on + * JVT-D100 + * \author + * Dong Tian + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + +/*! + ************************************************************************ + * \brief + * Init the global variables for spare picture information + ************************************************************************ + */ +static void InitSparePicture(SEIParameters *p_SEI) +{ + if ( p_SEI->seiSparePicturePayload.data != NULL ) + CloseSparePicture(p_SEI); + + p_SEI->seiSparePicturePayload.data = malloc( sizeof(Bitstream) ); + if ( p_SEI->seiSparePicturePayload.data == NULL ) no_mem_exit("InitSparePicture: seiSparePicturePayload.data"); + p_SEI->seiSparePicturePayload.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if ( p_SEI->seiSparePicturePayload.data->streamBuffer == NULL ) no_mem_exit("InitSparePicture: seiSparePicturePayload.data->streamBuffer"); + memset( p_SEI->seiSparePicturePayload.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiSparePicturePayload.num_spare_pics = 0; + p_SEI->seiSparePicturePayload.target_frame_num = 0; + + p_SEI->seiSparePicturePayload.data->bits_to_go = 8; + p_SEI->seiSparePicturePayload.data->byte_pos = 0; + p_SEI->seiSparePicturePayload.data->byte_buf = 0; +} + +/*! + ************************************************************************ + * \brief + * Close the global variables for spare picture information + ************************************************************************ + */ +static void CloseSparePicture(SEIParameters *p_SEI) +{ + if (p_SEI->seiSparePicturePayload.data->streamBuffer) + free(p_SEI->seiSparePicturePayload.data->streamBuffer); + p_SEI->seiSparePicturePayload.data->streamBuffer = NULL; + if (p_SEI->seiSparePicturePayload.data) + free(p_SEI->seiSparePicturePayload.data); + p_SEI->seiSparePicturePayload.data = NULL; + p_SEI->seiSparePicturePayload.num_spare_pics = 0; + p_SEI->seiSparePicturePayload.target_frame_num = 0; +} + +/*! + ************************************************************************ + * \brief + * Calculate the spare picture info, save the result in map_sp + * then compose the spare picture information. + * \par Output + * the spare picture payload is available in *seiSparePicturePayload* + * the syntax elements in the loop (see FCD), excluding the two elements + * at the beginning. + ************************************************************************ + */ +void CalculateSparePicture() +{ + /* + int i, j, tmp, i0, j0, m; + byte **map_sp; + int delta_spare_frame_num; + Bitstream *tmpBitstream; + + int num_of_mb=(p_Vid->height >> 4) * (p_Vid->width >> 4); + int threshold1 = 16*16*p_Inp->SPDetectionThreshold; + int threshold2 = num_of_mb * p_Inp->SPPercentageThreshold / 100; + int ref_area_indicator; + int CandidateSpareFrameNum, SpareFrameNum; + int possible_spare_pic_num; + + // define it for debug purpose + #define WRITE_MAP_IMAGE + +#ifdef WRITE_MAP_IMAGE + byte **y; + int k; + FILE* fp; + static int first = 1; + char map_file_name[255]="map.yuv"; +#endif + + // basic check + if (fb->picbuf_short[0]->used==0 || fb->picbuf_short[1]->used==0) + { +#ifdef WRITE_MAP_IMAGE + fp = fopen( map_file_name, "wb" ); + assert( fp != NULL ); + // write the map image + for (i=0; i < p_Vid->height; i++) + for (j=0; j < p_Vid->width; j++) + fputc(0, fp); + + for (k=0; k < 2; k++) + for (i=0; i < p_Vid->height >> 1; i++) + for (j=0; j < p_Vid->width >> 1; j++) + fputc(128, fp); + fclose( fp ); +#endif + seiHasSparePicture = FALSE; + return; + } + seiHasSparePicture = TRUE; + + // set the global bitstream memory. + InitSparePicture(); + seiSparePicturePayload.target_frame_num = p_Vid->number % MAX_FN; + // init the local bitstream memory. + tmpBitstream = malloc(sizeof(Bitstream)); + if ( tmpBitstream == NULL ) no_mem_exit("CalculateSparePicture: tmpBitstream"); + tmpBitstream->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if ( tmpBitstream->streamBuffer == NULL ) no_mem_exit("CalculateSparePicture: tmpBitstream->streamBuffer"); + memset( tmpBitstream->streamBuffer, 0, MAXRTPPAYLOADLEN); + +#ifdef WRITE_MAP_IMAGE + if ( first ) + { + fp = fopen( map_file_name, "wb" ); + first = 0; + } + else + fp = fopen( map_file_name, "ab" ); + get_mem2D(&y, p_Vid->height, p_Vid->width); +#endif + get_mem2D(&map_sp, p_Vid->height >> 4, p_Vid->width >> 4); + + if (fb->picbuf_short[2]->used!=0) possible_spare_pic_num = 2; + else possible_spare_pic_num = 1; + // loop over the spare pictures + for (m=0; mbits_to_go = 8; + tmpBitstream->byte_pos = 0; + tmpBitstream->byte_buf = 0; + memset( tmpBitstream->streamBuffer, 0, MAXRTPPAYLOADLEN); + + // set delta_spare_frame_num + // the order of the following lines cannot be changed. + if (m==0) + CandidateSpareFrameNum = seiSparePicturePayload.target_frame_num - 1; // TargetFrameNum - 1; + else + CandidateSpareFrameNum = SpareFrameNum - 1; + if ( CandidateSpareFrameNum < 0 ) CandidateSpareFrameNum = MAX_FN - 1; + SpareFrameNum = fb->picbuf_short[m+1]->frame_num_256; + delta_spare_frame_num = CandidateSpareFrameNum - SpareFrameNum; + assert( delta_spare_frame_num == 0 ); + + // calculate the spare macroblock map of one spare picture + // the results are stored into map_sp[][] + for (i=0; i < p_Vid->height >> 4; i++) + for (j=0; j < p_Vid->width >> 4; j++) + { + tmp = 0; + for (i0=0; i0<16; i0++) + for (j0=0; j0<16; j0++) + tmp+=iabs(fb->picbuf_short[m+1]->Refbuf11[(i*16+i0)*p_Vid->width+j*16+j0]- + fb->picbuf_short[0]->Refbuf11[(i*16+i0)*p_Vid->width+j*16+j0]); + tmp = (tmp<=threshold1? 255 : 0); + map_sp[i][j] = (tmp==0? 1 : 0); +#ifdef WRITE_MAP_IMAGE +// if (m==0) + { + for (i0=0; i0<16; i0++) + for (j0=0; j0<16; j0++) + y[i*16+i0][j*16+j0]=tmp; + } +#endif + } + + // based on map_sp[][], compose the spare picture information + // and write the spare picture information to a temp bitstream + tmp = 0; + for (i=0; i < p_Vid->height >> 4; i++) + for (j=0; j < p_Vid->width >> 4; j++) + if (map_sp[i][j]==0) tmp++; + if ( tmp > threshold2 ) + ref_area_indicator = 0; + else if ( !CompressSpareMBMap(p_Vid, map_sp, tmpBitstream) ) + ref_area_indicator = 1; + else + ref_area_indicator = 2; + +// printf( "ref_area_indicator = %d\n", ref_area_indicator ); + +#ifdef WRITE_MAP_IMAGE + // write the map to a file +// if (m==0) + { + // write the map image + for (i=0; i < p_Vid->height; i++) + for (j=0; j < p_Vid->width; j++) + { + if ( ref_area_indicator == 0 ) fputc(255, fp); + else fputc(y[i][j], fp); + } + + for (k=0; k < 2; k++) + for (i=0; i < p_Vid->height >> 1; i++) + for (j=0; j < p_Vid->width >> 1; j++) + fputc(128, fp); + } +#endif + + // Finnally, write the current spare picture information to + // the global variable: seiSparePicturePayload + ComposeSparePictureMessage(p_SEI, delta_spare_frame_num, ref_area_indicator, tmpBitstream); + seiSparePicturePayload.num_spare_pics++; + } // END for (m=0; m<2; m++) + + free_mem2D( map_sp ); + free( tmpBitstream->streamBuffer ); + free( tmpBitstream ); + +#ifdef WRITE_MAP_IMAGE + free_mem2D( y ); + fclose( fp ); +#undef WRITE_MAP_IMAGE +#endif + */ +} + +/*! + ************************************************************************ + * \brief + * compose the spare picture information. + * \param p_SEI + * SEI message + * \param delta_spare_frame_num + * see FCD + * \param ref_area_indicator + * Indicate how to represent the spare mb map + * \param tmpBitstream + * pointer to a buffer to save the payload + * \par Output + * bitstream: the composed spare picture payload are + * ready to put into the sei_message. + ************************************************************************ + */ +void ComposeSparePictureMessage(SEIParameters *p_SEI, int delta_spare_frame_num, int ref_area_indicator, Bitstream *tmpBitstream) +{ + Bitstream *bitstream = p_SEI->seiSparePicturePayload.data; + SyntaxElement sym; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + + sym.value1 = delta_spare_frame_num; + writeSyntaxElement2Buf_UVLC(&sym, bitstream); + sym.value1 = ref_area_indicator; + writeSyntaxElement2Buf_UVLC(&sym, bitstream); + + AppendTmpbits2Buf( bitstream, tmpBitstream ); +} + +/*! + ************************************************************************ + * \brief + * test if the compressed spare mb map will occupy less mem and + * fill the payload buffer. + * \param p_Vid + * Image parameters for current picture coding + * \param map_sp + * in which the spare picture information are stored. + * \param bitstream + * pointer to a buffer to save the payload + * \return + * TRUE: If it is compressed version, \n + * FALSE: If it is not compressed. + ************************************************************************ + */ +Boolean CompressSpareMBMap(VideoParameters *p_Vid, unsigned char **map_sp, Bitstream *bitstream) +{ + int j, k; + int noc, bit0, bitc; + SyntaxElement sym; + int x, y, left, right, bottom, top, directx, directy; + + // this is the size of the uncompressed mb map: + int size_uncompressed = (p_Vid->height >> 4) * (p_Vid->width >> 4); + int size_compressed = 0; + Boolean ret; + + // initialization + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + noc = 0; + bit0 = 0; + bitc = bit0; + + // compress the map, the result goes to the temporal bitstream buffer + x = ( (p_Vid->width >> 4) - 1 ) / 2; + y = ( (p_Vid->height >> 4) - 1 ) / 2; + left = right = x; + top = bottom = y; + directx = 0; + directy = 1; + for (j=0; jheight >> 4; j++) + for (k=0; kwidth >> 4; k++) + { + // check current mb + if ( map_sp[y][x] == bitc ) noc++; + else + { + sym.value1 = noc; + size_compressed += writeSyntaxElement2Buf_UVLC(&sym, bitstream); // the return value indicate the num of bits written + noc=0; + } + // go to the next mb: + if ( directx == -1 && directy == 0 ) + { + if (x > left) x--; + else if (x == 0) + { + y = bottom + 1; + bottom++; + directx = 1; + directy = 0; + } + else if (x == left) + { + x--; + left--; + directx = 0; + directy = 1; + } + } + else if ( directx == 1 && directy == 0 ) + { + if (x < right) x++; + else if (x == (p_Vid->width >> 4) - 1) + { + y = top - 1; + top--; + directx = -1; + directy = 0; + } + else if (x == right) + { + x++; + right++; + directx = 0; + directy = -1; + } + } + else if ( directx == 0 && directy == -1 ) + { + if ( y > top) y--; + else if (y == 0) + { + x = left - 1; + left--; + directx = 0; + directy = 1; + } + else if (y == top) + { + y--; + top--; + directx = -1; + directy = 0; + } + } + else if ( directx == 0 && directy == 1 ) + { + if (y < bottom) y++; + else if (y == (p_Vid->height >> 4) - 1) + { + x = right+1; + right++; + directx = 0; + directy = -1; + } + else if (y == bottom) + { + y++; + bottom++; + directx = 1; + directy = 0; + } + } + } + if (noc!=0) + { + sym.value1 = noc; + size_compressed += writeSyntaxElement2Buf_UVLC(&sym, bitstream); + } + + ret = (size_compressedbyte_buf = 0; + bitstream->bits_to_go = 8; + bitstream->byte_pos = 0; + for (j=0; jheight >> 4; j++) + { + for (k=0; kwidth >> 4; k++) + { + bitstream->byte_buf <<= 1; + if (map_sp[j][k]) bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if (bitstream->bits_to_go==0) + { + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + } + } + } + + return ret; +} + +/*! + ************************************************************************ + * \brief + * Finalize the spare picture SEI payload. + * The spare picture paylaod will be ready for encapsulation, and it + * should be called before current picture packetized. + * \par Input + * seiSparePicturePayload.data: points to the payload starting from + * delta_spare_frame_num. (See FCD) + * \par Output + * seiSparePicturePayload.data is updated, pointing to the whole spare + * picture information: spare_picture( PayloadSize ) (See FCD) + * Make sure it is byte aligned. + ************************************************************************ + */ +static void FinalizeSpareMBMap(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + int CurrFrameNum = p_Vid->number % MAX_FN; + int delta_frame_num; + SyntaxElement sym; + Bitstream *dest, *source; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + + source = p_SEI->seiSparePicturePayload.data; + dest = malloc(sizeof(Bitstream)); + if ( dest == NULL ) no_mem_exit("FinalizeSpareMBMap: dest"); + dest->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if ( dest->streamBuffer == NULL ) no_mem_exit("FinalizeSpareMBMap: dest->streamBuffer"); + dest->bits_to_go = 8; + dest->byte_pos = 0; + dest->byte_buf = 0; + memset( dest->streamBuffer, 0, MAXRTPPAYLOADLEN); + + // delta_frame_num + delta_frame_num = CurrFrameNum - p_SEI->seiSparePicturePayload.target_frame_num; + if ( delta_frame_num < 0 ) delta_frame_num += MAX_FN; + sym.value1 = delta_frame_num; + writeSyntaxElement2Buf_UVLC(&sym, dest); + + // num_spare_pics_minus1 + sym.value1 = p_SEI->seiSparePicturePayload.num_spare_pics - 1; + writeSyntaxElement2Buf_UVLC(&sym, dest); + + // copy the other bits + AppendTmpbits2Buf( dest, source); + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( dest->bits_to_go != 8 ) + { + (dest->byte_buf) <<= 1; + dest->byte_buf |= 1; + dest->bits_to_go--; + if ( dest->bits_to_go != 0 ) (dest->byte_buf) <<= (dest->bits_to_go); + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + p_SEI->seiSparePicturePayload.payloadSize = dest->byte_pos; + + // the payload is ready now + p_SEI->seiSparePicturePayload.data = dest; + free( source->streamBuffer ); + free( source ); +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on subseq information sei messages + * \brief + * JVT-D098 + * \author + * Dong Tian + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + +/*! + ************************************************************************ + * \brief + * init subseqence info + ************************************************************************ + */ +void InitSubseqInfo(SEIParameters *p_SEI, int currLayer) +{ + static uint16 id = 0; + + p_SEI->seiHasSubseqInfo = TRUE; + p_SEI->seiSubseqInfo[currLayer].subseq_layer_num = currLayer; + p_SEI->seiSubseqInfo[currLayer].subseq_id = id++; + p_SEI->seiSubseqInfo[currLayer].last_picture_flag = 0; + p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt = (unsigned int) -1; + p_SEI->seiSubseqInfo[currLayer].payloadSize = 0; + + p_SEI->seiSubseqInfo[currLayer].data = malloc( sizeof(Bitstream) ); + if ( p_SEI->seiSubseqInfo[currLayer].data == NULL ) no_mem_exit("InitSubseqInfo: p_SEI->seiSubseqInfo[currLayer].data"); + p_SEI->seiSubseqInfo[currLayer].data->streamBuffer = malloc( MAXRTPPAYLOADLEN ); + if ( p_SEI->seiSubseqInfo[currLayer].data->streamBuffer == NULL ) no_mem_exit("InitSubseqInfo: p_SEI->seiSubseqInfo[currLayer].data->streamBuffer"); + p_SEI->seiSubseqInfo[currLayer].data->bits_to_go = 8; + p_SEI->seiSubseqInfo[currLayer].data->byte_pos = 0; + p_SEI->seiSubseqInfo[currLayer].data->byte_buf = 0; + memset( p_SEI->seiSubseqInfo[currLayer].data->streamBuffer, 0, MAXRTPPAYLOADLEN ); +} + +/*! + ************************************************************************ + * \brief + * update subsequence info + ************************************************************************ + */ +void UpdateSubseqInfo(VideoParameters *p_Vid, InputParameters *p_Inp, int currLayer) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + if (p_Vid->type != B_SLICE) + { + p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt ++; + p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt = p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt % MAX_FN; + } + + if ( currLayer == 0 ) + { + if ( p_Vid->number == p_Inp->no_frames - 1 ) + p_SEI->seiSubseqInfo[currLayer].last_picture_flag = 1; + else + p_SEI->seiSubseqInfo[currLayer].last_picture_flag = 0; + } + if ( currLayer == 1 ) + { + if ( (((p_Vid->curr_frm_idx - p_Vid->last_idr_code_order) % (p_Inp->NumFramesInELSubSeq + 1) == 0) && (p_Inp->NumberBFrames != 0) && ((p_Vid->curr_frm_idx - p_Vid->last_idr_code_order) > 0)) || // there are B frames + (((p_Vid->curr_frm_idx - p_Vid->last_idr_code_order) % (p_Inp->NumFramesInELSubSeq + 1) == p_Inp->NumFramesInELSubSeq) && (p_Inp->NumberBFrames==0)) // there are no B frames + ) + p_SEI->seiSubseqInfo[currLayer].last_picture_flag = 1; + else + p_SEI->seiSubseqInfo[currLayer].last_picture_flag = 0; + } +} + +/*! + ************************************************************************ + * \brief + * Finalize subseqence info + ************************************************************************ + */ +static void FinalizeSubseqInfo(SEIParameters *p_SEI, int currLayer) +{ + SyntaxElement sym; + Bitstream *dest = p_SEI->seiSubseqInfo[currLayer].data; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + + sym.value1 = p_SEI->seiSubseqInfo[currLayer].subseq_layer_num; + writeSyntaxElement2Buf_UVLC(&sym, dest); + sym.value1 = p_SEI->seiSubseqInfo[currLayer].subseq_id; + writeSyntaxElement2Buf_UVLC(&sym, dest); + sym.bitpattern = p_SEI->seiSubseqInfo[currLayer].last_picture_flag; + sym.len = 1; + writeSyntaxElement2Buf_Fixed(&sym, dest); + sym.value1 = p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt; + writeSyntaxElement2Buf_UVLC(&sym, dest); + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( dest->bits_to_go != 8 ) + { + (dest->byte_buf) <<= 1; + dest->byte_buf |= 1; + dest->bits_to_go--; + if ( dest->bits_to_go != 0 ) (dest->byte_buf) <<= (dest->bits_to_go); + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + p_SEI->seiSubseqInfo[currLayer].payloadSize = dest->byte_pos; + +// printf("layer %d, last picture %d, stored_cnt %d\n", currLayer, p_SEI->seiSubseqInfo[currLayer].last_picture_flag, p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt ); +} + +/*! + ************************************************************************ + * \brief + * Clear the payload buffer + ************************************************************************ + */ +static void ClearSubseqInfoPayload(SEIParameters *p_SEI, int currLayer) +{ + p_SEI->seiSubseqInfo[currLayer].data->bits_to_go = 8; + p_SEI->seiSubseqInfo[currLayer].data->byte_pos = 0; + p_SEI->seiSubseqInfo[currLayer].data->byte_buf = 0; + memset( p_SEI->seiSubseqInfo[currLayer].data->streamBuffer, 0, MAXRTPPAYLOADLEN ); + p_SEI->seiSubseqInfo[currLayer].payloadSize = 0; +} + +/*! + ************************************************************************ + * \brief + * Close the global variables for spare picture information + ************************************************************************ + */ +void CloseSubseqInfo(SEIParameters *p_SEI, int currLayer) +{ + p_SEI->seiSubseqInfo[currLayer].stored_frame_cnt = (unsigned int) -1; + p_SEI->seiSubseqInfo[currLayer].payloadSize = 0; + + free( p_SEI->seiSubseqInfo[currLayer].data->streamBuffer ); + free( p_SEI->seiSubseqInfo[currLayer].data ); +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on subseq layer characteristic sei messages + * \brief + * JVT-D098 + * \author + * Dong Tian + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + +/*! + ************************************************************************ + * \brief + * Init the global variables for spare picture information + ************************************************************************ + */ +static void InitSubseqLayerInfo(SEIParameters *p_SEI) +{ + int i; + p_SEI->seiHasSubseqLayerInfo = TRUE; + p_SEI->seiSubseqLayerInfo.layer_number = 0; + for (i=0; iseiSubseqLayerInfo.bit_rate[i] = 0; + p_SEI->seiSubseqLayerInfo.frame_rate[i] = 0; + p_SEI->seiSubseqLayerInfo.layer_number++; + } +} + +/*! + ************************************************************************ + * \brief + * + ************************************************************************ + */ +void CloseSubseqLayerInfo() +{ +} + +/*! + ************************************************************************ + * \brief + * Write the data to buffer, which is byte aligned + ************************************************************************ + */ +static void FinalizeSubseqLayerInfo(SEIParameters *p_SEI) +{ + int i, pos; + pos = 0; + p_SEI->seiSubseqLayerInfo.payloadSize = 0; + for (i=0; iseiSubseqLayerInfo.layer_number; i++) + { + *((uint16*)&(p_SEI->seiSubseqLayerInfo.data[pos])) = p_SEI->seiSubseqLayerInfo.bit_rate[i]; + pos += 2; + *((uint16*)&(p_SEI->seiSubseqLayerInfo.data[pos])) = p_SEI->seiSubseqLayerInfo.frame_rate[i]; + pos += 2; + p_SEI->seiSubseqLayerInfo.payloadSize += 4; + } +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on subseq characteristic sei messages + * \brief + * JVT-D098 + * \author + * Dong Tian + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + +void InitSubseqChar(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + p_SEI->seiSubseqChar.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiSubseqChar.data == NULL ) no_mem_exit("InitSubseqChar: p_SEI->seiSubseqChar.data"); + p_SEI->seiSubseqChar.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiSubseqChar.data->streamBuffer == NULL ) no_mem_exit("InitSubseqChar: p_SEI->seiSubseqChar.data->streamBuffer"); + ClearSubseqCharPayload(p_SEI); + + p_SEI->seiSubseqChar.subseq_layer_num = p_Vid->layer; + p_SEI->seiSubseqChar.subseq_id = p_SEI->seiSubseqInfo[p_Vid->layer].subseq_id; + p_SEI->seiSubseqChar.duration_flag = 0; + p_SEI->seiSubseqChar.average_rate_flag = 0; + p_SEI->seiSubseqChar.num_referenced_subseqs = 0; +} + +static void ClearSubseqCharPayload(SEIParameters *p_SEI) +{ + memset( p_SEI->seiSubseqChar.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiSubseqChar.data->bits_to_go = 8; + p_SEI->seiSubseqChar.data->byte_pos = 0; + p_SEI->seiSubseqChar.data->byte_buf = 0; + p_SEI->seiSubseqChar.payloadSize = 0; + + p_SEI->seiHasSubseqChar = FALSE; +} + +void UpdateSubseqChar(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + + p_SEI->seiSubseqChar.subseq_layer_num = p_Vid->layer; + p_SEI->seiSubseqChar.subseq_id = p_SEI->seiSubseqInfo[p_Vid->layer].subseq_id; + p_SEI->seiSubseqChar.duration_flag = 0; + p_SEI->seiSubseqChar.average_rate_flag = 0; + p_SEI->seiSubseqChar.average_bit_rate = 100; + p_SEI->seiSubseqChar.average_frame_rate = 30; + p_SEI->seiSubseqChar.num_referenced_subseqs = 0; + p_SEI->seiSubseqChar.ref_subseq_layer_num[0] = 1; + p_SEI->seiSubseqChar.ref_subseq_id[0] = 2; + p_SEI->seiSubseqChar.ref_subseq_layer_num[1] = 3; + p_SEI->seiSubseqChar.ref_subseq_id[1] = 4; + + p_SEI->seiHasSubseqChar = TRUE; +} + +static void FinalizeSubseqChar(SEIParameters *p_SEI) +{ + int i; + SyntaxElement sym; + Bitstream *dest = p_SEI->seiSubseqChar.data; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + + sym.value1 = p_SEI->seiSubseqChar.subseq_layer_num; + writeSyntaxElement2Buf_UVLC(&sym, dest); + sym.value1 = p_SEI->seiSubseqChar.subseq_id; + writeSyntaxElement2Buf_UVLC(&sym, dest); + sym.bitpattern = p_SEI->seiSubseqChar.duration_flag; + sym.len = 1; + writeSyntaxElement2Buf_Fixed(&sym, dest); + if ( p_SEI->seiSubseqChar.duration_flag ) + { + sym.bitpattern = p_SEI->seiSubseqChar.subseq_duration; + sym.len = 32; + writeSyntaxElement2Buf_Fixed(&sym, dest); + } + sym.bitpattern = p_SEI->seiSubseqChar.average_rate_flag; + sym.len = 1; + writeSyntaxElement2Buf_Fixed(&sym, dest); + if ( p_SEI->seiSubseqChar.average_rate_flag ) + { + sym.bitpattern = p_SEI->seiSubseqChar.average_bit_rate; + sym.len = 16; + writeSyntaxElement2Buf_Fixed(&sym, dest); + sym.bitpattern = p_SEI->seiSubseqChar.average_frame_rate; + sym.len = 16; + writeSyntaxElement2Buf_Fixed(&sym, dest); + } + sym.value1 = p_SEI->seiSubseqChar.num_referenced_subseqs; + writeSyntaxElement2Buf_UVLC(&sym, dest); + for (i=0; iseiSubseqChar.num_referenced_subseqs; i++) + { + sym.value1 = p_SEI->seiSubseqChar.ref_subseq_layer_num[i]; + writeSyntaxElement2Buf_UVLC(&sym, dest); + sym.value1 = p_SEI->seiSubseqChar.ref_subseq_id[i]; + writeSyntaxElement2Buf_UVLC(&sym, dest); + } + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( dest->bits_to_go != 8 ) + { + (dest->byte_buf) <<= 1; + dest->byte_buf |= 1; + dest->bits_to_go--; + if ( dest->bits_to_go != 0 ) (dest->byte_buf) <<= (dest->bits_to_go); + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + p_SEI->seiSubseqChar.payloadSize = dest->byte_pos; +} + +static void CloseSubseqChar(SEIParameters *p_SEI) +{ + if (p_SEI->seiSubseqChar.data) + { + free(p_SEI->seiSubseqChar.data->streamBuffer); + free(p_SEI->seiSubseqChar.data); + } + p_SEI->seiSubseqChar.data = NULL; +} + + +// JVT-D099 +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on scene information SEI message + * \brief + * JVT-D099 + * \author + * Ye-Kui Wang + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ +void InitSceneInformation(SEIParameters *p_SEI) +{ + p_SEI->seiHasSceneInformation = TRUE; + + p_SEI->seiSceneInformation.scene_id = 0; + p_SEI->seiSceneInformation.scene_transition_type = 0; + p_SEI->seiSceneInformation.second_scene_id = -1; + + p_SEI->seiSceneInformation.data = malloc( sizeof(Bitstream) ); + if(p_SEI-> seiSceneInformation.data == NULL ) no_mem_exit("InitSceneInformation: seiSceneInformation.data"); + p_SEI->seiSceneInformation.data->streamBuffer = malloc( MAXRTPPAYLOADLEN ); + if( p_SEI->seiSceneInformation.data->streamBuffer == NULL ) no_mem_exit("InitSceneInformation: seiSceneInformation.data->streamBuffer"); + p_SEI->seiSceneInformation.data->bits_to_go = 8; + p_SEI->seiSceneInformation.data->byte_pos = 0; + p_SEI->seiSceneInformation.data->byte_buf = 0; + memset( p_SEI->seiSceneInformation.data->streamBuffer, 0, MAXRTPPAYLOADLEN ); +} + +void CloseSceneInformation(SEIParameters *p_SEI) +{ + if (p_SEI->seiSceneInformation.data) + { + free(p_SEI->seiSceneInformation.data->streamBuffer); + free(p_SEI->seiSceneInformation.data); + } + p_SEI->seiSceneInformation.data = NULL; +} + +void FinalizeSceneInformation(SEIParameters *p_SEI) +{ + SyntaxElement sym; + Bitstream *dest = p_SEI->seiSceneInformation.data; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + + sym.bitpattern = p_SEI->seiSceneInformation.scene_id; + sym.len = 8; + writeSyntaxElement2Buf_Fixed(&sym, dest); + + sym.value1 = p_SEI->seiSceneInformation.scene_transition_type; + writeSyntaxElement2Buf_UVLC(&sym, dest); + + if(p_SEI->seiSceneInformation.scene_transition_type > 3) + { + sym.bitpattern = p_SEI->seiSceneInformation.second_scene_id; + sym.len = 8; + writeSyntaxElement2Buf_Fixed(&sym, dest); + } + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( dest->bits_to_go != 8 ) + { + (dest->byte_buf) <<= 1; + dest->byte_buf |= 1; + dest->bits_to_go--; + if ( dest->bits_to_go != 0 ) (dest->byte_buf) <<= (dest->bits_to_go); + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + p_SEI->seiSceneInformation.payloadSize = dest->byte_pos; +} + +// HasSceneInformation: To include a scene information SEI into the next slice/DP, +// set HasSceneInformation to be TRUE when calling this function. Otherwise, +// set HasSceneInformation to be FALSE. +void UpdateSceneInformation(SEIParameters *p_SEI, Boolean HasSceneInformation, int sceneID, int sceneTransType, int secondSceneID) +{ + p_SEI->seiHasSceneInformation = HasSceneInformation; + + assert (sceneID < 256); + p_SEI->seiSceneInformation.scene_id = sceneID; + + assert (sceneTransType <= 6 ); + p_SEI->seiSceneInformation.scene_transition_type = sceneTransType; + + if(sceneTransType > 3) + { + assert (secondSceneID < 256); + p_SEI->seiSceneInformation.second_scene_id = secondSceneID; + } +} +// End JVT-D099 + + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on Pan Scan messages + * \brief + * Based on FCD + * \author + * Shankar Regunathan + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + +static void InitPanScanRectInfo(SEIParameters *p_SEI) +{ + p_SEI->seiPanScanRectInfo.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiPanScanRectInfo.data == NULL ) no_mem_exit("InitPanScanRectInfo: p_SEI->seiPanScanRectInfo.data"); + p_SEI->seiPanScanRectInfo.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiPanScanRectInfo.data->streamBuffer == NULL ) no_mem_exit("InitPanScanRectInfo: p_SEI->seiPanScanRectInfo.data->streamBuffer"); + ClearPanScanRectInfoPayload(p_SEI); + + p_SEI->seiPanScanRectInfo.pan_scan_rect_id = 0; + p_SEI->seiPanScanRectInfo.pan_scan_rect_cancel_flag = 0; + p_SEI->seiPanScanRectInfo.pan_scan_cnt_minus1 = 0; + memset( p_SEI->seiPanScanRectInfo.pan_scan_rect_left_offset, 0, 3 * sizeof ( int ) ); + memset( p_SEI->seiPanScanRectInfo.pan_scan_rect_right_offset, 0, 3 * sizeof ( int ) ); + memset( p_SEI->seiPanScanRectInfo.pan_scan_rect_top_offset, 0, 3 * sizeof ( int ) ); + memset( p_SEI->seiPanScanRectInfo.pan_scan_rect_bottom_offset, 0, 3 * sizeof ( int ) ); + p_SEI->seiPanScanRectInfo.pac_scan_rect_repetition_period = 0; +} + + +void ClearPanScanRectInfoPayload(SEIParameters *p_SEI) +{ + memset( p_SEI->seiPanScanRectInfo.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiPanScanRectInfo.data->bits_to_go = 8; + p_SEI->seiPanScanRectInfo.data->byte_pos = 0; + p_SEI->seiPanScanRectInfo.data->byte_buf = 0; + p_SEI->seiPanScanRectInfo.payloadSize = 0; + + p_SEI->seiHasPanScanRectInfo = FALSE; +} + +void UpdatePanScanRectInfo( VideoParameters *p_Vid ) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + + { + p_SEI->seiPanScanRectInfo.pan_scan_rect_id = 0; + p_SEI->seiPanScanRectInfo.pan_scan_rect_cancel_flag = 0; + p_SEI->seiPanScanRectInfo.pan_scan_cnt_minus1 = 0; + p_SEI->seiPanScanRectInfo.pan_scan_rect_left_offset[0] = 0; + p_SEI->seiPanScanRectInfo.pan_scan_rect_right_offset[0] = 160; + p_SEI->seiPanScanRectInfo.pan_scan_rect_top_offset[0] = 0; + p_SEI->seiPanScanRectInfo.pan_scan_rect_bottom_offset[0] = 160; + p_SEI->seiPanScanRectInfo.pac_scan_rect_repetition_period = 1; + } + + p_SEI->seiHasPanScanRectInfo = TRUE; +} + +void FinalizePanScanRectInfo(SEIParameters *p_SEI) +{ + int i; + Bitstream *bitstream = p_SEI->seiPanScanRectInfo.data; + + write_ue_v( "SEI: pan_scan_rect_id", p_SEI->seiPanScanRectInfo.pan_scan_rect_id, bitstream ); + write_u_1( "SEI: pan_scan_rect_cancel_flag", p_SEI->seiPanScanRectInfo.pan_scan_rect_cancel_flag, bitstream ); + if ( !(p_SEI->seiPanScanRectInfo.pan_scan_rect_cancel_flag) ) + { + write_ue_v( "SEI: pan_scan_cnt_minus1", p_SEI->seiPanScanRectInfo.pan_scan_cnt_minus1, bitstream ); + for ( i = 0; i <= p_SEI->seiPanScanRectInfo.pan_scan_cnt_minus1; i++ ) + { + write_se_v( "SEI: pan_scan_rect_left_offset[X]", p_SEI->seiPanScanRectInfo.pan_scan_rect_left_offset[i], bitstream ); + write_se_v( "SEI: pan_scan_rect_right_offset[X]", p_SEI->seiPanScanRectInfo.pan_scan_rect_right_offset[i], bitstream ); + write_se_v( "SEI: pan_scan_rect_top_offset[X]", p_SEI->seiPanScanRectInfo.pan_scan_rect_top_offset[i], bitstream ); + write_se_v( "SEI: pan_scan_rect_bottom_offset[X]", p_SEI->seiPanScanRectInfo.pan_scan_rect_bottom_offset[i], bitstream ); + } + write_ue_v( "SEI: pac_scan_rect_repetition_period", p_SEI->seiPanScanRectInfo.pac_scan_rect_repetition_period, bitstream ); + } + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiPanScanRectInfo.payloadSize = bitstream->byte_pos; +} + + +void ClosePanScanRectInfo(SEIParameters *p_SEI) +{ + if (p_SEI->seiPanScanRectInfo.data) + { + free(p_SEI->seiPanScanRectInfo.data->streamBuffer); + free(p_SEI->seiPanScanRectInfo.data); + } + p_SEI->seiPanScanRectInfo.data = NULL; +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on arbitrary (unregistered) data + * \brief + * Based on FCD + * \author + * Shankar Regunathan + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ +static void InitUser_data_unregistered(SEIParameters *p_SEI) +{ + + p_SEI->seiUser_data_unregistered.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiUser_data_unregistered.data == NULL ) no_mem_exit("InitUser_data_unregistered: p_SEI->seiUser_data_unregistered.data"); + p_SEI->seiUser_data_unregistered.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiUser_data_unregistered.data->streamBuffer == NULL ) no_mem_exit("InitUser_data_unregistered: p_SEI->seiUser_data_unregistered.data->streamBuffer"); + p_SEI->seiUser_data_unregistered.byte = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiUser_data_unregistered.byte == NULL ) no_mem_exit("InitUser_data_unregistered: p_SEI->seiUser_data_unregistered.byte"); + ClearUser_data_unregistered(p_SEI); + +} + + +static void ClearUser_data_unregistered(SEIParameters *p_SEI) +{ + memset( p_SEI->seiUser_data_unregistered.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiUser_data_unregistered.data->bits_to_go = 8; + p_SEI->seiUser_data_unregistered.data->byte_pos = 0; + p_SEI->seiUser_data_unregistered.data->byte_buf = 0; + p_SEI->seiUser_data_unregistered.payloadSize = 0; + + memset( p_SEI->seiUser_data_unregistered.byte, 0, MAXRTPPAYLOADLEN); + p_SEI->seiUser_data_unregistered.total_byte = 0; + + p_SEI->seiHasUser_data_unregistered_info = FALSE; +} + +void UpdateUser_data_unregistered(SEIParameters *p_SEI) +{ + int i, temp_data; + int total_byte; + + + total_byte = 7; + for(i = 0; i < total_byte; i++) + { + temp_data = i * 4; + p_SEI->seiUser_data_unregistered.byte[i] = (char) iClip3(0, 255, temp_data); + } + p_SEI->seiUser_data_unregistered.total_byte = total_byte; +} + +static void FinalizeUser_data_unregistered(SEIParameters *p_SEI) +{ + int i; + SyntaxElement sym; + Bitstream *dest = p_SEI->seiUser_data_unregistered.data; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + +// #define PRINT_USER_DATA_UNREGISTERED_INFO + for( i = 0; i < p_SEI->seiUser_data_unregistered.total_byte; i++) + { + sym.bitpattern = p_SEI->seiUser_data_unregistered.byte[i]; + sym.len = 8; // b (8) + writeSyntaxElement2Buf_Fixed(&sym, dest); +#ifdef PRINT_USER_DATA_UNREGISTERED_INFO + printf("Unreg data payload_byte = %d\n", p_SEI->seiUser_data_unregistered.byte[i]); +#endif + } +#ifdef PRINT_USER_DATA_UNREGISTERED_INFO +#undef PRINT_USER_DATA_UNREGISTERED_INFO +#endif + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( dest->bits_to_go != 8 ) + { + (dest->byte_buf) <<= 1; + dest->byte_buf |= 1; + dest->bits_to_go--; + if ( dest->bits_to_go != 0 ) (dest->byte_buf) <<= (dest->bits_to_go); + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + p_SEI->seiUser_data_unregistered.payloadSize = dest->byte_pos; +} + +static void CloseUser_data_unregistered(SEIParameters *p_SEI) +{ + if (p_SEI->seiUser_data_unregistered.data) + { + free(p_SEI->seiUser_data_unregistered.data->streamBuffer); + free(p_SEI->seiUser_data_unregistered.data); + } + p_SEI->seiUser_data_unregistered.data = NULL; + if(p_SEI->seiUser_data_unregistered.byte) + { + free(p_SEI->seiUser_data_unregistered.byte); + } +} + + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on registered ITU_T_T35 user data + * \brief + * Based on FCD + * \author + * Shankar Regunathan + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ +void InitUser_data_registered_itu_t_t35(SEIParameters *p_SEI) +{ + + p_SEI->seiUser_data_registered_itu_t_t35.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiUser_data_registered_itu_t_t35.data == NULL ) no_mem_exit("InitUser_data_unregistered: p_SEI->seiUser_data_registered_itu_t_t35.data"); + p_SEI->seiUser_data_registered_itu_t_t35.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiUser_data_registered_itu_t_t35.data->streamBuffer == NULL ) no_mem_exit("InitUser_data_unregistered: p_SEI->seiUser_data_registered_itu_t_t35.data->streamBuffer"); + p_SEI->seiUser_data_registered_itu_t_t35.byte = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiUser_data_registered_itu_t_t35.data == NULL ) no_mem_exit("InitUser_data_unregistered: p_SEI->seiUser_data_registered_itu_t_t35.byte"); + ClearUser_data_registered_itu_t_t35(p_SEI); + +} + + +static void ClearUser_data_registered_itu_t_t35(SEIParameters *p_SEI) +{ + memset( p_SEI->seiUser_data_registered_itu_t_t35.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiUser_data_registered_itu_t_t35.data->bits_to_go = 8; + p_SEI->seiUser_data_registered_itu_t_t35.data->byte_pos = 0; + p_SEI->seiUser_data_registered_itu_t_t35.data->byte_buf = 0; + p_SEI->seiUser_data_registered_itu_t_t35.payloadSize = 0; + + memset( p_SEI->seiUser_data_registered_itu_t_t35.byte, 0, MAXRTPPAYLOADLEN); + p_SEI->seiUser_data_registered_itu_t_t35.total_byte = 0; + p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code = 0; + p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code_extension_byte = 0; + + p_SEI->seiHasUser_data_registered_itu_t_t35_info = FALSE; +} + +void UpdateUser_data_registered_itu_t_t35(SEIParameters *p_SEI) +{ + int i, temp_data; + int total_byte; + int country_code = 82; // Country_code for India + + if(country_code < 0xFF) + { + p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code = country_code; + } + else + { + p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code = 0xFF; + p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code_extension_byte = country_code - 0xFF; + } + + total_byte = 7; + for(i = 0; i < total_byte; i++) + { + temp_data = i * 3; + p_SEI->seiUser_data_registered_itu_t_t35.byte[i] = (char) iClip3(0, 255, temp_data); + } + p_SEI->seiUser_data_registered_itu_t_t35.total_byte = total_byte; +} + +static void FinalizeUser_data_registered_itu_t_t35(SEIParameters *p_SEI) +{ + int i; + SyntaxElement sym; + Bitstream *dest = p_SEI->seiUser_data_registered_itu_t_t35.data; + + sym.type = SE_HEADER; + sym.mapping = ue_linfo; + + sym.bitpattern = p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code; + sym.len = 8; + writeSyntaxElement2Buf_Fixed(&sym, dest); + +// #define PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO + printf(" ITU_T_T35_COUNTRTY_CODE %d \n", p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code); +#endif + + if(p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code == 0xFF) + { + sym.bitpattern = p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code_extension_byte; + sym.len = 8; + writeSyntaxElement2Buf_Fixed(&sym, dest); +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO + printf(" ITU_T_T35_COUNTRTY_CODE_EXTENSION_BYTE %d \n", p_SEI->seiUser_data_registered_itu_t_t35.itu_t_t35_country_code_extension_byte); +#endif + } + + for( i = 0; i < p_SEI->seiUser_data_registered_itu_t_t35.total_byte; i++) + { + sym.bitpattern = p_SEI->seiUser_data_registered_itu_t_t35.byte[i]; + sym.len = 8; // b (8) + writeSyntaxElement2Buf_Fixed(&sym, dest); +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO + printf("itu_t_t35 payload_byte = %d\n", p_SEI->seiUser_data_registered_itu_t_t35.byte[i]); +#endif + } +#ifdef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO +#undef PRINT_USER_DATA_REGISTERED_ITU_T_T35_INFO +#endif + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( dest->bits_to_go != 8 ) + { + (dest->byte_buf) <<= 1; + dest->byte_buf |= 1; + dest->bits_to_go--; + if ( dest->bits_to_go != 0 ) (dest->byte_buf) <<= (dest->bits_to_go); + dest->bits_to_go = 8; + dest->streamBuffer[dest->byte_pos++]=dest->byte_buf; + dest->byte_buf = 0; + } + p_SEI->seiUser_data_registered_itu_t_t35.payloadSize = dest->byte_pos; +} + +void CloseUser_data_registered_itu_t_t35(SEIParameters *p_SEI) +{ + if (p_SEI->seiUser_data_registered_itu_t_t35.data) + { + free(p_SEI->seiUser_data_registered_itu_t_t35.data->streamBuffer); + free(p_SEI->seiUser_data_registered_itu_t_t35.data); + } + p_SEI->seiUser_data_registered_itu_t_t35.data = NULL; + if(p_SEI->seiUser_data_registered_itu_t_t35.byte) + { + free(p_SEI->seiUser_data_registered_itu_t_t35.byte); + } +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on random access message + * \brief + * Based on FCD + * \author + * Shankar Regunathan + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ +static void InitRandomAccess(SEIParameters *p_SEI) +{ + p_SEI->seiRecoveryPoint.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiRecoveryPoint.data == NULL ) no_mem_exit("InitRandomAccess: seiRandomAccess.data"); + p_SEI->seiRecoveryPoint.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiRecoveryPoint.data->streamBuffer == NULL ) no_mem_exit("InitRandomAccess: seiRandomAccess.data->streamBuffer"); + ClearRandomAccess(p_SEI); +} + + +void ClearRandomAccess(SEIParameters *p_SEI) +{ + memset( p_SEI->seiRecoveryPoint.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiRecoveryPoint.data->bits_to_go = 8; + p_SEI->seiRecoveryPoint.data->byte_pos = 0; + p_SEI->seiRecoveryPoint.data->byte_buf = 0; + p_SEI->seiRecoveryPoint.payloadSize = 0; + + p_SEI->seiRecoveryPoint.recovery_frame_cnt = 0; + p_SEI->seiRecoveryPoint.broken_link_flag = 0; + p_SEI->seiRecoveryPoint.exact_match_flag = 0; + p_SEI->seiRecoveryPoint.changing_slice_group_idc = 0; + + p_SEI->seiHasRecoveryPoint_info = FALSE; +} + +void UpdateRandomAccess(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + if(p_Vid->type == I_SLICE) + { + p_SEI->seiRecoveryPoint.recovery_frame_cnt = 0; + p_SEI->seiRecoveryPoint.exact_match_flag = 1; + p_SEI->seiRecoveryPoint.broken_link_flag = 0; + p_SEI->seiRecoveryPoint.changing_slice_group_idc = 0; + p_SEI->seiHasRecoveryPoint_info = TRUE; + } + else + { + p_SEI->seiHasRecoveryPoint_info = FALSE; + } +} + +static void FinalizeRandomAccess(SEIParameters *p_SEI) +{ + Bitstream *bitstream = p_SEI->seiRecoveryPoint.data; + + write_ue_v( "SEI: recovery_frame_cnt", p_SEI->seiRecoveryPoint.recovery_frame_cnt, bitstream); + write_u_1 ( "SEI: exact_match_flag", p_SEI->seiRecoveryPoint.exact_match_flag, bitstream); + write_u_1 ( "SEI: broken_link_flag", p_SEI->seiRecoveryPoint.broken_link_flag, bitstream); + write_u_v (2, "SEI: changing_slice_group_idc", p_SEI->seiRecoveryPoint.changing_slice_group_idc, bitstream); + + +// #define PRINT_RECOVERY_POINT +#ifdef PRINT_RECOVERY_POINT + printf(" recovery_frame_cnt %d \n", p_SEI->seiRecoveryPoint.recovery_frame_cnt); + printf(" exact_match_flag %d \n", p_SEI->seiRecoveryPoint.exact_match_flag); + printf(" broken_link_flag %d \n", p_SEI->seiRecoveryPoint.broken_link_flag); + printf(" changing_slice_group_idc %d \n", p_SEI->seiRecoveryPoint.changing_slice_group_idc); + printf(" %d %d \n", bitstream->byte_pos, bitstream->bits_to_go); + +#undef PRINT_RECOVERY_POINT +#endif + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiRecoveryPoint.payloadSize = bitstream->byte_pos; +} + +void CloseRandomAccess(SEIParameters *p_SEI) +{ + if (p_SEI->seiRecoveryPoint.data) + { + free(p_SEI->seiRecoveryPoint.data->streamBuffer); + free(p_SEI->seiRecoveryPoint.data); + } + p_SEI->seiRecoveryPoint.data = NULL; +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on HDR tone-mapping messages + * \brief + * Based on JVT-T060 + * \author + * Jane Zhao, sharp labs of america + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ +static int ParseToneMappingConfigFile(SEIParameters *p_SEI, InputParameters *p_Inp, ToneMappingSEI *pSeiToneMapping) +{ + int i; + int ret; + FILE* fp; + char buf[1024]; + unsigned int tmp; + + printf ("Parsing Tone mapping cfg file %s ..........\n\n", p_Inp->ToneMappingFile); + if ((fp = fopen(p_Inp->ToneMappingFile, "r")) == NULL) + { + fprintf(stdout, "Tone mapping config file %s is not found, disable tone mapping SEI\n", p_Inp->ToneMappingFile); + p_SEI->seiHasTone_mapping=FALSE; + + return 1; + } + + //read the tone mapping config file + while (fscanf(fp, "%s", buf)!=EOF) + { + ret = 1; + if (strcmp(buf, "tone_map_id")==0) + { + ret = fscanf(fp, " = %ud\n", &(pSeiToneMapping->tone_map_id)); + } + else if (strcmp(buf, "tone_map_cancel_flag")==0) + { + ret = fscanf(fp, " = %ud\n", &tmp); + pSeiToneMapping->tone_map_cancel_flag = (unsigned char) (tmp ? 1 : 0); + } + else if (strcmp(buf, "tone_map_repetition_period")==0) + { + ret = fscanf(fp, " = %ud\n", &(pSeiToneMapping->tone_map_repetition_period)); + } + else if (strcmp(buf, "coded_data_bit_depth")==0) + { + ret = fscanf(fp, " = %ud\n", &tmp); + pSeiToneMapping->coded_data_bit_depth = (unsigned char) tmp; + } + else if (strcmp(buf, "sei_bit_depth")==0) + { + ret = fscanf(fp, " = %ud\n", &tmp); + pSeiToneMapping->sei_bit_depth = (unsigned char) tmp; + } + else if (strcmp(buf, "model_id")==0) + { + ret = fscanf(fp, " = %ud\n", &(pSeiToneMapping->model_id)); + } + //else if (model_id ==0) + else if (strcmp(buf, "min_value")==0) + { + ret = fscanf(fp, " = %d\n", &(pSeiToneMapping->min_value)); + } + else if (strcmp(buf, "max_value")==0) + { + ret = fscanf(fp, " = %d\n", &(pSeiToneMapping->max_value)); + } + //(model_id == 1) + else if (strcmp(buf, "sigmoid_midpoint")==0) + { + ret = fscanf(fp, " = %d\n", &(pSeiToneMapping->sigmoid_midpoint)); + } + else if (strcmp(buf, "sigmoid_width")==0) + { + ret = fscanf(fp, " = %d\n", &(pSeiToneMapping->sigmoid_width)); + } + // (model_id == 2) + else if (strcmp(buf, "start_of_coded_interval")==0) + { + int max_output_num = 1<<(pSeiToneMapping->sei_bit_depth); + ret = fscanf(fp, " = "); + if (ret!=0) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + for (i=0; i < max_output_num; i++) + { + ret = fscanf(fp, "%d\n", &(pSeiToneMapping->start_of_coded_interval[i])); + if (ret!=1) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + } + } + //(model_id == 3) + else if (strcmp(buf, "num_pivots")==0) + { + ret = fscanf(fp, " = %d\n", &(pSeiToneMapping->num_pivots)); + } + + else if (strcmp(buf, "coded_pivot_value")==0) + { + ret = fscanf(fp, " = "); + if (ret!=0) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + for (i=0; i < pSeiToneMapping->num_pivots; i++) + { + ret = fscanf(fp, "%d\n", &(pSeiToneMapping->coded_pivot_value[i])); + if (ret!=1) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + } + } + else if (strcmp(buf, "sei_pivot_value")==0) + { + ret = fscanf(fp, " = "); + if (ret!=0) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + for (i=0; i < pSeiToneMapping->num_pivots; i++) + { + ret = fscanf(fp, "%d\n", &(pSeiToneMapping->sei_pivot_value[i])); + if (ret!=1) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + } + } + else + { + // read till the line end + if (NULL == fgets(buf, sizeof(buf), fp)) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + } + if (ret!=1) + { + error ("ParseToneMappingConfigFile: error parsing tone mapping config file",500); + } + } + + fclose(fp); + + return 0; +} + +static void InitToneMapping(SEIParameters *p_SEI, InputParameters *p_Inp) +{ + if (p_Inp->ToneMappingSEIPresentFlag == 0) + { + p_SEI->seiHasTone_mapping = FALSE; + return; + } + else + p_SEI->seiHasTone_mapping = TRUE; + + p_SEI->seiToneMapping.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiToneMapping.data == NULL ) no_mem_exit("InitToneMapping: seiToneMapping.data"); + p_SEI->seiToneMapping.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiToneMapping.data->streamBuffer == NULL ) no_mem_exit("InitToneMapping: seiToneMapping.data->streamBuffer"); + memset( p_SEI->seiToneMapping.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiToneMapping.data->bits_to_go = 8; + p_SEI->seiToneMapping.data->byte_pos = 0; + p_SEI->seiToneMapping.data->byte_buf = 0; + p_SEI->seiToneMapping.payloadSize = 0; + + // read tone mapping config from file + ParseToneMappingConfigFile(p_SEI, p_Inp, &p_SEI->seiToneMapping); +} + +static void FinalizeToneMapping(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + + Bitstream *bitstream = p_SEI->seiToneMapping.data; + int i; + + write_ue_v("SEI: tone_map_id" , p_SEI->seiToneMapping.tone_map_id, bitstream); + write_u_1("SEI: tone_map_cancel_flag" , p_SEI->seiToneMapping.tone_map_cancel_flag, bitstream); + +#ifdef PRINT_TONE_MAPPING + printf("frame %d: Tone-mapping SEI message\n", p_Vid->frame_num); + printf("tone_map_id = %d\n", p_SEI->seiToneMapping.tone_map_id); + printf("tone_map_cancel_flag = %d\n", p_SEI->seiToneMapping.tone_map_cancel_flag); +#endif + if (!p_SEI->seiToneMapping.tone_map_cancel_flag) + { + write_ue_v( "SEI: tone_map_repetition_period", p_SEI->seiToneMapping.tone_map_repetition_period, bitstream); + write_u_v (8,"SEI: coded_data_bit_depth" , p_SEI->seiToneMapping.coded_data_bit_depth, bitstream); + write_u_v (8,"SEI: sei_bit_depth" , p_SEI->seiToneMapping.sei_bit_depth, bitstream); + write_ue_v( "SEI: model_id" , p_SEI->seiToneMapping.model_id, bitstream); + +#ifdef PRINT_TONE_MAPPING + printf("tone_map_repetition_period = %d\n", p_SEI->seiToneMapping.tone_map_repetition_period); + printf("coded_data_bit_depth = %d\n", p_SEI->seiToneMapping.coded_data_bit_depth); + printf("sei_bit_depth = %d\n", p_SEI->seiToneMapping.sei_bit_depth); + printf("model_id = %d\n", p_SEI->seiToneMapping.model_id); +#endif + if (p_SEI->seiToneMapping.model_id == 0) + { // linear mapping + write_u_v (32,"SEI: min_value", p_SEI->seiToneMapping.min_value, bitstream); + write_u_v (32,"SEI: min_value", p_SEI->seiToneMapping.max_value, bitstream); +#ifdef PRINT_TONE_MAPPING + printf("min_value = %d, max_value = %d\n", p_SEI->seiToneMapping.min_value, p_SEI->seiToneMapping.max_value); +#endif + } + else if (p_SEI->seiToneMapping.model_id == 1) + { // sigmoidal mapping + write_u_v (32,"SEI: sigmoid_midpoint", p_SEI->seiToneMapping.sigmoid_midpoint, bitstream); + write_u_v (32,"SEI: sigmoid_width", p_SEI->seiToneMapping.sigmoid_width, bitstream); +#ifdef PRINT_TONE_MAPPING + printf("sigmoid_midpoint = %d, sigmoid_width = %d\n", p_SEI->seiToneMapping.sigmoid_midpoint, p_SEI->seiToneMapping.sigmoid_width); +#endif + } + else if (p_SEI->seiToneMapping.model_id == 2) + { // user defined table mapping + int bit_depth_val = 1 << p_SEI->seiToneMapping.sei_bit_depth; + for (i=0; iseiToneMapping.coded_data_bit_depth+7)>>3)<<3), "SEI: start_of_coded_interval", p_SEI->seiToneMapping.start_of_coded_interval[i], bitstream); +#ifdef PRINT_TONE_MAPPING + //printf("start_of_coded_interval[%d] = %d\n", i, p_SEI->seiToneMapping.start_of_coded_interval[i]); +#endif + } + } + else if (p_SEI->seiToneMapping.model_id == 3) + { // piece-wise linear mapping + write_u_v (16,"SEI: num_pivots", p_SEI->seiToneMapping.num_pivots, bitstream); +#ifdef PRINT_TONE_MAPPING + printf("num_pivots = %d\n", p_SEI->seiToneMapping.num_pivots); +#endif + for (i=0; i < p_SEI->seiToneMapping.num_pivots; i++) + { + write_u_v( (((p_SEI->seiToneMapping.coded_data_bit_depth+7)>>3)<<3), "SEI: coded_pivot_value", p_SEI->seiToneMapping.coded_pivot_value[i], bitstream); + write_u_v( (((p_SEI->seiToneMapping.sei_bit_depth+7)>>3)<<3), "SEI: sei_pivot_value", p_SEI->seiToneMapping.sei_pivot_value[i], bitstream); +#ifdef PRINT_TONE_MAPPING + printf("coded_pivot_value[%d] = %d, sei_pivot_value[%d] = %d\n", i, p_SEI->seiToneMapping.coded_pivot_value[i], i, p_SEI->seiToneMapping.sei_pivot_value[i]); +#endif + } + } + } // end !tone_map_cancel_flag + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiToneMapping.payloadSize = bitstream->byte_pos; +} + + +void UpdateToneMapping(SEIParameters *p_SEI) +{ + // return; + + // you may manually generate some test case here +} + +static void ClearToneMapping(SEIParameters *p_SEI) +{ + memset( p_SEI->seiToneMapping.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiToneMapping.data->bits_to_go = 8; + p_SEI->seiToneMapping.data->byte_pos = 0; + p_SEI->seiToneMapping.data->byte_buf = 0; + p_SEI->seiToneMapping.payloadSize = 0; + + p_SEI->seiHasTone_mapping=FALSE; +} + +static void CloseToneMapping(SEIParameters *p_SEI) +{ + + if (p_SEI->seiToneMapping.data) + { + free(p_SEI->seiToneMapping.data->streamBuffer); + free(p_SEI->seiToneMapping.data); + } + p_SEI->seiToneMapping.data = NULL; + p_SEI->seiHasTone_mapping = FALSE; +} + +/* + ************************************************************************ + * \functions on post-filter message + * \brief + * Based on JVT-U035 + * \author + * Steffen Wittmann + ************************************************************************ + */ +static void InitPostFilterHints(SEIParameters *p_SEI) +{ + p_SEI->seiPostFilterHints.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiPostFilterHints.data == NULL ) no_mem_exit("InitPostFilterHints: p_SEI->seiPostFilterHints.data"); + p_SEI->seiPostFilterHints.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiPostFilterHints.data->streamBuffer == NULL ) no_mem_exit("InitPostFilterHints: p_SEI->seiPostFilterHints.data->streamBuffer"); + ClearPostFilterHints(p_SEI); +} + +static void ClearPostFilterHints(SEIParameters *p_SEI) +{ + memset( p_SEI->seiPostFilterHints.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + p_SEI->seiPostFilterHints.data->bits_to_go = 8; + p_SEI->seiPostFilterHints.data->byte_pos = 0; + p_SEI->seiPostFilterHints.data->byte_buf = 0; + p_SEI->seiPostFilterHints.payloadSize = 0; + + p_SEI->seiPostFilterHints.filter_hint_size_y = 0; + p_SEI->seiPostFilterHints.filter_hint_size_x = 0; + p_SEI->seiPostFilterHints.filter_hint_type = 0; + p_SEI->seiPostFilterHints.additional_extension_flag = 0; +} + +void UpdatePostFilterHints(SEIParameters *p_SEI) +{ + unsigned int color_component, cx, cy; + p_SEI->seiPostFilterHints.filter_hint_type = 0; //define filter_hint_type here + p_SEI->seiPostFilterHints.filter_hint_size_y = p_SEI->seiPostFilterHints.filter_hint_size_x = 5; //define filter_hint_size here + get_mem3Dint(&p_SEI->seiPostFilterHints.filter_hint, 3, p_SEI->seiPostFilterHints.filter_hint_size_y, p_SEI->seiPostFilterHints.filter_hint_size_x); + + for (color_component = 0; color_component < 3; color_component ++) + for (cy = 0; cy < p_SEI->seiPostFilterHints.filter_hint_size_y; cy ++) + for (cx = 0; cx < p_SEI->seiPostFilterHints.filter_hint_size_x; cx ++) + p_SEI->seiPostFilterHints.filter_hint[color_component][cy][cx] = 1; //define filter_hint here + + p_SEI->seiPostFilterHints.additional_extension_flag = 0; +} + +static void FinalizePostFilterHints(SEIParameters *p_SEI) +{ + Bitstream *bitstream = p_SEI->seiPostFilterHints.data; + unsigned int color_component, cx, cy; + + write_ue_v( "SEI: post_filter_hint_size_y", p_SEI->seiPostFilterHints.filter_hint_size_y, bitstream); + write_ue_v( "SEI: post_filter_hint_size_x", p_SEI->seiPostFilterHints.filter_hint_size_x, bitstream); + write_u_v (2,"SEI: post_filter_hint_type", p_SEI->seiPostFilterHints.filter_hint_type, bitstream); + + for (color_component = 0; color_component < 3; color_component ++) + for (cy = 0; cy < p_SEI->seiPostFilterHints.filter_hint_size_y; cy ++) + for (cx = 0; cx < p_SEI->seiPostFilterHints.filter_hint_size_x; cx ++) + write_se_v("SEI: post_filter_hints", p_SEI->seiPostFilterHints.filter_hint[color_component][cy][cx], bitstream); + + write_u_1 ("SEI: post_filter_additional_extension_flag", p_SEI->seiPostFilterHints.additional_extension_flag, bitstream); + +// #define PRINT_POST_FILTER_HINTS +#ifdef PRINT_POST_FILTER_HINTS + printf(" post_filter_hint_size_y %d \n", p_SEI->seiPostFilterHints.filter_hint_size_y); + printf(" post_filter_hint_size_x %d \n", p_SEI->seiPostFilterHints.filter_hint_size_x); + printf(" post_filter_hint_type %d \n", p_SEI->seiPostFilterHints.filter_hint_type); + for (color_component = 0; color_component < 3; color_component ++) + for (cy = 0; cy < p_SEI->seiPostFilterHints.filter_hint_size_y; cy ++) + for (cx = 0; cx < p_SEI->seiPostFilterHints.filter_hint_size_x; cx ++) + printf(" post_filter_hint[%d][%d][%d] %d \n", color_component, cy, cx, filter_hint[color_component][cy][cx]); + + printf(" additional_extension_flag %d \n", p_SEI->seiPostFilterHints.additional_extension_flag); + +#undef PRINT_POST_FILTER_HINTS +#endif + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiPostFilterHints.payloadSize = bitstream->byte_pos; +} + +static void ClosePostFilterHints(SEIParameters *p_SEI) +{ + if (p_SEI->seiPostFilterHints.data) + { + free(p_SEI->seiPostFilterHints.data->streamBuffer); + free(p_SEI->seiPostFilterHints.data); + if (p_SEI->seiPostFilterHints.filter_hint) + free_mem3Dint(p_SEI->seiPostFilterHints.filter_hint); + } + p_SEI->seiPostFilterHints.data = NULL; +} + +/* +**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +* \functions to write SEI message into NAL +* \brief +**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +*/ +int Write_SEI_NALU(VideoParameters *p_Vid, int len) +{ + NALU_t *nalu = NULL; + int RBSPlen = 0; + byte *rbsp; + + if (HaveAggregationSEI(p_Vid)) + { + SEIParameters *p_SEI = p_Vid->p_SEI; + + nalu = AllocNALU(MAXNALUSIZE); + rbsp = p_SEI->sei_message[AGGREGATION_SEI].data; + RBSPlen = p_SEI->sei_message[AGGREGATION_SEI].payloadSize; + RBSPtoNALU (rbsp, nalu, RBSPlen, NALU_TYPE_SEI, NALU_PRIORITY_DISPOSABLE, 1); + nalu->startcodeprefix_len = 4; + + len += p_Vid->WriteNALU (p_Vid, nalu, p_Vid->f_out); + FreeNALU (nalu); + } + + return len; +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on buffering period SEI message + * \brief + * Based on final Recommendation + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ +void InitBufferingPeriod(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + p_SEI->seiBufferingPeriod.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiBufferingPeriod.data == NULL ) + no_mem_exit("InitBufferingPeriod: seiBufferingPeriod.data"); + + p_SEI->seiBufferingPeriod.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiBufferingPeriod.data->streamBuffer == NULL ) + no_mem_exit("InitBufferingPeriod: seiBufferingPeriod.data->streamBuffer"); + + ClearBufferingPeriod(p_SEI, p_Vid->active_sps); +} + +void ClearBufferingPeriod(SEIParameters *p_SEI, seq_parameter_set_rbsp_t *active_sps) +{ + unsigned int SchedSelIdx; + memset( p_SEI->seiBufferingPeriod.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + + p_SEI->seiBufferingPeriod.data->bits_to_go = 8; + p_SEI->seiBufferingPeriod.data->byte_pos = 0; + p_SEI->seiBufferingPeriod.data->byte_buf = 0; + p_SEI->seiBufferingPeriod.payloadSize = 0; + + p_SEI->seiBufferingPeriod.seq_parameter_set_id = active_sps->seq_parameter_set_id; + if ( active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag ) + { + for ( SchedSelIdx = 0; SchedSelIdx <= active_sps->vui_seq_parameters.nal_hrd_parameters.cpb_cnt_minus1; SchedSelIdx++ ) + { + p_SEI->seiBufferingPeriod.nal_initial_cpb_removal_delay[SchedSelIdx] = 0; + p_SEI->seiBufferingPeriod.nal_initial_cpb_removal_delay_offset[SchedSelIdx] = 0; + } + } + if ( active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag ) + { + for ( SchedSelIdx = 0; SchedSelIdx <= active_sps->vui_seq_parameters.vcl_hrd_parameters.cpb_cnt_minus1; SchedSelIdx++ ) + { + p_SEI->seiBufferingPeriod.vcl_initial_cpb_removal_delay[SchedSelIdx] = 0; + p_SEI->seiBufferingPeriod.vcl_initial_cpb_removal_delay_offset[SchedSelIdx] = 0; + } + } + + p_SEI->seiHasBufferingPeriod_info = FALSE; +} + +void UpdateBufferingPeriod(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + p_SEI->seiHasBufferingPeriod_info = FALSE; +} + +static void FinalizeBufferingPeriod(SEIParameters *p_SEI, seq_parameter_set_rbsp_t *active_sps) +{ + unsigned int SchedSelIdx; + Bitstream *bitstream = p_SEI->seiBufferingPeriod.data; + + write_ue_v( "SEI: seq_parameter_set_id", p_SEI->seiBufferingPeriod.seq_parameter_set_id, bitstream); + if ( active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag ) + { + for ( SchedSelIdx = 0; SchedSelIdx <= active_sps->vui_seq_parameters.nal_hrd_parameters.cpb_cnt_minus1; SchedSelIdx++ ) + { + write_u_v( active_sps->vui_seq_parameters.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1, + "SEI: initial_cpb_removal_delay", p_SEI->seiBufferingPeriod.nal_initial_cpb_removal_delay[SchedSelIdx], bitstream); + write_u_v( active_sps->vui_seq_parameters.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1, + "SEI: initial_cpb_removal_delay_offset", p_SEI->seiBufferingPeriod.nal_initial_cpb_removal_delay_offset[SchedSelIdx], bitstream); + } + } + if ( active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag ) + { + for ( SchedSelIdx = 0; SchedSelIdx <= active_sps->vui_seq_parameters.vcl_hrd_parameters.cpb_cnt_minus1; SchedSelIdx++ ) + { + write_u_v( active_sps->vui_seq_parameters.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1, + "SEI: initial_cpb_removal_delay", p_SEI->seiBufferingPeriod.vcl_initial_cpb_removal_delay[SchedSelIdx], bitstream); + write_u_v( active_sps->vui_seq_parameters.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1, + "SEI: initial_cpb_removal_delay_offset", p_SEI->seiBufferingPeriod.vcl_initial_cpb_removal_delay_offset[SchedSelIdx], bitstream); + } + } + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiBufferingPeriod.payloadSize = bitstream->byte_pos; +} + +static void CloseBufferingPeriod(SEIParameters *p_SEI) +{ + if (p_SEI->seiBufferingPeriod.data) + { + free(p_SEI->seiBufferingPeriod.data->streamBuffer); + free(p_SEI->seiBufferingPeriod.data); + } + p_SEI->seiBufferingPeriod.data = NULL; +} + +/* + ************************************************************************ + * \brief + * Initialize Picture Timing SEI data + ************************************************************************ + */ +void InitPicTiming(SEIParameters *p_SEI) +{ + p_SEI->seiPicTiming.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiPicTiming.data == NULL ) + no_mem_exit("InitPicTiming: seiPicTiming.data"); + + p_SEI->seiPicTiming.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiPicTiming.data->streamBuffer == NULL ) + no_mem_exit("InitPicTiming: seiPicTiming.data->streamBuffer"); + + ClearPicTiming(p_SEI); +} + +/* + ************************************************************************ + * \brief + * Clear Picture Timing SEI data + ************************************************************************ + */ +void ClearPicTiming(SEIParameters *p_SEI) +{ + memset( p_SEI->seiPicTiming.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + + p_SEI->seiPicTiming.data->bits_to_go = 8; + p_SEI->seiPicTiming.data->byte_pos = 0; + p_SEI->seiPicTiming.data->byte_buf = 0; + p_SEI->seiPicTiming.payloadSize = 0; + + // initialization + p_SEI->seiPicTiming.cpb_removal_delay = 0; + p_SEI->seiPicTiming.dpb_output_delay = 0; + p_SEI->seiPicTiming.pic_struct = 0; + memset(p_SEI->seiPicTiming.clock_timestamp_flag, 0, MAX_PIC_STRUCT_VALUE * sizeof(Boolean) ); // 0 == FALSE + p_SEI->seiPicTiming.ct_type = 0; + p_SEI->seiPicTiming.nuit_field_based_flag = FALSE; + p_SEI->seiPicTiming.counting_type = 0; + p_SEI->seiPicTiming.full_timestamp_flag = FALSE; + p_SEI->seiPicTiming.discontinuity_flag = FALSE; + p_SEI->seiPicTiming.cnt_dropped_flag = FALSE; + p_SEI->seiPicTiming.n_frames = 0; + p_SEI->seiPicTiming.seconds_value = 0; + p_SEI->seiPicTiming.minutes_value = 0; + p_SEI->seiPicTiming.hours_value = 0; + p_SEI->seiPicTiming.seconds_flag = FALSE; + p_SEI->seiPicTiming.minutes_flag = FALSE; + p_SEI->seiPicTiming.hours_flag = FALSE; + p_SEI->seiPicTiming.time_offset = 0; + + p_SEI->seiHasPicTiming_info = FALSE; +} + +/* + ************************************************************************ + * \brief + * Derive pic_struct flag (Table D-1) + ************************************************************************ + */ +static int get_pic_struct( VideoParameters *p_Vid, int frame_no, int field_pic_flag, int top ) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + + if ( field_pic_flag ) + { + if ( top ) + { + return 1; + } + else + { + return 2; + } + } + else + { + if ( !p_Inp->SEIVUI32Pulldown ) + { + return 0; + } + else + { + int order = (frame_no % 4); + int pic_struct_a[4] = {0,5,6,0}; + int pic_struct_b[4] = {0,0,7,0}; + int pic_struct_c[4] = {3,5,6,3}; + int pic_struct_d[4] = {0,5,4,6}; + int pic_struct_e[4] = {3,5,4,6}; + + switch( p_Inp->SEIVUI32Pulldown ) + { + default: + case 1: + return pic_struct_a[order]; + break; + case 2: + return pic_struct_b[order]; + break; + case 3: + return pic_struct_c[order]; + break; + case 4: + return pic_struct_d[order]; + break; + case 5: + return pic_struct_e[order]; + break; + } + } + } +} + + +/* + ************************************************************************ + * \brief + * Update Picture Timing SEI data + ************************************************************************ + */ +void UpdatePicTiming(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + // initialize the values + if ( p_Inp->SEIVUI32Pulldown ) + { + int fld_flag = p_Vid->fld_flag; + // pic_struct + p_Vid->pic_struct = get_pic_struct( p_Vid, p_Vid->frm_no_in_file, fld_flag, (p_Vid->structure == TOP_FIELD) ? 1 : 0 ); + + if ( active_sps->vui_seq_parameters.pic_struct_present_flag ) + { + int NumClockTS = 0, i; + int bottom_field_flag = (p_Vid->structure == BOTTOM_FIELD); + p_SEI->seiPicTiming.pic_struct = p_Vid->pic_struct; + // interpret pic_struct + switch( p_SEI->seiPicTiming.pic_struct ) + { + case 0: + default: + // frame + assert( fld_flag == FALSE ); + NumClockTS = 1; + break; + case 1: + // top field + assert( (p_Vid->fld_flag == TRUE) && (bottom_field_flag == FALSE) ); + NumClockTS = 1; + break; + case 2: + // bottom field + assert( (p_Vid->fld_flag == TRUE) && (bottom_field_flag == TRUE) ); + NumClockTS = 1; + break; + case 3: + // top field, bottom field, in that order + case 4: + // bottom field, top field, in that order + assert( p_Vid->fld_flag == FALSE ); + NumClockTS = 2; + break; + case 5: + // top field, bottom field, top field repeated, in that order + case 6: + // bottom field, top field, bottom field repeated, in that order + assert( p_Vid->fld_flag == FALSE ); + NumClockTS = 3; + case 7: + // frame doubling + assert( (p_Vid->fld_flag == FALSE) && active_sps->vui_seq_parameters.fixed_frame_rate_flag == 1 ); + NumClockTS = 2; + break; + case 8: + // frame tripling + assert( (p_Vid->fld_flag == FALSE) && active_sps->vui_seq_parameters.fixed_frame_rate_flag == 1 ); + NumClockTS = 3; + break; + } + for ( i = 0; i < NumClockTS; i++ ) + { + p_SEI->seiPicTiming.clock_timestamp_flag[i] = FALSE; + if ( p_SEI->seiPicTiming.clock_timestamp_flag[i] ) + { + int seconds = 0; + int minutes = 0; + int hours = 0; + int time_offset_length; + assert( seconds >= 0 && seconds <= 59 ); + assert( minutes >= 0 && minutes <= 59 ); + assert( hours >= 0 && hours <= 23 ); + + p_SEI->seiPicTiming.ct_type = 0; + p_SEI->seiPicTiming.nuit_field_based_flag = FALSE; + p_SEI->seiPicTiming.counting_type = 0; + p_SEI->seiPicTiming.full_timestamp_flag = FALSE; + p_SEI->seiPicTiming.discontinuity_flag = FALSE; + p_SEI->seiPicTiming.cnt_dropped_flag = FALSE; + p_SEI->seiPicTiming.n_frames = 0; + + if ( p_SEI->seiPicTiming.full_timestamp_flag ) + { + p_SEI->seiPicTiming.seconds_value = seconds; + p_SEI->seiPicTiming.minutes_value = minutes; + p_SEI->seiPicTiming.hours_value = hours; + } + else + { + p_SEI->seiPicTiming.seconds_flag = FALSE; + if (p_SEI->seiPicTiming.seconds_flag) + { + p_SEI->seiPicTiming.seconds_value = seconds; + p_SEI->seiPicTiming.minutes_flag = FALSE; + if (p_SEI->seiPicTiming.minutes_flag) + { + p_SEI->seiPicTiming.minutes_value = minutes; + p_SEI->seiPicTiming.hours_flag = FALSE; + if (p_SEI->seiPicTiming.hours_flag) + { + p_SEI->seiPicTiming.hours_value = hours; + } + } + } + } + if (active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + time_offset_length = active_sps->vui_seq_parameters.vcl_hrd_parameters.time_offset_length; + else if (active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + time_offset_length = active_sps->vui_seq_parameters.nal_hrd_parameters.time_offset_length; + else + time_offset_length = 24; + if ( time_offset_length ) + { + p_SEI->seiPicTiming.time_offset = 0; + } + } + } + } + p_SEI->seiHasPicTiming_info = TRUE; + } + else + { + p_SEI->seiHasPicTiming_info = FALSE; + } +} + +/* + ************************************************************************ + * \brief + * Finalize Picture Timing SEI data + ************************************************************************ + */ +static void FinalizePicTiming(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + Bitstream *bitstream = p_SEI->seiPicTiming.data; + // CpbDpbDelaysPresentFlag can also be set "by some means not specified in this Recommendation | International Standard" + Boolean CpbDpbDelaysPresentFlag = (Boolean) (active_sps->vui_parameters_present_flag + && ( (active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag != 0) + ||(active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag != 0))); + hrd_parameters_t *hrd = NULL; + + if (active_sps->vui_seq_parameters.vcl_hrd_parameters_present_flag) + { + hrd = &(active_sps->vui_seq_parameters.vcl_hrd_parameters); + } + else if (active_sps->vui_seq_parameters.nal_hrd_parameters_present_flag) + { + hrd = &(active_sps->vui_seq_parameters.nal_hrd_parameters); + } + else + { + hrd = NULL; + } + + if ( CpbDpbDelaysPresentFlag ) + { + write_u_v( hrd->cpb_removal_delay_length_minus1 + 1, "SEI: cpb_removal_delay", p_SEI->seiPicTiming.cpb_removal_delay, bitstream); + write_u_v( hrd->dpb_output_delay_length_minus1 + 1, "SEI: dpb_output_delay", p_SEI->seiPicTiming.dpb_output_delay, bitstream); + } + if ( active_sps->vui_seq_parameters.pic_struct_present_flag ) + { + int NumClockTS = 0, i; + int bottom_field_flag = (p_Vid->structure == BOTTOM_FIELD); + + write_u_v( 4, "SEI: pic_struct", p_SEI->seiPicTiming.pic_struct, bitstream); + // interpret pic_struct + switch( p_SEI->seiPicTiming.pic_struct ) + { + case 0: + default: + // frame + assert( p_Vid->fld_flag == FALSE ); + NumClockTS = 1; + break; + case 1: + // top field + assert( (p_Vid->fld_flag == TRUE) && (bottom_field_flag == FALSE) ); + NumClockTS = 1; + break; + case 2: + // bottom field + assert( (p_Vid->fld_flag == TRUE) && (bottom_field_flag == TRUE) ); + NumClockTS = 1; + break; + case 3: + // top field, bottom field, in that order + case 4: + // bottom field, top field, in that order + assert( p_Vid->fld_flag == FALSE ); + NumClockTS = 2; + break; + case 5: + // top field, bottom field, top field repeated, in that order + case 6: + // bottom field, top field, bottom field repeated, in that order + assert( p_Vid->fld_flag == FALSE ); + NumClockTS = 3; + break; + case 7: + // frame doubling + assert( (p_Vid->fld_flag == FALSE) && active_sps->vui_seq_parameters.fixed_frame_rate_flag == 1 ); + NumClockTS = 2; + break; + case 8: + // frame tripling + assert( (p_Vid->fld_flag == FALSE) && active_sps->vui_seq_parameters.fixed_frame_rate_flag == 1 ); + NumClockTS = 3; + break; + } + for ( i = 0; i < NumClockTS; i++ ) + { + write_u_1( "SEI: clock_timestamp_flag", p_SEI->seiPicTiming.clock_timestamp_flag[i], bitstream); + if ( p_SEI->seiPicTiming.clock_timestamp_flag[i] ) + { + write_u_v( 2, "SEI: ct_type", p_SEI->seiPicTiming.ct_type, bitstream); + write_u_1( "SEI: nuit_field_based_flag", p_SEI->seiPicTiming.nuit_field_based_flag, bitstream); + write_u_v( 5, "SEI: counting_type", p_SEI->seiPicTiming.counting_type, bitstream); + write_u_1( "SEI: full_timestamp_flag", p_SEI->seiPicTiming.full_timestamp_flag, bitstream); + write_u_1( "SEI: discontinuity_flag", p_SEI->seiPicTiming.discontinuity_flag, bitstream); + write_u_1( "SEI: cnt_dropped_flag", p_SEI->seiPicTiming.cnt_dropped_flag, bitstream); + write_u_v( 8, "SEI: n_frames", p_SEI->seiPicTiming.n_frames, bitstream); + + if ( p_SEI->seiPicTiming.full_timestamp_flag ) + { + write_u_v( 6, "SEI: seconds_value", p_SEI->seiPicTiming.seconds_value, bitstream); + write_u_v( 6, "SEI: minutes_value", p_SEI->seiPicTiming.minutes_value, bitstream); + write_u_v( 5, "SEI: hours_value", p_SEI->seiPicTiming.hours_value, bitstream); + } + else + { + write_u_1( "SEI: seconds_flag", p_SEI->seiPicTiming.seconds_flag, bitstream); + if (p_SEI->seiPicTiming.seconds_flag) + { + write_u_v( 6, "SEI: seconds_value", p_SEI->seiPicTiming.seconds_value, bitstream); + write_u_1( "SEI: minutes_flag", p_SEI->seiPicTiming.minutes_flag, bitstream); + if (p_SEI->seiPicTiming.minutes_flag) + { + write_u_v( 6, "SEI: minutes_value", p_SEI->seiPicTiming.minutes_value, bitstream); + write_u_1( "SEI: hours_flag", p_SEI->seiPicTiming.hours_flag, bitstream); + if (p_SEI->seiPicTiming.hours_flag) + { + write_u_v( 5, "SEI: hours_value", p_SEI->seiPicTiming.hours_value, bitstream); + } + } + } + } + if ( hrd == NULL ) + { + write_u_v( 24, "SEI: time_offset", p_SEI->seiPicTiming.time_offset, bitstream); + } + else + { + write_u_v( hrd->time_offset_length, "SEI: time_offset", p_SEI->seiPicTiming.time_offset, bitstream); + } + } + } + } + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiPicTiming.payloadSize = bitstream->byte_pos; +} + +/* + ************************************************************************ + * \brief + * Close Picture Timing SEI data + ************************************************************************ + */ +static void ClosePicTiming(SEIParameters *p_SEI) +{ + if (p_SEI->seiPicTiming.data) + { + free(p_SEI->seiPicTiming.data->streamBuffer); + free(p_SEI->seiPicTiming.data); + } + p_SEI->seiPicTiming.data = NULL; +} + +/* + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * \functions on frame packing arrangement SEI message + * \brief + * Based on pre-published Recommendation + **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + +//! Frame packing arrangement Information +static void InitFramePackingArrangement(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + + p_SEI->seiFramePackingArrangement.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiFramePackingArrangement.data == NULL ) + no_mem_exit("InitFramePackingArrangement: seiFramePackingArrangement.data"); + + p_SEI->seiFramePackingArrangement.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiFramePackingArrangement.data->streamBuffer == NULL ) + no_mem_exit("InitFramePackingArrangement: seiFramePackingArrangement.data->streamBuffer"); + + ClearFramePackingArrangement(p_SEI); +} + +void ClearFramePackingArrangement(SEIParameters *p_SEI) +{ + memset( p_SEI->seiFramePackingArrangement.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + + p_SEI->seiFramePackingArrangement.data->bits_to_go = 8; + p_SEI->seiFramePackingArrangement.data->byte_pos = 0; + p_SEI->seiFramePackingArrangement.data->byte_buf = 0; + p_SEI->seiFramePackingArrangement.payloadSize = 0; + + p_SEI->seiFramePackingArrangement.frame_packing_arrangement_id = 0; + p_SEI->seiFramePackingArrangement.frame_packing_arrangement_cancel_flag = FALSE; + p_SEI->seiFramePackingArrangement.frame_packing_arrangement_type = 0; + p_SEI->seiFramePackingArrangement.quincunx_sampling_flag = FALSE; + p_SEI->seiFramePackingArrangement.content_interpretation_type = 0; + p_SEI->seiFramePackingArrangement.spatial_flipping_flag = FALSE; + p_SEI->seiFramePackingArrangement.frame0_flipped_flag = FALSE; + p_SEI->seiFramePackingArrangement.field_views_flag = FALSE; + p_SEI->seiFramePackingArrangement.current_frame_is_frame0_flag = FALSE; + p_SEI->seiFramePackingArrangement.frame0_self_contained_flag = FALSE; + p_SEI->seiFramePackingArrangement.frame1_self_contained_flag = FALSE; + /*p_SEI->seiFramePackingArrangement.frame0_grid_position_x = 0; + p_SEI->seiFramePackingArrangement.frame0_grid_position_y = 0; + p_SEI->seiFramePackingArrangement.frame1_grid_position_x = 0; + p_SEI->seiFramePackingArrangement.frame1_grid_position_y = 0;*/ + p_SEI->seiFramePackingArrangement.frame_packing_arrangement_reserved_byte = 0; + p_SEI->seiFramePackingArrangement.frame_packing_arrangement_repetition_period = 0; + p_SEI->seiFramePackingArrangement.frame_packing_arrangement_extension_flag = FALSE; + + p_SEI->seiHasFramePackingArrangement_info = FALSE; +} + +void UpdateFramePackingArrangement(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + + p_SEI->seiHasFramePackingArrangement_info = FALSE; +} + +static void FinalizeFramePackingArrangement(SEIParameters *p_SEI, InputParameters *p_Inp) +{ + Bitstream *bitstream = p_SEI->seiFramePackingArrangement.data; + + write_ue_v( "SEI: frame_packing_arrangement_id", (int)p_SEI->seiFramePackingArrangement.frame_packing_arrangement_id, bitstream ); + write_u_1( "SEI: frame_packing_arrangement_cancel_flag", (int)p_SEI->seiFramePackingArrangement.frame_packing_arrangement_cancel_flag, bitstream ); + if ( p_SEI->seiFramePackingArrangement.frame_packing_arrangement_cancel_flag == FALSE ) + { + write_u_v( 7, "SEI: frame_packing_arrangement_type", (int)p_SEI->seiFramePackingArrangement.frame_packing_arrangement_type, bitstream ); + write_u_1( "SEI: quincunx_sampling_flag", (int)p_SEI->seiFramePackingArrangement.quincunx_sampling_flag, bitstream ); + write_u_v( 6, "SEI: content_interpretation_type", (int)p_SEI->seiFramePackingArrangement.content_interpretation_type, bitstream ); + write_u_1( "SEI: spatial_flipping_flag", (int)p_SEI->seiFramePackingArrangement.spatial_flipping_flag, bitstream ); + write_u_1( "SEI: frame0_flipped_flag", (int)p_SEI->seiFramePackingArrangement.frame0_flipped_flag, bitstream ); + write_u_1( "SEI: field_views_flag", (int)p_SEI->seiFramePackingArrangement.field_views_flag, bitstream ); + write_u_1( "SEI: current_frame_is_frame0_flag", (int)p_SEI->seiFramePackingArrangement.current_frame_is_frame0_flag, bitstream ); + write_u_1( "SEI: frame0_self_contained_flag", (int)p_SEI->seiFramePackingArrangement.frame0_self_contained_flag, bitstream ); + write_u_1( "SEI: frame1_self_contained_flag", (int)p_SEI->seiFramePackingArrangement.frame1_self_contained_flag, bitstream ); + if ( p_SEI->seiFramePackingArrangement.quincunx_sampling_flag == FALSE && p_SEI->seiFramePackingArrangement.frame_packing_arrangement_type != 5 ) + { + write_u_v( 4, "SEI: frame0_grid_position_x", (int)p_SEI->seiFramePackingArrangement.frame0_grid_position_x, bitstream ); + write_u_v( 4, "SEI: frame0_grid_position_y", (int)p_SEI->seiFramePackingArrangement.frame0_grid_position_y, bitstream ); + write_u_v( 4, "SEI: frame1_grid_position_x", (int)p_SEI->seiFramePackingArrangement.frame1_grid_position_x, bitstream ); + write_u_v( 4, "SEI: frame1_grid_position_y", (int)p_SEI->seiFramePackingArrangement.frame1_grid_position_y, bitstream ); + } + + + write_u_v( 8, "SEI: frame_packing_arrangement_reserved_byte", (int)p_SEI->seiFramePackingArrangement.frame_packing_arrangement_reserved_byte, bitstream ); + write_ue_v( "SEI: frame_packing_arrangement_repetition_period", (int)p_SEI->seiFramePackingArrangement.frame_packing_arrangement_repetition_period, bitstream ); + } + write_u_1( "SEI: frame_packing_arrangement_extension_flag", (int)p_SEI->seiFramePackingArrangement.frame_packing_arrangement_extension_flag, bitstream ); + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiFramePackingArrangement.payloadSize = bitstream->byte_pos; +} + +static void CloseFramePackingArrangement(SEIParameters *p_SEI) +{ + if (p_SEI->seiFramePackingArrangement.data) + { + free(p_SEI->seiFramePackingArrangement.data->streamBuffer); + free(p_SEI->seiFramePackingArrangement.data); + } + p_SEI->seiFramePackingArrangement.data = NULL; +} + +/* + ************************************************************************ + * \brief + * Initialize dec_ref_pic_marking Repetition SEI data + ************************************************************************ + */ +static void InitDRPMRepetition(SEIParameters *p_SEI) +{ + p_SEI->seiDRPMRepetition.data = malloc( sizeof(Bitstream) ); + if( p_SEI->seiDRPMRepetition.data == NULL ) + no_mem_exit("InitDRPMRepetition: p_SEI->seiDRPMRepetition.data"); + + p_SEI->seiDRPMRepetition.data->streamBuffer = malloc(MAXRTPPAYLOADLEN); + if( p_SEI->seiDRPMRepetition.data->streamBuffer == NULL ) + no_mem_exit("InitDRPMRepetition: p_SEI->seiDRPMRepetition.data->streamBuffer"); + + ClearDRPMRepetition(p_SEI); +} + +/* + ************************************************************************ + * \brief + * Clear dec_ref_pic_marking Repetition SEI data + ************************************************************************ + */ +void ClearDRPMRepetition(SEIParameters *p_SEI) +{ + memset( p_SEI->seiDRPMRepetition.data->streamBuffer, 0, MAXRTPPAYLOADLEN); + + p_SEI->seiDRPMRepetition.data->bits_to_go = 8; + p_SEI->seiDRPMRepetition.data->byte_pos = 0; + p_SEI->seiDRPMRepetition.data->byte_buf = 0; + p_SEI->seiDRPMRepetition.payloadSize = 0; + + p_SEI->seiDRPMRepetition.original_bottom_field_flag = FALSE; + p_SEI->seiDRPMRepetition.original_field_pic_flag = FALSE; + p_SEI->seiDRPMRepetition.original_frame_num = 0; + p_SEI->seiDRPMRepetition.original_idr_flag = FALSE; + if ( p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved != NULL ) + { + free_drpm_buffer( p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved ); + p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved = NULL; + } + + p_SEI->seiHasDRPMRepetition_info = FALSE; +} + +/* + ************************************************************************ + * \brief + * Update dec_ref_pic_marking Repetition data + ************************************************************************ + */ +void UpdateDRPMRepetition(SEIParameters *p_SEI) +{ + if ( p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved != NULL ) + { + p_SEI->seiHasDRPMRepetition_info = TRUE; + } + else + { + p_SEI->seiHasDRPMRepetition_info = FALSE; + } +} + +/* + ************************************************************************ + * \brief + * Finalize dec_ref_pic_marking Repetition SEI data + ************************************************************************ + */ +static void FinalizeDRPMRepetition(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + + Bitstream *bitstream = p_SEI->seiDRPMRepetition.data; + + // SEI message bits + write_u_1( "SEI: original_idr_flag", p_SEI->seiDRPMRepetition.original_idr_flag, bitstream); + write_ue_v( "SEI: original_frame_num", p_SEI->seiDRPMRepetition.original_frame_num, bitstream); + if ( !active_sps->frame_mbs_only_flag ) + { + write_u_1( "SEI: original_field_pic_flag", p_SEI->seiDRPMRepetition.original_field_pic_flag, bitstream); + if ( p_SEI->seiDRPMRepetition.original_field_pic_flag ) + { + write_u_1( "SEI: original_bottom_field_flag", p_SEI->seiDRPMRepetition.original_bottom_field_flag, bitstream); + } + } + // now repeat dec_ref_pic_marking_buffer info + dec_ref_pic_marking( bitstream, + p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved, + p_SEI->seiDRPMRepetition.original_idr_flag, 0, 0); + + // make sure the payload is byte aligned, stuff bits are 10..0 + if ( bitstream->bits_to_go != 8 ) + { + (bitstream->byte_buf) <<= 1; + bitstream->byte_buf |= 1; + bitstream->bits_to_go--; + if ( bitstream->bits_to_go != 0 ) + (bitstream->byte_buf) <<= (bitstream->bits_to_go); + bitstream->bits_to_go = 8; + bitstream->streamBuffer[bitstream->byte_pos++]=bitstream->byte_buf; + bitstream->byte_buf = 0; + } + p_SEI->seiDRPMRepetition.payloadSize = bitstream->byte_pos; +} + +/* + ************************************************************************ + * \brief + * Close dec_ref_pic_marking Repetition SEI data + ************************************************************************ + */ +static void CloseDRPMRepetition(SEIParameters *p_SEI) +{ + if (p_SEI->seiDRPMRepetition.data) + { + free(p_SEI->seiDRPMRepetition.data->streamBuffer); + free(p_SEI->seiDRPMRepetition.data); + } + p_SEI->seiDRPMRepetition.data = NULL; + if ( p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved != NULL ) + { + free_drpm_buffer( p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved ); + p_SEI->seiDRPMRepetition.dec_ref_pic_marking_buffer_saved = NULL; + } +} + +/*! + ***************************************************************************** + * \brief + * Prepare the aggregation sei message. + * + * \date + * September 10, 2002 + * + * \author + * Dong Tian tian@cs.tut.fi + *****************************************************************************/ +void PrepareAggregationSEIMessage(VideoParameters *p_Vid) +{ + SEIParameters *p_SEI = p_Vid->p_SEI; + Boolean has_aggregation_sei_message = FALSE; + + clear_sei_message(p_SEI, AGGREGATION_SEI); + + // prepare the sei message here + // write the spare picture sei payload to the aggregation sei message + if (p_SEI->seiHasSparePicture && p_Vid->type != B_SLICE) + { + FinalizeSpareMBMap(p_Vid); + assert(p_SEI->seiSparePicturePayload.data->byte_pos == p_SEI->seiSparePicturePayload.payloadSize); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiSparePicturePayload.data->streamBuffer, p_SEI->seiSparePicturePayload.payloadSize, SEI_SPARE_PIC); + has_aggregation_sei_message = TRUE; + } + // write the sub sequence information sei paylaod to the aggregation sei message + if (p_SEI->seiHasSubseqInfo) + { + FinalizeSubseqInfo(p_SEI, p_Vid->layer); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiSubseqInfo[p_Vid->layer].data->streamBuffer, p_SEI->seiSubseqInfo[p_Vid->layer].payloadSize, SEI_SUB_SEQ_INFO); + ClearSubseqInfoPayload(p_SEI, p_Vid->layer); + has_aggregation_sei_message = TRUE; + } + // write the sub sequence layer information sei paylaod to the aggregation sei message + if (p_SEI->seiHasSubseqLayerInfo && p_Vid->number == 0) + { + FinalizeSubseqLayerInfo(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiSubseqLayerInfo.data, p_SEI->seiSubseqLayerInfo.payloadSize, SEI_SUB_SEQ_LAYER_CHARACTERISTICS); + p_SEI->seiHasSubseqLayerInfo = FALSE; + has_aggregation_sei_message = TRUE; + } + // write the sub sequence characteristics payload to the aggregation sei message + if (p_SEI->seiHasSubseqChar) + { + FinalizeSubseqChar(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiSubseqChar.data->streamBuffer, p_SEI->seiSubseqChar.payloadSize, SEI_SUB_SEQ_CHARACTERISTICS); + ClearSubseqCharPayload(p_SEI); + has_aggregation_sei_message = TRUE; + } + // write the pan scan rectangle info sei playload to the aggregation sei message + if (p_SEI->seiHasPanScanRectInfo) + { + FinalizePanScanRectInfo(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiPanScanRectInfo.data->streamBuffer, p_SEI->seiPanScanRectInfo.payloadSize, SEI_PAN_SCAN_RECT); + ClearPanScanRectInfoPayload(p_SEI); + has_aggregation_sei_message = TRUE; + } + // write the arbitrary (unregistered) info sei playload to the aggregation sei message + if (p_SEI->seiHasUser_data_unregistered_info) + { + FinalizeUser_data_unregistered(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiUser_data_unregistered.data->streamBuffer, p_SEI->seiUser_data_unregistered.payloadSize, SEI_USER_DATA_UNREGISTERED); + ClearUser_data_unregistered(p_SEI); + has_aggregation_sei_message = TRUE; + } + // write the arbitrary (unregistered) info sei playload to the aggregation sei message + if (p_SEI->seiHasUser_data_registered_itu_t_t35_info) + { + FinalizeUser_data_registered_itu_t_t35(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiUser_data_registered_itu_t_t35.data->streamBuffer, p_SEI->seiUser_data_registered_itu_t_t35.payloadSize, SEI_USER_DATA_REGISTERED_ITU_T_T35); + ClearUser_data_registered_itu_t_t35(p_SEI); + has_aggregation_sei_message = TRUE; + } + // more aggregation sei payload is written here... + + // write the scene information SEI payload + if (p_SEI->seiHasSceneInformation) + { + FinalizeSceneInformation(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiSceneInformation.data->streamBuffer, p_SEI->seiSceneInformation.payloadSize, SEI_SCENE_INFO); + has_aggregation_sei_message = TRUE; + } + + if (p_SEI->seiHasTone_mapping) + { + FinalizeToneMapping(p_Vid); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiToneMapping.data->streamBuffer, p_SEI->seiToneMapping.payloadSize, SEI_TONE_MAPPING); + ClearToneMapping(p_SEI); + has_aggregation_sei_message = TRUE; + } + + if (p_SEI->seiHasPostFilterHints_info) + { + FinalizePostFilterHints(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiPostFilterHints.data->streamBuffer, p_SEI->seiPostFilterHints.payloadSize, SEI_POST_FILTER_HINTS); + has_aggregation_sei_message = TRUE; + } + + if (p_SEI->seiHasBufferingPeriod_info) + { + FinalizeBufferingPeriod(p_SEI, p_Vid->active_sps); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiBufferingPeriod.data->streamBuffer, p_SEI->seiBufferingPeriod.payloadSize, SEI_BUFFERING_PERIOD); + has_aggregation_sei_message = TRUE; + } + + if (p_SEI->seiHasPicTiming_info) + { + FinalizePicTiming(p_Vid); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiPicTiming.data->streamBuffer, p_SEI->seiPicTiming.payloadSize, SEI_PIC_TIMING); + has_aggregation_sei_message = TRUE; + } + + if (p_SEI->seiHasRecoveryPoint_info) + { + FinalizeRandomAccess(p_SEI); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiRecoveryPoint.data->streamBuffer, p_SEI->seiRecoveryPoint.payloadSize, SEI_RECOVERY_POINT); + ClearRandomAccess(p_SEI); + has_aggregation_sei_message = TRUE; + } + + if (p_SEI->seiHasDRPMRepetition_info) + { + FinalizeDRPMRepetition(p_Vid); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiDRPMRepetition.data->streamBuffer, p_SEI->seiDRPMRepetition.payloadSize, SEI_DEC_REF_PIC_MARKING_REPETITION); + has_aggregation_sei_message = TRUE; + ClearDRPMRepetition(p_SEI); // to reset the drpm buffer into NULL + } + + if (p_SEI->seiHasFramePackingArrangement_info) + { + FinalizeFramePackingArrangement(p_SEI, p_Vid->p_Inp); + write_sei_message(p_SEI, AGGREGATION_SEI, p_SEI->seiFramePackingArrangement.data->streamBuffer, p_SEI->seiFramePackingArrangement.payloadSize, SEI_FRAME_PACKING_ARRANGEMENT); + has_aggregation_sei_message = TRUE; + } + + // after all the sei payload is written + if (has_aggregation_sei_message) + { + finalize_sei_message(p_SEI, AGGREGATION_SEI); + } +} + +/*! + ************************************************************************ + * \brief + * Free dec_ref_pic_marking_bufffer structure + ************************************************************************ + */ +void free_drpm_buffer( DecRefPicMarking_t *pDRPM ) +{ + DecRefPicMarking_t *pTmp = pDRPM, *pPrev; + + if (pTmp == NULL) + return; + + while( pTmp->Next != NULL ) + { + pPrev = pTmp; + pTmp = pTmp->Next; + free( pPrev ); + } + free( pTmp ); +} + diff --git a/lencod/src/slice.c b/lencod/src/slice.c new file mode 100644 index 0000000..c4038e7 --- /dev/null +++ b/lencod/src/slice.c @@ -0,0 +1,2451 @@ +/*! + ************************************************************************************** + * \file + * slice.c + * \brief + * generate the slice header, setup the bit buffer for slices, + * and generates the slice NALU(s) + + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Thomas Stockhammer + * - Detlev Marpe + * - Stephan Wenger + * - Alexis Michael Tourapis + *************************************************************************************** + */ + +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "header.h" +#include "nal.h" +#include "rtp.h" +#include "fmo.h" +#include "vlc.h" +#include "image.h" +#include "cabac.h" +#include "biariencode.h" +#include "elements.h" +#include "macroblock.h" +#include "memalloc.h" +#include "mode_decision_p8x8.h" +#include "symbol.h" +#include "context_ini.h" +#include "enc_statistics.h" +#include "ratectl.h" +#include "me_epzs.h" +#include "me_epzs_int.h" +#include "wp.h" +#include "slice.h" +#include "rdoq.h" +#include "wp_mcprec.h" +#include "q_offsets.h" +#include "conformance.h" +#include "list_reorder.h" +#include "md_common.h" +#include "mmco.h" +#include "mv_search.h" +#include "quant4x4.h" +#include "quant8x8.h" +#include "quantChroma.h" +#include "rdopt.h" +#include "rdopt_coding_state.h" +#include "lambda.h" +#include "intra4x4.h" +#include "intra8x8.h" +#include "intra16x16.h" +#include "mc_prediction.h" +#include "rd_intra_jm.h" +#include "rd_intra_jm444.h" + +// Local declarations +static Slice *malloc_slice(VideoParameters *p_Vid, InputParameters *p_Inp); +static Slice *malloc_slice_lite(VideoParameters *p_Vid, InputParameters *p_Inp); + +int allocate_block_mem(Slice *currSlice) +{ + int alloc_size = 0; + alloc_size += get_mem2Dint(&currSlice->tblk4x4, BLOCK_SIZE, BLOCK_SIZE); + alloc_size += get_mem2Dint(&currSlice->tblk16x16, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + alloc_size += get_mem4Dint(&currSlice->i16blk4x4, BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + + return (alloc_size); +} + + +void free_block_mem(Slice *currSlice) +{ + if(currSlice->i16blk4x4) + free_mem4Dint(currSlice->i16blk4x4); + if(currSlice->tblk16x16) + free_mem2Dint(currSlice->tblk16x16); + if(currSlice->tblk4x4) + free_mem2Dint(currSlice->tblk4x4); +} + +/*! + *********************************************************************** + * \brief + * Initializes the p_Vid->nz_coeff + * \par Input: + * none + * \par Output: + * none + * \ side effects + * sets currSlice->p_Vid->nz_coef[][][][] to -1 + *********************************************************************** + */ +static void CAVLC_init(Slice *currSlice) +{ + memset(&currSlice->p_Vid->nz_coeff[0][0][0], 0, currSlice->PicSizeInMbs * 4 * (4 + currSlice->num_blk8x8_uv)* sizeof(int)); +} + +static int alloc_rddata(Slice *currSlice, RD_DATA *rd_data) +{ + int alloc_size = 0; + + alloc_size += get_mem3Dpel(&(rd_data->rec_mb), 3, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + alloc_size += get_mem_ACcoeff (currSlice->p_Vid, &(rd_data->cofAC)); + alloc_size += get_mem_DCcoeff (&(rd_data->cofDC)); + + if ((currSlice->slice_type != I_SLICE) && currSlice->slice_type != SI_SLICE) + { + alloc_size += get_mem5Dmv (&(rd_data->all_mv), 2, currSlice->max_num_references, 9, 4, 4); + } + + // Why is this stored as height_blk * width_blk? + alloc_size += get_mem2D((byte***)&(rd_data->ipredmode), currSlice->height_blk, currSlice->width_blk); + alloc_size += get_mem3D((byte****)&(rd_data->refar), 2, 4, 4); + + return alloc_size; +} + + +static void nullify_rddata(RD_DATA *rd_data) +{ + rd_data->rec_mb = NULL; + + rd_data->cofAC = NULL; + rd_data->cofDC = NULL; + rd_data->all_mv = NULL; + + rd_data->ipredmode = NULL; + rd_data->refar = NULL; + + rd_data->all_mv = NULL; + rd_data->bipred_mv = NULL; +} + +static void free_rddata(Slice *currSlice, RD_DATA *rd_data) +{ + if(rd_data->refar) + free_mem3D((byte***) rd_data->refar); + if(rd_data->ipredmode) + free_mem2D((byte**) rd_data->ipredmode); + + if ((currSlice->slice_type != I_SLICE) && currSlice->slice_type != SI_SLICE) + { + if(rd_data->all_mv) + free_mem5Dmv (rd_data->all_mv); + } + + if(rd_data->cofDC) + free_mem_DCcoeff (rd_data->cofDC); + if(rd_data->cofAC) + free_mem_ACcoeff (rd_data->cofAC); + + if(rd_data->rec_mb) + free_mem3Dpel(rd_data->rec_mb); +} + + +/*! + ************************************************************************ + * \brief + * This function generates the slice (and partition) header(s) + * + * \return number of bits used for the slice (and partition) header(s) + * + * \par Side effects: + * Adds slice/partition header symbols to the symbol buffer + * increments Picture->no_slices, allocates memory for the + * slice, sets p_Vid->currSlice + ************************************************************************ +*/ +static int start_slice(Slice *currSlice, StatParameters *cur_stats) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + EncodingEnvironmentPtr eep; + Bitstream *currStream; + int header_len = 0; + int i; + int NumberOfPartitions = (currSlice->partition_mode == PAR_DP_1?1:3); + + //one partition for an IDR image + if(currSlice->idr_flag) + { + NumberOfPartitions = 1; + } + + RTPUpdateTimestamp (p_Vid, currSlice->frame_no); // this has no side effects, just leave it for all NALs + + for (i = 0; i < NumberOfPartitions; i++) + { + currStream = (currSlice->partArr[i]).bitstream; + + currStream->write_flag = 0; + if (i==0) // First partition + header_len += SliceHeader (currSlice); + else // Second/Third partition + header_len += Partition_BC_Header(currSlice, i); + + //! Initialize CABAC + if (currSlice->symbol_mode == CABAC) + { + eep = &((currSlice->partArr[i]).ee_cabac); + if (currStream->bits_to_go != 8) + header_len += currStream->bits_to_go; + writeVlcByteAlign(p_Vid, currStream, cur_stats); + + eep->p_Vid = p_Vid; + arienco_start_encoding(eep, currStream->streamBuffer, &(currStream->byte_pos)); + + arienco_reset_EC(eep); + } + else + { + // Initialize CA-VLC + CAVLC_init(currSlice); + } + } + + if(currSlice->symbol_mode == CABAC) + { + init_contexts(currSlice); + } + +#if MVC_EXTENSION_ENABLE + if(p_Vid->p_Inp->num_of_views > 1 && p_Vid->view_id == 1 && currSlice->nal_reference_idc && currSlice->slice_nr==0) + { + for(i=0; ilistXsize[0]; i++) + { + if(currSlice->listX[0][i]->view_id == 0) + break; + } + if(ilistXsize[0]) + p_Vid->enc_picture->ref_pic_na[0] = i; + for(i=0; ilistXsize[1]; i++) + { + if(currSlice->listX[1][i]->view_id == 0) + break; + } + if(ilistXsize[1]) + p_Vid->enc_picture->ref_pic_na[1] = i; + } +#endif + return header_len; +} + +/*! +************************************************************************ +* \brief +* This creates a NAL unit structures for all data partition of the slice +* +************************************************************************ +*/ +void create_slice_nalus(Slice *currSlice, int is_bottom) +{ + // KS: this is approx. max. allowed code picture size + //const int buffer_size = 500 + p_Vid->FrameSizeInMbs * (128 + 256 * p_Vid->bitdepth_luma + 512 * p_Vid->bitdepth_chroma); + int buffer_size = currSlice->partArr[0].bitstream->buffer_size; +#if (MVC_EXTENSION_ENABLE) + VideoParameters *p_Vid = currSlice->p_Vid; + //InputParameters *p_Inp = currSlice->p_Inp; +#endif + + int part; + NALU_t *nalu; + + for (part=0; part< currSlice->max_part_nr; part++) + { + if (currSlice->partArr[part].bitstream->write_flag) + { + nalu = AllocNALU(buffer_size); + currSlice->partArr[part].nal_unit = nalu; + nalu->startcodeprefix_len = 1+ (currSlice->start_mb_nr == 0 && part == 0 ?ZEROBYTES_SHORTSTARTCODE+1:ZEROBYTES_SHORTSTARTCODE); + nalu->forbidden_bit = 0; + +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2) //if(p_Inp->num_of_views==2) + { + nalu->priority_id = p_Vid->priority_id; + nalu->view_id = p_Vid->dpb_layer_id; + nalu->temporal_id = p_Vid->temporal_id; + nalu->anchor_pic_flag = p_Vid->anchor_pic_flag[is_bottom]; + nalu->inter_view_flag = p_Vid->inter_view_flag[is_bottom]; + nalu->non_idr_flag = !nalu->anchor_pic_flag; + nalu->reserved_one_bit = 1; + } +#endif + + if (currSlice->idr_flag) + { + nalu->nal_unit_type = NALU_TYPE_IDR; + nalu->nal_reference_idc = NALU_PRIORITY_HIGHEST; + } + else + { + //different nal header for different partitions + if(currSlice->partition_mode == 0) + { +#if (MVC_EXTENSION_ENABLE) + if(p_Vid->num_of_layers == 2) //if(p_Inp->num_of_views==2) + { + nalu->nal_unit_type = p_Vid->dpb_layer_id/*p_Vid->view_id*/==0 ? NALU_TYPE_SLICE : NALU_TYPE_SLC_EXT; + } + else + nalu->nal_unit_type = NALU_TYPE_SLICE; +#else + nalu->nal_unit_type = NALU_TYPE_SLICE; +#endif + } + else + { + nalu->nal_unit_type = (NaluType) (NALU_TYPE_DPA + part); + } + + if (currSlice->nal_reference_idc !=0) + { + nalu->nal_reference_idc = NALU_PRIORITY_HIGH; + } + else + { + nalu->nal_reference_idc = NALU_PRIORITY_DISPOSABLE; + } + } + } + else + { + currSlice->partArr[part].nal_unit = NULL; + } + } +} + +/*! + ************************************************************************ + * \brief + * This function terminates a slice (but doesn't write it out), + * the old terminate_slice (0) + * \return + * 0 if OK, \n + * 1 in case of error + * + ************************************************************************ + */ +static int terminate_slice(Macroblock *currMB, int lastslice, StatParameters *cur_stats ) +{ + Slice *currSlice = currMB->p_Slice; + VideoParameters *p_Vid = currMB->p_Vid; + + Bitstream *currStream; + NALU_t *currNalu; + EncodingEnvironmentPtr eep; + int part; + int tmp_stuffingbits = currMB->bits.mb_stuffing; + + if (currSlice->symbol_mode == CABAC) + write_terminating_bit (currSlice, 1); // only once, not for all partitions + + create_slice_nalus(currSlice, p_Vid->structure == BOTTOM_FIELD ? 1 : 0); + + for (part = 0; part < currSlice->max_part_nr; part++) + { + currStream = (currSlice->partArr[part]).bitstream; + currNalu = (currSlice->partArr[part]).nal_unit; + if (currStream->write_flag) + { + if (currSlice->symbol_mode == CAVLC) + { + SODBtoRBSP(currStream); + currNalu->len = RBSPtoEBSP(currNalu->buf, currStream->streamBuffer, currStream->byte_pos); + } + else // CABAC + { + eep = &((currSlice->partArr[part]).ee_cabac); + // terminate the arithmetic code + arienco_done_encoding(currMB, eep); + set_pic_bin_count(p_Vid, eep); + + currStream->bits_to_go = eep->Ebits_to_go; + currStream->byte_buf = 0; + + currNalu->len = RBSPtoEBSP(currNalu->buf, currStream->streamBuffer, currStream->byte_pos); + + // NumBytesInNALunit is: payload length + 1 byte header + p_Vid->bytes_in_picture += currNalu->len + 1; + + if (lastslice && (part==(currSlice->max_part_nr - 1))) + { + addCabacZeroWords(p_Vid, currNalu, cur_stats); + } + } // CABAC + } + } // partition loop + + if( currSlice->symbol_mode == CABAC ) + { + store_contexts(currSlice); + } + + cur_stats->bit_use_stuffing_bits[currSlice->slice_type] += currMB->bits.mb_stuffing - tmp_stuffingbits; + + return 0; +} + +static void init_bipred_enabled(VideoParameters *p_Vid) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int mode; + + memset(p_Vid->bipred_enabled, 0, sizeof(int)*MAXMODE); + if (p_Vid->currentSlice->slice_type != B_SLICE || !p_Inp->BiPredMotionEstimation) + return; + + for(mode = 1; mode < 5; mode++) + p_Vid->bipred_enabled[mode] = (p_Inp->BiPredSearch[mode - 1]) ? 1: 0; +} + +/*! +************************************************************************ +* \brief +* Encodes one slice +* \par +* returns the number of coded MBs in the SLice +************************************************************************ +*/ +int encode_one_slice (VideoParameters *p_Vid, int SliceGroupId, int TotalCodedMBs) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + Boolean end_of_slice = FALSE; + + int len; + int NumberOfCodedMBs = 0; + Macroblock* currMB = NULL; + int CurrentMbAddr; + StatParameters *cur_stats = &p_Vid->enc_picture->stats; + Slice *currSlice = NULL; + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + change_plane_JV( p_Vid, p_Vid->colour_plane_id ); + } + + p_Vid->cod_counter = 0; + + CurrentMbAddr = FmoGetFirstMacroblockInSlice (p_Vid, SliceGroupId); + // printf ("\n\nEncode_one_slice: PictureID %d SliceGroupId %d SliceID %d FirstMB %d \n", p_Vid->frame_no, SliceGroupId, p_Vid->current_slice_nr, CurrentMbInScanOrder); + + p_Vid->enc_picture->temporal_layer = p_Vid->p_curr_frm_struct->temporal_layer; + init_slice (p_Vid, &currSlice, CurrentMbAddr); + currSlice->rdoq_motion_copy = 0; + init_bipred_enabled(p_Vid); + + // Initialize quantization functions based on rounding/quantization method + // Done here since we may wish to disable adaptive rounding on occasional intervals (even at a frame or gop level). + init_quant_4x4 (currSlice); + init_quant_8x8 (currSlice); + init_quant_Chroma(currSlice); + + currSlice->set_lagrangian_multipliers(currSlice); + + if (currSlice->symbol_mode == CABAC) + { + SetCtxModelNumber (currSlice); + } + + p_Vid->checkref = (short) (p_Inp->rdopt && p_Inp->RestrictRef && (currSlice->slice_type==P_SLICE || currSlice->slice_type==SP_SLICE)); + + len = start_slice (currSlice, cur_stats); + + // Rate control + if (p_Inp->RCEnable) + rc_store_slice_header_bits( p_Vid, p_Inp, len ); + + // Update statistics + p_Vid->p_Stats->bit_slice += len; + cur_stats->bit_use_header[currSlice->slice_type] += len; + + if(currSlice->UseRDOQuant == 1 && currSlice->RDOQ_QP_Num > 1) + get_dQP_table(currSlice); + + while (end_of_slice == FALSE) // loop over macroblocks + { + Boolean recode_macroblock = FALSE; + if (p_Vid->AdaptiveRounding && p_Inp->AdaptRndPeriod && (p_Vid->current_mb_nr % p_Inp->AdaptRndPeriod == 0)) + { + CalculateOffset4x4Param(p_Vid); + if(p_Inp->Transform8x8Mode) + CalculateOffset8x8Param(p_Vid); + } + + if(currSlice->UseRDOQuant) // This needs revisit + currSlice->rddata = &currSlice->rddata_trellis_curr; + else + currSlice->rddata = &currSlice->rddata_top_frame_mb; // store data in top frame MB + + start_macroblock (currSlice, &currMB, CurrentMbAddr, FALSE); + + + if(currSlice->UseRDOQuant) + { + trellis_coding(currMB); + } + else + { + p_Vid->masterQP = p_Vid->qp; + + currSlice->encode_one_macroblock (currMB); + end_encode_one_macroblock(currMB); + + write_macroblock (currMB, 1); + } + + end_macroblock (currMB, &end_of_slice, &recode_macroblock); + currMB->prev_recode_mb = recode_macroblock; + // printf ("encode_one_slice: mb %d, slice %d, bitbuf bytepos %d EOS %d\n", + // p_Vid->current_mb_nr, p_Vid->current_slice_nr, + // currSlice->partArr[0].bitstream->byte_pos, end_of_slice); + + if (recode_macroblock == FALSE) // The final processing of the macroblock has been done + { + p_Vid->SumFrameQP += currMB->qp; + CurrentMbAddr = FmoGetNextMBNr (p_Vid, CurrentMbAddr); + if (CurrentMbAddr == -1) // end of slice + { + // printf ("FMO End of Slice Group detected, current MBs %d, force end of slice\n", NumberOfCodedMBs+1); + end_of_slice = TRUE; + } + NumberOfCodedMBs++; // only here we are sure that the coded MB is actually included in the slice + next_macroblock (currMB); + } + else + { + //!Go back to the previous MB to recode it + p_Vid->current_mb_nr = FmoGetPreviousMBNr(p_Vid, p_Vid->current_mb_nr); + p_Vid->NumberofCodedMacroBlocks--; + if(p_Vid->current_mb_nr == -1 ) // The first MB of the slice group is too big, + // which means it's impossible to encode picture using current slice bits restriction + { + snprintf (errortext, ET_SIZE, "Error encoding first MB with specified parameter, bits of current MB may be too big"); + error (errortext, 300); + } + } + } + + + if ((p_Inp->WPIterMC) && (p_Vid->frameOffsetAvail == 0) && p_Vid->nal_reference_idc) + { + compute_offset(currSlice); + } + p_Vid->num_ref_idx_l0_active = currSlice->num_ref_idx_active[LIST_0]; + p_Vid->num_ref_idx_l1_active = currSlice->num_ref_idx_active[LIST_1]; + + terminate_slice (currMB, (NumberOfCodedMBs + TotalCodedMBs >= (int)p_Vid->PicSizeInMbs), cur_stats ); + return NumberOfCodedMBs; +} + + +/*! +************************************************************************ +* \brief +* Encodes one slice (MBAFF Frame) +* \par +* returns the number of coded MBs in the SLice +************************************************************************ +*/ +int encode_one_slice_MBAFF (VideoParameters *p_Vid, int SliceGroupId, int TotalCodedMBs) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + Boolean end_of_slice = FALSE; + Boolean recode_macroblock; + int len; + int NumberOfCodedMBs = 0; + Macroblock* currMB = NULL; + int CurrentMbAddr; + double FrameRDCost = DBL_MAX, FieldRDCost = DBL_MAX; + StatParameters *cur_stats = &p_Vid->enc_picture->stats; + Slice *currSlice = NULL; + + if( (p_Inp->separate_colour_plane_flag != 0) ) + { + change_plane_JV( p_Vid, p_Vid->colour_plane_id ); + } + + p_Vid->cod_counter = 0; + + CurrentMbAddr = FmoGetFirstMacroblockInSlice (p_Vid, SliceGroupId); + // printf ("\n\nEncode_one_slice: PictureID %d SliceGroupId %d SliceID %d FirstMB %d \n", p_Vid->frame_no, SliceGroupId, p_Vid->current_slice_nr, CurrentMbInScanOrder); + + init_slice (p_Vid, &currSlice, CurrentMbAddr); + currSlice->rdoq_motion_copy = 0; + init_bipred_enabled(p_Vid); + + // Initialize quantization functions based on rounding/quantization method + // Done here since we may wish to disable adaptive rounding on occasional intervals (even at a frame or gop level). + init_quant_4x4 (currSlice); + init_quant_8x8 (currSlice); + init_quant_Chroma(currSlice); + + currSlice->set_lagrangian_multipliers(currSlice); + + if (currSlice->symbol_mode == CABAC) + { + SetCtxModelNumber (currSlice); + } + + p_Vid->checkref = (short) (p_Inp->rdopt && p_Inp->RestrictRef && (currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE)); + + len = start_slice (currSlice, cur_stats); + + // Rate control + if (p_Inp->RCEnable) + rc_store_slice_header_bits( p_Vid, p_Inp, len ); + + // Update statistics + p_Vid->p_Stats->bit_slice += len; + cur_stats->bit_use_header[currSlice->slice_type] += len; + + while (end_of_slice == FALSE) // loop over macroblocks + { + + if (p_Vid->AdaptiveRounding && p_Inp->AdaptRndPeriod && (p_Vid->current_mb_nr % p_Inp->AdaptRndPeriod == 0)) + { + CalculateOffset4x4Param(p_Vid); + if(p_Inp->Transform8x8Mode) + CalculateOffset8x8Param(p_Vid); + } + + //! This following ugly code breaks slices, at least for a slice mode that accumulates a certain + //! number of bits into one slice. + //! The suggested algorithm is as follows: + //! + //! SaveState (Bitstream, stats, etc. etc.); + //! BitsForThisMBPairInFrameMode = CodeMB (Upper, FRAME_MODE) + CodeMB (Lower, FRAME_MODE); + //! DistortionForThisMBPairInFrameMode = CalculateDistortion(Upper) + CalculateDistortion (Lower); + //! RestoreState(); + //! BitsForThisMBPairInFieldMode = CodeMB (Upper, FIELD_MODE) + CodeMB (Lower, FIELD_MODE); + //! DistortionForThisMBPairInFrameMode = CalculateDistortion(Upper) + CalculateDistortion (Lower); + //! FrameFieldMode = Decision (...) + //! RestoreState() + //! if (FrameFieldMode == FRAME) { + //! CodeMB (Upper, FRAME); CodeMB (Lower, FRAME); + //! } else { + //! CodeMB (Upper FIELD); CodeMB (Lower, FIELD); + //! } + //! + //! Open questions/issues: + //! 1. CABAC/CA-VLC state: It seems that the CABAC/CA_VLC states are changed during the + //! dummy encoding processes (for the R-D based selection), but that they are never + //! reset, once the selection is made. I believe that this breaks the MB-adaptive + //! frame/field coding. The necessary code for the state saves is readily available + //! in macroblock.c, start_macroblock() and end_macroblock() (this code needs + //! to be double checked that it works with CA-VLC as well + //! 2. would it be an option to allocate Bitstreams with zero data in them (or copy the + //! already generated bitstream) for the "test coding"? + + p_Vid->write_macroblock = FALSE; + if (p_Inp->MbInterlace == ADAPTIVE_CODING || p_Inp->MbInterlace == FRAME_MB_PAIR_CODING) + { + //================ code MB pair as frame MB ================ + //---------------------------------------------------------- + recode_macroblock = FALSE; + //set mv limits to frame type + update_mv_limits(p_Vid, FALSE); + + p_Vid->field_mode = FALSE; // MB coded as frame + p_Vid->top_field = FALSE; // Set top field to 0 + + //Rate control + p_Vid->write_macroblock = FALSE; + p_Vid->bot_MB = FALSE; + + // save RC state only when it is going to change + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + { + if ( p_Inp->MbInterlace == ADAPTIVE_CODING + && p_Vid->NumberofCodedMacroBlocks > 0 && (p_Vid->NumberofCodedMacroBlocks % p_Vid->BasicUnit) == 0 ) + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad_init, p_Vid->p_rc_quad ); // save initial RC status + if ( p_Inp->MbInterlace == ADAPTIVE_CODING ) + rc_copy_generic( p_Vid, p_Vid->p_rc_gen_init, p_Vid->p_rc_gen ); // save initial RC status + } + + start_macroblock (currSlice, &currMB, CurrentMbAddr, FALSE); + + currSlice->rddata = &currSlice->rddata_top_frame_mb; // store data in top frame MB + p_Vid->masterQP = p_Vid->qp; + currSlice->encode_one_macroblock (currMB); // code the MB as frame + end_encode_one_macroblock(currMB); + + FrameRDCost = currSlice->rddata->min_rdcost; + //*** Top MB coded as frame MB ***// + + //Rate control + p_Vid->bot_MB = TRUE; //for Rate control + + // go to the bottom MB in the MB pair + p_Vid->field_mode = FALSE; // MB coded as frame //GB + + start_macroblock (currSlice, &currMB, CurrentMbAddr + 1, FALSE); + currSlice->rddata = &currSlice->rddata_bot_frame_mb; // store data in top frame MB + p_Vid->masterQP = p_Vid->qp; + currSlice->encode_one_macroblock (currMB); // code the MB as frame + end_encode_one_macroblock(currMB); + + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + { + if ( p_Inp->MbInterlace == ADAPTIVE_CODING + && p_Vid->NumberofCodedMacroBlocks > 0 && (p_Vid->NumberofCodedMacroBlocks % p_Vid->BasicUnit) == 0 ) + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad_best, p_Vid->p_rc_quad ); // restore initial RC status + + if ( p_Inp->MbInterlace == ADAPTIVE_CODING ) + rc_copy_generic( p_Vid, p_Vid->p_rc_gen_best, p_Vid->p_rc_gen ); // save frame RC stats + } + + FrameRDCost += currSlice->rddata->min_rdcost; + //*** Bottom MB coded as frame MB ***// + } + + if ((p_Inp->MbInterlace == ADAPTIVE_CODING) || (p_Inp->MbInterlace == FIELD_CODING)) + { + //Rate control + p_Vid->bot_MB = FALSE; + //set mv limits to field type + update_mv_limits(p_Vid, TRUE); + + //=========== start coding the MB pair as a field MB pair ============= + //--------------------------------------------------------------------- + p_Vid->field_mode = TRUE; // MB coded as field + p_Vid->top_field = TRUE; // Set top field to 1 + p_Inp->num_ref_frames <<= 1; + currSlice->num_ref_idx_active[LIST_0] <<= 1; + currSlice->num_ref_idx_active[LIST_0] += 1; + + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + { + if ( p_Inp->MbInterlace == ADAPTIVE_CODING + && p_Vid->NumberofCodedMacroBlocks > 0 && (p_Vid->NumberofCodedMacroBlocks % p_Vid->BasicUnit) == 0 ) + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_quad_init ); // restore initial RC status + + if ( p_Inp->MbInterlace == ADAPTIVE_CODING ) + rc_copy_generic( p_Vid, p_Vid->p_rc_gen, p_Vid->p_rc_gen_init ); // reset RC stats + } + + start_macroblock (currSlice, &currMB, CurrentMbAddr, TRUE); + + currSlice->rddata = &currSlice->rddata_top_field_mb; // store data in top frame MB + // TopFieldIsSkipped = 0; // set the top field MB skipped flag to 0 + p_Vid->masterQP = p_Vid->qp; + currSlice->encode_one_macroblock (currMB); // code the MB as field + end_encode_one_macroblock(currMB); + + FieldRDCost = currSlice->rddata->min_rdcost; + //*** Top MB coded as field MB ***// + //Rate control + p_Vid->bot_MB = TRUE;//for Rate control + + p_Vid->top_field = FALSE; // Set top field to 0 + start_macroblock (currSlice, &currMB, CurrentMbAddr+1, TRUE); + currSlice->rddata = &currSlice->rddata_bot_field_mb; // store data in top frame MB + p_Vid->masterQP = p_Vid->qp; + currSlice->encode_one_macroblock (currMB); // code the MB as field + end_encode_one_macroblock(currMB); + + FieldRDCost += currSlice->rddata->min_rdcost; + //*** Bottom MB coded as field MB ***// + } + + //Rate control + p_Vid->write_mbaff_frame = 0; //Rate control + + //=========== decide between frame/field MB pair ============ + //----------------------------------------------------------- + if ( ((p_Inp->MbInterlace == ADAPTIVE_CODING) && (FrameRDCost < FieldRDCost)) || p_Inp->MbInterlace == FRAME_MB_PAIR_CODING ) + { + p_Vid->field_mode = FALSE; + p_Vid->MBPairIsField = FALSE; + + if ( p_Inp->MbInterlace != FRAME_MB_PAIR_CODING ) + { + p_Inp->num_ref_frames >>= 1; + currSlice->num_ref_idx_active[LIST_0] -= 1; + currSlice->num_ref_idx_active[LIST_0] >>= 1; + } + + if ( p_Inp->RCEnable && p_Inp->RCUpdateMode <= MAX_RC_MODE ) + { + if ( p_Inp->MbInterlace == ADAPTIVE_CODING + && p_Vid->NumberofCodedMacroBlocks > 0 && (p_Vid->NumberofCodedMacroBlocks % p_Vid->BasicUnit) == 0 ) + rc_copy_quadratic( p_Vid, p_Inp, p_Vid->p_rc_quad, p_Vid->p_rc_quad_best ); // restore initial RC status + + if ( p_Inp->MbInterlace == ADAPTIVE_CODING ) + rc_copy_generic( p_Vid, p_Vid->p_rc_gen, p_Vid->p_rc_gen_best ); // restore frame RC stats + } + + //Rate control + p_Vid->write_mbaff_frame = 1; //for Rate control + } + else + { + p_Vid->field_mode = TRUE; + p_Vid->MBPairIsField = TRUE; + } + + //Rate control + p_Vid->write_macroblock = TRUE;//Rate control + + if (p_Vid->MBPairIsField) + p_Vid->top_field = TRUE; + else + p_Vid->top_field = FALSE; + + //Rate control + p_Vid->bot_MB = FALSE;// for Rate control + + // go back to the Top MB in the MB pair + start_macroblock (currSlice, &currMB, CurrentMbAddr, p_Vid->field_mode); + + currSlice->rddata = p_Vid->field_mode ? &currSlice->rddata_top_field_mb : &currSlice->rddata_top_frame_mb; + copy_rdopt_data (currMB); // copy the MB data for Top MB from the temp buffers + write_macroblock (currMB, 1); // write the Top MB data to the bitstream + end_macroblock (currMB, &end_of_slice, &recode_macroblock); // done coding the Top MB + currMB->prev_recode_mb = recode_macroblock; + + if (recode_macroblock == FALSE) // The final processing of the macroblock has been done + { + p_Vid->SumFrameQP += currMB->qp; + + CurrentMbAddr = FmoGetNextMBNr (p_Vid, CurrentMbAddr); + if (CurrentMbAddr == -1) // end of slice + { + end_of_slice = TRUE; + } + NumberOfCodedMBs++; // only here we are sure that the coded MB is actually included in the slice + next_macroblock (currMB); + + //Rate control + p_Vid->bot_MB = TRUE;//for Rate control + // go to the Bottom MB in the MB pair + p_Vid->top_field = FALSE; + start_macroblock (currSlice, &currMB, CurrentMbAddr, p_Vid->field_mode); + + currSlice->rddata = p_Vid->field_mode ? &currSlice->rddata_bot_field_mb : &currSlice->rddata_bot_frame_mb; + copy_rdopt_data (currMB); // copy the MB data for Bottom MB from the temp buffers + + write_macroblock (currMB, 0); // write the Bottom MB data to the bitstream + end_macroblock (currMB, &end_of_slice, &recode_macroblock); // done coding the Top MB + currMB->prev_recode_mb = recode_macroblock; + if (recode_macroblock == FALSE) // The final processing of the macroblock has been done + { + p_Vid->SumFrameQP += currMB->qp; + + CurrentMbAddr = FmoGetNextMBNr (p_Vid, CurrentMbAddr); + if (CurrentMbAddr == -1) // end of slice + { + end_of_slice = TRUE; + } + NumberOfCodedMBs++; // only here we are sure that the coded MB is actually included in the slice + next_macroblock (currMB); + } + else + { + //Go back to the beginning of the macroblock pair to recode it + p_Vid->current_mb_nr = FmoGetPreviousMBNr(p_Vid, p_Vid->current_mb_nr); + p_Vid->NumberofCodedMacroBlocks -= 2; + if(p_Vid->current_mb_nr == -1 ) // The first MB of the slice group is too big, + // which means it's impossible to encode picture using current slice bits restriction + { + snprintf (errortext, ET_SIZE, "Error encoding first MB with specified parameter, bits of current MB may be too big"); + error (errortext, 300); + } + } + } + else + { + //!Go back to the previous MB to recode it + p_Vid->current_mb_nr = FmoGetPreviousMBNr(p_Vid, p_Vid->current_mb_nr); + p_Vid->NumberofCodedMacroBlocks--; + if(p_Vid->current_mb_nr == -1 ) // The first MB of the slice group is too big, + // which means it's impossible to encode picture using current slice bits restriction + { + snprintf (errortext, ET_SIZE, "Error encoding first MB with specified parameter, bits of current MB may be too big"); + error (errortext, 300); + } + } + + if (p_Vid->MBPairIsField) // if MB Pair was coded as field the buffer size variables back to frame mode + { + p_Inp->num_ref_frames >>= 1; + currSlice->num_ref_idx_active[LIST_0] -= 1; + currSlice->num_ref_idx_active[LIST_0] >>= 1; + } + + p_Vid->field_mode = p_Vid->top_field = FALSE; // reset to frame mode + + if ( !end_of_slice ) + { + assert( CurrentMbAddr < (int)p_Vid->PicSizeInMbs ); + assert( CurrentMbAddr >= 0 ); + if (CurrentMbAddr == FmoGetLastCodedMBOfSliceGroup (p_Vid, FmoMB2SliceGroup (p_Vid, CurrentMbAddr))) + end_of_slice = TRUE; // just in case it doesn't get set in end_macroblock + } + } + + p_Vid->num_ref_idx_l0_active = currSlice->num_ref_idx_active[LIST_0]; + p_Vid->num_ref_idx_l1_active = currSlice->num_ref_idx_active[LIST_1]; + + terminate_slice (currMB, (NumberOfCodedMBs + TotalCodedMBs >= (int)p_Vid->PicSizeInMbs), cur_stats ); + return NumberOfCodedMBs; +} + +static void setup_cabac(Slice *currSlice, char *listXsize) +{ + seq_parameter_set_rbsp_t *active_sps = currSlice->active_sps; + int i; + + if (currSlice->slice_type == I_SLICE) + { + currSlice->set_modes_and_reframe = set_modes_and_reframe_i_slice; + currSlice->store_8x8_motion_vectors = NULL; + currSlice->writeMB_Skip = NULL; + currSlice->writeMB_typeInfo = writeMB_I_typeInfo_CABAC; + currSlice->writeB8_typeInfo = writeB8_typeInfo_CABAC; + currSlice->writeMotionInfo2NAL = NULL; + currSlice->write_MB_layer = write_i_slice_MB_layer; + for (i=0; i<6; i++) + { + currSlice->writeRefFrame[i] = NULL; + } + } + else if (currSlice->slice_type == B_SLICE) + { + currSlice->set_modes_and_reframe = set_modes_and_reframe_b_slice; + currSlice->store_8x8_motion_vectors = store_8x8_motion_vectors_b_slice; + currSlice->writeMB_Skip = writeMB_Bskip_flagInfo_CABAC; + currSlice->writeMB_typeInfo = writeMB_B_typeInfo_CABAC; + currSlice->writeB8_typeInfo = writeB8_B_typeInfo_CABAC; + currSlice->writeMotionInfo2NAL = write_b_slice_motion_info_to_NAL; + currSlice->write_MB_layer = write_b_slice_MB_layer; + for (i=0; i<6; i++) + { + switch (listXsize[i]) + { + case 0: + currSlice->writeRefFrame[i] = NULL; + break; + case 1: + currSlice->writeRefFrame[i] = writeRefPic_Dummy; + break; + default: + currSlice->writeRefFrame[i] = writeRefPic_B_CABAC; + } + } + } + else + { + currSlice->set_modes_and_reframe = set_modes_and_reframe_p_slice; + currSlice->store_8x8_motion_vectors = store_8x8_motion_vectors_p_slice; + currSlice->writeMB_Skip = writeMB_Pskip_flagInfo_CABAC; + currSlice->writeMB_typeInfo = writeMB_P_typeInfo_CABAC; + currSlice->writeB8_typeInfo = writeB8_typeInfo_CABAC; + currSlice->writeMotionInfo2NAL = write_p_slice_motion_info_to_NAL; + currSlice->write_MB_layer = write_p_slice_MB_layer; + + for (i=0; i<6; i++) + { + switch (listXsize[i]) + { + case 0: + currSlice->writeRefFrame[i] = NULL; + break; + case 1: + currSlice->writeRefFrame[i] = writeRefPic_Dummy; + break; + default: + currSlice->writeRefFrame[i] = writeRefPic_P_CABAC; + } + } + } + + currSlice->writeIntraPredMode = writeIntraPredMode_CABAC; + currSlice->writeCoeff16x16 = writeCoeff16x16_CABAC; + currSlice->writeMVD = writeMVD_CABAC; + currSlice->writeCBP = writeCBP_CABAC; + currSlice->writeDquant = writeDquant_CABAC; + currSlice->writeCIPredMode = writeCIPredMode_CABAC; + currSlice->writeFieldModeInfo = writeFieldModeInfo_CABAC; + currSlice->writeMB_transform_size = writeMB_transform_size_CABAC; + + if (active_sps->chroma_format_idc == YUV444) + currSlice->write_and_store_CBP_block_bit = write_and_store_CBP_block_bit_444; + else + currSlice->write_and_store_CBP_block_bit = write_and_store_CBP_block_bit; + + memset(currSlice->coeff, 0 , 64 * sizeof(int)); + currSlice->coeff_ctr = 0; + currSlice->pos = 0; +} + +static void setup_cavlc(Slice *currSlice, char *listXsize) +{ + seq_parameter_set_rbsp_t *active_sps = currSlice->active_sps; + + int i; + currSlice->writeMB_typeInfo = writeUVLC_CAVLC; + currSlice->writeIntraPredMode = writeIntraPredMode_CAVLC; + currSlice->writeB8_typeInfo = writeSE_UVLC; + currSlice->writeCoeff16x16 = writeCoeff16x16_CAVLC; + for (i=0; i<6; i++) + { + switch (listXsize[i]) + { + case 0: + currSlice->writeRefFrame[i] = NULL; + break; + case 1: + currSlice->writeRefFrame[i] = writeRefPic_Dummy; + break; + case 2: + currSlice->writeRefFrame[i] = writeRefPic_2Ref_CAVLC; + break; + default: + currSlice->writeRefFrame[i] = writeRefPic_NRef_CAVLC; + break; + } + } + + if (currSlice->slice_type == I_SLICE || currSlice->slice_type == SI_SLICE) + { + currSlice->set_modes_and_reframe = set_modes_and_reframe; + currSlice->store_8x8_motion_vectors = NULL; + currSlice->writeMotionInfo2NAL = NULL; + currSlice->write_MB_layer = write_i_slice_MB_layer; + } + else if (currSlice->slice_type == B_SLICE) + { + currSlice->set_modes_and_reframe = set_modes_and_reframe_b_slice; + currSlice->store_8x8_motion_vectors = store_8x8_motion_vectors_b_slice; + currSlice->writeMotionInfo2NAL = write_b_slice_motion_info_to_NAL; + currSlice->write_MB_layer = write_b_slice_MB_layer; + } + else + { + currSlice->set_modes_and_reframe = set_modes_and_reframe_p_slice; + currSlice->store_8x8_motion_vectors = store_8x8_motion_vectors_p_slice; + currSlice->writeMotionInfo2NAL = write_p_slice_motion_info_to_NAL; + currSlice->write_MB_layer = write_p_slice_MB_layer; + } + + currSlice->writeMVD = writeSVLC_CAVLC; + currSlice->writeCBP = writeCBP_VLC; + currSlice->writeDquant = writeSVLC_CAVLC; + currSlice->writeCIPredMode = writeUVLC_CAVLC; + currSlice->writeFieldModeInfo = writeFlag_CAVLC; + currSlice->writeMB_transform_size = writeFlag_CAVLC; + + // We should move this to the sequence level and create a new function + if (active_sps->chroma_format_idc == YUV444) + currSlice->writeCoeff4x4_CAVLC = writeCoeff4x4_CAVLC_444; + else + currSlice->writeCoeff4x4_CAVLC = writeCoeff4x4_CAVLC_normal; +} + +static void setup_slice(Slice *currSlice) +{ + if (currSlice->P444_joined) + { + currSlice->luma_residual_coding = luma_residual_coding_p444; + currSlice->luma_residual_coding_8x8 = luma_residual_coding_p444_8x8; + } + else + { + if (currSlice->slice_type == SP_SLICE) + currSlice->luma_residual_coding = luma_residual_coding_sp; + else + currSlice->luma_residual_coding = luma_residual_coding; + currSlice->luma_residual_coding_8x8 = luma_residual_coding_8x8; + } + + if (currSlice->slice_type == SP_SLICE) + currSlice->chroma_residual_coding = chroma_residual_coding_sp; + else if (currSlice->slice_type == SI_SLICE) + currSlice->chroma_residual_coding = chroma_residual_coding_si; + else + currSlice->chroma_residual_coding = chroma_residual_coding; + + if (currSlice->slice_type == P_SLICE || currSlice->slice_type == SP_SLICE) + { + currSlice->weighted_prediction = (byte) currSlice->p_Vid->active_pps->weighted_pred_flag; + currSlice->set_modes_and_refs_for_blocks = set_modes_and_refs_for_blocks_p_slice; + currSlice->set_coeff_and_recon_8x8 = set_coeff_and_recon_8x8_p_slice; + currSlice->init_lists = init_lists_p_slice; + currSlice->submacroblock_mode_decision = submacroblock_mode_decision_p_slice; + currSlice->set_motion_vectors_mb = SetMotionVectorsMBPSlice; + } + else if (currSlice->slice_type == B_SLICE) + { + currSlice->weighted_prediction = (byte) currSlice->p_Vid->active_pps->weighted_bipred_idc; + currSlice->set_modes_and_refs_for_blocks = set_modes_and_refs_for_blocks_b_slice; + currSlice->set_coeff_and_recon_8x8 = set_coeff_and_recon_8x8_b_slice; + currSlice->init_lists = init_lists_b_slice; + currSlice->submacroblock_mode_decision = submacroblock_mode_decision_b_slice; + currSlice->set_motion_vectors_mb = SetMotionVectorsMBBSlice; + } + else + { + currSlice->set_modes_and_refs_for_blocks = set_modes_and_refs_for_blocks_i_slice; + currSlice->set_coeff_and_recon_8x8 = NULL; + currSlice->init_lists = init_lists_i_slice; + currSlice->submacroblock_mode_decision = NULL; + currSlice->set_motion_vectors_mb = SetMotionVectorsMBISlice; + } + + if (currSlice->mb_aff_frame_flag) + { + currSlice->set_intrapred_4x4 = set_intrapred_4x4_mbaff; + currSlice->set_intrapred_8x8 = set_intrapred_8x8_mbaff; + currSlice->set_intrapred_16x16 = set_intrapred_16x16_mbaff; + currSlice->rdo_low_intra_chroma_decision = rdo_low_intra_chroma_decision_mbaff; + currSlice->intra_chroma_prediction = intra_chroma_prediction_mbaff; + if (currSlice->direct_spatial_mv_pred_flag) //spatial direct + currSlice->Get_Direct_Motion_Vectors = Get_Direct_MV_Spatial_MBAFF; + else + currSlice->Get_Direct_Motion_Vectors = Get_Direct_MV_Temporal; + } + else + { + currSlice->set_intrapred_4x4 = set_intrapred_4x4; + currSlice->set_intrapred_8x8 = set_intrapred_8x8; + currSlice->set_intrapred_16x16 = set_intrapred_16x16; + currSlice->rdo_low_intra_chroma_decision = rdo_low_intra_chroma_decision; + currSlice->intra_chroma_prediction = intra_chroma_prediction; + if (currSlice->direct_spatial_mv_pred_flag) //spatial direct + currSlice->Get_Direct_Motion_Vectors = Get_Direct_MV_Spatial_Normal; + else + currSlice->Get_Direct_Motion_Vectors = Get_Direct_MV_Temporal; + } + + if (currSlice->active_sps->chroma_format_idc == YUV444) + currSlice->mode_decision_for_I16x16_MB = mode_decision_for_I16x16_MB_444; + else if(currSlice->p_Inp->I16rdo) + currSlice->mode_decision_for_I16x16_MB = mode_decision_for_I16x16_MB_RDO; + else + currSlice->mode_decision_for_I16x16_MB = mode_decision_for_I16x16_MB; +} + +static void ClipWPParams(Slice *currSlice ) +{ + int list, ref, comp; + + for(list = 0; list <= (currSlice->slice_type == B_SLICE ? LIST_1:LIST_0); list++) + { + for(ref = 0; ref < currSlice->listXsize[list]; ref++) + { + for(comp = PLANE_Y; comp <= PLANE_V; comp++) + { + currSlice->wp_weight[list][ref][comp] = sClip3(-128, 127, currSlice->wp_weight[list][ref][comp]); + currSlice->wp_offset[list][ref][comp] = sClip3(-128, 127, currSlice->wp_offset[list][ref][comp]); + } + } + } +} + +void setup_open_gop_lists(VideoParameters *p_Vid, Slice *currSlice) +{ + int i, j; + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + for (i = 0; i < currSlice->listXsize[0]; i++) + { + if (currSlice->listX[LIST_0][i]->poc < p_Vid->last_valid_reference && p_Vid->ThisPOC >= p_Vid->last_valid_reference) + { + //remove invalid reference from list + for (j = i; j < currSlice->listXsize[LIST_0]-1; j++) + { + currSlice->listX[LIST_0][j] = currSlice->listX[LIST_0][j+1]; + } + currSlice->listXsize[LIST_0]--; + i--; + } + } + + for (i = 0; i < currSlice->listXsize[LIST_1]; i++) + { + if (currSlice->listX[LIST_1][i]->poc < p_Vid->last_valid_reference && p_Vid->ThisPOC >= p_Vid->last_valid_reference) + { + //remove invalid reference from list + for (j = i; j < currSlice->listXsize[LIST_1]-1; j++) + { + currSlice->listX[LIST_1][j] = currSlice->listX[LIST_1][j+1]; + } + currSlice->listXsize[LIST_1]--; + i--; + } + } + + // Below code is not the best but avoids problem with the creation of an empty + // list. For MVC we could be doing more intelligent tricks with the inter-layer + // reference. + if (currSlice->slice_type == B_SLICE) + { + if (currSlice->listXsize[LIST_1] == 0 && currSlice->listXsize[LIST_0] != 0) + { + if (currSlice->listXsize[LIST_0] > 1) + currSlice->listX[LIST_1][0] = currSlice->listX[LIST_0][1]; + else + currSlice->listX[LIST_1][0] = currSlice->listX[LIST_0][0]; + currSlice->listXsize[LIST_1]++; + } + else if (currSlice->listXsize[LIST_0] == 0 && currSlice->listXsize[LIST_1] != 0) + { + if (currSlice->listXsize[LIST_1] > 1) + currSlice->listX[LIST_0][0] = currSlice->listX[LIST_1][1]; + else + currSlice->listX[LIST_0][0] = currSlice->listX[LIST_1][0]; + currSlice->listXsize[LIST_0]++; + } + else + { + // Could this scenario happen for the EL case? Need to revisit. + } + } + + currSlice->num_ref_idx_active[LIST_0] = currSlice->listXsize[LIST_0]; + currSlice->num_ref_idx_active[LIST_1] = currSlice->listXsize[LIST_1]; + } +} + + +void set_slice (VideoParameters *p_Vid, Slice *currSlice) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + // Using this trick we can basically reference back to the image and input parameter structures + currSlice->p_Vid = p_Vid; + currSlice->p_Inp = p_Inp; + currSlice->layer_id = p_Vid->dpb_layer_id; + currSlice->p_Dpb = p_Vid->p_Dpb_layer[p_Vid->dpb_layer_id]; + currSlice->active_sps = p_Vid->active_sps; + currSlice->active_pps = p_Vid->active_pps; + currSlice->picture_id = (p_Vid->frame_no & 0xFF); // % 255 + currSlice->slice_nr = p_Vid->current_slice_nr; + currSlice->idr_flag = p_Vid->currentPicture->idr_flag; + currSlice->slice_type = p_Vid->type; + currSlice->frame_no = p_Vid->frame_no; + currSlice->frame_num = p_Vid->frame_num; + currSlice->max_frame_num = p_Vid->max_frame_num; + currSlice->framepoc = p_Vid->framepoc; + currSlice->ThisPOC = p_Vid->ThisPOC; + currSlice->qp = p_Vid->p_curr_frm_struct->qp; + currSlice->start_mb_nr = p_Vid->current_mb_nr; + currSlice->colour_plane_id = p_Vid->colour_plane_id; + + currSlice->si_frame_indicator = currSlice->slice_type == SI_SLICE ? TRUE : FALSE; + currSlice->sp2_frame_indicator = p_Vid->sp2_frame_indicator; + + currSlice->P444_joined = p_Vid->P444_joined; + currSlice->disthres = p_Inp->disthres; + currSlice->UseRDOQuant = p_Inp->UseRDOQuant; + currSlice->RDOQ_QP_Num = p_Inp->RDOQ_QP_Num; + currSlice->Transform8x8Mode = p_Inp->Transform8x8Mode; + + currSlice->slice_too_big = dummy_slice_too_big; + currSlice->width_blk = p_Vid->width_blk; + currSlice->height_blk = p_Vid->height_blk; + currSlice->partition_mode = (short) p_Inp->partition_mode; + currSlice->PicSizeInMbs = p_Vid->PicSizeInMbs; + currSlice->num_blk8x8_uv = p_Vid->num_blk8x8_uv; + currSlice->nal_reference_idc = p_Vid->nal_reference_idc; + currSlice->bitdepth_luma = p_Vid->bitdepth_luma; + currSlice->bitdepth_chroma = p_Vid->bitdepth_chroma; + currSlice->bitdepth_scale[0] = p_Vid->bitdepth_scale[0]; + currSlice->bitdepth_scale[1] = p_Vid->bitdepth_scale[1]; + currSlice->bitdepth_luma_qp_scale = p_Vid->bitdepth_luma_qp_scale; + currSlice->bitdepth_chroma_qp_scale = p_Vid->bitdepth_chroma_qp_scale; + currSlice->bitdepth_lambda_scale = p_Vid->bitdepth_lambda_scale; + currSlice->direct_spatial_mv_pred_flag = p_Vid->direct_spatial_mv_pred_flag; + currSlice->mb_aff_frame_flag = p_Vid->mb_aff_frame_flag; + currSlice->structure = p_Vid->structure; + currSlice->num_ref_idx_active[LIST_0] = (char) (p_Vid->active_pps->num_ref_idx_l0_default_active_minus1 + 1); + currSlice->num_ref_idx_active[LIST_1] = (char) (p_Vid->active_pps->num_ref_idx_l1_default_active_minus1 + 1); + currSlice->DFDisableIdc = (p_Vid->TurnDBOff) ? 1 : p_Vid->DFDisableIdc; + currSlice->DFAlphaC0Offset = p_Vid->DFAlphaC0Offset; + currSlice->DFBetaOffset = p_Vid->DFBetaOffset; + currSlice->view_id = p_Vid->view_id; + + // Edited by Joao Carreira + currSlice->flag_Force_InterView = p_Vid->p_Inp->Force_InterView; +} + +/*! + ************************************************************************ + * \brief + * Initializes the parameters for a new slice and + * allocates the memory for the coded slice in the Picture structure + * \par Side effects: + * Adds slice/partition header symbols to the symbol buffer + * increments Picture->no_slices, allocates memory for the + * slice, sets p_Vid->currSlice + ************************************************************************ + */ +void init_slice (VideoParameters *p_Vid, Slice **currSlice, int start_mb_addr) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i,j; + + int layer_id = p_Vid->dpb_layer_id; + + seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; + Picture *currPic = p_Vid->currentPicture; + DataPartition *dataPart; + Bitstream *currStream; + int active_ref_lists = (p_Vid->mb_aff_frame_flag) ? 6 : 2; + DecodedPictureBuffer *p_Dpb = p_Vid->p_Dpb_layer[layer_id]; + int alloc_size = 0; + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views == 2) + { + int enable_inter_view = (p_Vid->nal_reference_idc || p_Inp->enable_inter_view_flag) ? 1 : 0; + p_Vid->priority_id = 0; + p_Vid->temporal_id = 0; + p_Vid->inter_view_flag[0] = ((layer_id == 0) ? enable_inter_view : 0); + p_Vid->inter_view_flag[1] = ((layer_id == 0) ? enable_inter_view : 0); + + if(p_Vid->structure!=BOTTOM_FIELD) + p_Vid->anchor_pic_flag[0] = (((p_Vid->currentPicture->idr_flag && p_Vid->nal_reference_idc!=0) || p_Vid->prev_view_is_anchor) ? 1:0); + else // bottom will follow top for now + p_Vid->anchor_pic_flag[1] = 0; //p_Vid->anchor_pic_flag[0]; + p_Vid->non_idr_flag[p_Vid->structure!=BOTTOM_FIELD ? 0:1] = !p_Vid->anchor_pic_flag[p_Vid->structure!=BOTTOM_FIELD ? 0:1]; + } +#endif + + p_Vid->current_mb_nr = start_mb_addr; + + // Allocate new Slice in the current Picture, and set p_Vid->currentSlice + assert (currPic != NULL); + currPic->no_slices++; + + if (currPic->no_slices >= MAXSLICEPERPICTURE) + error ("Too many slices per picture, increase MAXSLICEPERPICTURE in global.h.", -1); + + currPic->slices[currPic->no_slices - 1] = malloc_slice(p_Vid, p_Inp); + *currSlice = currPic->slices[currPic->no_slices-1]; + + p_Vid->currentSlice = *currSlice; + set_slice (p_Vid, *currSlice); + + // primary and redundant slices: number of references overriding. + if(p_Inp->redundant_pic_flag) + { + if(!p_Vid->redundant_coding) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin(p_Vid->number,p_Inp->NumRefPrimary); + } + else + { + // 1 reference picture for redundant slices + (*currSlice)->num_ref_idx_active[LIST_0] = 1; + } + } + + for (i = 0; i < (*currSlice)->max_part_nr; i++) + { + dataPart = &(*currSlice)->partArr[i]; + + currStream = dataPart->bitstream; + currStream->bits_to_go = 8; + currStream->byte_pos = 0; + currStream->byte_buf = 0; + } + + // code now also considers fields. Issue whether we should account this within the appropriate input p_Inp directly + if (((*currSlice)->slice_type == P_SLICE || (*currSlice)->slice_type == SP_SLICE) && p_Inp->P_List0_refs[layer_id]) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin((*currSlice)->num_ref_idx_active[LIST_0], p_Inp->P_List0_refs[layer_id] * ((p_Vid->structure !=0) + 1)); +#if CRA + if ( p_Inp->useCRA ) + { + if ( ( ((*currSlice)->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) 1; + } + } +#endif + } + + if ((*currSlice)->slice_type == B_SLICE ) + { + if (p_Inp->B_List0_refs[layer_id]) + { +#if B0_MORE_REF + if ( p_Inp->BLevel0MoreRef ) + { + if ( ((*currSlice)->ThisPOC/2) % (p_Vid->p_Inp->NumberBFrames+1) == 0 ) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin((*currSlice)->num_ref_idx_active[LIST_0], p_Inp->P_List0_refs[layer_id] * ((p_Vid->structure !=0) + 1)); + } + else + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin((*currSlice)->num_ref_idx_active[LIST_0], p_Inp->B_List0_refs[layer_id] * ((p_Vid->structure !=0) + 1)); + } + } + else +#endif + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin((*currSlice)->num_ref_idx_active[LIST_0], p_Inp->B_List0_refs[layer_id] * ((p_Vid->structure !=0) + 1)); + +#if CRA + if ( p_Inp->useCRA ) + { + if ( ( ((*currSlice)->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) 1; + } + } +#endif + } + if (p_Inp->B_List1_refs[layer_id]) + { + (*currSlice)->num_ref_idx_active[LIST_1] = (char) imin((*currSlice)->num_ref_idx_active[LIST_1], p_Inp->B_List1_refs[layer_id] * ((p_Vid->structure !=0) + 1)); +#if B0_MORE_REF + if ( p_Inp->BLevel0MoreRef ) + { + if ( ((*currSlice)->ThisPOC/2) % (p_Vid->p_Inp->NumberBFrames+1) == 0 ) + { + (*currSlice)->num_ref_idx_active[LIST_1] = (*currSlice)->num_ref_idx_active[LIST_0]; + } + } +#endif +#if CRA + if ( p_Inp->useCRA ) + { + if ( ( ((*currSlice)->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + (*currSlice)->num_ref_idx_active[LIST_1] = (*currSlice)->num_ref_idx_active[LIST_0]; + } + } +#endif + } + get_mem3D((byte ****)(void*)&(*currSlice)->direct_ref_idx, (*currSlice)->height_blk, (*currSlice)->width_blk, 2); + get_mem2D((byte ***) (void*)&(*currSlice)->direct_pdir, (*currSlice)->height_blk, (*currSlice)->width_blk); + } + + setup_slice(*currSlice); + update_pic_num(*currSlice); + + (*currSlice)->init_lists(*currSlice); + + // assign list sizes + (*currSlice)->num_ref_idx_active[LIST_0] = (*currSlice)->listXsize[LIST_0]; + (*currSlice)->num_ref_idx_active[LIST_1] = (*currSlice)->listXsize[LIST_1]; + +#if CRA + if ( p_Inp->useCRA ) + { + if ( ( (*currSlice)->slice_type == B_SLICE || (*currSlice)->slice_type == P_SLICE ) && (*currSlice)->p_Dpb->ref_frames_in_buffer >= 2 ) + { + if ( ( ((*currSlice)->ThisPOC/2) - (p_Vid->p_Inp->NumberBFrames+1) ) % p_Vid->p_Inp->intra_period == 0 ) + { + cra_ref_management_frame_pic(p_Dpb, p_Vid->frame_num); + } + } + } +#endif + +#if HM50_LIKE_MMCO + if ( p_Inp->HM50LikeMMCO ) + { + if (p_Vid->structure == FRAME && p_Dpb->ref_frames_in_buffer == active_sps->num_ref_frames) + hm50_ref_management_frame_pic(p_Dpb, p_Vid->frame_num); + } +#endif + +#if LD_REF_SETTING + if ( p_Inp->useF701RefForLD ) + { + if (p_Vid->structure == FRAME && p_Dpb->ref_frames_in_buffer == active_sps->num_ref_frames) + low_delay_ref_management_frame_pic(p_Dpb, p_Vid->frame_num); + } +#endif + + //Perform memory management based on poc distances + if (p_Inp->SetFirstAsLongTerm && p_Vid->number == 0) + { + mmco_long_term(p_Vid, p_Vid->number); + } + else if (p_Vid->nal_reference_idc && p_Inp->PocMemoryManagement == 1) + { + if (p_Vid->structure == FRAME && p_Dpb->ref_frames_in_buffer == active_sps->num_ref_frames) + poc_based_ref_management_frame_pic(p_Dpb, p_Vid->frame_num); + else if (p_Vid->structure == TOP_FIELD && p_Dpb->ref_frames_in_buffer== active_sps->num_ref_frames) + poc_based_ref_management_field_pic(p_Dpb, (p_Vid->frame_num << 1) + 1); + else if (p_Vid->structure == BOTTOM_FIELD) + poc_based_ref_management_field_pic(p_Dpb, (p_Vid->frame_num << 1) + 1); + } + else if (p_Vid->nal_reference_idc && p_Inp->PocMemoryManagement == 2) + { + if (p_Vid->structure == FRAME) + tlyr_based_ref_management_frame_pic(p_Vid, p_Vid->frame_num); + } + + set_default_ref_pic_lists(*currSlice); + + // initialize reordering arrays + init_ref_pic_list_reordering(*currSlice, p_Inp->ReferenceReorder); + alloc_ref_pic_list_reordering_buffer(*currSlice); + +#if (MVC_EXTENSION_ENABLE) + p_Vid->MVCInterViewReorder = 0; + + if(p_Vid->num_of_layers == 2 && p_Inp->MVCInterViewReorder == 1 && layer_id == 1) + { + // enable MVC reordering + p_Vid->MVCInterViewReorder = 1; + + (*currSlice)->reorder_lists( *currSlice ); + + if((*currSlice)->listXsize[0]!=0) + { + StorablePicture *Inter_ViewL0 = (*currSlice)->listX[0][(*currSlice)->listXsize[0]-1]; + //StorablePicture *Inter_ViewL0 = (*currSlice)->p_Dpb->fs_ilref[0]->frame; + //printf("value %d %d %d \n", (*currSlice)->listXsize[0], (*currSlice)->p_Dpb->fs_ilref[0]->frame, (*currSlice)->p_Dpb->fs_ilref[0]->frame); + for(i=(*currSlice)->listXsize[0] - 1; i>0; i--) + (*currSlice)->listX[0][i] = (*currSlice)->listX[0][i - 1]; + (*currSlice)->listX[0][0] = Inter_ViewL0; + (*currSlice)->listXsize[0] = (char) imin ((*currSlice)->listXsize[0], (*currSlice)->num_ref_idx_active[LIST_0]); + } + // perform reordering of interview pictures + } + else +#endif + // reference list reordering + // RPLR for redundant pictures + // !KS: that should actually be moved somewhere else + if(p_Inp->redundant_pic_flag && p_Vid->redundant_coding) + { + alloc_ref_pic_list_reordering_buffer(*currSlice); + (*currSlice)->ref_pic_list_reordering_flag[LIST_0] = 1; + (*currSlice)->modification_of_pic_nums_idc[LIST_0][0] = 0; + (*currSlice)->modification_of_pic_nums_idc[LIST_0][1] = 3; + (*currSlice)->abs_diff_pic_num_minus1[LIST_0][0] = p_Vid->redundant_ref_idx - 1; + (*currSlice)->long_term_pic_idx[LIST_0][0] = 0; + + reorder_ref_pic_list ( *currSlice, LIST_0); + } + else if (( (*currSlice)->slice_type == P_SLICE || (*currSlice)->slice_type == B_SLICE) && p_Inp->WPMCPrecision && p_Vid->pWPX->curr_wp_rd_pass->algorithm != WP_REGULAR ) + wp_mcprec_reorder_lists( *currSlice ); + else + (*currSlice)->reorder_lists( *currSlice ); + + if (p_Inp->EnableOpenGOP) + setup_open_gop_lists(p_Vid, *currSlice); + + +#if PRINTREFLIST +#if (MVC_EXTENSION_ENABLE) + if ( (*currSlice)->slice_type == P_SLICE ) + { + // print out for debug purpose + if(p_Vid->current_slice_nr==0) + { + if((*currSlice)->listXsize[0]>0) + { + printf("\n"); + printf(" ** (CurViewID:%d) %s Ref Pic List 0 ****\n", layer_id, (*currSlice)->structure==FRAME ? "FRM":((*currSlice)->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(int)((*currSlice)->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, (*currSlice)->listX[0][i]->poc, (*currSlice)->listX[0][i]->pic_num, (*currSlice)->listX[0][i]->view_id); + } + } + } + } + else if ( (*currSlice)->slice_type == B_SLICE ) + { + // print out for debug purpose + if(p_Vid->current_slice_nr==0) + { + if(((*currSlice)->listXsize[0]>0) || ((*currSlice)->listXsize[1]>0)) + printf("\n"); + if((*currSlice)->listXsize[0]>0) + { + printf(" ** (CurViewID:%d) %s Ref Pic List 0 ****\n", layer_id, (*currSlice)->structure==FRAME ? "FRM":((*currSlice)->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(int)((*currSlice)->listXsize[0]); i++) //ref list 0 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, (*currSlice)->listX[0][i]->poc, (*currSlice)->listX[0][i]->pic_num, (*currSlice)->listX[0][i]->view_id); + } + } + if((*currSlice)->listXsize[1]>0) + { + printf(" ** (CurViewID:%d) %s Ref Pic List 1 ****\n", layer_id, (*currSlice)->structure==FRAME ? "FRM":((*currSlice)->structure==TOP_FIELD ? "TOP":"BOT")); + for(i=0; i<(int)((*currSlice)->listXsize[1]); i++) //ref list 1 + { + printf(" %2d -> POC: %4d PicNum: %4d ViewID: %d\n", i, (*currSlice)->listX[1][i]->poc, (*currSlice)->listX[1][i]->pic_num, (*currSlice)->listX[1][i]->view_id); + } + } + } + } +#endif +#endif + + (*currSlice)->max_num_references = (short) p_Vid->max_num_references; + + if (((*currSlice)->slice_type != I_SLICE) && (*currSlice)->slice_type != SI_SLICE) + { + alloc_size += get_mem5Dmv (&((*currSlice)->all_mv), 2, (*currSlice)->max_num_references, 9, 4, 4); + + if (p_Inp->BiPredMotionEstimation && ((*currSlice)->slice_type == B_SLICE)) + { + alloc_size += get_mem6Dmv (&((*currSlice)->bipred_mv), 2, 2, (*currSlice)->max_num_references, 9, 4, 4); + } + + if (p_Inp->UseRDOQuant && p_Inp->RDOQ_QP_Num > 1) + { + if (p_Inp->Transform8x8Mode && p_Inp->RDOQ_CP_MV) + { + get_mem4Dmv (&(*currSlice)->tmp_mv8, 2, (*currSlice)->max_num_references, 4, 4); + get_mem3Ddistblk(&(*currSlice)->motion_cost8, 2, (*currSlice)->max_num_references, 4); + get_mem4Dmv (&(*currSlice)->tmp_mv4, 2, (*currSlice)->max_num_references, 4, 4); + get_mem3Ddistblk(&(*currSlice)->motion_cost4, 2, (*currSlice)->max_num_references, 4); + } + } + } + + if (p_Vid->mb_aff_frame_flag) + init_mbaff_lists(*currSlice); + + if (((*currSlice)->slice_type != I_SLICE && (*currSlice)->slice_type != SI_SLICE) && (p_Vid->active_pps->weighted_pred_flag == 1 || (p_Vid->active_pps->weighted_bipred_idc > 0 && ((*currSlice)->slice_type == B_SLICE)))) + { + if ((*currSlice)->slice_type == P_SLICE || (*currSlice)->slice_type == SP_SLICE) + { + int wp_type = (p_Inp->GenerateMultiplePPS && p_Inp->RDPictureDecision) && (p_Vid->enc_picture != p_Vid->enc_frame_picture[1]); + p_Vid->EstimateWPPSlice (*currSlice, wp_type); + } + else + p_Vid->EstimateWPBSlice (*currSlice); + + ClipWPParams( *currSlice ); + } + + if ((*currSlice)->slice_type == B_SLICE) + { + // Allocation should be based on slice size, not image + compute_colocated(*currSlice, (*currSlice)->listX); + } + + if ((*currSlice)->slice_type != I_SLICE && (*currSlice)->slice_type != SI_SLICE) + { + p_Vid->searchRange.min_x = -p_Inp->search_range[layer_id] << 2; + p_Vid->searchRange.max_x = p_Inp->search_range[layer_id] << 2; + p_Vid->searchRange.min_y = -p_Inp->search_range[layer_id] << 2; + p_Vid->searchRange.max_y = p_Inp->search_range[layer_id] << 2; + + if (p_Inp->SearchMode[layer_id] == EPZS) + { + if (((*currSlice)->p_EPZS = (EPZSParameters*) calloc(1, sizeof(EPZSParameters)))==NULL) + no_mem_exit("init_slice: p_EPZS"); + EPZSStructInit (*currSlice); + EPZSSliceInit (*currSlice); + } + } + + + if ((*currSlice)->symbol_mode == CAVLC) + { + setup_cavlc(*currSlice, (*currSlice)->listXsize); + } + else + { + setup_cabac(*currSlice, (*currSlice)->listXsize); + } + + // assign luma common reference picture pointers to be used for ME/sub-pel interpolation + + for(i = 0; i < active_ref_lists; i++) + { + for(j = 0; j < (*currSlice)->listXsize[i]; j++) + { + if( (*currSlice)->listX[i][j] ) + { + (*currSlice)->listX[i][j]->p_curr_img = (*currSlice)->listX[i][j]->p_img [(short) p_Vid->colour_plane_id]; + (*currSlice)->listX[i][j]->p_curr_img_sub = (*currSlice)->listX[i][j]->p_img_sub[(short) p_Vid->colour_plane_id]; + } + } + } + + if (p_Inp->UseRDOQuant) + { + if (((*currSlice)->estBitsCabac = (estBitsCabacStruct*) calloc(NUM_BLOCK_TYPES, sizeof(estBitsCabacStruct)))==NULL) + no_mem_exit("init_slice: (*currSlice)->estBitsCabac"); + + init_rdoq_slice(*currSlice); + + alloc_rddata(*currSlice, &(*currSlice)->rddata_trellis_curr); + if (p_Inp->RDOQ_QP_Num > 1) + { + alloc_rddata(*currSlice, &(*currSlice)->rddata_trellis_best); + } + } + + if(p_Vid->mb_aff_frame_flag) + { + alloc_rddata(*currSlice, &(*currSlice)->rddata_top_frame_mb); + alloc_rddata(*currSlice, &(*currSlice)->rddata_bot_frame_mb); + if ( p_Inp->MbInterlace != FRAME_MB_PAIR_CODING ) + { + alloc_rddata(*currSlice, &(*currSlice)->rddata_top_field_mb); + alloc_rddata(*currSlice, &(*currSlice)->rddata_bot_field_mb); + } + } + + if ((*currSlice)->slice_type == B_SLICE) + { + (*currSlice)->set_motion_vectors_mb = SetMotionVectorsMBBSlice; + } + else if ((*currSlice)->slice_type == P_SLICE || (*currSlice)->slice_type == SP_SLICE) + { + (*currSlice)->set_motion_vectors_mb = SetMotionVectorsMBPSlice; + } + else + { + (*currSlice)->set_motion_vectors_mb = SetMotionVectorsMBISlice; + } + + get_mem3Dpel(&((*currSlice)->mb_pred), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem3Dint(&((*currSlice)->mb_rres), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem3Dint(&((*currSlice)->mb_ores), MAX_PLANE, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem4Dpel(&((*currSlice)->mpr_4x4), MAX_PLANE, 9, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem4Dpel(&((*currSlice)->mpr_8x8), MAX_PLANE, 9, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + get_mem4Dpel(&((*currSlice)->mpr_16x16), MAX_PLANE, 5, MB_BLOCK_SIZE, MB_BLOCK_SIZE); + + get_mem_ACcoeff (p_Vid, &((*currSlice)->cofAC)); + get_mem_DCcoeff (&((*currSlice)->cofDC)); + + allocate_block_mem(*currSlice); + init_coding_state_methods(*currSlice); + init_rdopt(*currSlice); +} + +/*! + ************************************************************************ + * \brief + * Lite-weight initialization of the parameters for a new slice and + * allocates the memory for the coded slice in the Picture structure + * \par Side effects: + * Adds slice/partition header symbols to the symbol buffer + * increments Picture->no_slices, allocates memory for the + * slice, sets p_Vid->currSlice + ************************************************************************ + */ +void init_slice_lite (VideoParameters *p_Vid, Slice **currSlice, int start_mb_addr) +{ + InputParameters *p_Inp = p_Vid->p_Inp; + int i,j; +#if (MVC_EXTENSION_ENABLE) + int layer_id = p_Vid->dpb_layer_id; +#else + int layer_id = 0; +#endif + int active_ref_lists = (p_Vid->mb_aff_frame_flag) ? 6 : 2; + +#if (MVC_EXTENSION_ENABLE) + if(p_Inp->num_of_views == 2) + { + int enable_inter_view = (p_Vid->nal_reference_idc || p_Inp->enable_inter_view_flag) ? 1 : 0; + p_Vid->priority_id = 0; + p_Vid->temporal_id = 0; + p_Vid->inter_view_flag[0] = ((layer_id == 0) ? enable_inter_view : 0); + p_Vid->inter_view_flag[1] = ((layer_id == 0) ? enable_inter_view : 0); + + if(p_Vid->structure!=BOTTOM_FIELD) + p_Vid->anchor_pic_flag[0] = (((p_Vid->currentPicture->idr_flag && p_Vid->nal_reference_idc!=0) || p_Vid->prev_view_is_anchor) ? 1:0); + else // bottom will follow top for now + p_Vid->anchor_pic_flag[1] = 0; //p_Vid->anchor_pic_flag[0]; + p_Vid->non_idr_flag[p_Vid->structure!=BOTTOM_FIELD ? 0:1] = !p_Vid->anchor_pic_flag[p_Vid->structure!=BOTTOM_FIELD ? 0:1]; + } +#endif + + *currSlice = malloc_slice_lite(p_Vid, p_Inp); + + set_slice (p_Vid, *currSlice); + + + if (((*currSlice)->slice_type == P_SLICE || (*currSlice)->slice_type == SP_SLICE) && p_Inp->P_List0_refs[layer_id]) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin((*currSlice)->num_ref_idx_active[LIST_0], p_Inp->P_List0_refs[layer_id] * ((p_Vid->structure !=0) + 1)); + } + + if ((*currSlice)->slice_type == B_SLICE ) + { + if (p_Inp->B_List0_refs[layer_id]) + { + (*currSlice)->num_ref_idx_active[LIST_0] = (char) imin((*currSlice)->num_ref_idx_active[LIST_0], p_Inp->B_List0_refs[layer_id] * ((p_Vid->structure !=0) + 1)); + } + if (p_Inp->B_List1_refs[layer_id]) + { + (*currSlice)->num_ref_idx_active[LIST_1] = (char) imin((*currSlice)->num_ref_idx_active[LIST_1], p_Inp->B_List1_refs[layer_id] * ((p_Vid->structure !=0) + 1)); + } + } + + setup_slice(*currSlice); + + update_pic_num(*currSlice); + (*currSlice)->init_lists(*currSlice); + + // assign list 0 size from list size + (*currSlice)->num_ref_idx_active[LIST_0] = (*currSlice)->listXsize[LIST_0]; + (*currSlice)->num_ref_idx_active[LIST_1] = (*currSlice)->listXsize[LIST_1]; + + set_default_ref_pic_lists(*currSlice); + + init_ref_pic_list_reordering(*currSlice, p_Inp->ReferenceReorder); + alloc_ref_pic_list_reordering_buffer(*currSlice); + +#if (MVC_EXTENSION_ENABLE) + p_Vid->MVCInterViewReorder = 0; + if(p_Vid->num_of_layers == 2 && p_Inp->MVCInterViewReorder == 1 && layer_id == 1) + { + // enable MVC reordering + p_Vid->MVCInterViewReorder = 1; + + if((*currSlice)->listXsize[0]!=0) + { + StorablePicture *Inter_ViewL0 = (*currSlice)->listX[0][(*currSlice)->listXsize[0]-1]; + for(i=(*currSlice)->listXsize[0] - 1; i>0; i--) + (*currSlice)->listX[0][i] = (*currSlice)->listX[0][i - 1]; + (*currSlice)->listX[0][0] = Inter_ViewL0; + (*currSlice)->listXsize[0] = (char) imin ((*currSlice)->listXsize[0], (*currSlice)->num_ref_idx_active[LIST_0]); + } + (*currSlice)->reorder_lists( *currSlice ); + // perform reordering of interview pictures + } + else +#endif + // reference list reordering + // RPLR for redundant pictures + // !KS: that should actually be moved somewhere else + if(p_Inp->redundant_pic_flag && p_Vid->redundant_coding) + { + (*currSlice)->ref_pic_list_reordering_flag[LIST_0] = 1; + (*currSlice)->modification_of_pic_nums_idc[LIST_0][0] = 0; + (*currSlice)->modification_of_pic_nums_idc[LIST_0][1] = 3; + (*currSlice)->abs_diff_pic_num_minus1[LIST_0][0] = p_Vid->redundant_ref_idx - 1; + (*currSlice)->long_term_pic_idx[LIST_0][0] = 0; + + reorder_ref_pic_list ( *currSlice, LIST_0); + } + else if ( ((*currSlice)->slice_type == P_SLICE || (*currSlice)->slice_type == B_SLICE) && p_Inp->WPMCPrecision && p_Vid->pWPX->curr_wp_rd_pass->algorithm != WP_REGULAR ) + wp_mcprec_reorder_lists( *currSlice ); + else + (*currSlice)->reorder_lists( *currSlice ); + + if (p_Inp->EnableOpenGOP) + setup_open_gop_lists(p_Vid, *currSlice); + + + (*currSlice)->max_num_references = (short) p_Vid->max_num_references; + + if (p_Vid->mb_aff_frame_flag) + init_mbaff_lists(*currSlice); + + // assign luma common reference picture pointers to be used for ME/sub-pel interpolation + for(i = 0; i < active_ref_lists; i++) + { + for(j = 0; j < (*currSlice)->listXsize[i]; j++) + { + if( (*currSlice)->listX[i][j] ) + { + (*currSlice)->listX[i][j]->p_curr_img = (*currSlice)->listX[i][j]->p_img [(short) p_Vid->colour_plane_id]; + (*currSlice)->listX[i][j]->p_curr_img_sub = (*currSlice)->listX[i][j]->p_img_sub[(short) p_Vid->colour_plane_id]; + } + } + } + + (*currSlice)->estBitsCabac = NULL; + nullify_rddata(&((*currSlice)->rddata_trellis_curr)); + nullify_rddata(&((*currSlice)->rddata_trellis_best)); + + if(p_Vid->mb_aff_frame_flag) + { + nullify_rddata(&((*currSlice)->rddata_top_frame_mb)); + nullify_rddata(&((*currSlice)->rddata_bot_frame_mb)); + if ( p_Inp->MbInterlace != FRAME_MB_PAIR_CODING ) + { + nullify_rddata(&((*currSlice)->rddata_top_field_mb)); + nullify_rddata(&((*currSlice)->rddata_bot_field_mb)); + } + } + + (*currSlice)->all_mv = NULL; + (*currSlice)->bipred_mv = NULL; + + (*currSlice)->tmp_mv8 = NULL; + (*currSlice)->motion_cost8 = NULL; + (*currSlice)->tmp_mv4 = NULL; + (*currSlice)->motion_cost4 = NULL; + (*currSlice)->p_EPZS = NULL; + + (*currSlice)->mb_pred = NULL; + (*currSlice)->mb_rres = NULL; + (*currSlice)->mb_ores = NULL; + (*currSlice)->mpr_4x4 = NULL; + (*currSlice)->mpr_8x8 = NULL; + (*currSlice)->mpr_16x16 = NULL; + + (*currSlice)->cofAC = NULL; + (*currSlice)->cofDC = NULL; + + (*currSlice)->tblk4x4 = NULL; + (*currSlice)->tblk16x16 = NULL; + (*currSlice)->i16blk4x4 = NULL; + + (*currSlice)->direct_ref_idx = NULL; + (*currSlice)->direct_pdir = NULL; + + init_coding_state_methods(*currSlice); +} + +/*! + ************************************************************************ + * \brief + * Allocates a slice structure along with its dependent data structures + * \return + * Pointer to a Slice + ************************************************************************ + */ +static Slice *malloc_slice(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + int i; + DataPartition *dataPart; + Slice *currSlice; + int cr_size = (p_Inp->separate_colour_plane_flag != 0) ? 0 : 512; + + int buffer_size; + + switch (p_Inp->slice_mode) + { + case 2: + //buffer_size = imax(2 * p_Inp->slice_argument, 500 + (128 + 256 * p_Vid->bitdepth_luma + 512 * p_Vid->bitdepth_chroma)); + buffer_size = imax(2 * p_Inp->slice_argument, 764); + break; + case 1: + buffer_size = 500 + p_Inp->slice_argument * ((128 + 256 * p_Vid->bitdepth_luma + cr_size * p_Vid->bitdepth_chroma) >> 3); + break; + default: + buffer_size = 500 + p_Vid->FrameSizeInMbs * ((128 + 256 * p_Vid->bitdepth_luma + cr_size * p_Vid->bitdepth_chroma) >> 3); + break; + } + + // KS: this is approx. max. allowed code picture size + if ((currSlice = (Slice *) calloc(1, sizeof(Slice))) == NULL) no_mem_exit ("malloc_slice: currSlice structure"); + + currSlice->p_Vid = p_Vid; + currSlice->p_Inp = p_Inp; + + if (((currSlice->p_RDO) = (RDOPTStructure *) calloc(1, sizeof(RDOPTStructure)))==NULL) + no_mem_exit("malloc_slice: p_RDO"); + + currSlice->symbol_mode = (char) p_Inp->symbol_mode; + + if (currSlice->symbol_mode == CABAC) + { + // create all context models + currSlice->mot_ctx = create_contexts_MotionInfo (); + currSlice->tex_ctx = create_contexts_TextureInfo(); + } + + currSlice->max_part_nr = p_Inp->partition_mode==0?1:3; + + //for IDR p_Vid there should be only one partition + if(p_Vid->currentPicture->idr_flag) + currSlice->max_part_nr = 1; + + assignSE2partition[0] = assignSE2partition_NoDP; + //ZL + //for IDR p_Vid all the syntax element should be mapped to one partition + if(!p_Vid->currentPicture->idr_flag && p_Inp->partition_mode == 1) + assignSE2partition[1] = assignSE2partition_DP; + else + assignSE2partition[1] = assignSE2partition_NoDP; + + currSlice->num_mb = 0; // no coded MBs so far + + if ((currSlice->partArr = (DataPartition *) calloc(currSlice->max_part_nr, sizeof(DataPartition))) == NULL) + no_mem_exit ("malloc_slice: partArr"); + for (i=0; imax_part_nr; i++) // loop over all data partitions + { + dataPart = &(currSlice->partArr[i]); + if ((dataPart->bitstream = (Bitstream *) calloc(1, sizeof(Bitstream))) == NULL) + no_mem_exit ("malloc_slice: Bitstream"); + if ((dataPart->bitstream->streamBuffer = (byte *) calloc(buffer_size, sizeof(byte))) == NULL) + no_mem_exit ("malloc_slice: StreamBuffer"); + dataPart->bitstream->buffer_size = buffer_size; + // Initialize storage of bitstream parameters + // Set pointers + dataPart->p_Slice = currSlice; + dataPart->p_Vid = p_Vid; + dataPart->p_Inp = p_Inp; + } + + if (p_Inp->WeightedPrediction || p_Inp->WeightedBiprediction || p_Inp->GenerateMultiplePPS) + { + // Currently only use up to 32 references. Need to use different indicator such as maximum num of references in list + get_mem3Dshort(&currSlice->wp_weight , 6, MAX_REFERENCE_PICTURES, 3); + get_mem3Dshort(&currSlice->wp_offset , 6, MAX_REFERENCE_PICTURES, 3); + get_mem4Dshort(&currSlice->wbp_weight, 6, MAX_REFERENCE_PICTURES, MAX_REFERENCE_PICTURES, 3); + } + + return currSlice; +} + + + + +/*! + ************************************************************************ + * \brief + * Allocates a light-weight slice structure along with its dependent data structures + * \return + * Pointer to a Slice + ************************************************************************ + */ +static Slice *malloc_slice_lite(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + Slice *currSlice; + //int cr_size = (p_Inp->separate_colour_plane_flag != 0) ? 0 : 512; + + if ((currSlice = (Slice *) calloc(1, sizeof(Slice))) == NULL) no_mem_exit ("malloc_slice: currSlice structure"); + + currSlice->p_Vid = p_Vid; + currSlice->p_Inp = p_Inp; + currSlice->p_RDO = NULL; + + currSlice->symbol_mode = (char) p_Inp->symbol_mode; + { + // create all context models + currSlice->mot_ctx = NULL; + currSlice->tex_ctx = NULL; + } + + currSlice->max_part_nr = p_Inp->partition_mode==0?1:3; + + //for IDR p_Vid there should be only one partition + if(p_Vid->currentPicture->idr_flag) + currSlice->max_part_nr = 1; + + assignSE2partition[0] = assignSE2partition_NoDP; + //ZL + //for IDR p_Vid all the syntax element should be mapped to one partition + if(!p_Vid->currentPicture->idr_flag && p_Inp->partition_mode == 1) + assignSE2partition[1] = assignSE2partition_DP; + else + assignSE2partition[1] = assignSE2partition_NoDP; + + currSlice->num_mb = 0; // no coded MBs so far + + currSlice->partArr = NULL; + + if (p_Inp->WeightedPrediction || p_Inp->WeightedBiprediction || p_Inp->GenerateMultiplePPS) + { + // Currently only use up to 32 references. Need to use different indicator such as maximum num of references in list + get_mem3Dshort(&currSlice->wp_weight, 6, MAX_REFERENCE_PICTURES, 3); + get_mem3Dshort(&currSlice->wp_offset, 6, MAX_REFERENCE_PICTURES, 3); + get_mem4Dshort(&currSlice->wbp_weight, 6, MAX_REFERENCE_PICTURES, MAX_REFERENCE_PICTURES, 3); + } + + return currSlice; +} + + + +/*! + ************************************************************************ + * \brief + * This function frees nal units + * + ************************************************************************ + */ +static void free_nal_unit(Picture *pic) +{ + int partition, slice; + Slice *currSlice; + + // loop over all slices of the picture + for (slice=0; slice < pic->no_slices; slice++) + { + currSlice = pic->slices[slice]; + + // loop over the partitions + if (currSlice != NULL) + { + for (partition=0; partition < currSlice->max_part_nr; partition++) + { + // free only if the partition has content + if (currSlice->partArr[partition].bitstream->write_flag ) + { + if (currSlice->partArr[partition].nal_unit != NULL) + { + FreeNALU(currSlice->partArr[partition].nal_unit); + currSlice->partArr[partition].nal_unit = NULL; + } + } + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * Memory frees of the Slice structure and of its dependent + * data structures + * \param currSlice + * Slice to be freed + ************************************************************************ + */ +void free_slice(Slice *currSlice) +{ + if (currSlice != NULL) + { + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + int i; + DataPartition *dataPart; + + for (i=0; i<6; i++) + { + if (currSlice->listX[i]) + { + free (currSlice->listX[i]); + currSlice->listX[i] = NULL; + } + } + + for (i = 0; i < currSlice->max_part_nr; i++) // loop over all data partitions + { + if ( currSlice->partArr != NULL) + { + dataPart = &(currSlice->partArr[i]); + + if (dataPart != NULL) + { + if (dataPart->bitstream != NULL) + { + if (dataPart->bitstream->streamBuffer != NULL) + { + free(dataPart->bitstream->streamBuffer); + dataPart->bitstream->streamBuffer = NULL; + } + free(dataPart->bitstream); + dataPart->bitstream = NULL; + } + } + } + } + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + free_ref_pic_list_reordering_buffer (currSlice); + + // free structure for rd-opt. mode decision + if(currSlice->p_RDO) + { + clear_rdopt (currSlice); + free (currSlice->p_RDO); + } + + if(currSlice->cofAC) + free_mem_ACcoeff (currSlice->cofAC); + if(currSlice->cofDC) + free_mem_DCcoeff (currSlice->cofDC); + + if(currSlice->mb_rres) + free_mem3Dint(currSlice->mb_rres ); + if(currSlice->mb_ores) + free_mem3Dint(currSlice->mb_ores ); + if(currSlice->mb_pred) + free_mem3Dpel(currSlice->mb_pred ); + if(currSlice->mpr_16x16) + free_mem4Dpel(currSlice->mpr_16x16); + if(currSlice->mpr_8x8) + free_mem4Dpel(currSlice->mpr_8x8 ); + if(currSlice->mpr_4x4) + free_mem4Dpel(currSlice->mpr_4x4 ); + + + if (currSlice->partArr != NULL) + { + free(currSlice->partArr); + currSlice->partArr = NULL; + } + + if (currSlice->symbol_mode == CABAC) + { + if(currSlice->mot_ctx) + delete_contexts_MotionInfo(currSlice->mot_ctx); + if(currSlice->tex_ctx) + delete_contexts_TextureInfo(currSlice->tex_ctx); + } + + if (p_Inp->WeightedPrediction || p_Inp->WeightedBiprediction || p_Inp->GenerateMultiplePPS) + { + free_mem3Dshort(currSlice->wp_weight ); + free_mem3Dshort(currSlice->wp_offset ); + free_mem4Dshort(currSlice->wbp_weight); + } + + if (currSlice->UseRDOQuant) + { + free(currSlice->estBitsCabac); + + free_rddata(currSlice, &currSlice->rddata_trellis_curr); + if(currSlice->RDOQ_QP_Num > 1) + { + free_rddata(currSlice, &currSlice->rddata_trellis_best); + } + } + + if(currSlice->mb_aff_frame_flag) + { + free_rddata(currSlice, &currSlice->rddata_top_frame_mb); + free_rddata(currSlice, &currSlice->rddata_bot_frame_mb); + + if ( p_Inp->MbInterlace != FRAME_MB_PAIR_CODING ) + { + free_rddata(currSlice, &currSlice->rddata_top_field_mb); + free_rddata(currSlice, &currSlice->rddata_bot_field_mb); + } + } + + if ((currSlice->slice_type == P_SLICE) || (currSlice->slice_type == SP_SLICE) || (currSlice->slice_type == B_SLICE)) + { + if(currSlice->all_mv) + free_mem5Dmv (currSlice->all_mv); + if (p_Inp->BiPredMotionEstimation && (currSlice->slice_type == B_SLICE) && currSlice->bipred_mv) + free_mem6Dmv(currSlice->bipred_mv); + + if (currSlice->UseRDOQuant && currSlice->RDOQ_QP_Num > 1) + { + if (p_Inp->Transform8x8Mode && p_Inp->RDOQ_CP_MV) + { + if(currSlice->tmp_mv8) + free_mem4Dmv (currSlice->tmp_mv8); + if(currSlice->motion_cost8) + free_mem3Ddistblk(currSlice->motion_cost8); + if(currSlice->tmp_mv4) + free_mem4Dmv (currSlice->tmp_mv4); + if(currSlice->motion_cost4) + free_mem3Ddistblk(currSlice->motion_cost4); + } + } + } + + if (currSlice->slice_type == B_SLICE) + { + if(currSlice->direct_ref_idx) + free_mem3D((byte ***)currSlice->direct_ref_idx); + if(currSlice->direct_pdir) + free_mem2D((byte **) currSlice->direct_pdir); + } + + free_block_mem(currSlice); + + if (currSlice->slice_type != I_SLICE && currSlice->slice_type != SI_SLICE) + { + if (p_Inp->SearchMode[p_Vid->view_id] == EPZS) + { + if(currSlice->p_EPZS) + EPZSStructDelete (currSlice); + } + } + + free(currSlice); + } +} + +/*! + ************************************************************************ + * \brief + * Memory frees of all Slice structures and of its dependent + * data structures + * \par Input: + * Picture *currPic + ************************************************************************ + */ +void free_slice_list(Picture *currPic) +{ + int i; + + if (currPic != NULL) + { + free_nal_unit(currPic); + + for (i = 0; i < currPic->no_slices; i++) + { + free_slice (currPic->slices[i]); + currPic->slices[i] = NULL; + } + } +} + +void UpdateMELambda(Slice *currSlice) +{ + InputParameters *p_Inp = currSlice->p_Inp; + + if (p_Inp->UpdateLambdaChromaME) + { + VideoParameters *p_Vid = currSlice->p_Vid; + int j, k, qp; + if (currSlice->slice_type == B_SLICE) + j = currSlice->nal_reference_idc ? 5 : B_SLICE; + else + j = currSlice->slice_type; + + switch(p_Vid->yuv_format) + { + case YUV420: + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + for (k = 0; k < 3; k++) + { + if ((p_Inp->MEErrorMetric[k] == ERROR_SAD) && (p_Inp->ChromaMEEnable)) + { + p_Vid->lambda_mf[j][qp][k] = (3 * p_Vid->lambda_mf[j][qp][k] + 1) >> 1; + p_Vid->lambda_me[j][qp][k] *= 1.5; + } + } + } + break; + case YUV422: + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + for (k = 0; k < 3; k++) + { + if ((p_Inp->MEErrorMetric[k] == ERROR_SAD) && (p_Inp->ChromaMEEnable)) + { + p_Vid->lambda_mf[j][qp][k] *= 2; + p_Vid->lambda_me[j][qp][k] *= 2.0; + } + } + } + break; + case YUV444: + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + for (k = 0; k < 3; k++) + { + if ((p_Inp->MEErrorMetric[k] == ERROR_SAD) && (p_Inp->ChromaMEEnable)) + { + p_Vid->lambda_mf[j][qp][k] *= 3; + p_Vid->lambda_me[j][qp][k] *= 3.0; + } + } + } + break; + default: + break; + } + } +} + + +void SetLagrangianMultipliersOn(Slice *currSlice) +{ + InputParameters *p_Inp = currSlice->p_Inp; + + if (p_Inp->UseExplicitLambdaParams == 1) // consideration of explicit lambda weights. + get_explicit_lambda(currSlice); + else if (p_Inp->UseExplicitLambdaParams == 2) // consideration of fixed lambda values. + get_fixed_lambda(currSlice); + else + { + switch(currSlice->slice_type) + { + case I_SLICE: + get_implicit_lambda_i_slice(currSlice); + break; + default: + case P_SLICE: + get_implicit_lambda_p_slice(currSlice); + break; + case B_SLICE: + get_implicit_lambda_b_slice(currSlice); + break; + case SI_SLICE: + case SP_SLICE: + get_implicit_lambda_sp_slice(currSlice); + break; + } + } + + UpdateMELambda(currSlice); + if ( p_Inp->UseRDOQuant ) + { + set_rdoq_lambda(currSlice); + } +} + + +void SetLagrangianMultipliersOff(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + int qp, j, k; + double qp_temp; + + for (j = 0; j < 6; j++) + { + for (qp = -currSlice->bitdepth_luma_qp_scale; qp < 52; qp++) + { + qp_temp = (double)qp + currSlice->bitdepth_luma_qp_scale - SHIFT_QP; + + switch (p_Inp->UseExplicitLambdaParams) + { + case 1: // explicit lambda weights + p_Vid->lambda_md[j][qp] = sqrt(p_Inp->LambdaWeight[j] * pow (2, qp_temp/3.0)); + break; + case 2: // explicit lambda + p_Vid->lambda_md[j][qp] = sqrt(p_Inp->FixedLambda[j]); + break; + default: + p_Vid->lambda_md[j][qp] = QP2QUANT[imax(0,qp - SHIFT_QP)]; + break; + } + + for (k = F_PEL; k <= Q_PEL; k++) + { + p_Vid->lambda_me[j][qp][k] = (p_Inp->MEErrorMetric[k] == ERROR_SSE && p_Inp->MESoftenSSEMetric == 0) ? (p_Vid->lambda_md[j][qp] * p_Vid->lambda_md[j][qp]) : p_Vid->lambda_md[j][qp]; + p_Vid->lambda_mf[j][qp][k] = LAMBDA_FACTOR (p_Vid->lambda_me[j][qp][k]); + } + + if (p_Inp->CtxAdptLagrangeMult == 1) + { + int lambda_qp = (qp >= 32 && !p_Inp->RCEnable) ? imax(0, qp-4) : imax(0, qp-6); + p_Vid->lambda_mf_factor[j][qp] = log (p_Vid->lambda_me[j][lambda_qp][Q_PEL] + 1.0) / log (2.0); + } + } + } + UpdateMELambda(currSlice); + if ( p_Inp->UseRDOQuant ) + { + set_rdoq_lambda(currSlice); + } +} + + + diff --git a/lencod/src/symbol.c b/lencod/src/symbol.c new file mode 100644 index 0000000..c1580f3 --- /dev/null +++ b/lencod/src/symbol.c @@ -0,0 +1,18 @@ + +/*! +*************************************************************************** +* +* \file symbol.c +* +* \brief +* Generic Symbol writing interface +* +* \date +* 18 Jan 2006 +* +* \author +* Karsten Suehring +**************************************************************************/ + +#include "global.h" +#include "symbol.h" diff --git a/lencod/src/transcode_enc.c b/lencod/src/transcode_enc.c new file mode 100644 index 0000000..d5537eb --- /dev/null +++ b/lencod/src/transcode_enc.c @@ -0,0 +1,81 @@ +/*! +************************************************************************ +* \file transcode_enc.c +* +* \brief +* Functions to use trancoding information from decoder +* +* \author +* - João Carreira +* +************************************************************************ +*/ + +#include "transcode_enc.h" +#include "transcode_common.h" + +typedef struct trans_t +{ + int p_filein[MAX_VIEW_NUM]; + int file_EOF[MAX_VIEW_NUM]; + + TRANS_FRAME_NODE_T vTransNodes[MAX_TRANSCODED_FRAMES]; + +} TRANS_ENC_T; + +void initTranscodeModule( VideoParameters *p_Vid ) +{ + TRANS_ENC_T *TranscodeModule = NULL; + char out_ViewFileName[FILE_NAME_SIZE], chBuf[FILE_NAME_SIZE], *pch; + int i, layer; + + if ( ( TranscodeModule = (TRANS_ENC_T*)calloc(1, sizeof(TRANS_ENC_T)) ) == NULL ) + no_mem_exit("alloc_video_params: p_Vid->p_Transcode"); + + memset(TranscodeModule,0,sizeof(TRANS_ENC_T)); + memset(TranscodeModule->p_filein,-1,MAX_NUM_DPB_LAYERS*sizeof(int)); + + for(layer=0; layernum_of_layers; layer++ ) + { + if ((strcasecmp(p_Vid->p_Inp->TranscodeFile[layer], "\"\"")!=0) && (strlen(p_Vid->p_Inp->TranscodeFile[layer])>0)) + { + if ((TranscodeModule->p_filein[layer]=open(p_Vid->p_Inp->TranscodeFile[layer], OPENFLAGS_READ, OPEN_PERMISSIONS))==-1) + { + snprintf(errortext, ET_SIZE, "Error open file %s ", p_Vid->p_Inp->TranscodeFile[layer]); + error(errortext,500); + } + } + } + + p_Vid->p_Transcode = TranscodeModule; +} + +void closeTranscodeModule( VideoParameters *p_Vid ) +{ + TRANS_ENC_T *TranscodeModule = (TRANS_ENC_T *) p_Vid->p_Transcode; + int i; + for(i=0; ip_filein[i] != -1 ) + { + close( TranscodeModule->p_filein[i] ); + } + } + free(TranscodeModule); + p_Vid->p_Transcode = NULL; +} + +void readTranscodingInfo( VideoParameters *p_Vid ) +{ + TRANS_ENC_T *TranscodeModule = (TRANS_ENC_T *) p_Vid->p_Transcode; + int layer_id = p_Vid->view_id; //! improve this + + if( TranscodeModule->file_EOF[layer_id] == 0) + { + if( read_trans_node( TranscodeModule->p_filein[layer_id], &(TranscodeModule->vTransNodes[0])) != 0 ) + { + TranscodeModule->file_EOF[layer_id] = 1; + } + } + return; +} \ No newline at end of file diff --git a/lencod/src/transform8x8.c b/lencod/src/transform8x8.c new file mode 100644 index 0000000..2f52d61 --- /dev/null +++ b/lencod/src/transform8x8.c @@ -0,0 +1,900 @@ +/*! + *************************************************************************** + * \file transform8x8.c + * + * \brief + * 8x8 transform functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Lowell Winger + * \date + * 12. October 2003 + ************************************************************************** + */ + +#include +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "blk_prediction.h" +#include "elements.h" +#include "vlc.h" +#include "transform8x8.h" +#include "transform.h" +#include "macroblock.h" +#include "symbol.h" +#include "mc_prediction.h" +#include "md_distortion.h" +#include "quant8x8.h" +#include "rdoq.h" +#include "q_matrix.h" +#include "q_offsets.h" +#include "rdopt.h" +#include "md_common.h" +#include "intra8x8.h" +#include "rdopt_coding_state.h" + +//! single scan pattern +static const byte SNGL_SCAN8x8[64][2] = { + {0,0}, {1,0}, {0,1}, {0,2}, {1,1}, {2,0}, {3,0}, {2,1}, + {1,2}, {0,3}, {0,4}, {1,3}, {2,2}, {3,1}, {4,0}, {5,0}, + {4,1}, {3,2}, {2,3}, {1,4}, {0,5}, {0,6}, {1,5}, {2,4}, + {3,3}, {4,2}, {5,1}, {6,0}, {7,0}, {6,1}, {5,2}, {4,3}, + {3,4}, {2,5}, {1,6}, {0,7}, {1,7}, {2,6}, {3,5}, {4,4}, + {5,3}, {6,2}, {7,1}, {7,2}, {6,3}, {5,4}, {4,5}, {3,6}, + {2,7}, {3,7}, {4,6}, {5,5}, {6,4}, {7,3}, {7,4}, {6,5}, + {5,6}, {4,7}, {5,7}, {6,6}, {7,5}, {7,6}, {6,7}, {7,7} +}; + +static const byte SNGL_SCAN8x8_CAVLC[64][2] = { + {0,0}, {1,1}, {1,2}, {2,2}, {4,1}, {0,5}, {3,3}, {7,0}, {3,4}, {1,7}, {5,3}, {6,3}, {2,7}, {6,4}, {5,6}, {7,5}, + {1,0}, {2,0}, {0,3}, {3,1}, {3,2}, {0,6}, {4,2}, {6,1}, {2,5}, {2,6}, {6,2}, {5,4}, {3,7}, {7,3}, {4,7}, {7,6}, + {0,1}, {3,0}, {0,4}, {4,0}, {2,3}, {1,5}, {5,1}, {5,2}, {1,6}, {3,5}, {7,1}, {4,5}, {4,6}, {7,4}, {5,7}, {6,7}, + {0,2}, {2,1}, {1,3}, {5,0}, {1,4}, {2,4}, {6,0}, {4,3}, {0,7}, {4,4}, {7,2}, {3,6}, {5,5}, {6,5}, {6,6}, {7,7} +}; + +//! field scan pattern +static const byte FIELD_SCAN8x8[64][2] = { // 8x8 + {0,0}, {0,1}, {0,2}, {1,0}, {1,1}, {0,3}, {0,4}, {1,2}, + {2,0}, {1,3}, {0,5}, {0,6}, {0,7}, {1,4}, {2,1}, {3,0}, + {2,2}, {1,5}, {1,6}, {1,7}, {2,3}, {3,1}, {4,0}, {3,2}, + {2,4}, {2,5}, {2,6}, {2,7}, {3,3}, {4,1}, {5,0}, {4,2}, + {3,4}, {3,5}, {3,6}, {3,7}, {4,3}, {5,1}, {6,0}, {5,2}, + {4,4}, {4,5}, {4,6}, {4,7}, {5,3}, {6,1}, {6,2}, {5,4}, + {5,5}, {5,6}, {5,7}, {6,3}, {7,0}, {7,1}, {6,4}, {6,5}, + {6,6}, {6,7}, {7,2}, {7,3}, {7,4}, {7,5}, {7,6}, {7,7} +}; + +static const byte FIELD_SCAN8x8_CAVLC[64][2] = { + {0,0}, {1,1}, {2,0}, {0,7}, {2,2}, {2,3}, {2,4}, {3,3}, {3,4}, {4,3}, {4,4}, {5,3}, {5,5}, {7,0}, {6,6}, {7,4}, + {0,1}, {0,3}, {1,3}, {1,4}, {1,5}, {3,1}, {2,5}, {4,1}, {3,5}, {5,1}, {4,5}, {6,1}, {5,6}, {7,1}, {6,7}, {7,5}, + {0,2}, {0,4}, {0,5}, {2,1}, {1,6}, {4,0}, {2,6}, {5,0}, {3,6}, {6,0}, {4,6}, {6,2}, {5,7}, {6,4}, {7,2}, {7,6}, + {1,0}, {1,2}, {0,6}, {3,0}, {1,7}, {3,2}, {2,7}, {4,2}, {3,7}, {5,2}, {4,7}, {5,4}, {6,3}, {6,5}, {7,3}, {7,7} +}; + + +//! array used to find expensive coefficients +static const byte COEFF_COST8x8[2][64] = +{ + {3,3,3,3,2,2,2,2,2,2,2,2,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9} +}; + + +// Predictor array index definitions +#define P_Z (PredPel[0]) +#define P_A (PredPel[1]) +#define P_B (PredPel[2]) +#define P_C (PredPel[3]) +#define P_D (PredPel[4]) +#define P_E (PredPel[5]) +#define P_F (PredPel[6]) +#define P_G (PredPel[7]) +#define P_H (PredPel[8]) +#define P_I (PredPel[9]) +#define P_J (PredPel[10]) +#define P_K (PredPel[11]) +#define P_L (PredPel[12]) +#define P_M (PredPel[13]) +#define P_N (PredPel[14]) +#define P_O (PredPel[15]) +#define P_P (PredPel[16]) +#define P_Q (PredPel[17]) +#define P_R (PredPel[18]) +#define P_S (PredPel[19]) +#define P_T (PredPel[20]) +#define P_U (PredPel[21]) +#define P_V (PredPel[22]) +#define P_W (PredPel[23]) +#define P_X (PredPel[24]) + + + +/*! +************************************************************************ +* \brief +* Residual DPCM for Intra lossless coding +* +* \par Input: +* block_x,block_y: Block position inside a macro block (0,8). +************************************************************************ +*/ +//For residual DPCM +static int Residual_DPCM_8x8(int ipmode, int **ores, int **rres,int block_y, int block_x) +{ + int i,j; + int temp[8][8]; + + if(ipmode==VERT_PRED) + { + for (j=0; j<8; j++) + temp[0][j] = ores[block_y][block_x+j]; + + for (i=1; i<8; i++) + for (j=0; j<8; j++) + temp[i][j] = ores[block_y+i][block_x+j] - ores[block_y+i-1][block_x+j]; + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + rres[block_y+i][block_x+j] = temp[i][j]; + } + else //HOR_PRED + { + for (i=0; i<8; i++) + temp[i][0] = ores[block_y + i][block_x]; + + for (i=0; i<8; i++) + for (j=1; j<8; j++) + temp[i][j] = ores[block_y+i][block_x+j] - ores[block_y+i][block_x+j-1]; + + for (i=0; i<8; i++) + for (j=0; j<8; j++) + rres[block_y+i][block_x+j] = temp[i][j]; + } + return 0; +} + +/*! +************************************************************************ +* \brief +* Inverse residual DPCM for Intra lossless coding +* +* \par Input: +* block_x,block_y: Block position inside a macro block (0,8). +************************************************************************ +*/ +//For residual DPCM +static int Inv_Residual_DPCM_8x8(Macroblock *currMB, int **m7, int block_y, int block_x) +{ + int i; + int temp[8][8]; + + if(currMB->ipmode_DPCM == VERT_PRED) + { + for(i=0; i<8; i++) + { + temp[0][i] = m7[block_y+0][block_x+i]; + temp[1][i] = temp[0][i] + m7[block_y+1][block_x+i]; + temp[2][i] = temp[1][i] + m7[block_y+2][block_x+i]; + temp[3][i] = temp[2][i] + m7[block_y+3][block_x+i]; + temp[4][i] = temp[3][i] + m7[block_y+4][block_x+i]; + temp[5][i] = temp[4][i] + m7[block_y+5][block_x+i]; + temp[6][i] = temp[5][i] + m7[block_y+6][block_x+i]; + temp[7][i] = temp[6][i] + m7[block_y+7][block_x+i]; + } + for(i=0; i<8; i++) + { + m7[block_y+1][block_x+i] = temp[1][i]; + m7[block_y+2][block_x+i] = temp[2][i]; + m7[block_y+3][block_x+i] = temp[3][i]; + m7[block_y+4][block_x+i] = temp[4][i]; + m7[block_y+5][block_x+i] = temp[5][i]; + m7[block_y+6][block_x+i] = temp[6][i]; + m7[block_y+7][block_x+i] = temp[7][i]; + } + } + else //HOR_PRED + { + for(i=0; i<8; i++) + { + temp[i][0] = m7[block_y+i][block_x+0]; + temp[i][1] = temp[i][0] + m7[block_y+i][block_x+1]; + temp[i][2] = temp[i][1] + m7[block_y+i][block_x+2]; + temp[i][3] = temp[i][2] + m7[block_y+i][block_x+3]; + temp[i][4] = temp[i][3] + m7[block_y+i][block_x+4]; + temp[i][5] = temp[i][4] + m7[block_y+i][block_x+5]; + temp[i][6] = temp[i][5] + m7[block_y+i][block_x+6]; + temp[i][7] = temp[i][6] + m7[block_y+i][block_x+7]; + } + for(i=0; i<8; i++) + { + m7[block_y+i][block_x+1] = temp[i][1]; + m7[block_y+i][block_x+2] = temp[i][2]; + m7[block_y+i][block_x+3] = temp[i][3]; + m7[block_y+i][block_x+4] = temp[i][4]; + m7[block_y+i][block_x+5] = temp[i][5]; + m7[block_y+i][block_x+6] = temp[i][6]; + m7[block_y+i][block_x+7] = temp[i][7]; + } + } + return 0; +} + +/*! + ************************************************************************************* + * \brief + * 8x8 Intra mode decision for a macroblock + ************************************************************************************* + */ +int mode_decision_for_I8x8_MB (Macroblock *currMB, int lambda, distblk *min_cost) +{ + Slice *currSlice = currMB->p_Slice; + int cur_cbp = 0, b8; + //int cr_cbp[3] = { 0, 0, 0}; + distblk cost8x8; + *min_cost = weighted_cost(lambda, 6); //6 bits overhead; + + if (currSlice->P444_joined == 0) + { + for (b8=0; b8<4; b8++) + { + if (currSlice->mode_decision_for_I8x8_blocks (currMB, b8, lambda, &cost8x8)) + { + cur_cbp |= (1<cmp_cbp[1] = currSlice->cmp_cbp[2] = 0; + currMB->cr_cbp[0] = 0; + currMB->cr_cbp[1] = 0; + currMB->cr_cbp[2] = 0; + + for (b8 = 0; b8 < 4; b8++) + { + if (currSlice->mode_decision_for_I8x8_blocks (currMB, b8, lambda, &cost8x8)) + { + cur_cbp |= (1<cr_cbp[k]) //if (cr_cbp[k]) + { + currSlice->cmp_cbp[k] |= (1 << b8); + cur_cbp |= currSlice->cmp_cbp[k]; + currSlice->cmp_cbp[k] = cur_cbp; + } + } + } + } + + return cur_cbp; +} + + +/*! + ************************************************************************************* + * \brief + * R-D Cost for an 8x8 Intra block + ************************************************************************************* + */ +distblk rdcost_for_8x8_intra_blocks(Macroblock *currMB, int *nonzero, int b8, int ipmode, int lambda, distblk min_rdcost, int mostProbableMode) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + distblk rdcost = 0; + int dummy = 0; + int rate; + distblk distortion = 0; + int block_x = (b8 & 0x01) << 3; + int block_y = (b8 >> 1) << 3; + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_y = currMB->opix_y + block_y; + + SyntaxElement se; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition *dataPart; + + //===== perform forward transform, Q, IQ, inverse transform, Reconstruction ===== + *nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, b8, &dummy, 1); + + //===== get distortion (SSD) of 8x8 block ===== + distortion += compute_SSE8x8(&p_Vid->pCurImg[pic_opix_y], &p_Vid->enc_picture->imgY[pic_pix_y], pic_pix_x, pic_pix_x); + if (distortion > min_rdcost) + { + //currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + return distortion; + } + currMB->ipmode_DPCM = NO_INTRA_PMODE; + + //===== RATE for INTRA PREDICTION MODE (SYMBOL MODE MUST BE SET TO CAVLC) ===== + se.value1 = (mostProbableMode == ipmode) ? -1 : ipmode < mostProbableMode ? ipmode : ipmode-1; + + //--- set position and type --- + se.context = b8; + se.type = SE_INTRAPREDMODE; + + //--- choose data partition --- + if (currSlice->slice_type != B_SLICE) + dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + else + dataPart = &(currSlice->partArr[partMap[SE_BFRAME]]); + + //--- encode and update rate --- + currSlice->writeIntraPredMode (&se, dataPart); + + rate = se.len; + + //===== RATE for LUMINANCE COEFFICIENTS ===== + + if (currSlice->symbol_mode == CAVLC) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 0, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 1, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 2, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 3, 0); + } + else + { + rate += writeCoeff8x8_CABAC (currMB, PLANE_Y, b8, 1); + } + rdcost = distortion + weight_cost(lambda, rate); + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + + return rdcost; +} + + +/*! + ************************************************************************************* + * \brief + * R-D Cost for an 8x8 Intra block + ************************************************************************************* + */ +distblk rdcost_for_8x8_intra_blocks_444(Macroblock *currMB, int *nonzero, int b8, int ipmode, int lambda, distblk min_rdcost, int mostProbableMode) +{ + VideoParameters *p_Vid = currMB->p_Vid; + Slice *currSlice = currMB->p_Slice; + distblk rdcost = 0; + int dummy = 0; + int rate; + distblk distortion = 0; + int block_x = (b8 & 0x01) << 3; + int block_y = (b8 >> 1) << 3; + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_y = currMB->opix_y + block_y; + + SyntaxElement se; + const int *partMap = assignSE2partition[currSlice->partition_mode]; + DataPartition *dataPart; + + if(currSlice->P444_joined == 0) + { + //===== perform forward transform, Q, IQ, inverse transform, Reconstruction ===== + *nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, b8, &dummy, 1); + + //===== get distortion (SSD) of 8x8 block ===== + distortion += compute_SSE8x8(&p_Vid->pCurImg[pic_opix_y], &p_Vid->enc_picture->imgY[pic_pix_y], pic_pix_x, pic_pix_x); + + currMB->ipmode_DPCM = NO_INTRA_PMODE; + + //===== RATE for INTRA PREDICTION MODE (SYMBOL MODE MUST BE SET TO CAVLC) ===== + se.value1 = (mostProbableMode == ipmode) ? -1 : ipmode < mostProbableMode ? ipmode : ipmode-1; + + //--- set position and type --- + se.context = b8; + se.type = SE_INTRAPREDMODE; + + //--- choose data partition --- + if (currSlice->slice_type != B_SLICE) + dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + else + dataPart = &(currSlice->partArr[partMap[SE_BFRAME]]); + + //--- encode and update rate --- + currSlice->writeIntraPredMode (&se, dataPart); + + rate = se.len; + + //===== RATE for LUMINANCE COEFFICIENTS ===== + + if (currSlice->symbol_mode == CAVLC) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 0, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 1, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 2, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, 3, 0); + } + else + { + rate += writeCoeff8x8_CABAC (currMB, PLANE_Y, b8, 1); + } + } + else + { + ColorPlane k; + //===== perform forward transform, Q, IQ, inverse transform, Reconstruction ===== + *nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, b8, &dummy, 1); + + //===== get distortion (SSD) of 8x8 block ===== + distortion += compute_SSE8x8(&p_Vid->pCurImg[pic_opix_y], &p_Vid->enc_picture->imgY[pic_pix_y], pic_pix_x, pic_pix_x); + + for (k = PLANE_U; k <= PLANE_V; k++) + { + select_plane(p_Vid, k); + currMB->c_nzCbCr[k ]= currMB->residual_transform_quant_luma_8x8(currMB, k, b8, &dummy,1); + distortion += compute_SSE8x8(&p_Vid->pImgOrg[k][pic_opix_y], &p_Vid->enc_picture->p_curr_img[pic_pix_y], pic_pix_x, pic_pix_x); + } + currMB->ipmode_DPCM = NO_INTRA_PMODE; + select_plane(p_Vid, PLANE_Y); + + //===== RATE for INTRA PREDICTION MODE (SYMBOL MODE MUST BE SET TO CAVLC) ===== + se.value1 = (mostProbableMode == ipmode) ? -1 : ipmode < mostProbableMode ? ipmode : ipmode-1; + + //--- set position and type --- + se.context = b8; + se.type = SE_INTRAPREDMODE; + + //--- choose data partition --- + if (currSlice->slice_type != B_SLICE) + dataPart = &(currSlice->partArr[partMap[SE_INTRAPREDMODE]]); + else + dataPart = &(currSlice->partArr[partMap[SE_BFRAME]]); + + //--- encode and update rate --- + currSlice->writeIntraPredMode (&se, dataPart); + rate = se.len; + + //===== RATE for LUMINANCE COEFFICIENTS ===== + + if (currSlice->symbol_mode == CAVLC) + { + int b4; + for(b4=0; b4<4; b4++) + { + rate += currSlice->writeCoeff4x4_CAVLC (currMB, LUMA, b8, b4, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CB, b8, b4, 0); + rate += currSlice->writeCoeff4x4_CAVLC (currMB, CR, b8, b4, 0); + } + } + else + { + rate += writeCoeff8x8_CABAC (currMB, PLANE_Y, b8, 1); + rate += writeCoeff8x8_CABAC (currMB, PLANE_U, b8, 1); + rate += writeCoeff8x8_CABAC (currMB, PLANE_V, b8, 1); + } + } + rdcost = distortion + weight_cost(lambda, rate); + currSlice->reset_coding_state (currMB, currSlice->p_RDO->cs_cm); + + return rdcost; +} + +static inline int check_zero(int **mb_ores, int block_x) +{ + int i, j, k = 0; + + for (j = 0; (j < BLOCK_SIZE_8x8) && (k == 0); j++) + { + for (i = block_x; (i< block_x + BLOCK_SIZE_8x8) && (k == 0); i++) + { + //k |= (mb_ores[j][i] != 0); + k |= mb_ores[j][i]; + } + } + return k; +} + +/*! + ************************************************************************ + * \brief + * The routine performs transform,quantization,inverse transform, adds the diff. + * to the prediction and writes the result to the decoded luma frame. Includes the + * RD constrained quantization also. + * + * \par Input: + * b8: Block position inside a macro block (0,1,2,3). + * + * \par Output: + * nonzero: 0 if no levels are nonzero. 1 if there are nonzero levels. + * coeff_cost: Counter for nonzero coefficients, used to discard expensive levels. + ************************************************************************ + */ +int residual_transform_quant_luma_8x8(Macroblock *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int nonzero = FALSE; + + int block_x = 8*(b8 & 0x01); + int block_y = 8*(b8 >> 1); + int pl_off = b8+ (pl<<2); + Slice *currSlice = currMB->p_Slice; + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + + int max_imgpel_value = p_Vid->max_imgpel_value; + + if (check_zero(&mb_ores[block_y], block_x) != 0) + { + int qp = (p_Vid->yuv_format==YUV444 && !currSlice->P444_joined)? currMB->qp_scaled[(int)(p_Vid->colour_plane_id)]: currMB->qp_scaled[pl]; + + // Variable p_Quant and some of its parameters could be all set outside + // to speed up the code (e.g. field mode, coeff_cost, etc). + QuantParameters *p_Quant = p_Vid->p_Quant; + + QuantMethods quant_methods; + quant_methods.block_x = block_x; + quant_methods.block_y = block_y; + + quant_methods.ACLevel = currSlice->cofAC[pl_off][0][0]; + quant_methods.ACRun = currSlice->cofAC[pl_off][0][1]; + + quant_methods.qp = qp; + quant_methods.q_params = p_Quant->q_params_8x8[pl][intra][qp]; + quant_methods.fadjust = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj8x8[pl][currMB->ar_mode][block_y]) : NULL; + quant_methods.coeff_cost = coeff_cost; + quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN8x8 : SNGL_SCAN8x8; + quant_methods.c_cost = COEFF_COST8x8[currSlice->disthres]; + + // Forward 8x8 transform + forward8x8(mb_ores, mb_rres, block_y, block_x); + + // Quantization process + nonzero = currSlice->quant_8x8(currMB, &mb_rres[block_y], &quant_methods); + } + else + { + currSlice->cofAC[pl_off][0][0][0] = 0; + } + + if (nonzero) + { + // Inverse 8x8 transform + inverse8x8(&mb_rres[block_y], &mb_rres[block_y], block_x); + + // generate final block + sample_reconstruct (&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], &mb_rres[block_y], block_x, currMB->pix_x + block_x, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, max_imgpel_value, DQ_BITS_8); + } + else // if (nonzero) => No transformed residual. Just use prediction. + { + copy_image_data_8x8 (&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], currMB->pix_x + block_x, block_x); + } + + // Decoded block moved to frame memory + return nonzero; +} + +/*! + ************************************************************************ + * \brief + * The routine performs transform,quantization,inverse transform, adds the diff. + * to the prediction and writes the result to the decoded luma frame. Includes the + * RD constrained quantization also. Used for CAVLC. + * + * \par Input: + * b8: Block position inside a macro block (0,1,2,3). + * + * \par Output: + * nonzero: 0 if no levels are nonzero. 1 if there are nonzero levels. + * coeff_cost: Counter for nonzero coefficients, used to discard expensive levels. + ************************************************************************ + */ +int residual_transform_quant_luma_8x8_cavlc(Macroblock *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int nonzero = FALSE; + + int block_x = 8*(b8 & 0x01); + int block_y = 8*(b8 >> 1); + int pl_off = b8+ (pl<<2); + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + Slice *currSlice = currMB->p_Slice; + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + + int max_imgpel_value = p_Vid->max_imgpel_value; + + int qp = currMB->qp_scaled[pl]; + + //if (check_zero(&mb_ores[block_y], block_x) != 0) + { + // Variable p_Quant and some of its parameters could be all set outside + // to speed up the code (e.g. field mode, coeff_cost, etc). + QuantParameters *p_Quant = p_Vid->p_Quant; + + QuantMethods quant_methods; + quant_methods.block_x = block_x; + quant_methods.block_y = block_y; + quant_methods.qp = qp; + quant_methods.q_params = p_Quant->q_params_8x8[pl][intra][qp]; + quant_methods.fadjust = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj8x8[pl][currMB->ar_mode][block_y]) : NULL; + quant_methods.coeff_cost = coeff_cost; + // quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN8x8 : SNGL_SCAN8x8; + quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN8x8_CAVLC : SNGL_SCAN8x8_CAVLC; + quant_methods.c_cost = COEFF_COST8x8[currSlice->disthres]; + + // Forward 8x8 transform + forward8x8(mb_ores, mb_rres, block_y, block_x); + + // Quantization process + nonzero = currSlice->quant_8x8cavlc(currMB, &mb_rres[block_y], &quant_methods, currSlice->cofAC[pl_off]); + } + + if (nonzero) + { + // Inverse 8x8 transform + inverse8x8(&mb_rres[block_y], &mb_rres[block_y], block_x); + + // generate final block + sample_reconstruct (&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], &mb_rres[block_y], block_x, currMB->pix_x + block_x, BLOCK_SIZE_8x8, BLOCK_SIZE_8x8, max_imgpel_value, DQ_BITS_8); + } + else // if (nonzero) => No transformed residual. Just use prediction. + { + copy_image_data_8x8(&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], currMB->pix_x + block_x, block_x); + } + + // Decoded block moved to frame memory + return nonzero; +} + +int residual_transform_quant_luma_8x8_ls(Macroblock *currMB, ColorPlane pl, int b8, int *coeff_cost, int intra) +{ + VideoParameters *p_Vid = currMB->p_Vid; + int i,j,coeff_ctr; + int scan_pos = 0,run = -1; + int nonzero = FALSE; + + int block_x = 8*(b8 & 0x01); + int block_y = 8*(b8 >> 1); + int pl_off = b8 + (pl<<2); + Slice *currSlice = currMB->p_Slice; + int* ACLevel = currSlice->cofAC[pl_off][0][0]; + int* ACRun = currSlice->cofAC[pl_off][0][1]; + imgpel **img_enc = p_Vid->enc_picture->p_curr_img; + imgpel **mb_pred = currSlice->mb_pred[pl]; + int **mb_ores = currSlice->mb_ores[pl]; + int **mb_rres = currSlice->mb_rres[pl]; + + int scan_poss[4] = { 0 }, runs[4] = { -1, -1, -1, -1 }; + int MCcoeff = 0; + int *m7; + int is_cavlc = (currSlice->symbol_mode == CAVLC); + + const byte (*pos_scan)[2] = currMB->is_field_mode ? FIELD_SCAN8x8 : SNGL_SCAN8x8; + + int **fadjust8x8 = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj8x8[pl][currMB->ar_mode][block_y]) :NULL; + + runs[0]=runs[1]=runs[2]=runs[3]=-1; + scan_poss[0] = scan_poss[1] = scan_poss[2] = scan_poss[3] = 0; + + if( (currMB->ipmode_DPCM < 2)&&(intra)) + { + Residual_DPCM_8x8(currMB->ipmode_DPCM, mb_ores, mb_rres, block_y, block_x); + } + else + { + for (j = block_y ; j < block_y + BLOCK_SIZE_8x8 ; j ++) + for (i = block_x ; i < block_x + BLOCK_SIZE_8x8 ; i ++) + mb_rres[j][i] = mb_ores[j][i] ; + } + + for (coeff_ctr=0; coeff_ctr < 64; coeff_ctr++) + { + i=pos_scan[coeff_ctr][0]; + j=pos_scan[coeff_ctr][1]; + + run++; + + if (currMB->luma_transform_size_8x8_flag && is_cavlc) + { + MCcoeff = (coeff_ctr & 3); + runs[MCcoeff]++; + } + + m7 = &mb_rres[block_y + j][block_x + i]; + + if (p_Vid->AdaptiveRounding) + { + fadjust8x8[j][block_x+i] = 0; + } + + if (*m7 != 0) + { + nonzero = TRUE; + + if (currMB->luma_transform_size_8x8_flag && is_cavlc) + { + *m7 = iClip3(-CAVLC_LEVEL_LIMIT, CAVLC_LEVEL_LIMIT, *m7); + *coeff_cost += MAX_VALUE; + + currSlice->cofAC[pl_off][MCcoeff][0][scan_poss[MCcoeff] ] = *m7; + currSlice->cofAC[pl_off][MCcoeff][1][scan_poss[MCcoeff]++] = runs[MCcoeff]; + ++scan_pos; + runs[MCcoeff]=-1; + } + else + { + *coeff_cost += MAX_VALUE; + ACLevel[scan_pos ] = *m7; + ACRun [scan_pos++] = run; + run=-1; // reset zero level counter + } + } + } + + if (!currMB->luma_transform_size_8x8_flag || !is_cavlc) + ACLevel[scan_pos] = 0; + else + { + for(i=0; i<4; i++) + currSlice->cofAC[pl_off][i][0][scan_poss[i]] = 0; + } + + if( (currMB->ipmode_DPCM < 2) && (intra)) + { + Inv_Residual_DPCM_8x8(currMB, mb_rres, block_y, block_x); + } + + for( j=block_y; jpix_y + j][currMB->pix_x + i]= (imgpel) mb_rres[j][i]; + } + } + + // Decoded block moved to frame memory + return nonzero; +} + + +/*static inline void compute_diff(int *diff, imgpel *cimg, imgpel *cmpr, int width) +{ + int i; + for (i = 0; i < width; i++) + { + *(diff++) = *(cimg++) - *(cmpr++); + } +}*/ + +/*! +************************************************************************************* +* \brief +* distortion for an 8x8 Intra block +************************************************************************************* +*/ +distblk compute_comp8x8_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost) +{ + short diff64[64]; + + int i, j; + short *diff = &diff64[0]; + imgpel *cimg, *cmpr; + + for (j=0; j<8; j++) + { + // compute_diff(diff, &cur_img[j][pic_opix_x], &mpr8x8[j][0], BLOCK_SIZE_8x8); + + cimg = &cur_img[j][pic_opix_x]; + cmpr = &mpr8x8[j][0]; + for (i=0; i<8; i++) + { + *diff++ = *cimg++ - *cmpr++; + } + + } + return p_Vid->distortion8x8 (diff64, min_cost); +} + + +/*! +************************************************************************************* +* \brief +* SAD distortion for an 8x8 Intra block +************************************************************************************* +*/ +distblk compute_sad8x8_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost) +{ + imgpel *cimg, *cmpr; + int i32Cost = 0; + int i, j; + int imin_cost = dist_down(min_cost); + + for (j=0; j<8; j++) + { + cimg = &cur_img[j][pic_opix_x]; + cmpr = &mpr8x8[j][0]; + for (i=0; i<8; i++) + { + i32Cost += iabs(*cimg++ - *cmpr++); + } + + if (i32Cost > imin_cost) + { + return min_cost; + } + } + return dist_scale(i32Cost); +} + +/*! +************************************************************************************* +* \brief +* SSE distortion for an 8x8 Intra block +************************************************************************************* +*/ +distblk compute_sse8x8_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost) +{ + int i, j; + imgpel *cimg, *cmpr; + int imin_cost = dist_down(min_cost); + int distortion = 0; + + for (j=0; j<8; j++) + { + cimg = &cur_img[j][pic_opix_x]; + cmpr = &mpr8x8[j][0]; + + for (i=0; i<8; i++) + { + distortion += iabs2(*cimg++ - *cmpr++); + } + + if (distortion > imin_cost) + { + return min_cost; + } + } + return dist_scale(distortion); +} +/*! +************************************************************************************* +* \brief +* SATD distortion for an 8x8 Intra block +************************************************************************************* +*/ +distblk compute_satd8x8_cost(VideoParameters *p_Vid, imgpel **cur_img, imgpel **mpr8x8, int pic_opix_x, distblk min_cost) +{ + int i, j; + short diff64[64]; + + short *diff = &diff64[0]; + imgpel *cimg, *cmpr; + + for (j=0; j<8; j++) + { + cimg = &cur_img[j][pic_opix_x]; + cmpr = &mpr8x8[j][0]; + for (i=0; i<8; i++) + { + *diff++ = *cimg++ - *cmpr++; + } + } + + return (dist_scale(HadamardSAD8x8 (diff64))); +} + diff --git a/lencod/src/transform8x8_H444.c b/lencod/src/transform8x8_H444.c new file mode 100644 index 0000000..af74e56 --- /dev/null +++ b/lencod/src/transform8x8_H444.c @@ -0,0 +1,424 @@ +/*! + *************************************************************************** + * \file transform8x8_H444.c + * + * \brief + * 8x8 transform functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Yuri Vatis + * - Jan Muenster + * - Lowell Winger + * \date + * 12. October 2003 + ************************************************************************** + */ + +#include +#include + +#include "global.h" + +#include "image.h" +#include "mb_access.h" +#include "elements.h" +#include "vlc.h" +#include "transform8x8.h" +#include "transform.h" +#include "macroblock.h" +#include "symbol.h" +#include "mc_prediction.h" +#include "quant8x8.h" +#include "rdoq.h" +#include "q_matrix.h" +#include "q_offsets.h" +#include "rdopt.h" +#include "md_common.h" +#include "intra8x8.h" +#include "rdopt_coding_state.h" +#include "blk_prediction.h" + +/*! + ************************************************************************************* + * \brief + * 8x8 Intra mode decision for a macroblock - Low complexity + ************************************************************************************* + */ +int mode_decision_for_I8x8_blocks_JM_Low444 (Macroblock *currMB, int b8, int lambda, distblk *min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + + int ipmode, best_ipmode = 0, j, dummy; + distblk cost; + int nonzero = 0; + int block_x = (b8 & 0x01) << 3; + int block_y = (b8 >> 1) << 3; + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_x = currMB->pix_x + block_x; + int pic_opix_y = currMB->opix_y + block_y; + int pic_block_x = pic_pix_x >> 2; + int pic_block_y = pic_pix_y >> 2; + int mb_block_y = (currMB->block_y) + ((b8 >> 1) << 1); + int mb_block_x = (currMB->block_x) + ((b8 & 0x01) << 1); + + //imgpel *img_org, *img_prd; + //int *residual; + int left_available, up_available, all_available; + int **mb_ores = currSlice->mb_ores[0]; + imgpel **mb_pred = currSlice->mb_pred[0]; + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block, top_block; + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + if (p_Inp->UseConstrainedIntraPred) + { + top_block.available = top_block.available ? p_Vid->intra_block [top_block.mb_addr] : 0; + left_block.available = left_block.available ? p_Vid->intra_block [left_block.mb_addr] : 0; + } + + if(b8 >> 1) + upMode = top_block.available ? p_Vid->ipredmode8x8[top_block.pos_y ][top_block.pos_x ] : -1; + else + upMode = top_block.available ? p_Vid->ipredmode [top_block.pos_y ][top_block.pos_x ] : -1; + + if(b8 & 0x01) + leftMode = left_block.available ? p_Vid->ipredmode8x8[left_block.pos_y][left_block.pos_x] : -1; + else + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + currMB->ipmode_DPCM = NO_INTRA_PMODE; //For residual DPCM + + //===== INTRA PREDICTION FOR 8x8 BLOCK ===== + currSlice->set_intrapred_8x8(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + if(currSlice->P444_joined) + { + select_plane(p_Vid, PLANE_U); + currSlice->set_intrapred_8x8(currMB, PLANE_U, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_V); + currSlice->set_intrapred_8x8(currMB, PLANE_V, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_Y); + } + + //===== LOOP OVER ALL 8x8 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + if( (ipmode==DC_PRED) || + ((ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED) && up_available ) || + ((ipmode==HOR_PRED||ipmode==HOR_UP_PRED) && left_available ) || + (all_available) ) + { + get_intrapred_8x8(currMB, PLANE_Y, ipmode, left_available, up_available); + cost = (ipmode == mostProbableMode) ? 0 : ( weighted_cost(lambda, 4) ); + cost += currSlice->compute_cost8x8(p_Vid, &p_Vid->pImgOrg[0][pic_opix_y], currSlice->mpr_8x8[0][ipmode], pic_opix_x, *min_cost - cost); + + if(currSlice->P444_joined) + { + get_intrapred_8x8(currMB, PLANE_U, ipmode, left_available, up_available); + cost += currSlice->compute_cost8x8(p_Vid, &p_Vid->pImgOrg[PLANE_U][pic_opix_y], currSlice->mpr_8x8[PLANE_U][ipmode], pic_opix_x, *min_cost - cost); + get_intrapred_8x8(currMB, PLANE_V, ipmode, left_available, up_available); + cost += currSlice->compute_cost8x8(p_Vid, &p_Vid->pImgOrg[PLANE_V][pic_opix_y], currSlice->mpr_8x8[PLANE_V][ipmode], pic_opix_x, *min_cost - cost); + } + + if (cost < *min_cost) + { + best_ipmode = ipmode; + *min_cost = cost; + } + } + } + + //===== set intra mode prediction ===== + p_Vid->ipredmode8x8[pic_block_y][pic_block_x] = (char) best_ipmode; + currMB->ipmode_DPCM = (char) best_ipmode; //For residual DPCM + + if(currSlice->P444_joined) + { + ColorPlane k; + p_Vid->CbCr_predmode_8x8[b8] = best_ipmode; + for (k = PLANE_U; k <= PLANE_V; k++) + { + currMB->cr_cbp[k] = 0; + select_plane(p_Vid, k); + /* + for (j=0; j<8; j++) + { + for (i=0; i<8; i++) + { + currSlice->mb_pred[k][block_y+j][block_x+i] = currSlice->mpr_8x8[k][best_ipmode][j][i]; + currSlice->mb_ores[k][block_y+j][block_x+i] = p_Vid->pImgOrg[k][currMB->pix_y + block_y + j][currMB->pix_x + block_x + i] - currSlice->mpr_8x8[k][best_ipmode][j][i]; + } + } + */ + copy_image_data_8x8(&currSlice->mb_pred[k][block_y], currSlice->mpr_8x8[k][best_ipmode], block_x, 0); + compute_residue(&(p_Vid->pImgOrg[k][currMB->pix_y+block_y]), &currSlice->mb_pred[k][block_y], &currSlice->mb_ores[k][block_y], block_x, currMB->pix_x+block_x, 8, 8); + + currMB->ipmode_DPCM = (short) best_ipmode; + if (currMB->residual_transform_quant_luma_8x8(currMB, k, b8, &dummy, 1)) + currMB->cr_cbp[k] = 1; + } + select_plane(p_Vid, PLANE_Y); + } + + currMB->intra_pred_modes8x8[4*b8] = (char) ((mostProbableMode == best_ipmode) + ? -1 + : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1)); + + for(j = mb_block_y; j < mb_block_y + 2; j++) //loop 4x4s in the subblock for 8x8 prediction setting + memset(&p_Vid->ipredmode8x8[j][mb_block_x], best_ipmode, 2 * sizeof(char)); + + // get prediction and prediction error + /* + for (j = block_y; j < block_y + 8; j++) + { + memcpy(&mb_pred[j][block_x],currSlice->mpr_8x8[0][best_ipmode][j - block_y], 8 * sizeof(imgpel)); + img_org = &p_Vid->pCurImg[currMB->opix_y + j][pic_opix_x]; + img_prd = &mb_pred[j][block_x]; + residual = &mb_ores[j][block_x]; + for (i=0; i<8; i++) + { + *residual++ = *img_org++ - *img_prd++; + } + } + */ + generate_pred_error_8x8(&p_Vid->pCurImg[currMB->opix_y+block_y], currSlice->mpr_8x8[0][best_ipmode], &mb_pred[block_y], &mb_ores[block_y], pic_opix_x, block_x); + + currMB->ipmode_DPCM = (short) best_ipmode; + nonzero = currMB->residual_transform_quant_luma_8x8 (currMB, PLANE_Y, b8, &dummy, 1); + return nonzero; +} + +/*! +************************************************************************************* +* \brief +* 8x8 Intra mode decision for a macroblock - High complexity +************************************************************************************* +*/ +int mode_decision_for_I8x8_blocks_JM_High444 (Macroblock *currMB, int b8, int lambda, distblk *min_cost) +{ + VideoParameters *p_Vid = currMB->p_Vid; + InputParameters *p_Inp = currMB->p_Inp; + Slice *currSlice = currMB->p_Slice; + RDOPTStructure *p_RDO = currSlice->p_RDO; + + int ipmode, best_ipmode = 0, j, dummy; + int c_nz, nonzero = 0; + distblk rdcost = 0; + distblk min_rdcost = DISTBLK_MAX; + int block_x = (b8 & 0x01) << 3; + int block_y = (b8 >> 1) << 3; + int pic_pix_x = currMB->pix_x + block_x; + int pic_pix_y = currMB->pix_y + block_y; + int pic_opix_x = currMB->pix_x + block_x; + int pic_opix_y = currMB->opix_y + block_y; + int pic_block_x = pic_pix_x >> 2; + int pic_block_y = pic_pix_y >> 2; + int mb_block_y = (currMB->block_y) + ((b8 >> 1) << 1); + int mb_block_x = (currMB->block_x) + ((b8 & 0x01) << 1); + + int uv; + int left_available, up_available, all_available; + + char upMode, leftMode; + int mostProbableMode; + + PixelPos left_block, top_block; + + int *mb_size = p_Vid->mb_size[IS_LUMA]; + + get4x4Neighbour(currMB, block_x - 1, block_y , mb_size, &left_block); + get4x4Neighbour(currMB, block_x, block_y - 1, mb_size, &top_block ); + + if (p_Inp->UseConstrainedIntraPred) + { + top_block.available = top_block.available ? p_Vid->intra_block [top_block.mb_addr ] : 0; + left_block.available = left_block.available ? p_Vid->intra_block [left_block.mb_addr] : 0; + } + + if(b8 >> 1) + upMode = top_block.available ? p_Vid->ipredmode8x8[top_block.pos_y ][top_block.pos_x ] : -1; + else + upMode = top_block.available ? p_Vid->ipredmode [top_block.pos_y ][top_block.pos_x ] : -1; + + if(b8 & 0x01) + leftMode = left_block.available ? p_Vid->ipredmode8x8[left_block.pos_y][left_block.pos_x] : -1; + else + leftMode = left_block.available ? p_Vid->ipredmode[left_block.pos_y][left_block.pos_x] : -1; + + mostProbableMode = (upMode < 0 || leftMode < 0) ? DC_PRED : upMode < leftMode ? upMode : leftMode; + *min_cost = DISTBLK_MAX; + currMB->ipmode_DPCM = NO_INTRA_PMODE; //For residual DPCM + + //===== INTRA PREDICTION FOR 8x8 BLOCK ===== + currSlice->set_intrapred_8x8(currMB, PLANE_Y, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + + if(currSlice->P444_joined) + { + select_plane(p_Vid, PLANE_U); + currSlice->set_intrapred_8x8(currMB, PLANE_U, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_V); + currSlice->set_intrapred_8x8(currMB, PLANE_V, pic_pix_x, pic_pix_y, &left_available, &up_available, &all_available); + select_plane(p_Vid, PLANE_Y); + } + + //===== LOOP OVER ALL 8x8 INTRA PREDICTION MODES ===== + for (ipmode = 0; ipmode < NO_INTRA_PMODE; ipmode++) + { + if( (ipmode==DC_PRED) || + ((ipmode==VERT_PRED||ipmode==VERT_LEFT_PRED||ipmode==DIAG_DOWN_LEFT_PRED) && up_available ) || + ((ipmode==HOR_PRED||ipmode==HOR_UP_PRED) && left_available ) || + (all_available) ) + { + get_intrapred_8x8(currMB, PLANE_Y, ipmode, left_available, up_available); + + // get prediction and prediction error + generate_pred_error_8x8(&p_Vid->pImgOrg[0][pic_opix_y], currSlice->mpr_8x8[0][ipmode], &currSlice->mb_pred[0][block_y], &currSlice->mb_ores[0][block_y], pic_opix_x, block_x); + + if(currSlice->P444_joined) + { + get_intrapred_8x8(currMB, PLANE_U, ipmode, left_available, up_available); + generate_pred_error_8x8(&p_Vid->pImgOrg[1][pic_opix_y], currSlice->mpr_8x8[1][ipmode], &currSlice->mb_pred[1][block_y], &currSlice->mb_ores[1][block_y], pic_opix_x, block_x); + get_intrapred_8x8(currMB, PLANE_V, ipmode, left_available, up_available); + generate_pred_error_8x8(&p_Vid->pImgOrg[2][pic_opix_y], currSlice->mpr_8x8[2][ipmode], &currSlice->mb_pred[2][block_y], &currSlice->mb_ores[2][block_y], pic_opix_x, block_x); + } + + currMB->ipmode_DPCM = (short) ipmode; + + // get and check rate-distortion cost + + rdcost = currSlice->rdcost_for_8x8_intra_blocks (currMB, &c_nz, b8, ipmode, lambda, min_rdcost, mostProbableMode); + if ((rdcost < min_rdcost) || (rdcost == min_rdcost && ipmode == mostProbableMode)) + { + //--- set coefficients --- + memcpy(p_RDO->coefAC8x8intra[b8][0][0][0],currSlice->cofAC[b8][0][0], 4 * 2 * 65 * sizeof(int)); + + //--- set reconstruction --- + copy_image_data_8x8(p_RDO->rec8x8[PLANE_Y], &p_Vid->enc_picture->imgY[pic_pix_y], 0, pic_pix_x); + + if (p_Vid->AdaptiveRounding) + { + for (j = block_y; j < block_y + 8; j++) + memcpy(&p_Vid->ARCofAdj8x8[0][DUMMY][j][block_x],&p_Vid->ARCofAdj8x8[0][I8MB][j][block_x], 8 * sizeof(int)); + + if (currSlice->P444_joined) + { + for (j = block_y; j < block_y + 8; j++) + { + memcpy(&p_Vid->ARCofAdj8x8[1][DUMMY][j][block_x],&p_Vid->ARCofAdj8x8[1][I8MB][j][block_x], 8 * sizeof(int)); + memcpy(&p_Vid->ARCofAdj8x8[2][DUMMY][j][block_x],&p_Vid->ARCofAdj8x8[2][I8MB][j][block_x], 8 * sizeof(int)); + } + } + } + + if (currSlice->P444_joined) + { + //--- set coefficients --- + for (uv=0; uv < 2; uv++) + { + memcpy(p_RDO->coefAC8x8intra[b8][uv + 1][0][0],currSlice->cofAC[4+b8+4*uv][0][0], 2 * 4 * 65 * sizeof(int)); + + currMB->cr_cbp[uv + 1] = currMB->c_nzCbCr[uv + 1]; + //--- set reconstruction --- + copy_image_data_8x8(p_RDO->rec8x8[uv + 1], &p_Vid->enc_picture->imgUV[uv][pic_pix_y], 0, pic_pix_x); + } + } + + //--- flag if transform coefficients must be coded --- + nonzero = c_nz; + + //--- set best mode update minimum cost --- + *min_cost = rdcost; + min_rdcost = rdcost; + best_ipmode = ipmode; + } + } + } + + //===== set intra mode prediction ===== + p_Vid->ipredmode8x8[pic_block_y][pic_block_x] = (char) best_ipmode; + currMB->ipmode_DPCM = (short) best_ipmode; //For residual DPCM + + if(currSlice->P444_joined) + { + ColorPlane k; + p_Vid->CbCr_predmode_8x8[b8] = best_ipmode; + for (k = PLANE_U; k <= PLANE_V; k++) + { + currMB->cr_cbp[k] = 0; + select_plane(p_Vid, k); + /* + for (j=0; j<8; j++) + { + for (i=0; i<8; i++) + { + currSlice->mb_pred[k][block_y+j][block_x+i] = currSlice->mpr_8x8[k][best_ipmode][j][i]; + currSlice->mb_ores[k][block_y+j][block_x+i] = p_Vid->pImgOrg[k][currMB->pix_y + block_y + j][currMB->pix_x + block_x + i] - currSlice->mpr_8x8[k][best_ipmode][j][i]; + } + } + */ + generate_pred_error_8x8(&p_Vid->pImgOrg[k][currMB->pix_y + block_y], currSlice->mpr_8x8[k][best_ipmode], &currSlice->mb_pred[k][block_y], &currSlice->mb_ores[k][block_y], currMB->pix_x + block_x, block_x); + currMB->ipmode_DPCM = (short) best_ipmode; + + if (currMB->residual_transform_quant_luma_8x8(currMB, k, b8, &dummy, 1)) + currMB->cr_cbp[k] = 1; + } + select_plane(p_Vid, PLANE_Y); + } + + currMB->intra_pred_modes8x8[4*b8] = (char) ((mostProbableMode == best_ipmode) + ? -1 + : (best_ipmode < mostProbableMode ? best_ipmode : best_ipmode-1)); + + memset(&p_Vid->ipredmode8x8[mb_block_y ][mb_block_x], best_ipmode, 2 * sizeof(char)); + memset(&p_Vid->ipredmode8x8[mb_block_y + 1][mb_block_x], best_ipmode, 2 * sizeof(char)); + + //===== restore coefficients ===== + memcpy(currSlice->cofAC[b8][0][0], p_RDO->coefAC8x8intra[b8][0][0][0], 4 * 2 * 65 * sizeof(int)); + + if (p_Vid->AdaptiveRounding) + { + for (j=block_y; j< block_y + 8; j++) + memcpy(&p_Vid->ARCofAdj8x8[0][I8MB][j][block_x], &p_Vid->ARCofAdj8x8[0][DUMMY][j][block_x], 8 * sizeof(int)); + + if (currSlice->P444_joined) + { + for (j=0; j<8; j++) + { + memcpy(&p_Vid->ARCofAdj8x8[1][I8MB][block_y + j][block_x], &p_Vid->ARCofAdj8x8[1][DUMMY][block_y + j][block_x], 8 * sizeof(int)); + memcpy(&p_Vid->ARCofAdj8x8[2][I8MB][block_y + j][block_x], &p_Vid->ARCofAdj8x8[2][DUMMY][block_y + j][block_x], 8 * sizeof(int)); + } + } + } + + //===== restore reconstruction and prediction (needed if single coeffs are removed) ===== + copy_image_data_8x8(&p_Vid->enc_picture->imgY[pic_pix_y], p_RDO->rec8x8[0], pic_pix_x, 0); + copy_image_data_8x8(&currSlice->mb_pred[0][block_y], currSlice->mpr_8x8[0][best_ipmode], block_x, 0); + + if (currSlice->P444_joined) + { + //===== restore coefficients ===== + memcpy(currSlice->cofAC[4 + b8 + 4*0][0][0], p_RDO->coefAC8x8intra[b8][1][0][0], 4 * 2 * 65 * sizeof(int)); + memcpy(currSlice->cofAC[4 + b8 + 4*1][0][0], p_RDO->coefAC8x8intra[b8][2][0][0], 4 * 2 * 65 * sizeof(int)); + + //===== restore reconstruction and prediction (needed if single coeffs are removed) ===== + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[0][pic_pix_y], p_RDO->rec8x8[1], pic_pix_x, 0); + copy_image_data_8x8(&p_Vid->enc_picture->imgUV[1][pic_pix_y], p_RDO->rec8x8[2], pic_pix_x, 0); + copy_image_data_8x8(&currSlice->mb_pred[1][block_y], currSlice->mpr_8x8[1][best_ipmode], block_x, 0); + copy_image_data_8x8(&currSlice->mb_pred[2][block_y], currSlice->mpr_8x8[2][best_ipmode], block_x, 0); + } + + return nonzero; +} + diff --git a/lencod/src/vlc.c b/lencod/src/vlc.c new file mode 100644 index 0000000..9fb3b2a --- /dev/null +++ b/lencod/src/vlc.c @@ -0,0 +1,1569 @@ + +/*! + *************************************************************************** + * \file vlc.c + * + * \brief + * (CA)VLC coding functions + * + * \author + * Main contributors (see contributors.h for copyright, address and affiliation details) + * - Inge Lille-Langoy + * - Detlev Marpe + * - Stephan Wenger + *************************************************************************** + */ + +#include "contributors.h" + +#include + +#include "global.h" +#include "enc_statistics.h" +#include "vlc.h" + +#if TRACE +#define SYMTRACESTRING(s) strncpy(sym.tracestring,s,TRACESTRING_SIZE) +#else +#define SYMTRACESTRING(s) // do nothing +#endif + +//! gives codeword number from CBP value, both for intra and inter +static const byte NCBP[2][48][2]= +{ + { // 0 1 2 3 4 5 6 7 8 9 10 11 + { 1, 0},{10, 1},{11, 2},{ 6, 5},{12, 3},{ 7, 6},{14,14},{ 2,10},{13, 4},{15,15},{ 8, 7},{ 3,11}, + { 9, 8},{ 4,12},{ 5,13},{ 0, 9},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0}, + { 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0}, + { 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0},{ 0, 0} + }, + { + { 3, 0},{29, 2},{30, 3},{17, 7},{31, 4},{18, 8},{37,17},{ 8,13},{32, 5},{38,18},{19, 9},{ 9,14}, + {20,10},{10,15},{11,16},{ 2,11},{16, 1},{33,32},{34,33},{21,36},{35,34},{22,37},{39,44},{ 4,40}, + {36,35},{40,45},{23,38},{ 5,41},{24,39},{ 6,42},{ 7,43},{ 1,19},{41, 6},{42,24},{43,25},{25,20}, + {44,26},{26,21},{46,46},{12,28},{45,27},{47,47},{27,22},{13,29},{28,23},{14,30},{15,31},{ 0,12} + } +}; + + +/*! + ************************************************************************************* + * \brief + * write_ue_v, writes an ue(v) syntax element, returns the length in bits + * + * \param tracestring + * the string for the trace file + * \param value + * the value to be coded + * \param bitstream + * the target bitstream the value should be coded into + * + * \return + * Number of bits used by the coded syntax element + * + * \ note + * This function writes always the bit buffer for the progressive scan flag, and + * should not be used (or should be modified appropriately) for the interlace crap + * When used in the context of the Parameter Sets, this is obviously not a + * problem. + * + ************************************************************************************* + */ +int write_ue_v (char *tracestring, int value, Bitstream *bitstream) +{ + SyntaxElement symbol, *sym=&symbol; + sym->value1 = value; + sym->value2 = 0; + + //assert (bitstream->streamBuffer != NULL); + + ue_linfo(sym->value1,sym->value2,&(sym->len),&(sym->inf)); + symbol2uvlc(sym); + + writeUVLC2buffer (sym, bitstream); + +#if TRACE + strncpy(sym->tracestring,tracestring,TRACESTRING_SIZE); + trace2out (sym); +#endif + + return (sym->len); +} + + +/*! + ************************************************************************************* + * \brief + * write_se_v, writes an se(v) syntax element, returns the length in bits + * + * \param tracestring + * the string for the trace file + * \param value + * the value to be coded + * \param bitstream + * the target bitstream the value should be coded into + * + * \return + * Number of bits used by the coded syntax element + * + * \ note + * This function writes always the bit buffer for the progressive scan flag, and + * should not be used (or should be modified appropriately) for the interlace crap + * When used in the context of the Parameter Sets, this is obviously not a + * problem. + * + ************************************************************************************* + */ +int write_se_v (char *tracestring, int value, Bitstream *bitstream) +{ + SyntaxElement symbol, *sym=&symbol; + sym->value1 = value; + sym->value2 = 0; + + //assert (bitstream->streamBuffer != NULL); + + se_linfo(sym->value1,sym->value2,&(sym->len),&(sym->inf)); + symbol2uvlc(sym); + + writeUVLC2buffer (sym, bitstream); + +#if TRACE + strncpy(sym->tracestring,tracestring,TRACESTRING_SIZE); + trace2out (sym); +#endif + + return (sym->len); +} + + +/*! + ************************************************************************************* + * \brief + * write_u_1, writes a flag (u(1) syntax element, returns the length in bits, + * always 1 + * + * \param tracestring + * the string for the trace file + * \param value + * the value to be coded + * \param bitstream + * the target bitstream the value should be coded into + * + * \return + * Number of bits used by the coded syntax element (always 1) + * + * \ note + * This function writes always the bit buffer for the progressive scan flag, and + * should not be used (or should be modified appropriately) for the interlace crap + * When used in the context of the Parameter Sets, this is obviously not a + * problem. + * + ************************************************************************************* + */ +Boolean write_u_1 (char *tracestring, int value, Bitstream *bitstream) +{ + SyntaxElement symbol, *sym=&symbol; + + sym->bitpattern = value; + sym->value1 = value; + sym->len = 1; + + //assert (bitstream->streamBuffer != NULL); + + writeUVLC2buffer(sym, bitstream); + +#if TRACE + strncpy(sym->tracestring,tracestring,TRACESTRING_SIZE); + trace2out (sym); +#endif + + return ((Boolean) sym->len); +} + + +/*! + ************************************************************************************* + * \brief + * write_u_v, writes a n bit fixed length syntax element, returns the length in bits, + * + * \param n + * length in bits + * \param tracestring + * the string for the trace file + * \param value + * the value to be coded + * \param bitstream + * the target bitstream the value should be coded into + * + * \return + * Number of bits used by the coded syntax element + * + * \ note + * This function writes always the bit buffer for the progressive scan flag, and + * should not be used (or should be modified appropriately) for the interlace crap + * When used in the context of the Parameter Sets, this is obviously not a + * problem. + * + ************************************************************************************* + */ + +int write_u_v (int n, char *tracestring, int value, Bitstream *bitstream) +{ + SyntaxElement symbol, *sym=&symbol; + + sym->bitpattern = value; + sym->value1 = value; + sym->len = n; + + //assert (bitstream->streamBuffer != NULL); + + writeUVLC2buffer(sym, bitstream); + +#if TRACE + strncpy(sym->tracestring,tracestring,TRACESTRING_SIZE); + trace2out (sym); +#endif + + return (sym->len); +} + + +/*! + ************************************************************************ + * \brief + * mapping for ue(v) syntax elements + * \param ue + * value to be mapped + * \param dummy + * dummy parameter + * \param info + * returns mapped value + * \param len + * returns mapped value length + ************************************************************************ + */ +void ue_linfo(int ue, int dummy, int *len,int *info) +{ + int i, nn =(ue + 1) >> 1; + + for (i=0; i < 33 && nn != 0; i++) + { + nn >>= 1; + } + *len = (i << 1) + 1; + *info = ue + 1 - (1 << i); +} + + +/*! + ************************************************************************ + * \brief + * mapping for se(v) syntax elements + * \param se + * value to be mapped + * \param dummy + * dummy parameter + * \param len + * returns mapped value length + * \param info + * returns mapped value + ************************************************************************ + */ +void se_linfo(int se, int dummy, int *len,int *info) +{ + int sign = (se <= 0) ? 1 : 0; + int n = iabs(se) << 1; // n+1 is the number in the code table. Based on this we find length and info + int nn = (n >> 1); + int i; + for (i = 0; i < 33 && nn != 0; i++) + { + nn >>= 1; + } + *len = (i << 1) + 1; + *info = n - (1 << i) + sign; +} + + +/*! + ************************************************************************ + * \par Input: + * Number in the code table + * \par Output: + * length and info + ************************************************************************ + */ +void cbp_linfo_intra_other(int cbp, int dummy, int *len,int *info) +{ + ue_linfo(NCBP[0][cbp][0], dummy, len, info); +} + + +/*! + ************************************************************************ + * \par Input: + * Number in the code table + * \par Output: + * length and info + ************************************************************************ + */ +void cbp_linfo_intra_normal(int cbp, int dummy, int *len,int *info) +{ + ue_linfo(NCBP[1][cbp][0], dummy, len, info); +} + +/*! + ************************************************************************ + * \par Input: + * Number in the code table + * \par Output: + * length and info + ************************************************************************ + */ +void cbp_linfo_inter_other(int cbp, int dummy, int *len,int *info) +{ + ue_linfo(NCBP[0][cbp][1], dummy, len, info); +} + +/*! + ************************************************************************ + * \par Input: + * Number in the code table + * \par Output: + * length and info + ************************************************************************ + */ +void cbp_linfo_inter_normal(int cbp, int dummy, int *len,int *info) +{ + ue_linfo(NCBP[1][cbp][1], dummy, len, info); +} + +/*! + ************************************************************************ + * \brief + * 2x2 transform of chroma DC + * \par Input: + * level and run for coefficients + * \par Output: + * length and info + * \note + * see ITU document for bit assignment + ************************************************************************ + */ +void levrun_linfo_c2x2(int level,int run,int *len,int *info) +{ + static const byte NTAB[2][2]= + { + {1,5}, + {3,0} + }; + static const byte LEVRUN[4]= + { + 2,1,0,0 + }; + + if (level == 0) // check if the coefficient sign EOB (level=0) + { + *len=1; + return; + } + else + { + int levabs = iabs(level); + int sign = level <= 0 ? 1 : 0; + int n = (levabs <= LEVRUN[run]) ? NTAB[levabs - 1][run] + 1 : (levabs - LEVRUN[run]) * 8 + run * 2; + int nn = n >> 1; + int i; + + for (i=0; i < 16 && nn != 0; i++) + { + nn >>= 1; + } + *len = (i << 1) + 1; + *info = n - (1 << i) + sign; + } +} + + +/*! + ************************************************************************ + * \brief + * Single scan coefficients + * \par Input: + * level and run for coefficients + * \par Output: + * length and info + * \note + * see ITU document for bit assignment + ************************************************************************ + */ +void levrun_linfo_inter(int level,int run,int *len,int *info) +{ + static const byte LEVRUN[16]= + { + 4,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0 + }; + static const byte NTAB[4][10]= + { + { 1, 3, 5, 9,11,13,21,23,25,27}, + { 7,17,19, 0, 0, 0, 0, 0, 0, 0}, + {15, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {29, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }; + + if (level == 0) // check for EOB + { + *len=1; + return; + } + else + { + + int sign = (level <= 0) ? 1 : 0; + int levabs = iabs(level); + + int n = (levabs <= LEVRUN[run]) ? NTAB[levabs - 1][run] + 1 : (levabs - LEVRUN[run]) * 32 + run * 2; + + int nn = n >> 1; + int i; + + for (i=0; i < 16 && nn != 0; i++) + { + nn >>= 1; + } + *len = (i << 1) + 1; + *info = n - (1 << i) + sign; + } +} + + +/*! + ************************************************************************ + * \brief + * Makes code word and passes it back + * A code word has the following format: 0 0 0 ... 1 Xn ...X2 X1 X0. + * + * \par Input: + * Info : Xn..X2 X1 X0 \n + * Length : Total number of bits in the codeword + ************************************************************************ + */ + // NOTE this function is called with sym->inf > (1<<(sym->len >> 1)). The upper bits of inf are junk +int symbol2uvlc(SyntaxElement *sym) +{ + int suffix_len = sym->len >> 1; + //assert (suffix_len < 32); + suffix_len = (1 << suffix_len); + sym->bitpattern = suffix_len | (sym->inf & (suffix_len - 1)); + return 0; +} + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +************************************************************************ +*/ +void writeSE_UVLC(SyntaxElement *se, DataPartition *dp) +{ + ue_linfo (se->value1,se->value2,&(se->len),&(se->inf)); + symbol2uvlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif +} + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +************************************************************************ +*/ +void writeSE_SVLC(SyntaxElement *se, DataPartition *dp) +{ + se_linfo (se->value1,se->value2,&(se->len),&(se->inf)); + symbol2uvlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif +} + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +************************************************************************ +*/ +void writeCBP_VLC (Macroblock* currMB, SyntaxElement *se, DataPartition *dp) +{ + if (currMB->mb_type == I4MB || currMB->mb_type == SI4MB || currMB->mb_type == I8MB) + { + currMB->cbp_linfo_intra (se->value1, se->value2, &(se->len), &(se->inf)); + } + else + { + currMB->cbp_linfo_inter (se->value1,se->value2,&(se->len),&(se->inf)); + } + symbol2uvlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif +} + + +/*! + ************************************************************************ + * \brief + * generates code and passes the codeword to the buffer + ************************************************************************ + */ +void writeIntraPredMode_CAVLC(SyntaxElement *se, DataPartition *dp) +{ + + if (se->value1 == -1) + { + se->len = 1; + se->inf = 1; + } + else + { + se->len = 4; + se->inf = se->value1; + } + + se->bitpattern = se->inf; + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return; +} + + +/*! + ************************************************************************ + * \brief + * generates UVLC code and passes the codeword to the buffer + * \author + * Tian Dong + ************************************************************************ + */ +int writeSyntaxElement2Buf_UVLC(SyntaxElement *se, Bitstream* this_streamBuffer ) +{ + + se->mapping(se->value1,se->value2,&(se->len),&(se->inf)); + + symbol2uvlc(se); + + writeUVLC2buffer(se, this_streamBuffer ); + +#if TRACE + if(se->type <= 1) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * writes UVLC code to the appropriate buffer + ************************************************************************ + */ +void writeUVLC2buffer(SyntaxElement *se, Bitstream *currStream) +{ + unsigned int mask = 1 << (se->len - 1); + byte *byte_buf = &currStream->byte_buf; + int *bits_to_go = &currStream->bits_to_go; + int i; + + // Add the new bits to the bitstream. + // Write out a byte if it is full + if ( se->len < 33 ) + { + for (i = 0; i < se->len; i++) + { + *byte_buf <<= 1; + + if (se->bitpattern & mask) + *byte_buf |= 1; + + mask >>= 1; + + if ((--(*bits_to_go)) == 0) + { + *bits_to_go = 8; + currStream->streamBuffer[currStream->byte_pos++] = *byte_buf; + *byte_buf = 0; + } + } + } + else + { + // zeros + for (i = 0; i < (se->len - 32); i++) + { + *byte_buf <<= 1; + + if ((--(*bits_to_go)) == 0) + { + *bits_to_go = 8; + currStream->streamBuffer[currStream->byte_pos++] = *byte_buf; + *byte_buf = 0; + } + } + // actual info + mask = (unsigned int) 1 << 31; + for (i = 0; i < 32; i++) + { + *byte_buf <<= 1; + + if (se->bitpattern & mask) + *byte_buf |= 1; + + mask >>= 1; + + if ((--(*bits_to_go)) == 0) + { + *bits_to_go = 8; + currStream->streamBuffer[currStream->byte_pos++] = *byte_buf; + *byte_buf = 0; + } + } + } +} + + +/*! + ************************************************************************ + * \brief + * generates UVLC code and passes the codeword to the buffer + * \author + * Tian Dong + ************************************************************************ + */ +int writeSyntaxElement2Buf_Fixed(SyntaxElement *se, Bitstream* this_streamBuffer ) +{ + writeUVLC2buffer(se, this_streamBuffer ); + +#if TRACE + if(se->type <= 1) + trace2out (se); +#endif + return (se->len); +} + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +* \author +* Tian Dong +************************************************************************ +*/ +void writeSE_Flag(SyntaxElement *se, DataPartition *dp ) +{ + se->len = 1; + se->bitpattern = (se->value1 & 1); + + writeUVLC2buffer(se, dp->bitstream ); + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif +} + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +* \author +* Tian Dong +************************************************************************ +*/ +void writeSE_invFlag(SyntaxElement *se, DataPartition *dp ) +{ + se->len = 1; + se->bitpattern = 1 - (se->value1 & 1); + + writeUVLC2buffer(se, dp->bitstream ); + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif +} + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +* \author +* Tian Dong +************************************************************************ +*/ +void writeSE_Dummy(SyntaxElement *se, DataPartition *dp ) +{ + se->len = 0; +} + + +/*! +************************************************************************ +* \brief +* generates UVLC code and passes the codeword to the buffer +* \author +* Tian Dong +************************************************************************ +*/ +void writeSE_Fix(SyntaxElement *se, Bitstream *bitstream ) +{ + writeUVLC2buffer(se, bitstream); + +#if TRACE + if(bitstream->trace_enabled) + trace2out (se); +#endif +} + + +/*! + ************************************************************************ + * \brief + * Makes code word and passes it back + * + * \par Input: + * Info : Xn..X2 X1 X0 \n + * Length : Total number of bits in the codeword + ************************************************************************ + */ + +int symbol2vlc(SyntaxElement *sym) +{ + int info_len = sym->len; + + // Convert info into a bitpattern int + sym->bitpattern = 0; + + // vlc coding + while(--info_len >= 0) + { + sym->bitpattern <<= 1; + sym->bitpattern |= (0x01 & (sym->inf >> info_len)); + } + return 0; +} + + +/*! + ************************************************************************ + * \brief + * generates VLC code and passes the codeword to the buffer + ************************************************************************ + */ +int writeSyntaxElement_VLC(SyntaxElement *se, DataPartition *dp) +{ + se->inf = se->value1; + se->len = se->value2; + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for NumCoeff and TrailingOnes + ************************************************************************ + */ + +int writeSyntaxElement_NumCoeffTrailingOnes(SyntaxElement *se, DataPartition *dp) +{ + static const byte lentab[3][4][17] = + { + { // 0702 + { 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16}, + { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16}, + { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16}, + { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}, + }, + { + { 2, 6, 6, 7, 8, 8, 9,11,11,12,12,12,13,13,13,14,14}, + { 0, 2, 5, 6, 6, 7, 8, 9,11,11,12,12,13,13,14,14,14}, + { 0, 0, 3, 6, 6, 7, 8, 9,11,11,12,12,13,13,13,14,14}, + { 0, 0, 0, 4, 4, 5, 6, 6, 7, 9,11,11,12,13,13,13,14}, + }, + { + { 4, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,10}, + { 0, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,10}, + { 0, 0, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10}, + { 0, 0, 0, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9,10,10,10}, + }, + + }; + + static const byte codtab[3][4][17] = + { + { + { 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7,4}, + { 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10,6}, + { 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9,5}, + { 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12,8}, + }, + { + { 3,11, 7, 7, 7, 4, 7,15,11,15,11, 8,15,11, 7, 9,7}, + { 0, 2, 7,10, 6, 6, 6, 6,14,10,14,10,14,10,11, 8,6}, + { 0, 0, 3, 9, 5, 5, 5, 5,13, 9,13, 9,13, 9, 6,10,5}, + { 0, 0, 0, 5, 4, 6, 8, 4, 4, 4,12, 8,12,12, 8, 1,4}, + }, + { + {15,15,11, 8,15,11, 9, 8,15,11,15,11, 8,13, 9, 5,1}, + { 0,14,15,12,10, 8,14,10,14,14,10,14,10, 7,12, 8,4}, + { 0, 0,13,14,11, 9,13, 9,13,10,13, 9,13, 9,11, 7,3}, + { 0, 0, 0,12,11,10, 9, 8,13,12,12,12, 8,12,10, 6,2}, + }, + }; + int vlcnum = se->len; + + // se->value1 : numcoeff + // se->value2 : numtrailingones + + if (vlcnum == 3) + { + se->len = 6; // 4 + 2 bit FLC + if (se->value1 > 0) + { + se->inf = ((se->value1-1) << 2) | se->value2; + } + else + { + se->inf = 3; + } + } + else + { + se->len = lentab[vlcnum][se->value2][se->value1]; + se->inf = codtab[vlcnum][se->value2][se->value1]; + } + + if (se->len == 0) + { + printf("ERROR: (numcoeff,trailingones) not valid: vlc=%d (%d, %d)\n", + vlcnum, se->value1, se->value2); + exit(-1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for NumCoeff and TrailingOnes for Chroma DC + ************************************************************************ + */ +int writeSyntaxElement_NumCoeffTrailingOnesChromaDC(VideoParameters *p_Vid, SyntaxElement *se, DataPartition *dp) +{ + static const byte lentab[3][4][17] = + { + //YUV420 + {{ 2, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 3, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV422 + {{ 1, 7, 7, 9, 9,10,11,12,13, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 2, 7, 7, 9,10,11,12,12, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 3, 7, 7, 9,10,11,12, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 5, 6, 7, 7,10,11, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV444 + {{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16}, + { 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16}, + { 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16}, + { 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16}} + }; + + static const byte codtab[3][4][17] = + { + //YUV420 + {{ 1, 7, 4, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1, 6, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV422 + {{ 1,15,14, 7, 6, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 1,13,12, 5, 6, 6, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 1,11,10, 4, 5, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 1, 1, 9, 8, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0}}, + //YUV444 + {{ 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7, 4}, + { 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10, 6}, + { 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9, 5}, + { 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12, 8}} + + }; + int yuv = p_Vid->yuv_format - 1; + + // se->value1 : numcoeff + // se->value2 : numtrailingones + se->len = lentab[yuv][se->value2][se->value1]; + se->inf = codtab[yuv][se->value2][se->value1]; + + if (se->len == 0) + { + printf("ERROR: (numcoeff,trailingones) not valid: (%d, %d)\n", + se->value1, se->value2); + exit(-1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for TotalZeros + ************************************************************************ + */ +int writeSyntaxElement_TotalZeros(SyntaxElement *se, DataPartition *dp) +{ + static const byte lentab[TOTRUN_NUM][16] = + { + { 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9}, + { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6}, + { 4,3,3,3,4,4,3,3,4,5,5,6,5,6}, + { 5,3,4,4,3,3,3,4,3,4,5,5,5}, + { 4,4,4,3,3,3,3,3,4,5,4,5}, + { 6,5,3,3,3,3,3,3,4,3,6}, + { 6,5,3,3,3,2,3,4,3,6}, + { 6,4,5,3,2,2,3,3,6}, + { 6,6,4,2,2,3,2,5}, + { 5,5,3,2,2,2,4}, + { 4,4,3,3,1,3}, + { 4,4,2,1,3}, + { 3,3,1,2}, + { 2,2,1}, + { 1,1}, + }; + + static const byte codtab[TOTRUN_NUM][16] = + { + {1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1}, + {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0}, + {5,7,6,5,4,3,4,3,2,3,2,1,1,0}, + {3,7,5,4,6,5,4,3,3,2,2,1,0}, + {5,4,3,7,6,5,4,3,2,1,1,0}, + {1,1,7,6,5,4,3,2,1,1,0}, + {1,1,5,4,3,3,2,1,1,0}, + {1,1,1,3,3,2,2,1,0}, + {1,0,1,3,2,1,1,1,}, + {1,0,1,3,2,1,1,}, + {0,1,1,2,1,3}, + {0,1,1,1,1}, + {0,1,1,1}, + {0,1,1}, + {0,1}, + }; + int vlcnum = se->len; + + // se->value1 : TotalZeros + se->len = lentab[vlcnum][se->value1]; + se->inf = codtab[vlcnum][se->value1]; + + if (se->len == 0) + { + printf("ERROR: (TotalZeros) not valid: (%d)\n",se->value1); + exit(-1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for TotalZeros for Chroma DC + ************************************************************************ + */ +int writeSyntaxElement_TotalZerosChromaDC(VideoParameters *p_Vid, SyntaxElement *se, DataPartition *dp) +{ + static const byte lentab[3][TOTRUN_NUM][16] = + { + //YUV420 + {{ 1,2,3,3}, + { 1,2,2}, + { 1,1}}, + //YUV422 + {{ 1,3,3,4,4,4,5,5}, + { 3,2,3,3,3,3,3}, + { 3,3,2,2,3,3}, + { 3,2,2,2,3}, + { 2,2,2,2}, + { 2,2,1}, + { 1,1}}, + //YUV444 + {{ 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9}, + { 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6}, + { 4,3,3,3,4,4,3,3,4,5,5,6,5,6}, + { 5,3,4,4,3,3,3,4,3,4,5,5,5}, + { 4,4,4,3,3,3,3,3,4,5,4,5}, + { 6,5,3,3,3,3,3,3,4,3,6}, + { 6,5,3,3,3,2,3,4,3,6}, + { 6,4,5,3,2,2,3,3,6}, + { 6,6,4,2,2,3,2,5}, + { 5,5,3,2,2,2,4}, + { 4,4,3,3,1,3}, + { 4,4,2,1,3}, + { 3,3,1,2}, + { 2,2,1}, + { 1,1}} + }; + + static const byte codtab[3][TOTRUN_NUM][16] = + { + //YUV420 + {{ 1,1,1,0}, + { 1,1,0}, + { 1,0}}, + //YUV422 + {{ 1,2,3,2,3,1,1,0}, + { 0,1,1,4,5,6,7}, + { 0,1,1,2,6,7}, + { 6,0,1,2,7}, + { 0,1,2,3}, + { 0,1,1}, + { 0,1}}, + //YUV444 + {{1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1}, + {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0}, + {5,7,6,5,4,3,4,3,2,3,2,1,1,0}, + {3,7,5,4,6,5,4,3,3,2,2,1,0}, + {5,4,3,7,6,5,4,3,2,1,1,0}, + {1,1,7,6,5,4,3,2,1,1,0}, + {1,1,5,4,3,3,2,1,1,0}, + {1,1,1,3,3,2,2,1,0}, + {1,0,1,3,2,1,1,1,}, + {1,0,1,3,2,1,1,}, + {0,1,1,2,1,3}, + {0,1,1,1,1}, + {0,1,1,1}, + {0,1,1}, + {0,1}} + }; + int vlcnum = se->len; + int yuv = p_Vid->yuv_format - 1; + + // se->value1 : TotalZeros + se->len = lentab[yuv][vlcnum][se->value1]; + se->inf = codtab[yuv][vlcnum][se->value1]; + + if (se->len == 0) + { + printf("ERROR: (TotalZeros) not valid: (%d)\n",se->value1); + exit(-1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for Run Before Next Coefficient, VLC0 + ************************************************************************ + */ +int writeSyntaxElement_Run(SyntaxElement *se, DataPartition *dp) +{ + static const byte lentab[TOTRUN_NUM][16] = + { + {1,1}, + {1,2,2}, + {2,2,2,2}, + {2,2,2,3,3}, + {2,2,3,3,3,3}, + {2,3,3,3,3,3,3}, + {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11}, + }; + + static const byte codtab[TOTRUN_NUM][16] = + { + {1,0}, + {1,1,0}, + {3,2,1,0}, + {3,2,1,1,0}, + {3,2,3,2,1,0}, + {3,0,1,3,2,5,4}, + {7,6,5,4,3,2,1,1,1,1,1,1,1,1,1}, + }; + int vlcnum = se->len; + + // se->value1 : run + se->len = lentab[vlcnum][se->value1]; + se->inf = codtab[vlcnum][se->value1]; + + if (se->len == 0) + { + printf("ERROR: (run) not valid: (%d)\n",se->value1); + exit(-1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for Coeff Level (VLC1) + ************************************************************************ + */ +int writeSyntaxElement_Level_VLC1(SyntaxElement *se, DataPartition *dp, int profile_idc) +{ + int level = se->value1; + int sign = (level < 0 ? 1 : 0); + int levabs = iabs(level); + + if (levabs < 8) + { + se->len = levabs * 2 + sign - 1; + se->inf = 1; + } + else if (levabs < 16) + { + // escape code1 + se->len = 19; + se->inf = 16 | ((levabs << 1) - 16) | sign; + } + else + { + int iMask = 4096, numPrefix = 0; + int levabsm16 = levabs + 2032; + + // escape code2 + if ((levabsm16) >= 4096) + { + numPrefix++; + while ((levabsm16) >= (4096 << numPrefix)) + { + numPrefix++; + } + } + + iMask <<= numPrefix; + se->inf = iMask | ((levabsm16 << 1) - iMask) | sign; + + /* Assert to make sure that the code fits in the VLC */ + /* make sure that we are in High Profile to represent level_prefix > 15 */ + if (numPrefix > 0 && !is_FREXT_profile( profile_idc )) + { + //error( "level_prefix must be <= 15 except in High Profile\n", 1000 ); + se->len = 0x0000FFFF; // This can be some other big number + return (se->len); + } + + se->len = 28 + (numPrefix << 1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +/*! + ************************************************************************ + * \brief + * write VLC for Coeff Level + ************************************************************************ + */ +int writeSyntaxElement_Level_VLCN(SyntaxElement *se, int vlc, DataPartition *dp, int profile_idc) +{ + int level = se->value1; + int sign = (level < 0 ? 1 : 0); + int levabs = iabs(level) - 1; + + int shift = vlc - 1; + int escape = (15 << shift); + + if (levabs < escape) + { + int sufmask = ~((0xffffffff) << shift); + int suffix = (levabs) & sufmask; + + se->len = ((levabs) >> shift) + 1 + vlc; + se->inf = (2 << shift) | (suffix << 1) | sign; + } + else + { + int iMask = 4096; + int levabsesc = levabs - escape + 2048; + int numPrefix = 0; + + if ((levabsesc) >= 4096) + { + numPrefix++; + while ((levabsesc) >= (4096 << numPrefix)) + { + numPrefix++; + } + } + + iMask <<= numPrefix; + se->inf = iMask | ((levabsesc << 1) - iMask) | sign; + + /* Assert to make sure that the code fits in the VLC */ + /* make sure that we are in High Profile to represent level_prefix > 15 */ + if (numPrefix > 0 && !is_FREXT_profile( profile_idc )) + { + //error( "level_prefix must be <= 15 except in High Profile\n", 1000 ); + se->len = 0x0000FFFF; // This can be some other big number + return (se->len); + } + se->len = 28 + (numPrefix << 1); + } + + symbol2vlc(se); + + writeUVLC2buffer(se, dp->bitstream); + + if(se->type != SE_HEADER) + dp->bitstream->write_flag = 1; + +#if TRACE + if(dp->bitstream->trace_enabled) + trace2out (se); +#endif + + return (se->len); +} + + +#if TRACE +int bitcounter = 0; + +/*! + ************************************************************************ + * \brief + * Write out a trace string on the trace file + ************************************************************************ + */ +void trace2out(SyntaxElement *sym) +{ + int i, chars; + + if (p_Enc->p_trace != NULL) + { + putc('@', p_Enc->p_trace); + chars = fprintf(p_Enc->p_trace, "%i", bitcounter); + while(chars++ < 6) + putc(' ',p_Enc->p_trace); + + chars += fprintf(p_Enc->p_trace, "%s", sym->tracestring); + while(chars++ < 55) + putc(' ',p_Enc->p_trace); + + // align bit pattern + if(sym->len<15) + { + for(i=0 ; i<15-sym->len ; i++) + fputc(' ', p_Enc->p_trace); + } + + // print bit pattern + bitcounter += sym->len; + for(i=1 ; i<=sym->len ; i++) + { + if((sym->bitpattern >> (sym->len-i)) & 0x1) + fputc('1', p_Enc->p_trace); + else + fputc('0', p_Enc->p_trace); + } + fprintf(p_Enc->p_trace, " (%3d) \n",sym->value1); + } + fflush (p_Enc->p_trace); +} + +void trace2out_cabac(SyntaxElement *sym) +{ + int chars; + + if (p_Enc->p_trace != NULL) + { + putc('@', p_Enc->p_trace); + chars = fprintf(p_Enc->p_trace, "%i", bitcounter); + while(chars++ < 6) + putc(' ',p_Enc->p_trace); + + chars += fprintf(p_Enc->p_trace, "%s", sym->tracestring); + while(chars++ < 70) + putc(' ',p_Enc->p_trace); + + fprintf(p_Enc->p_trace, " (%3d) \n",sym->value1); + } + fflush (p_Enc->p_trace); + bitcounter += sym->len; +} +#endif + + +/*! + ************************************************************************ + * \brief + * puts the less than 8 bits in the byte buffer of the Bitstream into + * the streamBuffer. + * + * \param p_Vid + * VideoParameters for current picture encoding + * \param currStream + * the Bitstream the alignment should be established + * \param cur_stats + * currently used statistics parameters + * + ************************************************************************ + */ +void writeVlcByteAlign(VideoParameters *p_Vid, Bitstream* currStream, StatParameters *cur_stats) +{ + if (currStream->bits_to_go < 8) + { // trailing bits to process + currStream->byte_buf = (byte) ((currStream->byte_buf << currStream->bits_to_go) | (0xff >> (8 - currStream->bits_to_go))); + currStream->streamBuffer[currStream->byte_pos++] = currStream->byte_buf; + cur_stats->bit_use_stuffing_bits[p_Vid->type] += currStream->bits_to_go; + currStream->bits_to_go = 8; + } +} + +/*! + ************************************************************************ + * \brief + * Resets the nz_coeff parameters for a macroblock + ************************************************************************/ +void reset_mb_nz_coeff(VideoParameters *p_Vid, int mb_number) +{ + memset(&p_Vid->nz_coeff [mb_number][0][0], 0, BLOCK_SIZE * (BLOCK_SIZE + p_Vid->num_blk8x8_uv) * sizeof(int)); +} + + +void writeUVLC_CAVLC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + writeSE_UVLC(se, dp); +} + +void writeSVLC_CAVLC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + writeSE_SVLC(se, dp); +} + +void writeFlag_CAVLC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp) +{ + writeSE_Flag(se, dp); +} + +int bs_bitlength(Bitstream *bitstream) +{ + return (bitstream->byte_pos*8+(8-bitstream->bits_to_go)); +} + +/*! +************************************************************************ +* \brief +* Dummy function for reference picture bit writing +* \author +************************************************************************ +*/ +void writeRefPic_Dummy(Macroblock *currMB, SyntaxElement *se, DataPartition *dp ) +{ + se->len = 0; +} + +/*! +************************************************************************ +* \brief +* Function for writing the bits for the reference index when up to 2 refs are available +* \author +************************************************************************ +*/ +void writeRefPic_2Ref_CAVLC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp ) +{ + writeSE_invFlag( se, dp ); +} + +/*! +************************************************************************ +* \brief +* Function for writing the bits for the reference index when N (N>2) refs are available +* \author +************************************************************************ +*/ +void writeRefPic_NRef_CAVLC(Macroblock *currMB, SyntaxElement *se, DataPartition *dp ) +{ + writeSE_UVLC( se, dp ); +} + +/*! + ************************************************************************ + * \brief + * Reads bits from the bitstream buffer + * + * \param buffer + * containing VLC-coded data bits + * \param totbitoffset + * bit offset from start of partition + * \param info + * returns value of the read bits + * \param bitcount + * total bytes in bitstream + * \param numbits + * number of bits to read + * + ************************************************************************ + */ +int GetBits (byte *buffer, + int totbitoffset, + int *info, + int bitcount, + int numbits) +{ + if ((totbitoffset + numbits ) > bitcount) + { + return 0; + } + else + { + int bitoffset = 7 - (totbitoffset & 0x07); // bit from start of byte + int byteoffset = (totbitoffset >> 3); // byte from start of buffer + int bitcounter = numbits; + byte *curbyte = &(buffer[byteoffset]); + int inf = 0; + + while (numbits--) + { + inf <<=1; + inf |= ((*curbyte)>> (bitoffset--)) & 0x01; + if (bitoffset == -1 ) + { //Move onto next byte to get all of numbits + curbyte++; + bitoffset = 7; + } + // Above conditional could also be avoided using the following: + // curbyte -= (bitoffset >> 3); + // bitoffset &= 0x07; + } + *info = inf; + + return bitcounter; // return absolute offset in bit from start of frame + } +} diff --git a/lencod/src/weighted_prediction.c b/lencod/src/weighted_prediction.c new file mode 100644 index 0000000..4570f74 --- /dev/null +++ b/lencod/src/weighted_prediction.c @@ -0,0 +1,885 @@ + +/*! +************************************************************************************* +* \file weighted_prediction.c +* +* \brief +* Estimate weights for WP using DC method +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +************************************************************************************* +*/ +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "wp.h" + +/*! +************************************************************************ +* \brief +* Initialize weighting parameter functions +************************************************************************ +*/ +void InitWP(VideoParameters *p_Vid, InputParameters *p_Inp, int force_wp_method) +{ + if(force_wp_method) + { + p_Vid->EstimateWPPSlice = EstimateWPPSliceAlg1; + p_Vid->EstimateWPBSlice = EstimateWPBSliceAlg1; + p_Vid->TestWPPSlice = TestWPPSliceAlg1; + p_Vid->TestWPBSlice = TestWPBSliceAlg1; + } + else + if (p_Inp->WPIterMC && p_Vid->nal_reference_idc) + { + p_Vid->EstimateWPPSlice = EstimateWPPSliceAlg2; + p_Vid->EstimateWPBSlice = EstimateWPBSliceAlg2; + p_Vid->TestWPPSlice = TestWPPSliceAlg2; + p_Vid->TestWPBSlice = TestWPBSliceAlg2; + } + else + { + int wp_method = p_Inp->WPMethod; + switch (wp_method) + { + default: + case 0: + p_Vid->EstimateWPPSlice = EstimateWPPSliceAlg0; + p_Vid->EstimateWPBSlice = EstimateWPBSliceAlg0; + p_Vid->TestWPPSlice = TestWPPSliceAlg0; + p_Vid->TestWPBSlice = TestWPBSliceAlg0; + break; + case 1: + p_Vid->EstimateWPPSlice = EstimateWPPSliceAlg1; + p_Vid->EstimateWPBSlice = EstimateWPBSliceAlg1; + p_Vid->TestWPPSlice = TestWPPSliceAlg1; + p_Vid->TestWPBSlice = TestWPBSliceAlg1; + break; + } + } +} + +void ResetWP(VideoParameters *p_Vid, InputParameters *p_Inp) +{ + short default_weights[3]; + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + int cur_slice, clist, n; + + default_weights[0] = 1 << luma_log_weight_denom; + default_weights[1] = default_weights[2] = 1 << chroma_log_weight_denom; + + p_Vid->wp_parameters_set = 0; + for (cur_slice = 0; cur_slice < p_Vid->num_slices_wp; cur_slice++) + { + for (clist = 0; clist < 2 ; clist++) + { + for (n = 0; n < p_Inp->num_ref_frames; n++) + { + p_Vid->wp_weights[0][clist][n][cur_slice] = default_weights[0]; + p_Vid->wp_offsets[0][clist][n][cur_slice] = 0; + p_Vid->wp_weights[1][clist][n][cur_slice] = default_weights[1]; + p_Vid->wp_offsets[1][clist][n][cur_slice] = 0; + p_Vid->wp_weights[2][clist][n][cur_slice] = default_weights[2]; + p_Vid->wp_offsets[2][clist][n][cur_slice] = 0; + } + } + } +} + +void ComputeImplicitWeights(Slice *currSlice, + short default_weight[3], + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + int i, j, comp; + short tx, td, tb, DistScaleFactor; + + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + td = (short) iClip3(-128, 127,(currSlice->listX[LIST_1][j]->poc - currSlice->listX[LIST_0][i]->poc)); + tb = (short) iClip3(-128, 127,(p_Vid->ThisPOC - currSlice->listX[LIST_0][i]->poc)); + for (comp = 0; comp < 3; comp++) + { + // implicit weights + if (td == 0) + { + im_weight[0][i][j][comp] = default_weight[comp]; + im_weight[1][i][j][comp] = default_weight[comp]; + } + else + { + tx = (short) (16384 + iabs(td >> 1))/td; + DistScaleFactor = sClip3(-1024, 1023, (tx*tb + 32 )>>6); + im_weight[1][i][j][comp] = DistScaleFactor >> 2; + if (im_weight[1][i][j][comp] < -64 || im_weight[1][i][j][comp] >128) + im_weight[1][i][j][comp] = default_weight[comp]; + im_weight[0][i][j][comp] = 64 - im_weight[1][i][j][comp]; + } + } + } + } +} + +/*! +************************************************************************ +* \brief +* Compute sum of samples in a picture +************************************************************************ +*/ +double ComputeImgSum(imgpel **CurrentImage, int height, int width) +{ + int i, j; + double sum_value = 0.0; + imgpel *p_tmp; + + for (i = 0; i < height; i++) + { + p_tmp = CurrentImage[i]; + for (j = 0; j < width; j++) + { + sum_value += (double) *(p_tmp++); + } + } + return sum_value; +} + +static int ComputeBlockSum(imgpel **CurrentImage, int height_in_blk, int width_in_blk, int blk_size_y, int blk_size_x, int cur_blk) +{ + int x, y; + int sum = 0; + + int blkx = cur_blk % width_in_blk; + int blky = cur_blk / width_in_blk; + int blk_start_x = blkx*blk_size_x; + int blk_start_y = blky*blk_size_y; + imgpel *img_ptr; + + for(y = 0; y < blk_size_y; y++) + { + img_ptr = &CurrentImage[blk_start_y + y][blk_start_x]; + for(x = 0; x < blk_size_x; x++) + { + sum += img_ptr[x]; + } + } + + return sum; +} + +void ComputeImgSumBlockBased(imgpel **CurrentImage, + int height_in_blk, int width_in_blk, + int blk_size_y, int blk_size_x, + int start_blk, int end_blk, double *dc) +{ + int cur_blk; + int block_sum; + int64 slice_sum = 0; + + for(cur_blk = start_blk; cur_blk < end_blk; cur_blk++) + { + block_sum = ComputeBlockSum(CurrentImage, height_in_blk, width_in_blk, blk_size_y, blk_size_x, cur_blk); + slice_sum += block_sum; + } + (*dc) = (double) slice_sum; +} + +int64 ComputeSumBlockBased(imgpel **CurrentImage, + int height_in_blk, int width_in_blk, + int blk_size_y, int blk_size_x, + int start_blk, int end_blk) +{ + int cur_blk; + int64 slice_sum = 0; + + for(cur_blk = start_blk; cur_blk < end_blk; cur_blk++) + { + slice_sum += ComputeBlockSum(CurrentImage, height_in_blk, width_in_blk, blk_size_y, blk_size_x, cur_blk); + } + return slice_sum; +} + +/*! +************************************************************************ +* \brief +* Estimates reference picture weighting factors for P slices +************************************************************************ +*/ + +void EstimateWPPSliceAlg0(Slice *currSlice, int select_offset) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + double dc_org = 0.0; + double dc_org_UV[2] = {0.0}; + double dc_ref[MAX_REFERENCE_PICTURES] = { 0.0 }; + double dc_ref_UV[MAX_REFERENCE_PICTURES][2] = { {0.0}}; + + int i, n, k; + short default_weight[3]; + short cur_weight, cur_offset; + int list_offset = ((currSlice->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[2][MAX_REFERENCE_PICTURES][3]; + short offset[2][MAX_REFERENCE_PICTURES][3]; + int clist; + + imgpel **tmpPtr; + + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + + currSlice->wp_luma_round = 1 << (currSlice->luma_log_weight_denom - 1); + currSlice->wp_chroma_round = 1 << (currSlice->chroma_log_weight_denom - 1); + default_weight[0] = 1 << currSlice->luma_log_weight_denom; + default_weight[1] = default_weight[2] = 1 << currSlice->chroma_log_weight_denom; + + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist = 0; clist < 2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + /* set all values to defaults */ + for (i = 0; i < 3; i++) + { + weight[clist][n][i] = default_weight[i]; + currSlice->wp_weight[clist][n][i] = default_weight[i]; + currSlice->wp_offset[clist][n][i] = 0; + offset[clist][n][i] = 0; + } + + // Y + tmpPtr = currSlice->listX[clist][n]->p_curr_img; + dc_ref[n] = ComputeImgSum(tmpPtr, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + // UV + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + } + } + + if (select_offset == 0) + { + if (dc_ref[n] != 0.0) + cur_weight = (short) (default_weight[0] * dc_org / dc_ref[n] + 0.5); + else + cur_weight = default_weight[0]; // only used when reference picture is black + cur_weight = sClip3(-128, 127, cur_weight); + cur_offset = 0; + + weight[clist][n][0] = cur_weight; + offset[clist][n][0] = cur_offset; + + if (p_Inp->ChromaWeightSupport == 1) + { + if (dc_ref_UV[n][0] != 0) + weight[clist][n][1] = (short) (default_weight[1] * dc_org_UV[0] / dc_ref_UV[n][0] + 0.5); + else + weight[clist][n][1] = default_weight[1]; // only used when reference picture is black + weight[clist][n][1] = sClip3(-128, 127, weight[clist][n][1]); + + if (dc_ref_UV[n][1] != 0) + weight[clist][n][2] = (short) (default_weight[2] * dc_org_UV[1] / dc_ref_UV[n][1] + 0.5); + else + weight[clist][n][2] = default_weight[2]; // only used when reference picture is black + weight[clist][n][2] = sClip3(-128, 127, weight[clist][n][2]); + } + } + else + { + cur_offset = (short) ((dc_org - dc_ref[n])/(p_Vid->size)+0.5); + cur_offset = (cur_offset+((p_Vid->bitdepth_luma-8)>>1))>>(p_Vid->bitdepth_luma-8); + cur_offset = sClip3( -128, 127, cur_offset); + cur_offset = cur_offset<<(p_Vid->bitdepth_luma-8); + cur_weight = default_weight[0]; + + weight[clist][n][0] = cur_weight; + offset[clist][n][0] = cur_offset; + + if (p_Inp->ChromaWeightSupport == 1) + { + offset[clist][n][1] = (short) ((dc_org_UV[0] - dc_ref_UV[n][0])/(p_Vid->size_cr)+0.5); + offset[clist][n][1] = (offset[clist][n][1] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][1] = sClip3( -128, 127, offset[clist][n][1]); + offset[clist][n][1] = offset[clist][n][1]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][1] = default_weight[1]; + + offset[clist][n][2] = (short) ((dc_org_UV[1] - dc_ref_UV[n][1])/(p_Vid->size_cr)+0.5); + offset[clist][n][2] = (offset[clist][n][2] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][2] = sClip3( -128, 127, offset[clist][n][2]); + offset[clist][n][2] = offset[clist][n][2]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][2] = default_weight[2]; + } + } + + for (i=0; i < 3; i ++) + { + currSlice->wp_weight[clist][n][i] = weight[clist][n][i]; + currSlice->wp_offset[clist][n][i] = offset[clist][n][i]; +#if DEBUG_WP + printf("index %d component %d weight %d offset %d\n",n,i,weight[0][n][i],offset[0][n][i]); +#endif + } + } + } + } +} + +/*! +************************************************************************ +* \brief +* Estimates reference picture weighting factors for B slices +************************************************************************ +*/ +void EstimateWPBSliceAlg0(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int i, j, k, n; + + int index; + int comp; + double dc_org = 0.0; + double dc_org_UV[2] = { 0.0 }; + double dc_ref[6][MAX_REFERENCE_PICTURES] = { {0.0} }; + double dc_ref_UV[6][MAX_REFERENCE_PICTURES][2] = { {{0.0}} }; + + short default_weight[3]; + int list_offset = ((currSlice->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[6][MAX_REFERENCE_PICTURES][3]; + short offset[6][MAX_REFERENCE_PICTURES][3]; + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + int clist; + short wf_weight, wf_offset; + imgpel **tmpPtr; + + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode. Values are fixed and it is important to show it here + { + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + } + else //! explicit mode. Values can be changed for higher precision. + { + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + } + + currSlice->wp_luma_round = 1 << (currSlice->luma_log_weight_denom - 1); + currSlice->wp_chroma_round = 1 << (currSlice->chroma_log_weight_denom - 1); + default_weight[0] = 1 << currSlice->luma_log_weight_denom; + default_weight[1] = 1 << currSlice->chroma_log_weight_denom; + default_weight[2] = 1 << currSlice->chroma_log_weight_denom; + + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode + { + ComputeImplicitWeights(currSlice, default_weight, im_weight); + + for (k = 0; k < 2; k++) + { + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[k][i][j][comp] = im_weight[k][i][j][comp]; + } + } + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wp_weight[clist][index][comp] = default_weight[comp]; + currSlice->wp_offset[clist][index][comp] = 0; + } + } + } + } + else + { + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + /* set all values to defaults */ + for (i = 0; i < 3; i++) + { + currSlice->wp_weight[clist][n][i] = default_weight[i]; + currSlice->wp_offset[clist][n][i] = 0; + offset [clist][n][i] = 0; + weight [clist][n][i] = default_weight[i]; + } + // To simplify these computations we may wish to perform these after a reference is + // stored in the reference buffer and attach them to the storedimage structure!!! + // Y + tmpPtr = currSlice->listX[clist][n]->p_curr_img; + dc_ref[clist][n] = ComputeImgSum(tmpPtr, p_Vid->height, p_Vid->width); + + if (dc_ref[clist][n] != 0.0) + wf_weight = (short) (default_weight[0] * dc_org / dc_ref[clist][n] + 0.5); + else + wf_weight = default_weight[0]; // only used when reference picture is black + wf_weight = sClip3(-128, 127, wf_weight); + wf_offset = 0; + + // printf("dc_org = %d, dc_ref = %d, weight[%d] = %d\n",dc_org, dc_ref[n],n,weight[n][0]); + + weight[clist][n][0] = wf_weight; + offset[clist][n][0] = wf_offset; + + // UV + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[clist][n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + + if (dc_ref_UV[clist][n][k] != 0.0) + wf_weight = (short) (default_weight[k + 1] * dc_org_UV[k] / dc_ref_UV[clist][n][k] + 0.5); + else + wf_weight = default_weight[k + 1]; // only used when reference picture is black + wf_weight = sClip3(-128, 127, wf_weight); + wf_offset = 0; + + weight[clist][n][k + 1] = wf_weight; + offset[clist][n][k + 1] = wf_offset; + } + } + else + { + weight[clist][n][1] = default_weight[1]; + weight[clist][n][2] = default_weight[2]; + offset[clist][n][1] = 0; + offset[clist][n][2] = 0; + } + + for (i = 0; i < 3; i++) + { + currSlice->wp_weight[clist][n][i] = weight[clist][n][i]; + currSlice->wp_offset[clist][n][i] = offset[clist][n][i]; +#if DEBUG_WP + printf("%d %d\n",currSlice->wp_weight[clist][index][comp],currSlice->wp_offset[clist][index][comp]); +#endif + } + } + } + } + + if (p_Vid->active_pps->weighted_bipred_idc != 1) + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + memcpy(currSlice->wp_weight[clist][index], default_weight, 3 * sizeof(short)); + memset(currSlice->wp_offset[clist][index], 0, 3 * sizeof(short)); + } + } + } + + + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[0][i][j][comp] = currSlice->wp_weight[0][i][comp]; + currSlice->wbp_weight[1][i][j][comp] = currSlice->wp_weight[1][j][comp]; + } +#if DEBUG_WP + printf ("bpw weight[%d][%d] = %d , %d (%d %d %d) (%d %d) (%d %d)\n", i, j, currSlice->wbp_weight[0][i][j][0], currSlice->wbp_weight[1][i][j][0], + p_Vid->enc_picture->poc,currSlice->listX[LIST_0][i]->poc, currSlice->listX[LIST_1][j]->poc, + DistScaleFactor ,tx,tx,tx); +#endif + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Tests P slice weighting factors to perform or not WP RD decision +************************************************************************ +*/ + +int TestWPPSliceAlg0(Slice *currSlice, int select_offset) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j, k, n; + + int index; + int comp; + double dc_org = 0.0; + double dc_org_UV[2] = {0.0}; + double dc_ref[MAX_REFERENCE_PICTURES] = { 0.0 }; + double dc_ref_UV[MAX_REFERENCE_PICTURES][2] = { {0.0}}; + + short default_weight[3]; + + int list_offset = ((p_Vid->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[2][MAX_REFERENCE_PICTURES][3]; + short offset[2][MAX_REFERENCE_PICTURES][3]; + //short wp_weight[6][MAX_REFERENCE_PICTURES][3]; + //short wp_offset[6][MAX_REFERENCE_PICTURES][3]; + int clist; + int perform_wp = 0; + imgpel **tmpPtr; + + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = default_weight[2] = 1 << chroma_log_weight_denom; + + /* set all values to defaults */ + for (i = 0; i < 2 + list_offset; i++) + { + for (j = 0; j < currSlice->listXsize[i]; j++) + { + for (n = 0; n < 3; n++) + { + weight[i][j][n] = default_weight[n]; + //wp_weight[i][j][n] = default_weight[n]; + //wp_offset[i][j][n] = 0; + offset[i][j][n] = 0; + } + } + } + + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist = 0; clist < 2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + tmpPtr = currSlice->listX[clist][n]->p_curr_img; + dc_ref[n] = ComputeImgSum(tmpPtr, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + } + } + + if (select_offset == 0) + { + if (dc_ref[n] != 0.0) + weight[clist][n][0] = (short) (default_weight[0] * dc_org / dc_ref[n] + 0.5); + else + weight[clist][n][0] = default_weight[0]; // only used when reference picture is black + weight[clist][n][0] = sClip3(-128, 127, weight[clist][n][0]); + + if (p_Inp->ChromaWeightSupport == 1) + { + if (dc_ref_UV[n][0] != 0) + weight[clist][n][1] = (short) (default_weight[1] * dc_org_UV[0] / dc_ref_UV[n][0] + 0.5); + else + weight[clist][n][1] = default_weight[1]; // only used when reference picture is black + weight[clist][n][1] = sClip3(-128, 127, weight[clist][n][1]); + + if (dc_ref_UV[n][1] != 0) + weight[clist][n][2] = (short) (default_weight[2] * dc_org_UV[1] / dc_ref_UV[n][1] + 0.5); + else + weight[clist][n][2] = default_weight[2]; // only used when reference picture is black + weight[clist][n][2] = sClip3(-128, 127, weight[clist][n][2]); + } + } + else + { + offset[clist][n][0] = (short) ((dc_org - dc_ref[n])/(p_Vid->size)+0.5); + offset[clist][n][0] = (offset[clist][n][0]+((p_Vid->bitdepth_luma-8)>>1))>>(p_Vid->bitdepth_luma-8); + offset[clist][n][0] = sClip3( -128, 127, offset[clist][n][0]); + offset[clist][n][0] = offset[clist][n][0]<<(p_Vid->bitdepth_luma-8); + weight[clist][n][0] = default_weight[0]; + + if (p_Inp->ChromaWeightSupport == 1) + { + offset[clist][n][1] = (short) ((dc_org_UV[0] - dc_ref_UV[n][0])/(p_Vid->size_cr)+0.5); + offset[clist][n][1] = (offset[clist][n][1] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][1] = sClip3( -128, 127, offset[clist][n][1]); + offset[clist][n][1] = offset[clist][n][1]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][1] = default_weight[1]; + + offset[clist][n][2] = (short) ((dc_org_UV[1] - dc_ref_UV[n][1])/(p_Vid->size_cr)+0.5); + offset[clist][n][2] = (offset[clist][n][2] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][2] = sClip3( -128, 127, offset[clist][n][2]); + offset[clist][n][2] = offset[clist][n][2]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][2] = default_weight[2]; + } + } + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp=0; comp < 3; comp ++) + { + int offset_test = p_Inp->RDPSliceBTest && p_Vid->active_sps->profile_idc != BASELINE + ? iabs(offset[clist][index][comp]) > 2 + : offset[clist][index][comp] != 0; + + if (weight[clist][index][comp] != default_weight[0] || offset_test) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + if (perform_wp == 1) break; + } + + return perform_wp; +} + +/*! +************************************************************************ +* \brief +* TestWPBSliceAlg0: +* Tests B slice weighting prediction +************************************************************************ +*/ +int TestWPBSliceAlg0(Slice *currSlice, int select_method) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j, k, n; +#if (MVC_EXTENSION_ENABLE) + int view_id = p_Vid->view_id; +#else + int view_id = 0; +#endif + + int index; + int comp; + double dc_org = 0.0; + double dc_org_UV[2] = { 0.0 }; + double dc_ref[6][MAX_REFERENCE_PICTURES] = { {0.0} }; + double dc_ref_UV[6][MAX_REFERENCE_PICTURES][2] = { {{0.0}} }; + + short default_weight[3]; + // this needs to be fixed. + int list_offset = ((p_Vid->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[6][MAX_REFERENCE_PICTURES][3]; + short offset[6][MAX_REFERENCE_PICTURES][3]; + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + short wp_weight[6][MAX_REFERENCE_PICTURES][3]; + short wp_offset[6][MAX_REFERENCE_PICTURES][3]; + //short wbp_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + + int clist; + short wf_weight, wf_offset; + int perform_wp = 1; + imgpel **tmpPtr; + + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = 1 << chroma_log_weight_denom; + default_weight[2] = 1 << chroma_log_weight_denom; + + /* set all values to defaults */ + for (i = 0; i < 2 + list_offset; i++) + { + for (j = 0; j < currSlice->listXsize[i]; j++) + { + for (n = 0; n < 3; n++) + { + wp_weight[i][j][n] = default_weight[n]; + wp_offset[i][j][n] = 0; + weight [i][j][n] = default_weight[n]; + offset [i][j][n] = 0; + } + } + } + + if (select_method == 1) //! implicit mode + { + ComputeImplicitWeights(currSlice, default_weight, im_weight); + + perform_wp = 0; + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + if (im_weight[1][i][j][0] != default_weight[0] || im_weight[1][i][j][0] != default_weight[0]) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + } + else + { + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + // To simplify these computations we may wish to perform these after a reference is + // stored in the reference buffer and attach them to the storedimage structure!!! + // Y + tmpPtr = currSlice->listX[clist][n]->p_curr_img; + dc_ref[clist][n] = ComputeImgSum(tmpPtr, p_Vid->height, p_Vid->width); + + if (dc_ref[clist][n] != 0.0) + wf_weight = (short) (default_weight[0] * dc_org / dc_ref[clist][n] + 0.5); + else + wf_weight = default_weight[0]; // only used when reference picture is black + wf_weight = sClip3(-128, 127, wf_weight); + wf_offset = 0; + + weight[clist][n][0] = wf_weight; + offset[clist][n][0] = wf_offset; + + // UV + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[clist][n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + + if (dc_ref_UV[clist][n][k] != 0.0) + wf_weight = (short) (default_weight[k + 1] * dc_org_UV[k] / dc_ref_UV[clist][n][k] + 0.5); + else + wf_weight = default_weight[k + 1]; // only used when reference picture is black + wf_weight = sClip3(-128, 127, wf_weight); + wf_offset = 0; + + weight[clist][n][k + 1] = wf_weight; + offset[clist][n][k + 1] = wf_offset; + } + } + else + { + weight[clist][n][1] = default_weight[1]; + weight[clist][n][2] = default_weight[2]; + offset[clist][n][1] = 0; + offset[clist][n][2] = 0; + } + } + } + + if (select_method == 0) //! explicit mode + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + memcpy(p_Vid->currentSlice->wp_weight[clist][index], weight[clist][index], 3 * sizeof(short)); + memcpy(p_Vid->currentSlice->wp_offset[clist][index], offset[clist][index], 3 * sizeof(short)); + } + } + } + else + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + memcpy(wp_weight[clist][index], default_weight, 3 * sizeof(short)); + memset(wp_offset[clist][index], 0, 3 * sizeof(short)); + } + } + } + } + + if (select_method == 0) //! explicit mode + { + int active_refs[2]; + + active_refs[0] = (p_Inp->B_List0_refs == 0 ? currSlice->listXsize[0] : imin(p_Inp->B_List0_refs[view_id], currSlice->listXsize[0])); + active_refs[1] = (p_Inp->B_List1_refs == 0 ? currSlice->listXsize[1] : imin(p_Inp->B_List1_refs[view_id], currSlice->listXsize[1])); + + perform_wp = 0; + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < active_refs[clist]; index++) + { + for (comp=0; comp < 3; comp ++) + { + if (wp_weight[clist][index][comp] != default_weight[comp]) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + if (perform_wp == 1) break; + } + } + return perform_wp; +} diff --git a/lencod/src/wp_lms.c b/lencod/src/wp_lms.c new file mode 100644 index 0000000..c46ad2f --- /dev/null +++ b/lencod/src/wp_lms.c @@ -0,0 +1,886 @@ + +/*! +************************************************************************************* +* \file wp_lms.c +* +* \brief +* Estimate weights for WP using LMS method +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Alexis Michael Tourapis +* - Athanasios Leontaris +* - Yan Ye +************************************************************************************* +*/ +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "wp.h" + + +static double ComputeBlockNormMean(imgpel **CurrentImage, + int height_in_blk, int width_in_blk, + int blk_size_y, int blk_size_x, + int cur_blk, double dc_mean) +{ + int blkx, blky; + int x, y; + double sum = 0.; + imgpel *img_ptr; + + blkx = cur_blk % width_in_blk; + blky = cur_blk / width_in_blk; + + for(y = 0; y < blk_size_y; y++) + { + img_ptr = &CurrentImage[blky*blk_size_y+y][blkx*blk_size_x]; + for(x = 0; x < blk_size_x; x++) + { + sum += dabs((double)img_ptr[x]-dc_mean); + } + } + + return sum; +} + +static void ComputeNormMeanBlockBased(imgpel **CurrentImage, int height_in_blk, int width_in_blk, + int blk_size_y, int blk_size_x, + int start_blk, int end_blk, + double dc_mean, double *norm_slice) +{ + int cur_blk; + double block_norm; + double norm; + + { + norm = 0.; + for(cur_blk = start_blk; cur_blk < end_blk; cur_blk++) + { + block_norm = ComputeBlockNormMean(CurrentImage, height_in_blk, width_in_blk, blk_size_y, blk_size_x, cur_blk, dc_mean); + norm += block_norm; + } + (*norm_slice) = (double) norm; + } +} + +void ComputeExplicitWPParamsLMS(Slice *currSlice, + int select_offset, + int start_mb, + int end_mb, + short default_weight[3], + short weight[6][MAX_REFERENCE_PICTURES][3], + short offset[6][MAX_REFERENCE_PICTURES][3]) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int clist, n, k, comp; + int slice_size, slice_size_cr; + + double dc_org[3]; + double dc_ref[3]; + double norm_org[3]; + double norm_ref[3]; + double numer[3]; + double denom[3]; + short cur_weight, cur_offset; + int bit_depth = (p_Vid->bitdepth_luma - 8); + + imgpel **cur_ref; + + for (clist=0; clist< 2; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + for (comp = 0; comp < 3; comp++) + { + weight[clist][n][comp] = default_weight[comp]; + offset[clist][n][comp] = 0; + } + } + } + + slice_size = (end_mb-start_mb)*MB_BLOCK_SIZE*MB_BLOCK_SIZE; + slice_size_cr = (end_mb-start_mb)*p_Vid->mb_cr_size_x*p_Vid->mb_cr_size_y; + + ComputeImgSumBlockBased(p_Vid->pCurImg, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, MB_BLOCK_SIZE, MB_BLOCK_SIZE, + start_mb, end_mb, &dc_org[0]); + + norm_org[0] = dc_org[0]/((double) slice_size); + ComputeNormMeanBlockBased(p_Vid->pCurImg, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, MB_BLOCK_SIZE, MB_BLOCK_SIZE, + start_mb, end_mb, norm_org[0], &numer[0]); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + ComputeImgSumBlockBased(p_Vid->pImgOrg[k + 1], p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, + start_mb, end_mb, &dc_org[k+1]); + } + } + + for (clist = 0; clist < 2; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + cur_ref = currSlice->listX[clist][n]->p_curr_img; + ComputeImgSumBlockBased(cur_ref, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, MB_BLOCK_SIZE, MB_BLOCK_SIZE, + start_mb, end_mb, &dc_ref[0]); + norm_ref[0] = dc_ref[0] / ((double) slice_size); + ComputeNormMeanBlockBased(cur_ref, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, MB_BLOCK_SIZE, MB_BLOCK_SIZE, + start_mb, end_mb, norm_ref[0], &denom[0]); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + cur_ref = currSlice->listX[clist][n]->imgUV[k]; + ComputeImgSumBlockBased(cur_ref, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, + start_mb, end_mb, &dc_ref[k+1]); + } + } + + if (select_offset == 0) + { + if (denom[0] != 0) + cur_weight = (short) (default_weight[0] * numer[0] / denom[0] + 0.5); + else + cur_weight = default_weight[0]; // only used when reference picture is black + cur_weight = sClip3(-128, 127, cur_weight); + + cur_offset = (short) (norm_org[0] - ((double) cur_weight * norm_ref[0] / (double) default_weight[0]) + 0.5); + cur_offset = (short) ((cur_offset + (bit_depth>>1)) >> bit_depth); + cur_offset = sClip3( -128, 127, cur_offset); + cur_offset = (short) (cur_offset << bit_depth); + weight[clist][n][0] = cur_weight; + offset[clist][n][0] = cur_offset; + + if (p_Inp->ChromaWeightSupport == 1) + { + if (dc_ref[1] != 0) + cur_weight = (short) (default_weight[1] * dc_org[1] / dc_ref[1] + 0.5); + else + cur_weight = default_weight[1]; // only used when reference picture is black + weight[clist][n][1] = sClip3(-128, 127, cur_weight); + + if (dc_ref[2] != 0) + cur_weight = (short) (default_weight[2] * dc_org[2] / dc_ref[2] + 0.5); + else + cur_weight = default_weight[2]; // only used when reference picture is black + weight[clist][n][2] = sClip3(-128, 127, cur_weight); + } + } + else + { + cur_offset = (short) ((dc_org[0] - dc_ref[0])/(slice_size)+0.5); + cur_offset = (cur_offset+((p_Vid->bitdepth_luma-8)>>1))>>(p_Vid->bitdepth_luma-8); + cur_offset = sClip3( -128, 127, cur_offset); + cur_offset = cur_offset<<(p_Vid->bitdepth_luma-8); + cur_weight = default_weight[0]; + + weight[clist][n][0] = cur_weight; + offset[clist][n][0] = cur_offset; + + if (p_Inp->ChromaWeightSupport == 1) + { + cur_offset = (short) ((dc_org[1] - dc_ref[1])/(slice_size_cr)+0.5); + cur_offset = (cur_offset + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + cur_offset = sClip3( -128, 127, cur_offset); + offset[clist][n][1] = cur_offset<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][1] = default_weight[1]; + + cur_offset = (short) ((dc_org[2] - dc_ref[2])/(slice_size_cr)+0.5); + cur_offset = (cur_offset + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + cur_offset = sClip3( -128, 127, cur_offset); + offset[clist][n][2] = cur_offset<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][2] = default_weight[2]; + } + } + } + } +} + + +void ComputeExplicitWPParamsJNT(Slice *currSlice, + int start_mb, + int end_mb, + short default_weight[3], + short weight[6][MAX_REFERENCE_PICTURES][3], + short offset[6][MAX_REFERENCE_PICTURES][3]) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int clist, n, k, comp; + + // all these should be converted to int64 + int64 dc_org[3]; + int64 dc_cur_ref[2][MAX_REFERENCE_PICTURES][3]; + short w0 = default_weight[0], w1 = default_weight[0]; + + imgpel **cur_ref; + + for (clist=0; clist< 2; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + for (comp = 0; comp < 3; comp++) + { + weight[clist][n][comp] = default_weight[comp]; + offset[clist][n][comp] = 0; + } + } + } + + dc_org[0] = ComputeSumBlockBased (p_Vid->pCurImg, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, MB_BLOCK_SIZE, MB_BLOCK_SIZE, + start_mb, end_mb); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org[k+1] = ComputeSumBlockBased(p_Vid->pImgOrg[k + 1], p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, + start_mb, end_mb); + } + } + + for (clist = 0; clist < 2; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + cur_ref = currSlice->listX[clist][n]->p_curr_img; + dc_cur_ref[clist][n][0] = ComputeSumBlockBased (cur_ref, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, MB_BLOCK_SIZE, MB_BLOCK_SIZE, start_mb, end_mb); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + cur_ref = currSlice->listX[clist][n]->imgUV[k]; + dc_cur_ref[clist][n][k+1] = ComputeSumBlockBased (cur_ref, p_Vid->FrameHeightInMbs, p_Vid->PicWidthInMbs, p_Vid->mb_cr_size_y, p_Vid->mb_cr_size_x, start_mb, end_mb); + } + } + } + } + + // setup list 1 references using zero ref of LIST_0 + for (n = 0; n < currSlice->listXsize[LIST_1]; n++) + { + + double temp_weight = ( (double)(dc_cur_ref[LIST_1][n][0] - dc_org[0]) / (double) (dc_org[0] - dc_cur_ref[LIST_0][0][0])); + + w0 = (short) (((double) default_weight[0] * 2 * temp_weight) / ( 1.0 + temp_weight) + 0.5); + w1 = (short) (((double) default_weight[0] * 2) / ( 1.0 + temp_weight) + 0.5); + + //printf("%.2f %.2f %.2f %.2f %d %d\n",temp_weight,dc_ref[1][0],dc_ref[0][0], dc_org[0], cm_weight[0 + list_offset][i][j][0] ,cm_weight[1 + list_offset][i][j][0] ); + if (w0 <= 0 || w1 <= 0) + { + w0 = default_weight[0]; + w1 = default_weight[0]; + } + + if (w1 < -64 || w1 > 128 || w0 < -64 || w0 >128) + { + w0 = default_weight[0]; + w1 = default_weight[0]; + } + + weight[LIST_1][n][0] = w1; + offset[LIST_1][n][0] = 0; + + if (p_Inp->ChromaWeightSupport == 1) + { + weight[LIST_1][n][1] = (short) ((double)(default_weight[1] * w1) / (double) default_weight[0]); + weight[LIST_1][n][2] = (short) ((double)(default_weight[2] * w1) / (double) default_weight[0]); + } + } + + // now set LIST_0 weights with 0 reference of LIST_1 + for (n = 0; n < currSlice->listXsize[LIST_0]; n++) + { + double temp_weight = ( (double)(dc_cur_ref[LIST_1][0][0] - dc_org[0]) / (double) (dc_org[0] - dc_cur_ref[LIST_0][n][0])); + + w0 = (short) (((double) default_weight[0] * 2 * temp_weight) / ( 1.0 + temp_weight) + 0.5); + w1 = (short) (((double) default_weight[0] * 2) / ( 1.0 + temp_weight) + 0.5); + + if (w0 <= 0 || w1 <= 0) + { + w0 = default_weight[0]; + w1 = default_weight[0]; + } + + if (w1 < -64 || w1 > 128 || w0 < -64 || w0 >128) + { + w0 = default_weight[0]; + w1 = default_weight[0]; + } + + weight[LIST_0][n][0] = w0; + offset[LIST_0][n][0] = 0; + + if (p_Inp->ChromaWeightSupport == 1) + { + weight[LIST_0][n][1] = (short) ((double)(default_weight[1] * w0) / (double) default_weight[0]); + weight[LIST_0][n][2] = (short) ((double)(default_weight[2] * w0) / (double) default_weight[0]); + } + } +} + +/*! +************************************************************************ +* \brief +* Estimates reference picture weighting factors for P slices +************************************************************************ +*/ + +void EstimateWPPSliceAlg1(Slice *currSlice, int select_offset) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + + int i, n; + short default_weight[3]; + int list_offset = ((currSlice->mb_aff_frame_flag) && (p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + int clist; + + int cur_slice; + + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + + currSlice->wp_luma_round = 1 << (currSlice->luma_log_weight_denom - 1); + currSlice->wp_chroma_round = 1 << (currSlice->chroma_log_weight_denom - 1); + default_weight[0] = 1 << currSlice->luma_log_weight_denom; + default_weight[1] = default_weight[2] = 1 << currSlice->chroma_log_weight_denom; + + if(p_Inp->slice_mode == 1) + { + cur_slice = p_Vid->current_mb_nr / p_Inp->slice_argument; + } + else + cur_slice = 0; + + if(p_Vid->wp_parameters_set == 0) + { + int start_mb, end_mb; + int comp; + + short weight[2][MAX_REFERENCE_PICTURES][3]; + short offset[2][MAX_REFERENCE_PICTURES][3]; + + if(p_Inp->slice_mode == 1) + { + start_mb = cur_slice * p_Inp->slice_argument; + end_mb = start_mb + p_Inp->slice_argument; + if(end_mb > (int)p_Vid->FrameSizeInMbs) + end_mb = p_Vid->FrameSizeInMbs; + } + else + { + start_mb = 0; + end_mb = p_Vid->FrameSizeInMbs; + } + + ComputeExplicitWPParamsLMS(currSlice, select_offset, start_mb, end_mb, default_weight, weight, offset); + + for (clist = 0; clist < 2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + for (comp=0; comp < 3; comp ++) + { + currSlice->wp_weight[clist][n][comp] = weight[clist][n][comp]; + currSlice->wp_offset[clist][n][comp] = offset[clist][n][comp]; + if(p_Vid->wp_weights) + p_Vid->wp_weights[comp][clist][n][cur_slice] = weight[clist][n][comp]; + if(p_Vid->wp_offsets) + p_Vid->wp_offsets[comp][clist][n][cur_slice] = offset[clist][n][comp]; + } +#if DEBUG_WP + for(comp = 0; comp < 3; comp++) + printf("slice %d: index %d component %d weight %d offset %d\n", cur_slice, n,comp,currSlice->wp_weight[clist][n][comp],currSlice->wp_offset[clist][n][comp]); +#endif + } + } + } + } + else + { + for (clist = 0; clist < 2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + for (i=0; i < 3; i ++) + { + currSlice->wp_weight[clist][n][i] = p_Vid->wp_weights[i][clist][n][cur_slice]; + currSlice->wp_offset[clist][n][i] = p_Vid->wp_offsets[i][clist][n][cur_slice]; +#if DEBUG_WP + printf("slice %d: index %d component %d weight %d offset %d\n", cur_slice, n,i,currSlice->wp_weight[clist][n][i],currSlice->wp_offset[clist][n][i]); +#endif + } + } + } + } + } +} + +/*! +************************************************************************ +* \brief +* Estimates reference picture weighting factors for B slices +************************************************************************ +*/ +void EstimateWPBSliceAlg1(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int i, j, n; + + int comp; + int k; + + short default_weight[3]; + int list_offset = ((currSlice->mb_aff_frame_flag) && (p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + int clist; + int cur_slice = 0; + + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode. Values are fixed and it is important to show it here + { + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + } + else //! explicit mode. Values can be changed for higher precision. + { + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + } + + currSlice->wp_luma_round = 1 << (currSlice->luma_log_weight_denom - 1); + currSlice->wp_chroma_round = 1 << (currSlice->chroma_log_weight_denom - 1); + default_weight[0] = 1 << currSlice->luma_log_weight_denom; + default_weight[1] = 1 << currSlice->chroma_log_weight_denom; + default_weight[2] = 1 << currSlice->chroma_log_weight_denom; + + if(p_Inp->slice_mode == 1) + { + cur_slice = p_Vid->current_mb_nr / p_Inp->slice_argument ; + } + else + cur_slice = 0; + + if (p_Vid->wp_parameters_set == 0) // single-pass coding + { + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode + { + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + + ComputeImplicitWeights(currSlice, default_weight, im_weight); + + for (k = 0; k < 2; k++) + { + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[k][i][j][comp] = im_weight[k][i][j][comp]; + } + } + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (i = 0; i < currSlice->listXsize[clist]; i++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wp_weight[clist][i][comp] = default_weight[comp]; + currSlice->wp_offset[clist][i][comp] = 0; + } + } + } + } + else // explicit mode + { + int start_mb, end_mb; + + int comp; + + short wp_weight[6][MAX_REFERENCE_PICTURES][3]; + short wp_offset[6][MAX_REFERENCE_PICTURES][3]; + + if(p_Inp->slice_mode == 1) + { + start_mb = cur_slice * p_Inp->slice_argument; + end_mb = start_mb + p_Inp->slice_argument; + if(end_mb > (int)p_Vid->FrameSizeInMbs) + end_mb = p_Vid->FrameSizeInMbs; + } + else + { + start_mb = 0; + end_mb = p_Vid->FrameSizeInMbs; + } + + if (p_Inp->EnhancedBWeightSupport == 2) + ComputeExplicitWPParamsJNT(currSlice, start_mb, end_mb, default_weight, wp_weight, wp_offset); + else + ComputeExplicitWPParamsLMS(currSlice, 0, start_mb, end_mb, default_weight, wp_weight, wp_offset); + + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + for (comp=0; comp < 3; comp ++) + { + currSlice->wp_weight[clist][n][comp] = wp_weight[clist][n][comp]; + currSlice->wp_offset[clist][n][comp] = wp_offset[clist][n][comp]; + if(p_Vid->wp_weights) + p_Vid->wp_weights[comp][clist][n][cur_slice] = wp_weight[clist][n][comp]; + if(p_Vid->wp_offsets) + p_Vid->wp_offsets[comp][clist][n][cur_slice] = wp_offset[clist][n][comp]; + } + } + } + } + + if (p_Vid->active_pps->weighted_bipred_idc != 1) + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + memcpy(currSlice->wp_weight[clist][n], default_weight, 3 * sizeof(short)); + memset(currSlice->wp_offset[clist][n], 0, 3 * sizeof(short)); + } + } + } + + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[0][i][j][comp] = currSlice->wp_weight[0][i][comp]; + currSlice->wbp_weight[1][i][j][comp] = currSlice->wp_weight[1][j][comp]; + } + } + } + } + } + else // multiple-pass coding, WP parameters have been decided and stored + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode + { + for (k = 0; k < 2; k++) + { + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[k][i][j][comp] = p_Vid->wbp_weight[comp][k][i][j][cur_slice]; + } + } + } + } + } + else // explicit WP mode (or no WP at all) + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) // use WP with pre-stored parameters + { + for (i=0; i < 3; i ++) + { + currSlice->wp_weight[clist][n][i] = p_Vid->wp_weights[i][clist][n][cur_slice]; + currSlice->wp_offset[clist][n][i] = p_Vid->wp_offsets[i][clist][n][cur_slice]; + } + } + } + } + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[0][i][j][comp] = currSlice->wp_weight[0][i][comp]; + currSlice->wbp_weight[1][i][j][comp] = currSlice->wp_weight[1][j][comp]; + } + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Tests P slice weighting factors to perform or not WP RD decision +************************************************************************ +*/ +int TestWPPSliceAlg1(Slice *currSlice, int select_offset) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j, n; + + int index; + int comp; + + short default_weight[3]; + + int list_offset = ((p_Vid->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[6][MAX_REFERENCE_PICTURES][3]; + short offset[6][MAX_REFERENCE_PICTURES][3]; + int clist; + int perform_wp = 0; + + int cur_slice, num_slice; + int start_mb, end_mb; + + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = default_weight[2] = 1 << chroma_log_weight_denom; + + /* set all values to defaults */ + for (i = 0; i < 2 + list_offset; i++) + { + for (j = 0; j < currSlice->listXsize[i]; j++) + { + for (n = 0; n < 3; n++) + { + weight[i][j][n] = default_weight[n]; + offset[i][j][n] = 0; + } + } + } + + num_slice = p_Vid->num_slices_wp; + for(cur_slice = 0; cur_slice < num_slice; cur_slice++) + { + if(p_Inp->slice_mode == 1) + { + start_mb = cur_slice * p_Inp->slice_argument; + end_mb = start_mb + p_Inp->slice_argument; + if(end_mb > (int)p_Vid->FrameSizeInMbs) + end_mb = p_Vid->FrameSizeInMbs; + } + else + { + start_mb = 0; + end_mb = p_Vid->FrameSizeInMbs; + } + + ComputeExplicitWPParamsLMS(currSlice, select_offset, start_mb, end_mb, default_weight, weight, offset); + + for (clist = 0; clist < 2; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + for (comp=0; comp < 3; comp ++) + { + p_Vid->wp_weights[comp][clist][n][cur_slice] = weight[clist][n][comp]; + p_Vid->wp_offsets[comp][clist][n][cur_slice] = offset[clist][n][comp]; + } +#if DEBUG_WP + printf ("weight[%d][%d][0] = %d\n", clist, n, weight[clist][n][0]); + printf ("offset[%d][%d][0] = %d\n", clist, n, offset[clist][n][0]); + printf ("weight[%d][%d][1] = %d\n", clist, n, weight[clist][n][1]); + printf ("offset[%d][%d][1] = %d\n", clist, n, offset[clist][n][1]); + printf ("weight[%d][%d][2] = %d\n", clist, n, weight[clist][n][2]); + printf ("offset[%d][%d][2] = %d\n", clist, n, offset[clist][n][2]); +#endif + } + } + } + + perform_wp = 0; + for(cur_slice = 0; cur_slice < num_slice; cur_slice++) + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp=0; comp < 3; comp ++) + { + int offset_test = p_Inp->RDPSliceBTest && p_Vid->active_sps->profile_idc != BASELINE + ? iabs(p_Vid->wp_offsets[comp][clist][index][cur_slice]) > 2 + : p_Vid->wp_offsets[comp][clist][index][cur_slice] != 0; + + if (p_Vid->wp_weights[comp][clist][index][cur_slice] != default_weight[comp] || offset_test) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + if (perform_wp == 1) break; + } + if(perform_wp == 1) break; + } + + p_Vid->wp_parameters_set = 1; + + return perform_wp; +} + + +/*! +************************************************************************ +* \brief +* TestWPBSliceAlg1: +* Tests B slice weighting prediction +************************************************************************ +*/ +int TestWPBSliceAlg1(Slice *currSlice, int select_method) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j, n; + + int index, comp; + + short default_weight[3]; + // this needs to be fixed. + int list_offset = ((p_Vid->mb_aff_frame_flag) && (p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + short wp_weight[6][MAX_REFERENCE_PICTURES][3]; + short wp_offset[6][MAX_REFERENCE_PICTURES][3]; + + int cur_slice, num_slice; + int start_mb, end_mb; + + int clist; + int perform_wp = 1; + + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = 1 << chroma_log_weight_denom; + default_weight[2] = 1 << chroma_log_weight_denom; + + if (select_method == 1) //! implicit WP + { + cur_slice = 0; + num_slice = p_Vid->num_slices_wp; + + ComputeImplicitWeights(currSlice, default_weight, im_weight); + + perform_wp = 1; + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + short weight0, weight1; + + if(perform_wp) + { + weight0 = im_weight[0][i][j][comp]; + weight1 = im_weight[1][i][j][comp]; + } + else + { + weight0 = default_weight[comp]; + weight1 = default_weight[comp]; + } + + // propagate implicit weights to all slices + for(cur_slice = 0; cur_slice < num_slice; cur_slice++) + { + p_Vid->wbp_weight[comp][0][i][j][cur_slice] = weight0; + p_Vid->wbp_weight[comp][1][i][j][cur_slice] = weight1; + } + } + } + } + } + else // explicit WP + { + num_slice = p_Vid->num_slices_wp; + for(cur_slice = 0; cur_slice < num_slice; cur_slice++) + { + if(p_Inp->slice_mode == 1) + { + start_mb = cur_slice * p_Inp->slice_argument; + end_mb = start_mb + p_Inp->slice_argument; + if(end_mb > (int)p_Vid->FrameSizeInMbs) + end_mb = p_Vid->FrameSizeInMbs; + } + else + { + start_mb = 0; + end_mb = p_Vid->FrameSizeInMbs; + } + + if (p_Inp->EnhancedBWeightSupport == 2) + ComputeExplicitWPParamsJNT(currSlice, start_mb, end_mb, default_weight, wp_weight, wp_offset); + else + ComputeExplicitWPParamsLMS(currSlice, 0, start_mb, end_mb, default_weight, wp_weight, wp_offset); + + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + for (comp=0; comp < 3; comp ++) + { + p_Vid->wp_weights[comp][clist][n][cur_slice] = wp_weight[clist][n][comp]; + p_Vid->wp_offsets[comp][clist][n][cur_slice] = wp_offset[clist][n][comp]; + } +#if DEBUG_WP + printf ("weight[%d][%d] = %d\n", clist, n, wp_weight[clist][n][0]); + printf ("offset[%d][%d] = %d\n", clist, n, wp_offset[clist][n][0]); +#endif + } + } + } + + perform_wp = 0; + for(cur_slice = 0; cur_slice < num_slice; cur_slice++) + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp=0; comp < 3; comp ++) + { + if (p_Vid->wp_weights[comp][clist][index][cur_slice] != default_weight[comp] || + p_Vid->wp_offsets[comp][clist][index][cur_slice] != 0) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + if (perform_wp == 1) break; + } + if(perform_wp == 1) break; + } + } + + p_Vid->wp_parameters_set = 1; + + return perform_wp; +} + + diff --git a/lencod/src/wp_mciter.c b/lencod/src/wp_mciter.c new file mode 100644 index 0000000..2359eec --- /dev/null +++ b/lencod/src/wp_mciter.c @@ -0,0 +1,874 @@ +/*! +************************************************************************************* +* \file wp_mciter.c +* +* \brief +* Estimate weights for WP using iterative MC method +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +************************************************************************************* +*/ +#include "contributors.h" + +#include +#include + +#include "global.h" +#include "image.h" +#include "wp.h" + +/*! +************************************************************************ +* \brief +* Estimates reference picture weighting factors for P slices +************************************************************************ +*/ + +void EstimateWPPSliceAlg2(Slice *currSlice, int select_offset) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + double dc_org = 0.0; + double dc_org_UV[2] = {0.0}; + double dc_ref[MAX_REFERENCE_PICTURES] = { 0.0 }; + double dc_ref_UV[MAX_REFERENCE_PICTURES][2] = { {0.0}}; + + int i, n, k; + short default_weight[3]; + int list_offset = ((currSlice->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[2][MAX_REFERENCE_PICTURES][3]; + short offset[2][MAX_REFERENCE_PICTURES][3]; + int clist; + + imgpel **tmpPtr; + + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + + currSlice->wp_luma_round = 1 << (currSlice->luma_log_weight_denom - 1); + currSlice->wp_chroma_round = 1 << (currSlice->chroma_log_weight_denom - 1); + default_weight[0] = 1 << currSlice->luma_log_weight_denom; + default_weight[1] = default_weight[2] = 1 << currSlice->chroma_log_weight_denom; + + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist = 0; clist < 2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + /* set all values to defaults */ + for (i = 0; i < 3; i++) + { + weight[clist][n][i] = default_weight[i]; + currSlice->wp_weight[clist][n][i] = default_weight[i]; + currSlice->wp_offset[clist][n][i] = 0; + offset[clist][n][i] = 0; + } + + // Y + tmpPtr = currSlice->listX[clist][n]->p_curr_img; + dc_ref[n] = ComputeImgSum(tmpPtr, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + // UV + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + } + } + + if (select_offset == 0) + { + if (dc_ref[n] != 0.0) + weight[clist][n][0] = (short) (default_weight[0] * dc_org / dc_ref[n] + 0.5); + else + weight[clist][n][0] = default_weight[0]; // only used when reference picture is black + weight[clist][n][0] = sClip3(-128, 127, weight[clist][n][0]); + if (p_Inp->ChromaWeightSupport == 1) + { + if (dc_ref_UV[n][0] != 0) + weight[clist][n][1] = (short) (default_weight[1] * dc_org_UV[0] / dc_ref_UV[n][0] + 0.5); + else + weight[clist][n][1] = default_weight[1]; // only used when reference picture is black + weight[clist][n][1] = sClip3(-128, 127, weight[clist][n][1]); + + if (dc_ref_UV[n][1] != 0) + weight[clist][n][2] = (short) (default_weight[2] * dc_org_UV[1] / dc_ref_UV[n][1] + 0.5); + else + weight[clist][n][2] = default_weight[2]; // only used when reference picture is black + weight[clist][n][2] = sClip3(-128, 127, weight[clist][n][2]); + } + } + else + { + offset[clist][n][0] = p_Vid->frameOffset[clist][n]; + + offset[clist][n][0] = (offset[clist][n][0]+((p_Vid->bitdepth_luma-8)>>1))>>(p_Vid->bitdepth_luma - 8); + offset[clist][n][0] = sClip3( -128, 127, offset[clist][n][0]); + offset[clist][n][0] = offset[clist][n][0]<<(p_Vid->bitdepth_luma-8); + weight[clist][n][0] = default_weight[0]; + + if (p_Inp->ChromaWeightSupport == 1) + { + offset[clist][n][1] = (short) ((dc_org_UV[0] - dc_ref_UV[n][0])/(p_Vid->size_cr)+0.5); + offset[clist][n][1] = (offset[clist][n][1] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma - 8); + offset[clist][n][1] = sClip3( -128, 127, offset[clist][n][1]); + offset[clist][n][1] = offset[clist][n][1]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][1] = default_weight[1]; + + offset[clist][n][2] = (short) ((dc_org_UV[1] - dc_ref_UV[n][1])/(p_Vid->size_cr)+0.5); + offset[clist][n][2] = (offset[clist][n][2] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][2] = sClip3( -128, 127, offset[clist][n][2]); + offset[clist][n][2] = offset[clist][n][2]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][2] = default_weight[2]; + } + } + + for (i=0; i < 3; i ++) + { + currSlice->wp_weight[clist][n][i] = weight[clist][n][i]; + currSlice->wp_offset[clist][n][i] = offset[clist][n][i]; +#if DEBUG_WP + printf("index %d component %d weight %d offset %d\n",n,i,weight[0][n][i],offset[0][n][i]); +#endif + } + } + } + } +} + +/*! +************************************************************************ +* \brief +* Estimates reference picture weighting factors for B slices +************************************************************************ +*/ +void EstimateWPBSliceAlg2(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int i, j, k, n; + + short tx, tb, td, DistScaleFactor; + + int index; + int comp; + //double dc_org = 0.0; + double dc_org_UV[2] = { 0.0 }; + double dc_ref_UV[6][MAX_REFERENCE_PICTURES][2] = { {{0.0}} }; + + short default_weight[3]; + int list_offset = ((currSlice->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[6][MAX_REFERENCE_PICTURES][3]; + short offset[6][MAX_REFERENCE_PICTURES][3]; + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + int clist; + short wf_weight, wf_offset; + imgpel **tmpPtr; + + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode. Values are fixed and it is important to show it here + { + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + } + else //! explicit mode. Values can be changed for higher precision. + { + currSlice->luma_log_weight_denom = 5; + currSlice->chroma_log_weight_denom = 5; + } + + currSlice->wp_luma_round = 1 << (currSlice->luma_log_weight_denom - 1); + currSlice->wp_chroma_round = 1 << (currSlice->chroma_log_weight_denom - 1); + default_weight[0] = 1 << currSlice->luma_log_weight_denom; + default_weight[1] = 1 << currSlice->chroma_log_weight_denom; + default_weight[2] = 1 << currSlice->chroma_log_weight_denom; + + if (p_Vid->active_pps->weighted_bipred_idc == 2) //! implicit mode + { + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + td = (short) iClip3(-128, 127,(currSlice->listX[LIST_1][j]->poc - currSlice->listX[LIST_0][i]->poc)); + tb = (short)iClip3(-128, 127,(p_Vid->enc_picture->poc - currSlice->listX[LIST_0][i]->poc)); + for (comp = 0; comp < 3; comp++) + { + // implicit weights + if (td == 0) + { + im_weight[0][i][j][comp] = default_weight[comp]; + im_weight[1][i][j][comp] = default_weight[comp]; + } + else + { + tx = (short) (16384 + iabs(td >> 1))/td; + DistScaleFactor = (short) iClip3(-1024, 1023, (tx*tb + 32 )>>6); + im_weight[1][i][j][comp] = DistScaleFactor>>2; + if (im_weight[1][i][j][comp] < -64 || im_weight[1][i][j][comp] >128) + im_weight[1][i][j][comp] = default_weight[comp]; + im_weight[0][i][j][comp] = 64 - im_weight[1][i][j][comp]; + } + } +#if DEBUG_WP + printf ("%d imp weight[%d][%d] = %d , %d (%d %d %d) (%d %d) (%d %d)\n",p_Vid->enc_picture->poc, i, j, im_weight[0][i][j][0], im_weight[1][i][j][0], + p_Vid->enc_picture->poc,currSlice->listX[LIST_0][i]->poc, currSlice->listX[LIST_1][j]->poc, + DistScaleFactor ,tx,td,tb); +#endif + } + } + + for (k = 0; k < 2; k++) + { + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[k][i][j][comp] = im_weight[k][i][j][comp]; + } + } + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wp_weight[clist][index][comp] = default_weight[comp]; + currSlice->wp_offset[clist][index][comp] = 0; + } + } + } + } + else + { + //dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + if ( wpxDetermineWP( currSlice, clist, n ) ) + { + /* set all values to defaults */ + for (i = 0; i < 3; i++) + { + currSlice->wp_weight[clist][n][i] = default_weight[i]; + currSlice->wp_offset[clist][n][i] = 0; + offset [clist][n][i] = 0; + weight [clist][n][i] = default_weight[i]; + } + + offset[clist][n][0] = wf_offset = p_Vid->frameOffset[clist][n]; + weight[clist][n][0] = wf_weight = default_weight[0]; + + + // UV + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[clist][n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + + if (dc_ref_UV[clist][n][k] != 0.0) + wf_weight = (short) (default_weight[k + 1] * dc_org_UV[k] / dc_ref_UV[clist][n][k] + 0.5); + else + wf_weight = default_weight[k + 1]; // only used when reference picture is black + wf_weight = sClip3(-128, 127, wf_weight); + wf_offset = 0; + + weight[clist][n][k + 1] = wf_weight; + offset[clist][n][k + 1] = wf_offset; + } + } + else + { + weight[clist][n][1] = default_weight[1]; + weight[clist][n][2] = default_weight[2]; + offset[clist][n][1] = 0; + offset[clist][n][2] = 0; + } + + for (i = 0; i < 3; i++) + { + currSlice->wp_weight[clist][n][i] = weight[clist][n][i]; + currSlice->wp_offset[clist][n][i] = offset[clist][n][i]; +#if DEBUG_WP + printf("%d %d\n",currSlice->wp_weight[clist][index][comp],currSlice->wp_offset[clist][index][comp]); +#endif + } + } + } + } + + if (p_Vid->active_pps->weighted_bipred_idc != 1) + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + memcpy(currSlice->wp_weight[clist][index], default_weight, 3 * sizeof(short)); + memset(currSlice->wp_offset[clist][index], 0, 3 * sizeof(short)); + } + } + } + + + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + currSlice->wbp_weight[0][i][j][comp] = currSlice->wp_weight[0][i][comp]; + currSlice->wbp_weight[1][i][j][comp] = currSlice->wp_weight[1][j][comp]; + } +#if DEBUG_WP + printf ("bpw weight[%d][%d] = %d , %d (%d %d %d) (%d %d) (%d %d)\n", i, j, currSlice->wbp_weight[0][i][j][0], currSlice->wbp_weight[1][i][j][0], + p_Vid->enc_picture->poc,currSlice->listX[LIST_0][i]->poc, currSlice->listX[LIST_1][j]->poc, + DistScaleFactor ,tx,tx,tx); +#endif + } + } + } +} + + +/*! +************************************************************************ +* \brief +* Tests P slice weighting factors to perform or not WP RD decision +************************************************************************ +*/ + +int TestWPPSliceAlg2(Slice *currSlice, int select_offset) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j, k, n; + + int index; + int comp; + double dc_org = 0.0; + double dc_org_UV[2] = {0.0}; + double dc_ref[MAX_REFERENCE_PICTURES] = { 0.0 }; + double dc_ref_UV[MAX_REFERENCE_PICTURES][2] = { {0.0}}; + + short default_weight[3]; + + int list_offset = ((p_Vid->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[2][MAX_REFERENCE_PICTURES][3]; + short offset[2][MAX_REFERENCE_PICTURES][3]; + short wp_weight[6][MAX_REFERENCE_PICTURES][3]; + short wp_offset[6][MAX_REFERENCE_PICTURES][3]; + int clist; + int perform_wp = 0; + imgpel **tmpPtr; + + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = default_weight[2] = 1 << chroma_log_weight_denom; + + /* set all values to defaults */ + for (i = 0; i < 2 + list_offset; i++) + { + for (j = 0; j < currSlice->listXsize[i]; j++) + { + for (n = 0; n < 3; n++) + { + weight[i][j][n] = default_weight[n]; + wp_weight[i][j][n] = default_weight[n]; + wp_offset[i][j][n] = 0; + offset[i][j][n] = 0; + } + } + } + + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist = 0; clist < 2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + tmpPtr = currSlice->listX[clist][n]->p_curr_img; + dc_ref[n] = ComputeImgSum(tmpPtr, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + } + } + + if (select_offset == 0) + { + if (dc_ref[n] != 0.0) + weight[clist][n][0] = (short) (default_weight[0] * dc_org / dc_ref[n] + 0.5); + else + weight[clist][n][0] = default_weight[0]; // only used when reference picture is black + weight[clist][n][0] = sClip3(-128, 127, weight[clist][n][0]); + if (p_Inp->ChromaWeightSupport == 1) + { + if (dc_ref_UV[n][0] != 0) + weight[clist][n][1] = (short) (default_weight[1] * dc_org_UV[0] / dc_ref_UV[n][0] + 0.5); + else + weight[clist][n][1] = default_weight[1]; // only used when reference picture is black + weight[clist][n][1] = sClip3(-128, 127, weight[clist][n][1]); + + if (dc_ref_UV[n][1] != 0) + weight[clist][n][2] = (short) (default_weight[2] * dc_org_UV[1] / dc_ref_UV[n][1] + 0.5); + else + weight[clist][n][2] = default_weight[2]; // only used when reference picture is black + weight[clist][n][2] = sClip3(-128, 127, weight[clist][n][2]); + } + } + else + { + offset[clist][n][0] = p_Vid->frameOffset[clist][n]; + + offset[clist][n][0] = (offset[clist][n][0]+((p_Vid->bitdepth_luma-8)>>1))>>(p_Vid->bitdepth_luma-8); + offset[clist][n][0] = sClip3( -128, 127, offset[clist][n][0]); + offset[clist][n][0] = offset[clist][n][0]<<(p_Vid->bitdepth_luma-8); + weight[clist][n][0] = default_weight[0]; + + if (p_Inp->ChromaWeightSupport == 1) + { + offset[clist][n][1] = (short) ((dc_org_UV[0] - dc_ref_UV[n][0])/(p_Vid->size_cr)+0.5); + offset[clist][n][1] = (offset[clist][n][1] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][1] = sClip3( -128, 127, offset[clist][n][1]); + offset[clist][n][1] = offset[clist][n][1]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][1] = default_weight[1]; + + offset[clist][n][2] = (short) ((dc_org_UV[1] - dc_ref_UV[n][1])/(p_Vid->size_cr)+0.5); + offset[clist][n][2] = (offset[clist][n][2] + ((p_Vid->bitdepth_chroma - 8)>>1))>>(p_Vid->bitdepth_chroma-8); + offset[clist][n][2] = sClip3( -128, 127, offset[clist][n][2]); + offset[clist][n][2] = offset[clist][n][2]<<(p_Vid->bitdepth_chroma - 8); + + weight[clist][n][2] = default_weight[2]; + } + } + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp=0; comp < 3; comp ++) + { + int offset_test = p_Inp->RDPSliceBTest && p_Vid->active_sps->profile_idc != BASELINE + ? iabs(offset[clist][index][comp]) > 2 + : offset[clist][index][comp] != 0; + + if (weight[clist][index][comp] != default_weight[0] || offset_test) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + if (perform_wp == 1) break; + } + + return perform_wp; +} + +/*! +************************************************************************ +* \brief +* TestWPBSliceAlg2: +* Tests B slice weighting prediction +************************************************************************ +*/ +int TestWPBSliceAlg2(Slice *currSlice, int select_method) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = p_Vid->p_Inp; + int i, j, k, n; +#if (MVC_EXTENSION_ENABLE) + int view_id = p_Vid->view_id; +#else + int view_id = 0; +#endif + + short tx, td, tb, DistScaleFactor; + + int index; + int comp; + double dc_org = 0.0; + double dc_org_UV[2] = { 0.0 }; + double dc_ref_UV[6][MAX_REFERENCE_PICTURES][2] = { {{0.0}} }; + + short default_weight[3]; + // this needs to be fixed. + int list_offset = ((p_Vid->mb_aff_frame_flag)&&(p_Vid->mb_data[p_Vid->current_mb_nr].mb_field))? (p_Vid->current_mb_nr & 0x01) ? 4 : 2 : 0; + short weight[6][MAX_REFERENCE_PICTURES][3]; + short offset[6][MAX_REFERENCE_PICTURES][3]; + short im_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + short wp_weight[6][MAX_REFERENCE_PICTURES][3]; + short wp_offset[6][MAX_REFERENCE_PICTURES][3]; + short wbp_weight[6][MAX_REFERENCE_PICTURES][MAX_REFERENCE_PICTURES][3]; + + int clist; + short wf_weight, wf_offset; + int perform_wp = 0; + imgpel **tmpPtr; + + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = 1 << chroma_log_weight_denom; + default_weight[2] = 1 << chroma_log_weight_denom; + + /* set all values to defaults */ + for (i = 0; i < 2 + list_offset; i++) + { + for (j = 0; j < currSlice->listXsize[i]; j++) + { + for (n = 0; n < 3; n++) + { + wp_weight[i][j][n] = default_weight[n]; + wp_offset[i][j][n] = 0; + offset [i][j][n] = 0; + weight [i][j][n] = default_weight[n]; + } + } + } + + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + td = (short) iClip3(-128, 127,(currSlice->listX[LIST_1][j]->poc - currSlice->listX[LIST_0][i]->poc)); + tb = (short) iClip3(-128, 127,(p_Vid->enc_picture->poc - currSlice->listX[LIST_0][i]->poc)); + for (comp = 0; comp < 3; comp++) + { + // implicit weights + if (td == 0) + { + im_weight[0][i][j][comp] = default_weight[comp]; + im_weight[1][i][j][comp] = default_weight[comp]; + } + else + { + tx = (short) (16384 + iabs(td >> 1))/td; + DistScaleFactor = sClip3(-1024, 1023, (tx*tb + 32 )>>6); + im_weight[1][i][j][comp] = DistScaleFactor >> 2; + if (im_weight[1][i][j][comp] < -64 || im_weight[1][i][j][comp] >128) + im_weight[1][i][j][comp] = default_weight[comp]; + im_weight[0][i][j][comp] = 64 - im_weight[1][i][j][comp]; + } + } + } + } + + + if (select_method == 1) //! implicit mode + { + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + wbp_weight[1][i][j][comp] = im_weight[1][i][j][comp] ; + wbp_weight[0][i][j][comp] = im_weight[0][i][j][comp]; + } + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + for (comp = 0; comp < 3; comp++) + { + wp_weight[clist][index][comp] = default_weight[comp]; + wp_offset[clist][index][comp] = 0; + } + } + } + } + else + { + dc_org = ComputeImgSum(p_Vid->pCurImg, p_Vid->height, p_Vid->width); + + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + dc_org_UV[k] = ComputeImgSum(p_Vid->pImgOrg[k + 1], p_Vid->height_cr, p_Vid->width_cr); + } + } + + for (clist=0; clist<2 + list_offset; clist++) + { + for (n = 0; n < currSlice->listXsize[clist]; n++) + { + offset[clist][n][0] = wf_offset = p_Vid->frameOffset[clist][n]; + weight[clist][n][0] = wf_weight = default_weight[0]; + + // UV + if (p_Inp->ChromaWeightSupport == 1) + { + for (k = 0; k < 2; k++) + { + tmpPtr = currSlice->listX[clist][n]->imgUV[k]; + dc_ref_UV[clist][n][k] = ComputeImgSum(tmpPtr, p_Vid->height_cr, p_Vid->width_cr); + + if (dc_ref_UV[clist][n][k] != 0.0) + wf_weight = (short) (default_weight[k + 1] * dc_org_UV[k] / dc_ref_UV[clist][n][k] + 0.5); + else + wf_weight = default_weight[k + 1]; // only used when reference picture is black + wf_weight = sClip3(-128, 127, wf_weight); + wf_offset = 0; + + weight[clist][n][k + 1] = wf_weight; + offset[clist][n][k + 1] = wf_offset; + } + } + else + { + weight[clist][n][1] = default_weight[1]; + weight[clist][n][2] = default_weight[2]; + offset[clist][n][1] = 0; + offset[clist][n][2] = 0; + } + } + } + + if (select_method == 0) //! explicit mode + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + memcpy(p_Vid->currentSlice->wp_weight[clist][index], weight[clist][index], 3 * sizeof(short)); + memcpy(p_Vid->currentSlice->wp_offset[clist][index], offset[clist][index], 3 * sizeof(short)); + } + } + } + else + { + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < currSlice->listXsize[clist]; index++) + { + memcpy(wp_weight[clist][index], default_weight, 3 * sizeof(short)); + memset(wp_offset[clist][index], 0, 3 * sizeof(short)); + } + } + } + + for (i = 0; i < currSlice->listXsize[LIST_0]; i++) + { + for (j = 0; j < currSlice->listXsize[LIST_1]; j++) + { + for (comp = 0; comp < 3; comp++) + { + wbp_weight[0][i][j][comp] = wp_weight[0][i][comp]; + wbp_weight[1][i][j][comp] = wp_weight[1][j][comp]; + } +#if DEBUG_WP + printf ("bpw weight[%d][%d] = %d , %d (%d %d %d) (%d %d) (%d %d)\n", i, j, p_Vid->currentSlice->wbp_weight[0][i][j][0], p_Vid->currentSlice->wbp_weight[1][i][j][0], + p_Vid->enc_picture->poc,currSlice->listX[LIST_0][i]->poc, currSlice->listX[LIST_1][j]->poc, + DistScaleFactor ,tx,tx,tx); +#endif + } + } + } + + if (select_method == 0) //! implicit mode + { + int active_refs[2]; + + active_refs[0] = (p_Inp->B_List0_refs == 0 ? currSlice->listXsize[0] : imin(p_Inp->B_List0_refs[view_id], currSlice->listXsize[0])); + active_refs[1] = (p_Inp->B_List1_refs == 0 ? currSlice->listXsize[1] : imin(p_Inp->B_List1_refs[view_id], currSlice->listXsize[1])); + + for (clist=0; clist<2 + list_offset; clist++) + { + for (index = 0; index < active_refs[clist]; index++) + { + for (comp=0; comp < 3; comp ++) + { + if (wp_weight[clist][index][comp] != default_weight[comp]) + { + perform_wp = 1; + break; + } + } + if (perform_wp == 1) break; + } + if (perform_wp == 1) break; + } + } + return perform_wp; +} + +void compute_offset(Slice *currSlice) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + PicMotionParams **motion = p_Vid->enc_picture->mv_info; + Macroblock *currMB; + int i, j, x, y, xj, yi, temp, valOrg; + int mvx=0, mvy=0; + int ref_frame=0; + int subblock=0; + int x_orig, y_orig; + int x_pos, y_pos; + int out4Y_width = (p_Vid->width + IMG_PAD_SIZE_X) * 4 - 1; + int out4Y_height = (p_Vid->height + IMG_PAD_SIZE_Y) * 4 - 1; + + int frame, list, offset; + double dtemp; + int numlists = (p_Vid->type == B_SLICE) ? 2 : 1; + + + for(list = 0; list < 2; list++) + { + for(frame = 0; frame < MAX_REFERENCE_PICTURES; frame++) + { + p_Vid->frameOffsetTotal[list][frame] = 0; + p_Vid->frameOffsetCount[list][frame] = 0; + } + } + + + for(i=0; iheight >> 4; i++) //y + { + for(j=0; jwidth >> 4; j++) //x + { + { + currMB = &p_Vid->mb_data[((i*p_Vid->width) >> 4)+j]; + if(IS_INTRA(currMB)) //intra macroblocks are not used for calculation of the filter coeffs. + continue; + + x_orig = MB_BLOCK_SIZE*j; + y_orig = MB_BLOCK_SIZE*i; + + for(subblock = 0; subblock < 16; subblock++) + { + //List 0 + x = x_orig+4*(subblock & 0x03); + y = y_orig+4*(subblock >> 2); + mvx = motion[y >> 2][x >> 2].mv[LIST_0].mv_x; + mvy = motion[y >> 2][x >> 2].mv[LIST_0].mv_y; + ref_frame = motion[y >> 2][x >> 2].ref_idx[LIST_0]; + + if(ref_frame != -1) + { + for(yi = 0; yi < 4; yi++) + { //y + for(xj = 0; xj < 4; xj++) + { //x + valOrg = p_Vid->pCurImg[y+yi][x+xj]; + + //y_pos = imax(0,imin(out4Y_height,4*(y+yi)+4*IMG_PAD_SIZE+mvy)); + y_pos = imax(-4*IMG_PAD_SIZE_Y, imin(out4Y_height, 4*(y+yi)+mvy)); + //x_pos = imax(0,imin(out4Y_width, 4*(x+xj)+4*IMG_PAD_SIZE+mvx)); + x_pos = imax(-4*IMG_PAD_SIZE_X, imin(out4Y_width, 4*(x+xj)+mvx)); + + temp=currSlice->listX[LIST_0][ref_frame]->p_curr_img_sub[(y_pos & 0x03)][(x_pos & 0x03)][y_pos >> 2][x_pos >> 2]; + p_Vid->frameOffsetTotal[LIST_0][ref_frame]+=(valOrg-temp); + p_Vid->frameOffsetCount[LIST_0][ref_frame]++; + } + } + } + + + //List 1 + mvx = motion[y >> 2][x >> 2].mv[LIST_1].mv_x; + mvy = motion[y >> 2][x >> 2].mv[LIST_1].mv_y; + ref_frame = motion[y >> 2][x >> 2].ref_idx[LIST_1]; + if(ref_frame != -1) + { + for(yi = 0; yi < 4; yi++) + { //y + for(xj = 0; xj < 4; xj++) + { //x + valOrg = p_Vid->pCurImg[y+yi][x+xj]; + + //y_pos = imax(0,imin(out4Y_height,4*(y+yi)+4*IMG_PAD_SIZE+mvy)); + y_pos = imax(-4*IMG_PAD_SIZE_Y, imin(out4Y_height, 4*(y+yi) + mvy)); + //x_pos = imax(0, imin(out4Y_width, 4*(x+xj)+4*IMG_PAD_SIZE+mvx)); + x_pos = imax(-4*IMG_PAD_SIZE_X, imin(out4Y_width, 4*(x+xj) + mvx)); + + temp=currSlice->listX[LIST_0][ref_frame]->p_curr_img_sub[(y_pos & 0x03)][(x_pos & 0x03)][y_pos >> 2][x_pos >> 2]; + p_Vid->frameOffsetTotal[LIST_1][ref_frame]+=(valOrg-temp); + p_Vid->frameOffsetCount[LIST_1][ref_frame]++; + } + } + } + }// for(subblock = 0; subblock < 16; subblock++) + } + } + + for(list = 0; list < numlists; list++) + { + for(frame = 0; frame < currSlice->listXsize[list]; frame++) + { + dtemp=(double)p_Vid->frameOffsetTotal[list][frame]; + + if (p_Vid->frameOffsetCount[list][frame]>0) + { + offset=(int)(fabs(dtemp)/(double)p_Vid->frameOffsetCount[list][frame]+0.5); + if (p_Vid->frameOffsetTotal[list][frame]>=0) + { + p_Vid->frameOffset[list][frame] = (short) offset; + } + else + { + p_Vid->frameOffset[list][frame] = (short) -offset; + } + //printf("list %d frame %d offset %d frameOffsetCount %d, frameOffsetTotal %d\n", list, frame, p_Vid->frameOffset[list][frame], p_Vid->frameOffsetCount[list][frame], p_Vid->frameOffsetTotal[list][frame]); + } + //else + //{ + //printf("list %d frame %d, frameOffsetCount=0\n", list, frame); + //} + } + } + } +} diff --git a/lencod/src/wp_mcprec.c b/lencod/src/wp_mcprec.c new file mode 100644 index 0000000..cbd731f --- /dev/null +++ b/lencod/src/wp_mcprec.c @@ -0,0 +1,375 @@ + +/*! +************************************************************************************* +* \file wp_mcprec.c +* +* \brief +* Improved Motion Compensation Precision Scheme using Weighted Prediction +* +* \author +* Main contributors (see contributors.h for copyright, address and affiliation details) +* - Athanasios Leontaris +* - Alexis Michael Tourapis +************************************************************************************* +*/ +#include "contributors.h" + +#include "global.h" +#include "image.h" +#include "slice.h" +#include "list_reorder.h" +#include "wp_mcprec.h" +#include "memalloc.h" + +/*! +************************************************************************ +* \brief +* Initialize WPR object structure +************************************************************************ +*/ + +void wpxInitWPXObject( VideoParameters *p_Vid ) +{ + p_Vid->pWPX = (WPXObject *)malloc( sizeof( WPXObject ) ); + if ( p_Vid->pWPX == NULL ) + { + fprintf( stdout, "\n Error initializing memory for WPXObject. Exiting...\n" ); + exit(1); + } + + // wp_ref_l0 + if ((p_Vid->pWPX->wp_ref_list[LIST_0] = (WeightedPredRefX *) calloc(MAX_REFERENCE_PICTURES, sizeof(WeightedPredRefX))) == NULL) + no_mem_exit("wpxInitWPXObject: p_Vid->pWPX->wp_ref_list[0]"); + // wp_ref_l1 + if ((p_Vid->pWPX->wp_ref_list[LIST_1] = (WeightedPredRefX *) calloc(MAX_REFERENCE_PICTURES, sizeof(WeightedPredRefX))) == NULL) + no_mem_exit("wpxInitWPXObject: p_Vid->pWPX->wp_ref_list[1]"); +} + +/*! +************************************************************************ +* \brief +* Free WPR object structure +************************************************************************ +*/ + +void wpxFreeWPXObject( VideoParameters *p_Vid ) +{ + // wp_ref_l0 + if (p_Vid->pWPX->wp_ref_list[LIST_0]) + free(p_Vid->pWPX->wp_ref_list[LIST_0]); + p_Vid->pWPX->wp_ref_list[LIST_0] = NULL; + // wp_ref_l1 + if (p_Vid->pWPX->wp_ref_list[LIST_1]) + free(p_Vid->pWPX->wp_ref_list[LIST_1]); + p_Vid->pWPX->wp_ref_list[LIST_1] = NULL; + + if ( p_Vid->pWPX != NULL ) + { + free( p_Vid->pWPX ); + } +} + +/*! +************************************************************************ +* \brief +* Initialize WPR coding passes +************************************************************************ +*/ + +void wpxInitWPXPasses( VideoParameters *p_Vid, InputParameters *p_Inp ) +{ + // initialize number of wp reference frames in each list + p_Vid->pWPX->num_wp_ref_list[LIST_0] = 0; + p_Vid->pWPX->num_wp_ref_list[LIST_1] = 0; + + switch( p_Inp->WPMCPrecision ) + { + default: + case 0: + break; + case 1: + p_Vid->pWPX->wp_rd_passes[0].algorithm = WP_REGULAR; + p_Vid->pWPX->wp_rd_passes[1].algorithm = WP_MCPREC_MINUS0; + break; + case 2: + p_Vid->pWPX->wp_rd_passes[0].algorithm = WP_REGULAR; + p_Vid->pWPX->wp_rd_passes[1].algorithm = WP_MCPREC_MINUS0; + p_Vid->pWPX->wp_rd_passes[2].algorithm = WP_MCPREC_MINUS1; + break; + } +} + +/*! +************************************************************************ +* \brief +* Modifies ref_pic_list for all lists +************************************************************************ +*/ + +void wpxModifyRefPicList( Slice *currSlice ) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + unsigned int i, j, cloned_refs; + int default_order_list0[32]; + int default_order_list1[32]; + int re_order[32], *list_order; + int pred_list; + DecodedPictureBuffer *p_Dpb = currSlice->p_Dpb; + + StorablePicture **list; + + // set memory + memset( (void *)default_order_list0, 1<<20, 32 * sizeof( int ) ); + memset( (void *)default_order_list1, 1<<20, 32 * sizeof( int ) ); + memset( (void *)re_order, 1<<20, 32 * sizeof( int ) ); + + // First assign default list orders + list = currSlice->listX[LIST_0]; + for (i=0; i<(unsigned int)(currSlice->num_ref_idx_active[LIST_0]); i++) + { + default_order_list0[i] = list[i]->pic_num; + } + if ( currSlice->slice_type == B_SLICE ) + { + list = currSlice->listX[LIST_1]; + for (i=0; i<(unsigned int)(currSlice->num_ref_idx_active[LIST_1]); i++) + { + default_order_list1[i] = list[i]->pic_num; + } + } + + // obtain the ref_pic_list using POC-based reordering if currSlice->slice_type != B_SLICE + if ( currSlice->slice_type == P_SLICE ) + { + int list_sign[32]; + int poc_diff[32]; + int tmp_value; + int abs_poc_dist; + + for (i=0; i < p_Dpb->ref_frames_in_buffer; i++) + { + re_order[i] = p_Dpb->fs_ref[i]->frame->pic_num; + if (p_Dpb->fs_ref[i]->is_used==3 && (p_Dpb->fs_ref[i]->frame->used_for_reference)&&(!p_Dpb->fs_ref[i]->frame->is_long_term)) + { + abs_poc_dist = iabs(p_Dpb->fs_ref[i]->frame->poc - p_Vid->enc_picture->poc) ; + poc_diff[i] = abs_poc_dist; + list_sign[i] = (p_Vid->enc_picture->poc < p_Dpb->fs_ref[i]->frame->poc) ? +1 : -1; + } + } + + // sort these references based on poc (temporal) distance + for (i=0; i< p_Dpb->ref_frames_in_buffer-1; i++) + { + for (j=i+1; j< p_Dpb->ref_frames_in_buffer; j++) + { + if (poc_diff[i]>poc_diff[j] || (poc_diff[i] == poc_diff[j] && list_sign[j] > list_sign[i])) + { + tmp_value = poc_diff[i]; + poc_diff[i] = poc_diff[j]; + poc_diff[j] = tmp_value; + tmp_value = re_order[i]; + re_order[i] = re_order[j]; + re_order[j] = tmp_value ; + tmp_value = list_sign[i]; + list_sign[i] = list_sign[j]; + list_sign[j] = tmp_value ; + } + } + } + } + // end of POC-based reordering of P_SLICE + + // loop over two lists + for ( pred_list = 0; pred_list < (1 + ( currSlice->slice_type == B_SLICE ? 1 : 0 )); pred_list++ ) + { + if ( pred_list == LIST_0 ) + { + list_order = (currSlice->slice_type == P_SLICE) ? re_order : default_order_list0; + } + else + { + list_order = default_order_list1; + } + + // check algorithms (more flexibility for the future...) + switch( p_Vid->pWPX->curr_wp_rd_pass->algorithm ) + { + default: + case WP_MCPREC_PLUS0: + case WP_MCPREC_PLUS1: + case WP_MCPREC_MINUS0: + case WP_MCPREC_MINUS1: + // ref 0 and 1 point to to the same reference + cloned_refs = p_Vid->pWPX->num_wp_ref_list[pred_list] = 2; + for ( j = 0; j < cloned_refs; j++ ) + { + p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[0]; + } + // shift the rest + for ( j = cloned_refs; j < p_Dpb->ref_frames_in_buffer; j++ ) + { + p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[j - (cloned_refs - 1)]; + p_Vid->pWPX->num_wp_ref_list[pred_list]++; + } + break; + case WP_MCPREC_MINUS_PLUS0: + // ref 0 and 1 point to to the same reference + cloned_refs = p_Vid->pWPX->num_wp_ref_list[pred_list] = 3; + for ( j = 0; j < cloned_refs; j++ ) + { + p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[0]; + } + // shift the rest + for ( j = cloned_refs; j < p_Dpb->ref_frames_in_buffer; j++ ) + { + p_Vid->pWPX->wp_ref_list[pred_list][j].PicNum = list_order[j - (cloned_refs - 1)]; + p_Vid->pWPX->num_wp_ref_list[pred_list]++; + } + break; + } + // constrain list length + p_Vid->pWPX->num_wp_ref_list[pred_list] = imin( p_Vid->pWPX->num_wp_ref_list[pred_list], + ( pred_list == LIST_0 ) ? currSlice->num_ref_idx_active[LIST_0] : currSlice->num_ref_idx_active[LIST_1] ); + } +} + +/*! +************************************************************************ +* \brief +* Determine whether it is fine to determine WP parameters +************************************************************************ +*/ + +int wpxDetermineWP( Slice *currSlice, int clist, int n ) +{ + VideoParameters *p_Vid = currSlice->p_Vid; + InputParameters *p_Inp = currSlice->p_Inp; + int i, j, determine_wp = 0; + short default_weight[3]; + // we assume it's the same as in the WP functions + short luma_log_weight_denom = 5; + short chroma_log_weight_denom = 5; + int cur_list = LIST_0; + + default_weight[0] = 1 << luma_log_weight_denom; + default_weight[1] = 1 << chroma_log_weight_denom; + default_weight[2] = 1 << chroma_log_weight_denom; + + if ( !p_Inp->WPMCPrecision ) + { + determine_wp = 1; + } + else + { + determine_wp = 0; + // check slice type + if ( currSlice->slice_type == P_SLICE ) + { + for (i = 0; i < 3; i++) + { + currSlice->wp_weight[clist][n][i] = default_weight[i]; + } + } + else if ( currSlice->slice_type == B_SLICE ) + { + cur_list = ((clist & 0x01) == LIST_1) ? LIST_0 : LIST_1; + + // single-list prediction + for (i = 0; i < 3; i++) + { + currSlice->wp_weight[clist][n][i] = default_weight[i]; + } + // bi-pred + for (j = 0; j < currSlice->listXsize[cur_list]; j++) + { + for (i = 0; i < 3; i++) + currSlice->wbp_weight[clist][n][j][i] = default_weight[i]; + } + } + // algorithm consideration + switch( p_Vid->pWPX->curr_wp_rd_pass->algorithm ) + { + case WP_MCPREC_PLUS0: + for (i = 0; i < 3; i++) + currSlice->wp_offset[clist][n][i] = (n == 1) ? 1 : 0; + break; + case WP_MCPREC_MINUS0: + for (i = 0; i < 3; i++) + currSlice->wp_offset[clist][n][i] = (n == 1) ? -1 : 0; + break; + case WP_MCPREC_PLUS1: + for (i = 0; i < 3; i++) + currSlice->wp_offset[clist][n][i] = (n == 0) ? 1 : 0; + break; + case WP_MCPREC_MINUS1: + for (i = 0; i < 3; i++) + currSlice->wp_offset[clist][n][i] = (n == 0) ? -1 : 0; + break; + case WP_MCPREC_MINUS_PLUS0: + for (i = 0; i < 3; i++) + currSlice->wp_offset[clist][n][i] = (n == 1) ? -1 : ((n == 2) ? 1 : 0); + break; + default: + case WP_REGULAR: + determine_wp = 1; + break; + } + // check list (play with the WP factors) + if ( currSlice->slice_type == B_SLICE && cur_list == LIST_0 ) + { + for (i = 0; i < 3; i++) + currSlice->wp_offset[clist][n][i] *= 2; + } + // zero out chroma offsets + for (i = 1; i < 3; i++) + { + currSlice->wp_offset[clist][n][i] = 0; + } + } + + return determine_wp; +} + +/*! +************************************************************************ +* \brief +* Modify number of references +************************************************************************ +*/ + +void wpxAdaptRefNum( Slice *currSlice ) +{ + InputParameters *p_Inp = currSlice->p_Inp; + VideoParameters *p_Vid = currSlice->p_Vid; +#if (MVC_EXTENSION_ENABLE) + int view_id = p_Vid->view_id; +#else + int view_id = 0; +#endif + + if ( p_Vid->pWPX->curr_wp_rd_pass->algorithm == WP_REGULAR ) + { + switch( currSlice->slice_type ) + { + default: + case I_SLICE: + break; + case P_SLICE: + if ( currSlice->num_ref_idx_active[LIST_0] == ( p_Inp->P_List0_refs[view_id] * ((currSlice->structure !=0) + 1) ) ) + { + currSlice->listXsize[LIST_0] = currSlice->num_ref_idx_active[LIST_0] = (char) imax( ((currSlice->structure !=0) + 1), currSlice->num_ref_idx_active[LIST_0] - ((currSlice->structure !=0) + 1) ); + } + break; + case B_SLICE: + if ( currSlice->num_ref_idx_active[LIST_0] == ( p_Inp->B_List0_refs[view_id] * ((currSlice->structure !=0) + 1) ) ) + { + currSlice->listXsize[LIST_0] = currSlice->num_ref_idx_active[LIST_0] = (char) imax( ((currSlice->structure !=0) + 1), currSlice->num_ref_idx_active[LIST_0] - ((currSlice->structure !=0) + 1) ); + } + if ( currSlice->num_ref_idx_active[LIST_1] == ( p_Inp->B_List1_refs[view_id] * ((currSlice->structure !=0) + 1) ) ) + { + currSlice->listXsize[LIST_1] = currSlice->num_ref_idx_active[LIST_1] = (char) imax( ((currSlice->structure !=0) + 1), currSlice->num_ref_idx_active[LIST_1] - ((currSlice->structure !=0) + 1) ); + } + break; + } + } +} diff --git a/lencod_vc10.vcxproj b/lencod_vc10.vcxproj new file mode 100644 index 0000000..2c72ed2 --- /dev/null +++ b/lencod_vc10.vcxproj @@ -0,0 +1,525 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + lencod + {9A39F1B7-3DFE-4263-8C02-8070F7D99AFA} + lencod + + + + Application + + + Application + + + Application + + + Application + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\bin\ + .\bin\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + true + true + .\bin\ + .\bin\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + false + false + + + + .\lencod/$(Configuration)_$(Platform)_vc9/lencod.tlb + + + + + Disabled + lencod/inc;lcommon/inc;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + false + + + .\lencod/$(Configuration)_$(Platform)_vc9/lencod.pch + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + true + Level3 + true + EditAndContinue + Default + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\lencod/$(Configuration)_$(Platform)_vc10/lencod.pdb + Console + false + + + MachineX86 + + + + + .\lencod/$(Configuration)_$(Platform)_vc9/lencod.tlb + + + + + Disabled + lencod/inc;lcommon/inc;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + false + + + .\lencod/$(Configuration)_$(Platform)_vc10/lencod.pch + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + true + Level3 + true + ProgramDatabase + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\lencod/$(Configuration)_$(Platform)_vc10/lencod.pdb + Console + false + + + + + + + .\lencod\$(Configuration)_$(Platform)_vc9/lencod.tlb + + + + + MaxSpeed + AnySuitable + lencod\inc;lcommon\inc;%(AdditionalIncludeDirectories) + WIN32;DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + false + + + .\lencod\$(Configuration)_$(Platform)_vc9/lencod.pch + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + true + Level3 + true + ProgramDatabase + Default + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /FIXED:NO %(AdditionalOptions) + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\lencod\$(Configuration)_$(Platform)_vc9/lencod.pdb + Console + false + + + MachineX86 + + + + + .\lencod\$(Configuration)_$(Platform)_vc9/lencod.tlb + + + + + MaxSpeed + AnySuitable + lencod\inc;lcommon\inc;%(AdditionalIncludeDirectories) + WIN32;DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreaded + true + false + + + .\lencod\$(Configuration)_$(Platform)_vc10/lencod.pch + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + .\lencod\$(Configuration)_$(Platform)_vc10\ + true + Level3 + true + ProgramDatabase + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /FIXED:NO %(AdditionalOptions) + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + .\lencod\$(Configuration)_$(Platform)_vc10/lencod.pdb + Console + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lencod_vc10.vcxproj.filters b/lencod_vc10.vcxproj.filters new file mode 100644 index 0000000..8ace497 --- /dev/null +++ b/lencod_vc10.vcxproj.filters @@ -0,0 +1,787 @@ + + + + + + + + + {38ba5398-c621-4c6f-a003-bd04c2d69989} + + + {cf3919dc-b0a3-47bb-bc41-b5cdb7f032b6} + + + {2187edb6-51a1-40f5-aa88-c7336509cc35} + + + {c774c2aa-4bbe-4343-8cda-2c1546cbfdab} + + + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Common Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Project Header Files + + + Common Header Files + + + Project Header Files + + + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Project Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + Common Source Files + + + src + + + src + + + Project Source Files + + + Common Source Files + + + Project Source Files + + + \ No newline at end of file diff --git a/lencod_vc10.vcxproj.user b/lencod_vc10.vcxproj.user new file mode 100644 index 0000000..b1d8a11 --- /dev/null +++ b/lencod_vc10.vcxproj.user @@ -0,0 +1,27 @@ + + + + -d trans_encoder_config_base.cfg + + + ..\jm_debug + WindowsLocalDebugger + + + -d trans_encoder_config_base.cfg + + + ..\jm_debug + WindowsLocalDebugger + + + -d encoder_debug.cfg + WindowsLocalDebugger + ..\jm_debug + + + -d trans_encoder_config_base.cfg + WindowsLocalDebugger + ..\jm_debug + + \ No newline at end of file diff --git a/lencod_vc7.vcproj b/lencod_vc7.vcproj new file mode 100644 index 0000000..b34b85a --- /dev/null +++ b/lencod_vc7.vcproj @@ -0,0 +1,1170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lencod_vc8.vcproj b/lencod_vc8.vcproj new file mode 100644 index 0000000..686bed2 --- /dev/null +++ b/lencod_vc8.vcproj @@ -0,0 +1,1980 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lencod_vc9.vcproj b/lencod_vc9.vcproj new file mode 100644 index 0000000..71d39a3 --- /dev/null +++ b/lencod_vc9.vcproj @@ -0,0 +1,1384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtp_loss/Makefile b/rtp_loss/Makefile new file mode 100644 index 0000000..9a0c45e --- /dev/null +++ b/rtp_loss/Makefile @@ -0,0 +1,97 @@ +### +### Makefile for H.264/AVC RTP loss tool +### +### generated for UNIX/LINUX environments +### by H. Schwarz, Limin Wang +### + + + +NAME= rtp_loss + +### include debug information: 1=yes, 0=no +DBG?= 0 +### enforce 32-bit build : 1=yes, 0=no +M32?= 0 + +DEPEND= dependencies + +BINDIR= ../bin +INCDIR= . +SRCDIR= . +OBJDIR= obj + + +LIBS= -lm +AFLAGS= +CFLAGS= -ffloat-store -fsigned-char +FLAGS= $(CFLAGS) -Wall -I$(INCDIR) -D __USE_LARGEFILE64 -D _FILE_OFFSET_BITS=64 + +ifeq ($(M32),1) +FLAGS+=-m32 +endif + +ifeq ($(DBG),1) +SUFFIX= .dbg +FLAGS+= -g +else +SUFFIX= +FLAGS+= -O2 + +endif + +OBJSUF= .o$(SUFFIX) + +SRC= $(wildcard $(SRCDIR)/*.cpp) +OBJ= $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o$(SUFFIX)) +BIN= $(BINDIR)/$(NAME)$(SUFFIX).exe + +.PHONY: default distclean clean tags depend + +default: messages objdir_mk depend bin + +messages: +ifeq ($(M32),1) + @echo 'Compiling with M32 support...' +endif +ifeq ($(DBG),1) + @echo 'Compiling with Debug support...' +endif + +clean: + @echo remove all objects + @rm -rf $(OBJDIR) + +distclean: clean + @rm -f $(DEPEND) tags + @rm -f $(BIN) + +tags: + @echo update tag table + @ctags *.h *.cpp + +bin: $(OBJ) + @echo + @echo 'creating binary "$(BIN)"' + @$(CXX) $(FLAGS) -o $(BIN) $(OBJ) $(LIBS) + @echo '... done' + @echo + +depend: + @echo + @echo 'checking dependencies' + @$(SHELL) -ec '$(CXX) $(FLAGS) -MM $(CFLAGS) -I$(INCDIR) $(SRC) \ + | sed '\''s@\(.*\)\.o[ :]@$(OBJDIR)/\1.o$(SUFFIX):@g'\'' \ + >$(DEPEND)' + @echo + +$(OBJDIR)/%.o$(SUFFIX): $(SRCDIR)/%.cpp + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +objdir_mk: + @echo 'Creating $(OBJDIR) ...' + @mkdir -p $(OBJDIR) + +-include $(DEPEND) + diff --git a/rtp_loss/ReadMe.txt b/rtp_loss/ReadMe.txt new file mode 100644 index 0000000..68b1c5d --- /dev/null +++ b/rtp_loss/ReadMe.txt @@ -0,0 +1,13 @@ +This programm can be used to simulate packet loss on RTP files. The C random number +generator is used for selecting the packets. The random number generator is not +initialized befur usage. Therefore subsequent runs of the tool will create identical +loss pattern. + +usage: + + rtp_loss.exe infile outfile losspercent + + + is an optinal parameter that specifies the number of RTP +packets that are kept at the beginning of the file. This can be useful if the loss +of parameter sets or IDR pictures shall be avoided. diff --git a/rtp_loss/rtp_loss.cpp b/rtp_loss/rtp_loss.cpp new file mode 100644 index 0000000..86c273f --- /dev/null +++ b/rtp_loss/rtp_loss.cpp @@ -0,0 +1,136 @@ +// rtp_loss.cpp : Defines the entry point for the console application. +// + +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +void print_usage(char *argv []) +{ + printf ("Usage: %s input_file output_file loss_percent \n", argv[0]); + exit (-1); +} + +int keep_packet(int loss_percent) +{ + int rnd; + if (loss_percent>100) + return 1; + if (loss_percent<=0) + return 0; + + rnd = int (100 * (((float) rand()) / RAND_MAX)); + + return (rnd >= loss_percent ); +} + +int main(int argc, char* argv[]) +{ + unsigned int bufsize, pacno=0; + unsigned char buf[65000]; + int i, intime; + FILE *fr; // file for reading + FILE *fw; // file for writing + + + if ((argc != 4) && (argc != 5)) + { + print_usage (argv); + } + + if (NULL == (fr = fopen (argv[1], "rb"))) + { + printf ("%s: cannot open H.264 packet file %s for reading\n", argv[0], argv[1]); + return -2; + } + + if (NULL == (fw = fopen (argv[2], "wb"))) + { + printf ("%s: cannot open H.264 packet file %s for reading\n", argv[0], argv[1]); + fclose (fr); + return -2; + } + + + if (argc==5) + { + for (i=0; i< atoi (argv[4]); i++) + { + if (4 != fread (&bufsize, 1, 4, fr)) + return 0; + if (4 != fread (&intime, 1, 4, fr)) + { + printf ("Panic, cannot read timestamp, old software version file?\n"); + return -1; + } + if (bufsize != fread (buf, 1, bufsize, fr)) + { + printf ("Problems while reading buffer, exit\n"); + return -3; + } + + if (4 != fwrite (&bufsize, 1, 4, fw)) + { + printf ("Problems while writing buffer size, exit\n"); + return -1; + } + if (4 != fwrite (&intime, 1, 4, fw)) + { + printf ("Problems while writing timestamp, exit\n"); + return -1; + } + if (bufsize != fwrite (buf, 1, bufsize, fw)) + { + printf ("Problems while writing buffer, exit\n"); + return -3; + } + pacno++; + } + + } + + for (;;) + { + if (4 != fread (&bufsize, 1, 4, fr)) + return 0; + if (4 != fread (&intime, 1, 4, fr)) + { + printf ("Panic, cannot read timestamp, old software version file?\n"); + return -1; + } + if (bufsize != fread (buf, 1, bufsize, fr)) + { + printf ("Problems while reading buffer, exit\n"); + return -3; + } + if (keep_packet(atoi (argv[3]))) + { + if (4 != fwrite (&bufsize, 1, 4, fw)) + { + printf ("Problems while writing buffer size, exit\n"); + return -1; + } + if (4 != fwrite (&intime, 1, 4, fw)) + { + printf ("Problems while writing timestamp, exit\n"); + return -1; + } + if (bufsize != fwrite (buf, 1, bufsize, fw)) + { + printf ("Problems while writing buffer, exit\n"); + return -3; + } + } + else + { + printf ("lost packet #%d\n", pacno); + } + pacno++; + + } +} diff --git a/rtp_loss/rtp_loss.h b/rtp_loss/rtp_loss.h new file mode 100644 index 0000000..e69de29 diff --git a/rtp_loss/rtp_loss_vc10.vcxproj b/rtp_loss/rtp_loss_vc10.vcxproj new file mode 100644 index 0000000..1e173f3 --- /dev/null +++ b/rtp_loss/rtp_loss_vc10.vcxproj @@ -0,0 +1,90 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {5160AFF8-033C-4944-8AD7-6E960344640F} + Win32Proj + rtp_loss_vc10 + rtp_loss + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + ..\bin\ + $(Configuration)_$(Platform)_vc10\ + + + false + ..\bin\ + $(Configuration)_$(Platform)_vc10\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/rtp_loss/rtp_loss_vc10.vcxproj.user b/rtp_loss/rtp_loss_vc10.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/rtp_loss/rtp_loss_vc10.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/rtp_loss/rtp_loss_vc7.vcproj b/rtp_loss/rtp_loss_vc7.vcproj new file mode 100644 index 0000000..0bce436 --- /dev/null +++ b/rtp_loss/rtp_loss_vc7.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtp_loss/rtp_loss_vc8.vcproj b/rtp_loss/rtp_loss_vc8.vcproj new file mode 100644 index 0000000..0c8f507 --- /dev/null +++ b/rtp_loss/rtp_loss_vc8.vcproj @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtp_loss/rtp_loss_vc9.vcproj b/rtp_loss/rtp_loss_vc9.vcproj new file mode 100644 index 0000000..1f37171 --- /dev/null +++ b/rtp_loss/rtp_loss_vc9.vcproj @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtpdump/Makefile b/rtpdump/Makefile new file mode 100644 index 0000000..9861833 --- /dev/null +++ b/rtpdump/Makefile @@ -0,0 +1,96 @@ +### +### Makefile for H.264/AVC RTP dump tool +### +### generated for UNIX/LINUX environments +### by H. Schwarz, Limin Wang +### + + + +NAME= rtpdump + +### include debug information: 1=yes, 0=no +DBG?= 0 +### enforce 32-bit build : 1=yes, 0=no +M32?= 0 + +DEPEND= dependencies + +BINDIR= ../bin +INCDIR= . +SRCDIR= . +OBJDIR= obj + + +LIBS= -lm +CFLAGS= -ffloat-store -fsigned-char +FLAGS= $(CFLAGS) -Wall -I$(INCDIR) -D __USE_LARGEFILE64 -D _FILE_OFFSET_BITS=64 + +ifeq ($(M32),1) +FLAGS+=-m32 +endif + +ifeq ($(DBG),1) +SUFFIX= .dbg +FLAGS+= -g +else +SUFFIX= +FLAGS+= -O2 + +endif + +OBJSUF= .o$(SUFFIX) + +SRC= $(wildcard $(SRCDIR)/*.cpp) +OBJ= $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o$(SUFFIX)) +BIN= $(BINDIR)/$(NAME)$(SUFFIX).exe + +.PHONY: default distclean clean tags depend + +default: messages objdir_mk depend bin + +messages: +ifeq ($(M32),1) + @echo 'Compiling with M32 support...' +endif +ifeq ($(DBG),1) + @echo 'Compiling with Debug support...' +endif + +clean: + @echo remove all objects + @rm -rf $(OBJDIR) + +distclean: clean + @rm -f $(DEPEND) tags + @rm -f $(BIN) + +tags: + @echo update tag table + @ctags *.h *.cpp + +bin: $(OBJ) + @echo + @echo 'creating binary "$(BIN)"' + @$(CXX) $(FLAGS) -o $(BIN) $(OBJ) $(LIBS) + @echo '... done' + @echo + +depend: + @echo + @echo 'checking dependencies' + @$(SHELL) -ec '$(CXX) $(FLAGS) -MM $(CFLAGS) -I$(INCDIR) $(SRC) \ + | sed '\''s@\(.*\)\.o[ :]@$(OBJDIR)/\1.o$(SUFFIX):@g'\'' \ + >$(DEPEND)' + @echo + +$(OBJDIR)/%.o$(SUFFIX): $(SRCDIR)/%.cpp + @echo 'compiling object file "$@" ...' + @$(CC) -c -o $@ $(FLAGS) $< + +objdir_mk: + @echo 'Creating $(OBJDIR) ...' + @mkdir -p $(OBJDIR) + +-include $(DEPEND) + diff --git a/rtpdump/ReadMe.txt b/rtpdump/ReadMe.txt new file mode 100644 index 0000000..7e3db1b --- /dev/null +++ b/rtpdump/ReadMe.txt @@ -0,0 +1,34 @@ +======================================================================== + CONSOLE APPLICATION : rtpdump +======================================================================== + + +AppWizard has created this rtpdump application for you. + +This file contains a summary of what you will find in each of the files that +make up your rtpdump application. + +rtpdump.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +rtpdump.cpp + This is the main application source file. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named rtpdump.pch and a precompiled types file named StdAfx.obj. + + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/rtpdump/rtpdump.cpp b/rtpdump/rtpdump.cpp new file mode 100644 index 0000000..7be3ac6 --- /dev/null +++ b/rtpdump/rtpdump.cpp @@ -0,0 +1,72 @@ + +// rtpdump.cpp : Defines the entry point for the console application. +// + +#include +#include +#include +#if defined(WIN32) || defined(WIN64) +#include +#else +#include +#endif + + +int main(int argc, char* argv[]) +{ + unsigned int bufsize, pacno=0, temp32; + unsigned short temp16; + unsigned char buf[65000]; + int i, intime; + FILE *f; + + if (argc != 2) + { + printf ("Usage: %s \n", argv[0]); + return -1; + } + + if (NULL == (f = fopen (argv[1], "rb"))) + { + printf ("%s: cannot open H.264 packet file %s for reading\n", argv[0], argv[1]); + return -2; + } + + for (;;) + { + if (4 != fread (&bufsize, 1, 4, f)) + return 0; + + if (4 != fread (&intime, 1, 4, f)) + { + printf ("Panic, cannot read timestamp, old software version file?\n"); + return -1; + } + printf ("\n\npacket #%4d containing %5d bytes\n", pacno++, bufsize); + if (bufsize != fread (buf, 1, bufsize, f)) + { + printf ("Problems while reading buffer, exit\n"); + return -3; + } + + for (i=0; i< 25; i++) + printf ("%02x ", buf[i]); + + printf ("\n"); + printf ("Version (V): %d\n", (buf[0] >> 6) & 0x03); + printf ("Padding (P): %d\n", (buf[0] >> 5) & 0x01); + printf ("Extension (X): %d\n", (buf[0] >> 4) & 0x01); + printf ("CSRC count (CC): %d\n", (buf[0] >> 0) & 0x0F); + printf ("Marker bit (M): %d\n", (buf[1] >> 7) & 0x01); + printf ("Payload Type (PT): %d\n", (buf[1] >> 0) & 0x7F); + memcpy (&temp16, &buf[2], 2); + printf ("Sequence Number: %d\n", ntohs(temp16)); + memcpy (&temp32, &buf[4], 4); + printf ("Timestamp: %d\n", ntohl(temp32)); + memcpy (&temp32, &buf[8], 4); + printf ("SSRC: %d\n", ntohl(temp32)); + + printf ("First Byte: 0x%x\n", buf[12]); + } +} + diff --git a/rtpdump/rtpdump_vc10.vcxproj b/rtpdump/rtpdump_vc10.vcxproj new file mode 100644 index 0000000..3574ee0 --- /dev/null +++ b/rtpdump/rtpdump_vc10.vcxproj @@ -0,0 +1,307 @@ + + + + + Debug_Analyser + Win32 + + + Debug_Analyser + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release_Analyser + Win32 + + + Release_Analyser + x64 + + + Release + Win32 + + + Release + x64 + + + + rtpdump + {BE2D5D97-BD3F-489B-A346-123834DDDBBD} + + + + Application + Unicode + true + + + Application + Unicode + true + + + Application + Unicode + true + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + + + Application + Unicode + + + Application + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\ + ..\bin\ + ..\bin\ + ..\bin\ + $(Configuration)_$(Platform)_vc10\ + $(Configuration)_$(Platform)_vc10\ + $(Configuration)_$(Platform)_vc10\ + $(Configuration)_$(Platform)_vc10\ + true + true + true + true + ..\bin\ + ..\bin\ + ..\bin\ + ..\bin\ + $(Configuration)_$(Platform)_vc10\ + $(Configuration)_$(Platform)_vc10\ + $(Configuration)_$(Platform)_vc10\ + $(Configuration)_$(Platform)_vc10\ + false + false + false + false + + + + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + Console + false + + + MachineX86 + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + Console + false + + + MachineX86 + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + Console + false + + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + Console + false + + + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + Console + true + true + false + + + MachineX86 + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + Console + true + true + false + + + MachineX86 + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + Console + true + true + false + + + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + Console + true + true + false + + + + + + + + + + + \ No newline at end of file diff --git a/rtpdump/rtpdump_vc10.vcxproj.user b/rtpdump/rtpdump_vc10.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/rtpdump/rtpdump_vc10.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/rtpdump/rtpdump_vc7.vcproj b/rtpdump/rtpdump_vc7.vcproj new file mode 100644 index 0000000..861a771 --- /dev/null +++ b/rtpdump/rtpdump_vc7.vcproj @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtpdump/rtpdump_vc8.vcproj b/rtpdump/rtpdump_vc8.vcproj new file mode 100644 index 0000000..f1650de --- /dev/null +++ b/rtpdump/rtpdump_vc8.vcproj @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtpdump/rtpdump_vc9.vcproj b/rtpdump/rtpdump_vc9.vcproj new file mode 100644 index 0000000..d47eb9c --- /dev/null +++ b/rtpdump/rtpdump_vc9.vcproj @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/unixprep.sh b/unixprep.sh new file mode 100644 index 0000000..246d4e1 --- /dev/null +++ b/unixprep.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +which sed || (echo "sed unavailable" 1>&2; exit 1) + +echo "Removing DOS LF chars..." +for f in l[ed][ne]cod/[si][rn]c/*.[ch] bin/*.cfg +do + sed -e "s/ //" < $f >$f.tmp && mv $f.tmp $f +done + +for f in l[ed][ne]cod/Makefile +do + sed -e "s/ //" < $f >$f.tmp && mv $f.tmp $f +done + +for f in rtpdump/*.cpp rtpdump/Makefile +do + sed -e "s/ //" < $f >$f.tmp && mv $f.tmp $f +done + +for f in rtp_loss/*.cpp rtp_loss/*.h rtp_loss/Makefile +do + sed -e "s/ //" < $f >$f.tmp && mv $f.tmp $f +done + + +echo "Done." +